像维护软件一样维护效率系统

7

标题可能会让人误以为我要介绍精密复杂的 PKM 体系,但实际上我 我不混“知识管理圈” 很久了。我想我数次安装和卸载 Emacs,仍然用 Neovim 写代码和写文,一部分原因是 Org Mode 对我毫无吸引力,甚至有可能会害了我。

好的软件不总是精巧复杂的,甚至大部分时候是简单的,或者说清晰明了,而且可拓展、可组合,在需要的时候不会因其形式或接口而派不上用场。比方说 grep 作为命令行工具,可以搜文件里的文本、可以搜目录里的文件名、可以搜终端历史里输入过的命令,也可以很轻易地集成到其他软件里搜别的东西。

这其实也不是我想谈的重点。实际上,即便是 grep 这样小巧简明的软件,在某些情况下也难以施展拳脚,比如面对完全不了解命令行界面的用户时。对他们而言,Raycast 和 Vicinae 等全局搜索框可能更好用,按下 ⌘ + 空格 就可以搜索应用、文件和各种快捷命令并执行。把两个关联不大的软件放在一起比较可能不恰当,但至少能证明我下面要抛出的观点:

好的软件应该是符合需求的软件。

想象你年迈的奶奶一点也看不清楚手机上的小字,而你却在一旁抱怨软件开发者没能统一设计语言,竟然在界面上放这么大的字儿和这么老派的配色,还给了这么多乱七八糟的设置项,一点也不优雅——这可不是好事。

用户画像和需求获取

我有点不太理解为什么有人喜欢浏览各种花哨的 Notion 模板,就像我用不了现成的 Neovim 和 Emacs 配置一样,噪音太多了。有人试图说服我一点一点来,有些功能放在那里不用就好。然而「不管某些小细节」对我来说很难,我需要在大脑里自己起一个垃圾收集器,持续不断地消耗 CPU,就为了释放内存。貌似许多人的 GC 是编程语言自带的,甚至可能 像 Java 一样 ,大部分时候都不运行。

最近我意识到这可能是我的神经特异性导致的。我今年才开始正视自己的孤独症(Autism)特质。神经多样性好像已经变成玩笑话了,大家说「自己没点病都不好意思上网」,我厌恶甚至指责这种说辞。要指责的一方面是把神经特异当作「神经反常」「精神病」的陈旧思想,另一方面是,这种说辞看似在攻击无病呻吟者,实际上加剧了神经特异者的边缘化,因为这话背后的意思是:大部分说自己是 ADHD 或 ASD 的人都在装酷。那真正的 ADHD 和 ASD 还怎么敢站在公共面前呢?而且他们本来就更不善社交。

我跑题了。我想说的是,我的确有很多孤独症人群常见的特质,而且这些特质影响了我的日常生活,也影响了我对自我管理体系的需求。

首先,我对感官信号过于敏感,我希望系统本身的感官刺激可控且令我安心。这几天看了一期讲 孤独症人群感官体验 的视频,频道主说自己睡觉的时候会觉得自己的心跳声像摇滚演唱会一样吵,我也是!我时常在半夜起身反复确认有没有地震,因为我的心跳好像震得我全身都在动一样。我和频道主一样,也会忧虑是不是自己的心脏有问题,然后为此辗转反侧。实际上就是我对某些信号太敏感了。

不只是自己的心跳,环境噪音也是。我不喜欢去酒吧这种吵的地方(清吧会好很多),因为要主动屏蔽杂乱的环境信息很累。就算是相对安静的环境,我也时常听到其他人没注意到的声响和小细节——这是一体两面的,对细节的关注在某些情况下是优势,但也是需要正视的劣势。

如果我的效率工具有太多不可控的感官刺激,我用起来会觉得很累。飞书的多维表格就是反例,它大体上是即时通信工具,我很难不被侧边栏的消息和表格各种花里胡哨的浮窗、工具栏分心。即便我并没有点击那些东西的欲望,我也会觉得要感官过载了。

