Workflow: a Programmer's Perspective


想写这个话题很久了。

概念

概念似乎生来就是用来被人混淆的。这里我暂时只用 Workflow – 或者说工作流 – 来描述:在微观的层次上为完成特定具体任务所执行的一系列动作。好吧这样一句拼凑出来的描述恐怕只会更加混淆。来看这么个例子:

分析“入门级电脑用户启动浏览器”这一任务的工作流。

一个比较粗糙(或者说在本文的观点看来抽象层级太高)的分析如下:

而我期望的分析粒度至少应该达到:

当然实际情况要比这个复杂些,比如第2、3步可以交换,鼠标箭头的当前位置很可能也不必临时去找 – 完成前一个任务时很可能就已经在使用鼠标了。不过相信这个例子能大致描述得清我想讨论的 Workflow 是怎样的概念。

为了快些 getting shit done,工作流这一层面是我能想到的最容易改善的地方。这里我不想考虑易学习性甚至易用性,效率几乎是唯一的标尺。所以我暂时不想用“程序员的用户体验”或“编程活动的人机交互”来指代这里的主题,workflow 是个足够好的单词。

问题与假设

YMMV, seriously.

短期记忆

工作状态下10秒钟之前的闪念我可以忘得一干二净,因为我要把相当多的信息装进短期记忆:API文档,眼前待解决的任务,临时插入的调试代码与相对应的调试信息等等。紧张的记忆空间限制了我在执行操作中进一步获取信息/反馈的能力。

单任务

一边敲键盘一边构思下一个待做功能的设计对我来说完全不可能。试着回忆一下你在连续按 Backspace 键试图删除一长串字符的时候,是否要分神注意一下是否删过了头?一旦因为注意力不集中出现操作失误,随之产生的沮丧感很是难受,至于数据丢失什么的就不止是低效,更是灾难(当然仅凭 Backspace 是制造不了多少数据丢失的)。

脑力 vs 体力

程序员是匠人(Craftsman),脑力与体力劳动都要亲自完成,而脑力劳动的部分 – 分析,设计,解决,验证 – 才是编程活动的重点所在。为了能把更多的注意力用在脑力劳动上,明显应该设法减少体力劳动的支出。

学习成本

考虑到自己转行的可能性实在太小,学习成本这种东西真的不算什么,不可以用”习惯”当作借口来掩饰懒惰。RTFM,折腾配置,寻找插件,都要知难而上。在漫长的职业生涯中最终应该会有收效的。

问题规模

完全 one off 的任务还是不必费心去优化了,等它重复出现的时候再说。越是频繁出现的操作就越是值得下功夫优化。你觉得 ESC 难按吗?Ctrl + 3是不是好很多?但最终我还是选择用软件把 CapsLock 映射到 ESC,不然出门真不好意思自称 Vimmist。

分析解决

输入焦点

终端的年代,键盘光标就是唯一的输入焦点。curse 界面虽然引入了高亮选中的隐喻,典型的如命令行下的操作系统安装界面,但”单一输入焦点”的原则还是坚持了下来。有些简单应用如 less,完全没有输入焦点,随时可以响应用户的命令输入。

输入焦点在移动至有效的区域之后才可以继续操作。考虑移动窗口位置这件事,以前只有窗口标题栏才能用作拖拽的 handle。印象中 Metacity 有一个明晃晃的选项来启用 Alt + 左键拖拽窗口任何部位移动,其它的现代窗口管理器自然也有类似的支持只是我没有用过不能一一列举1。哦对了,调整窗口大小也存在同样的问题。

我不能简单地说”鼠标箭头引入了一个新的输入焦点因此鼠标有罪”,毕竟现在部分 CLI 应用的复杂度也有了充分提升。我自己每天就在用两层 tmux,里面还有 weechat 和 Vim,都是多 tab/window 界面。加上无法避免的多应用协作,输入焦点切换总归要提到日程上来。加之软件界面对 context 的利用还太少,日渐增加的功能统一塞在屏幕边缘的工具栏/菜单/面板里,鼠标箭头只能疲于奔命(好像成语用得不是很恰当)。

印象中 Windows 自带的辅助工具中可以用一个动画来定位当前鼠标箭头的位置,在效率的压力下我们都是残障人士。奇怪那个打字时隐藏鼠标箭头的功能是谁发明的?也许在屏幕分辨率不高的年代一个箭头真的能挡住很多信息,但现在来看丢失前一个输入焦点的代价还是不小的2

信息传递

如果不能用肉眼看出颜色的 RGB(或者 HSL)表示,就乖乖地用取色器吧。等一下,如果有取色器存在为什么还要费力去看?要不干脆全交给程序处理吧?想必 Photoshop 那个被现代前端开发所不齿的自动导出 HTML 功能就是这么来的。虽然自动生成高质量代码的梦想还很遥远,但至少我们希望软件有完整可用的 API 可以方便地互相交换信息,而不是亲自动手复制粘贴。

是的,复制粘贴是最差的进程间通信方式。如果你在写自己的开发工具并需要对外提供 API,考虑利用 TCP socket 然后我们就可以直接用 netcat 访问而不是受限于特定的编程语言。干脆直接动用 HTTP server 也不错。

反馈信息

开头那个例子里依赖所剩距离来移动鼠标的步骤感觉像是机器人的思考方式,而实际上人类很可能也是这么做的,只不过整个动作太简单太自然,没怎么在主观意识里留下印象而已。