我的情况可能还要再极端一点,我去年 全面抛弃了数字记录 ,因为电子设备本身就是极大的感官干扰。即便全屏打开笔记编辑器,只运行一个应用,我的脑海中也会冒出数种可能性——这就不是感官刺激的范畴了,和注意力机制的关联更大。

之所以 Doom Emacs 里提前配置好的各种插件让我坐立难安,而 Clojure 标准库里丰富的函数并不会对我造成困扰,是因为函数在形式上是单一且确定的,只要当作接收参数然后返回特定值的黑箱就好,而 Emacs Mode 千千万,有的能收发邮件,有的能看 RSS 和 Hacker News,有的还能在 Matrix 上发消息,我永远也不知道下一个会以什么形式出现。

我希望系统的形式足够简单,简单到用几种甚至一种要素就能表示我想要表示的所有东西。就像 Lisp 只需要用 s-expr 就能表示所有的语言单元一样,我希望我在管理待办事项和备忘的时候,不需要频繁切换思维方式。

下一个需求有点矫情:我不喜欢有人教我做事。我至今没办法在别人看着我的情况下工作(不久前我的同事跟我交流工作的时候,盯着我写 Agent 的提示词,我感觉自己要爆炸了,原因很复杂)。我能接收批评指正,我不会把情绪带到工作上来,我也很少让情绪影响周围的人,但这意味着我要在大脑里另起一个线程,处理自己的胡思乱想。我当然不希望我自己的系统过于严格,让我没有喘息的机会,我希望我使用它的时候,心情是愉悦的,能立马感受到事情在我的掌控之内。

系统又不是主体,它怎么会教你做事?怎么会审判你?可很多时候就是这样。我错过了自己设置的截止日期,或者在安排要做某件事情的时间里提不起劲儿,我会责备自己太拖延、太懒惰。某个待办上写的事情我只做了一半,但当天已经结束了,我只能推迟到下一天——我知道给框框画勾很爽,但划掉框框再移动到下一页,糟糕的感觉也程度相当。

我还常常有这样的体验:做了某些事情之后(往往是逼自己做的),感觉身体很沉重,就算是做自己喜欢的事情也觉得累,根本不想动。这件事情有可能仅仅是跟指导老师发信息等回复而已。之前提到的那个视频里,频道主把这种现象比作「清醒的宿醉」。在这种情况下,若还有个严格的系统管制我,让我在自己的空间里也不得安宁,我只会想逃。效率系统的效果不应该是让人想逃避做事。

简单来说,我希望,就算我完全精神崩溃,生活糟糕得不能再糟,沉闷地过了几周甚至一个月之后,只要我决定再爬起来,我就可以立马打开我的笔记本,像什么事情都没发生一样做自己该做的事情。

所以,这样一套效率系统的业务需求是:帮助易受感官刺激影响、注意力容易分散、精力波动大的用户,建立简单直接且容易管理的生活和工作计划,并且不会在执行过程中感到压力山大。

需求分析和系统建模

业务需求已经确定,那么现在应该分析用户需求了。上个阶段的产物是对业务需求的整体描述,这个阶段的产物是具体的用例(Use cases)。

用例既描述了具体的用户需求,还界定了系统与外部实体的边界。谁在系统之内?谁在系统之外?谁与系统交互?做什么交互?系统最终要实现哪些交互背后的功能?这些问题都会通过规定用例得到解答。看起来做需求分析就该写用例呢。

但是我不。

软件需求工程的各种理论在我看来既有新学科的不成熟,又十分老派。比方说下面这个需求层次图,把软件需求分成业务需求、用户需求和功能需求(以及非功能需求和约束条件)的做法,其实相当局限。

这张图片来自 这篇论文 ,是有关为中小型企业开发的电商网站的需求分析方法的案例研究。很多需求工程方法论都是针对大型软件的,因为这些软件的需求很复杂、变动大,需要工程化的方法管理和维护。

这就是老派的点。至于为什么说不成熟,是因为这类方法论不仅实际应用不广,学究气息很重,而且很快就被新的软件开发模式替代了。比方说敏捷开发就可能认为,在前期制定过大的需求规格很有可能造成浪费,默认需求是持续变动的。还有不少软件团队不交付用例,而是交付用户故事(User story)。还有一种系统建模方式就叫作 故事驱动建模 ,系统建模也是需求工程的一个环节。

话说回那些简单的软件工具。你要如何想象 grep 的需求规格说明书呢?如果现在有人要开发一个新的 Vim 编辑器,他们会怎么收集和整理需求呢?在用例里写这种东西吗?——“1. 用户输入文本;2. 用户保存文件;3. 用户查看文件。”

总之,应该根据实际需要开发的软件的类型和特质选定需求分析方法,我决定描述类似用户故事的使用场景来分析用户需求:

  1. 用户需要规划一天的计划。
    1. 将前一天尚未完成或者主动推迟的事项移动到这一天;
    2. 从一个大的待办清单里挑选一些这天可以做的,放到这一天;
    3. 添加一些临时发生或一时兴起的事项;
    • 如何减轻第一步的心理压力?
  2. 用户在一天的某个时刻,需要确定接下来做什么。
    1. 打开当天的计划并浏览未完成事项;
    2. 逐项评估用户当下做这件事情的意愿;
    3. 选择意愿最高的事项执行;
    • 如何评估意愿?
    • 所有事项的执行意愿都低下的边界情况怎么处理?
  3. 用户突然收到通知、回忆起某件事情、产生了灵机一动的想法,或者发现了新鲜事物,需要处理。
    1. 评估事项的紧迫性和执行意愿:
      • 如果必须或十分想要立刻完成,先做记录,然后执行;
      • 如果不必立刻执行,先记录到当天的计划中但不执行;
    2. 继续之前的事项;
  4. 用户在一天结束时需要回顾计划完成情况。
    1. 观察所有被记录但尚未执行完毕的计划;
    2. 评估短期内的执行意愿和执行的必要性:
      • 如果必须做,且执行意愿较高,标记为需要移动到下一天(等到情景 1 发生时处理);
      • 如果必须做,但执行意愿不高,标记为搁置,移动到未定时间的大待办清单里;
      • 如果不必做,但执行意愿较高,标记为搁置,移动到未定时间的大待办清单里;
      • 如果不必做,且执行意愿不高,直接删除。
    • 同场景 1,如何减轻这个过程的心理压力?
  5. 用户需要定期回顾不定日期的大待办清单,对于每个事项:
    1. 评估执行意愿和必要性,删除执行意愿不高且不必做的事项,留下其他事项;
    2. 评估事项的紧急性,将紧急事项插入到当天或者第二天的计划中;
    3. 对于余下的事项,如果有新的想法和细节补充,可以做备注。
    • 长期滞留在大待办清单里的事项要怎么办?

不难发现,在上述描述中,用户与系统的边界很模糊,有很多事情是需要用户参与决策的。用户也是系统的一部分,甚至说制定系统就难以避免教育用户以某种方式做事。再者,这些场景中也有些模糊和疑惑的点。

无妨,需求本身就难以捉摸。需求工程中还有一个步骤叫作需求验证,常见的方法是追踪需求的跟踪关系(也就是能不能通过功能需求倒推到具体的用户需求,用户需求能不能推到最初的业务需求)、同行评审和…… 找用户确认。