高质量的反馈信息无疑可以提升效率,但太多的操作因为信息的不确定性强迫我们收集反馈才能完成任务,而不是一次性想好要做什么之后闭着眼睛就能解决问题。比如 Windows 上经典的切换窗口快捷键 alt+tab,在按下之前你没法确定要按多少次才能选到需要的目标。后来又出现了先切换应用后切换窗口的方案,Mac上就是这样,GNOME 3默认也这么搞,不仅没解决信息不确定的问题,反而增加了复杂度。Dock(包括win7任务栏)就部分解决了这个问题 - 应用可以 stick 在上面,用光影效果来标志启动状态。至于 Exposé …我无法理解这个功能为什么会被设计出来。

目前我的方案是用标签(Awesome的虚拟桌面实现)代表任务,winkey + 数字键切换标签。每个标签下最多两个可以互相覆盖的窗口,winkey + tab只在这两个窗口内切换,非此即彼。然后在这种确知信息的前提下就可以开始养成一点固定习惯 - 比如 Thunderbird 永远在 winkey + 8 的位置 - 效果尚可。

Declarative

再回到启动浏览器的例子。如果我已经把 Firefox 这个名字记在了长期记忆里,直接输入这几个字母就可以定位到这个应用,为什么还要在乎桌面图标的位置?另外树状的目录浏览真的有人喜欢吗?当我明确了要打开的文件名之后,有个模糊匹配直达目标就够了。简单说,构建隐喻和抽象时请一定向自然物靠拢,直接接受人类已经掌握的信息作为输入。

所以这里到了 Vim 闪光的地方 – 如果你想 Delete A fucking Word,那么就直接按 daw。不用考虑先按三下 Backspace 再按四下 Delete,或是要用鼠标从单词的一头拖动到另一头 – 后面两个方法都是不能”闭着眼睛完成”的(见前面”反馈信息”一节)。

假如意念替代键盘直接输入代码的日子还太早,我想至少先奢求一下眼睛控制鼠标。要求不高,能做到移动箭头就很满意了。而且看起来似乎并不遥远

肢体运动

程序员不是运动员,面对繁重的肢体运动我们只能设法规避而不是锻炼肌肉。手指运动不可避免,手腕乃至手臂的运动能省则省,Backspace 与 Enter 键我现在都嫌远3,更不要谈方向键那一坨。不知道霍金用来说话/打字的东西多少钱一个,便宜的话我想买俩。但是如果像莫尔斯编码那么麻烦还是算了。毕竟现在最坏情况我也有一只左手整个放在键盘上。

这里顺便提一下那个”屏幕上最容易点击的点有5个”的理论,如果考虑事后还要把鼠标移到下一个可操作区,恐怕角落4个点的价值会大大缩水。或许根据 context 直接在鼠标附近提供常用/可自行指定的操作才是未来吧。

肢体运动的另一个要点是要尽量平滑自然地完成日常操作,就像你使用筷子时那么自然,自然得像你加长的手指。前阵子偶然看到一位不认识的同事用 Vim 输入括号时手抬得很高,敲键盘那一下非常响,颇有一种”看我出个必杀啊哈哈”的感觉。事后推测是 inoremap 帮他完成了括号配对补全,但是考虑到”一对括号”这个任务太常见,每次都这样兴奋恐怕还是太费神了。

外部储存

可搜索的文档可能是继 chunky bacon 之后最好的发明。我甚至可以开始容忍 jQuery 中 .parent() 和 .parents() 这一对让人脱发的方法命名,反正每次用的时候都要去查。

其他

性能

没什么好说的。我在纠结代码的时候没有心情欣赏 OSX Spaces 切换的动画,而且动画状态下键盘操作完全不被响应。而且在 Lion 下似乎还不能彻底关掉

简单快速的软件就算不能大规模流行开来也总能拥有一批死忠用户。

视觉干扰

一旦你发现键盘可以起到类似电视遥控器的作用 - 在合适的状态可以直接完成几乎所有的常用指令 - 那么窗口的菜单栏标题栏工具栏统统都可以算作视觉干扰。把常用的功能绑定到键盘,然后把这些东西统统隐藏掉吧。

Once you see it you cannot unsee it

假如你觉得折腾这一套东西没什么大不了,找个理由说服自己稍微尝试一下,一下就好。恐怕很快你就会开始无法忍受动作缓慢的软件界面。

反对意见

有时连我自己也觉得这是浪费时间。

非核心竞争力

程序员毕竟不是打字员。能光速把代码敲出来并不等同于高质量的实现与设计。甚至有些工具还无形中鼓励了复制粘贴而不是坚持 DRY 原则。有没有必要先设法普及代码整洁的必要性然后再谈效率提升?

进步

有些手段可以让工作方式带来巨大变革,让你之前的努力白费。你只能寄希望于 API 把新旧工具环境连接起来。

非瓶颈

工作流存在优化的可能性并不代表整个编程活动中的效率瓶颈就在这里,只是这部分不需要影响/依赖协作者和具体的 codebase4,可以自己默默地努力而不需要等待整个团队跟进(比如切换版本控制)。

Yak Shaving

‘nuff said.

习惯与懒惰

Nah.

[完]

  1. 除 Metacity 外已知 KWin, Openbox, Awesome 都可以支持。 

  2. 试着回忆一下平时有没有为了寻找鼠标箭头而用力摇动鼠标。 

  3. 在 Terminal 下分别可以用 Ctrl + h 和 Ctrl + M 替代。严格来说 Ctrl + M 取代的是 Mac 的换行符 \r 而不是 Unix 的 \n。 

  4. 事实上编程语言的选用还是有影响的。