那么就让我问问自己,这些用户需求是否合理,其中的疑惑应该如何解决。

  • 如何减轻处理推迟计划的心理压力?
    • “如果能专注「怎么把所有的未完成事项都通过某种方式消除」,不管是做完的、推迟的还是取消的都一视同仁,就能减轻负担。就像消消乐一样,无论是连线消除的还是用道具消除的,消完了都会觉得爽。”
    • “不过这的确把责任交给用户了,是不是好事,大概要按情况评估。上述做法对不少用户可能无用,如果能接受用户群体缩小或部分用户不满,也是可以做这个取舍的。我认为这个体现在项目理念和用户手册里就好了。”
  • 如何评估意愿?
    • “啊,真是个刁钻的问题。想做就是想做,不想做就是不想做,这是很主观的体验欸。我认为主要问题是用户可能不会主动评估自己的意愿,习惯纠结事项本身的难易程度、紧急程度和重要程度,而很少听自己的想法。这类用户就是我们用户画像和业务需求里描述的那一类。”
    • “所以,与其尝试用另一个外在的指标量化「意愿」,不如在流程上引导用户自己做出判断。比如提问用户「从 0~5 打分,你觉得你自己有多想做这件事情?」或者「在事项 A 和 B 当中,你宁愿做哪个?」”
  • 所有事项的执行意愿都低下的边界情况怎么处理?
    • “同理,总能选出更愿意做的事情。我想系统本身也提供了一个有限的选项池,让用户不至于在一两件不想做的事情和一大堆未知、模糊的可能性里做选择,在少数事项里选择更不讨厌的,可能更容易把执行意愿提上来一点。”
    • “另外,之前业务需求的分析里还提到,目标用户容易出现精力骤降的情况。如果执行意愿都很低,可能是临时的精力问题。我们的业务需求之一就是不让用户在执行过程中感到压力,这种情况下要允许用户不做某些事情。我认为这些事情都可以通过已有的回收和推迟机制解决,也就是把事项挪到第二天或者大清单里。”
  • 长期滞留在大待办清单里的事项要怎么办?
    • “滞留会带来什么风险吗?我认为是没有的,就像系统回收站不清理,除了占用磁盘空间之外也没别的害处了,而磁盘空间可能并没有那么重要。”
    • “如果出现大量想做但短期内执行意愿不高的事项滞留,这确实是先前没有考虑过的场景,值得后续讨论。不过因为风险较低,现阶段可以先搁置,实现已有的需求就好。”

好了,已经收集完一波同行评审和用户反馈了——奇怪,回答问题这人怎么既是需求分析师,又是目标用户呢? 不过,现有的方案如果贸然投入成本开发,可能不会满足需求,因为仍有不少待定的点。然而,这些点即便是在内部反复讨论,可能也不会有突破,貌似只有投入开发才能够收集到真实的数据和反馈啊。

那就投入较小成本,做个原型产品试试看吧!

原型开发和迭代

我们其实还没有完成系统建模,这也是需求分析的一部分,但是一直纠结某个活动属于生命周期的哪个部分实在是太无聊了。不多言,直接来画状态机吧。(机什么?)

前文反复提到「记录」和「标记」的概念,一条记录可以被标记为「搁置」,可以被「移动」,还可以被「删除」。状态的变更也是规则的。简单来说,可以给系统中的记录或者说事项规定以下状态:

这张图里的方框代表待办(todo),画了一捺的方框代表正在进行(doing),打勾自然表示完成(done),删除或者说取消(cancelled)也应该是不言自明的。值得注意的是推迟(postponed)和搁置(suspended)的区别,推迟表示这件事情已经被移动到之后具体的某一天的计划里了,有了明确的去处,而搁置则与古希腊哲学的悬隔(Epoché,或者 suspension of judgement)有些关联,表示这件事情还没有去处,当下也不打算做出判断,不删也不做,应该移动到不定时间的大待办清单上。

此外,还有两个不是方框的标记,分别是事项(item)和笔记(note),前者记录那些没有计划(也不需要计划)但是做了的事情,留档记录;后者记录需要今天或这周晚些时候回顾的事情,其实更像是备忘(memo)。这看似是方框和非方框的两种形式,但其实都是对记录(record)的标记(mark)而已。一条记录由标记和描述组成,就只有这么一种直观的形式。

嗯?你问我这么设计的依据是什么?是这样的,我们观察目标用户很久了,他的笔记本上用的就是这些记号。他以前也有过别的标记体系,但最终留下来的是这么一套,对他而言足够简单直观。这难道不比花里胡哨的理论和看似严密的逻辑,更具说服力吗?

噢等等,等等,架构师先生,请您冷静一下。我知道您的函数式技术倾向让您认为状态是邪恶的,但难道您不认为我们要开发的这套系统是事件驱动的,必须要关心状态变更吗?难道你要让任务一开始就单线地递归执行到底,就为了维持清晰的数据流吗?你不觉得我们的目标用户其实并没有像猴子一样多的精力吗?嗯?你问我为什么要像英美文学里的小说人物一样说话?好吧,先生,我想我只能告诉你,写这段话的人最近不务正业,看小说看得有点太多了。

如此一来功能需求其实也比较清晰了,那么来选择技术栈吧!架构师先生,您别纠结要用 Emacs Lisp 还是 Lua 写了,客户点名儿要用 Spring Boot。唉?唉唉唉!我开玩笑的,您别掐自己人中啊!害,您瞧瞧这事儿办的。其实业务需求里写得已经很清楚了,目标用户需要感官刺激可控的,也不喜欢电子设备,我觉得呀,纸和笔就够啦。至于尺寸,咱也就别用那 A4 大夹板,也别用 A5 大活页了,客户反馈说他连 A5Slim 都写不满,还嫌重呢!A6!A6 就够啦!哎呀,您就别问我说话为什么这么像北京人啦,你又不是不知道这写字儿的人整天都在发什么神经。

我们先来看看 MVP 的效果怎么样吧。

恕我直言,女士,这就是两页非常普通,谁都能涂涂画画写出来的纸!

可先生,客户反馈他用这套方法感觉自己比以前任何时候都觉得轻松,完成的事情也不少,这难道我不是更符合需求的系统吗?先生,恕我直言,我觉得是时候拿出这张图了。

可是你看,那两页纸上还有很多不规范的地方,比如星号明明是用来标记笔记和备忘的,却也被用来给待办事项分区。笔记中间还有各种飘来飘去的箭头,根本不知道是什么意思!这系统未免有点混乱。

好问题,可这不正是让我们了解到了之前没能发现的需求吗?显然只定义记录和标记并没能解决目标用户的所有问题,他还有先前未发现的,给记录分区、分类的需求。至于那些箭头,很有可能也是我们需要建模在系统里的新要素。至于这会不会让系统变得过于复杂,难以拓展,留下技术债务,就是要进一步讨论的话题了。

CI/CD 和文档

还记得软件装在盒子里售卖的年代吗?我没经历过那个年代,我开始接触编程的时候,人们就已经完全拥抱 Web 了(如今反倒有逐渐抛弃 Web 的趋势),一切都部署在服务器上。我记得不久前还有好多人说 PHP 是最好的语言呢,如今…… 呃,PHP2Shell 的确让整个互联网都见识到了 PHP 的强悍。

再新一点的概念应该是 CI/CD,也就是持续集成,持续部署,把软件的生命周期变得更灵活了一些。软件没必要打磨到完美才发售,因为软件不再装在盒子里了,更新的成本很低。如果完全部署在云上,配合自动化工作流,也能很快把新的版本编译、打包、部署到服务器上。我认为,速度并不是 CI/CD 以及与之相关的软件开发模式的最大优势,而是能够一边开发一边收集反馈,可以快速收集和验证需求,及时调整开发方向,避免在前期投入大量成本。

效率系统也是,即便是纸笔,也可以很灵活。前期可以用易于调整的活页本运行原型系统,试验一两周之后收集和整理反馈(自己问自己也是很重要的),发现问题后一条条列出来,然后一条条找到解决方案。而且,别忘了,有问题的大概率不会是用户,而是系统。所以,用到难用的软件要大大方方(但清楚有条理)地指出问题,效率系统执行不下去也不该责备自己。这种时候应该迭代一个新版本,编译后部署到自己的笔记本或者别的什么载体上。

文档是软件的一部分,大的架构决策应该要有 ADR(架构决策记录)背书,也方便后来者理解「为什么要这么做?」,系统的各个组件应该要有文档描述其内部结构。我还听过一个说法,每一行代码都是有文档的,因为每行代码提交时都有写 commit 信息(前提是你真的有好好写这个东西)。即便是自己一个人的项目,我也喜欢手写 Issues 和 Pull Request 信息,设置以计划发布的版本号命名的里程碑(Milestone),这能帮助我思考和规划,也能帮我在后来追溯当时的想法。

单独在本子的某个地方,或者别的载体(比如博客)上写清楚系统这么设计的前因后果,也有助于自己梳理思路。此外,无论是描述效率系统还是开发软件,写文档都能让我对自己的系统有新的认识,偶尔也会因此蹦出新的想法来。

当然,也要警惕,无论是沉溺与架构决策还是挖掘新需求,都有可能系统偏离原本的需求和目的,最重要的是,这样一定会忽略大量的细节问题,而细节与全局同样重要。我想 Vibe-coder 们是没有想过这些问题的,他们的软件大多是做完就丢的东西,持续时间不会很长。一上来就把系统设计得庞大又复杂,就跟跑马拉松一上来就把配速拉到极限一样。除非你根本就不打算跑马拉松,否则我建议你认真对待细节,尽可能消除危险的模糊性。

最后

嗯?你问我这套系统怎么检索?怎么和其他系统集成在一起?怎么一键导入 Anki 制作成记忆卡片,一键扫描归档进 Zettelkasten,怎么把涂画变成 Mermaid 流程图?——为什么需要那些东西?

不过话说回来,数字笔记的确有很多好处,我会在我真的需要检索、回顾和快速捕捉的场景下使用数字笔记,比方说我最近干运维的活儿比较多,为了帮助我记住自己在哪台服务器上改了哪个配置,把哪个文件放在了哪台机子上,某个服务应该用哪个端口访问,这个端口有没有被 ufw 或者 fp 挡住等等,我会在做了某些操作之后立刻在 Logseq 里留下一条记录。

选择 Logseq 的原因也很简单,写标签很快,后续索引也方便,大纲式笔记也很适合做事件记录。更何况 Logseq 自带日记功能,我要记录只需要打开界面,直接把某条记录写进日记页,打上标签以后就能检索到。另外,它是用 Clojure 写的,我已经不知道是第几次提到这点了。

就这样吧,祝你也迭代出适合自己的系统。


  1. 这仅仅是针对我自己的情况而言,详情请阅读后文。我真的好害怕有 Emacs 用户跑过来教我 Emacs 和 Org Mode 的正确打开方式啊。
  2. Garbage collector(垃圾收集器),指代清理废旧、过期数据的机制,一般指编程语言的内存回收。
  3. 另称「自闭症」,也叫孤独症光谱障碍(Autism Spectrum Disorder, ASD)
  4. 求求 Emacs 用户不要过来告诉我很多 Emacs Mode 都可以把数据写成 Org Mode,放在一个 .org 文件里管理,形式上也很统一。 One man’s meat is another man’s poison.
  5. 我至今不能原谅 cl-annot ……
  6. 并不是公司的活儿,而是管理我自己的 VPS,我也把升级自己个人电脑的软件包当作运维工作。
  7. 分别是 Ubuntu 的 Uncomplicated Firewall,和 OpenBSD 的 Packet Filter。
  8. 至于缺点…… 他们仍然没有支持 XDG 基本目录规范,并且现在也包含 LLM 生成的代码,再者,ClojureScript 的性能真的不算好。
参与讨论