用Org-mode实践《奇特的一生》
《奇特的一生》
《奇特的一生》是一本传记体小说,描述了俄罗斯科学家柳比歇夫如何运用 时间统计法 度过了他的一生。所谓时间统计法,说起来实在不起眼:统计自己做 每件事情 的纯时间, “工作中的任何间歇,我都要创除。我计算的是纯时间,”柳比歇夫写道,“纯时间要比毛时间少得多。所谓毛时间,就是你花在这项工作上的时间。 ” 柳比歇夫典型的时间统计日记是这样的:
乌里扬诺夫斯克。一九六四年四月八日。
分类昆虫学:鉴定袋蛾,结束——二小时二十分。
开始写关于袋蛾的报告——一小时五分(1.0)。
附加工作:给达维陀娃和布里亚赫尔写信,六页——三小时二十分(0.5)。
路途往返——0.5。
休息——剃胡子。《乌里扬诺夫斯克真理报》——十五分,
《消息报》——十分,
《文学报》——二十分;
阿·托尔斯泰的《吸血鬼》,六十六页——一小时三十分。
听里姆斯基-柯萨科夫的沙皇的未婚妻。
基本工作合计——六小时四十五分。”
其中记录了一天当中各项活动花费的“纯时间”,最后合计了第一类工作(科研活动)的时间。此外,每月和每年,柳比歇夫都对自己的时间统计日记进行进一步汇总统计,将自己时间的花费清楚明了地列于眼前。正是这样一个简单的方法帮助柳比歇夫实现了“奇特的一生”。一般,柳比歇夫每天能有七、八个小时的 纯学术工作时间,最高纪录是十一小时三十分。
我们每个人一天的纯工作时间到底有多少呢?约摸估算一番,我想能达到柳比歇夫这个数字的少之又少。两小时?三小时?事实上,因为人对自己时间利用的估计是如此的不靠谱,实际的纯工作时间可能比你想像得还要少得多。物理学家Michael Nielsen在一篇文章中写道:
一个同事曾告诉我,他的一个朋友在一段时间里用码表记录自己每周做研究工作的时间。令他震惊的是,除去每天当中他陷入的所有其他事情–中断,邮件,上网,电话,没成效的会议,和朋友聊天等,他平均每天只用了半小时在研究工作上。如果说这是许多研究者的典型情况,我并不对此感到意外。
彼德.德鲁克在《卓有成效的管理者》中也谈到:
某公司的董事长,十分肯定地对我说他的时间大致分成三个部分:1/3用于与公司高级管理人员研讨业务;1/3用于接待重要客户;其余1/3则用于参加各种社会活动。但是,等实际记录了六个星期之后,跟他原来的估计比较,结果发现在上述三个方面,他几乎没花什么时间……这份时间记录是由他的秘书记下来的,当秘书把记录送给他看时,他简直一点儿都不能相信。
因此,看似简单的时间统计法恰恰蕴含了深刻的力量。唯有通过实际的统计数字,我们才能自知。我刚知道这个方法时,试过在纸上记录做每件事的起止时间,但总觉得统计起来麻烦。但事实上,不做统计,根本没法发挥这个方法的真正效果。
Org-mode
Org-mode是编辑器Emacs下的一个模式(现在也有了一个Vim下的克隆)。Emacs是一个古老的编辑器,以往只在部分程序员当中流行,因为可定制性极高,可用大量快捷键操作。虽然使用既有的配置文件入门并不困难,但我绝不认为这个编辑器适合所有人,也不认为它会流行起来。本文的方法只适合对电脑技术有一定好奇心和探索精神的人,对于Emacs和Org-mode的基础知识,可参考yibie的文章及相关参考资料。如果你是程序员,即使对Emacs没兴趣,不妨也可读下去,最后可用自己喜欢的方式实现一个类似的系统。
Org-mode最初被设计用于记录大纲式笔记,和Markdown语言类似,在纯文本的基础上加上一些简单的语法来实现排版,比如用*来表示各级标题:
* 大标题 |
** 中标题 |
*** 小标题 |
随着系统的进化,不断开发出TODO,行程表,导出等强大的功能。现在的Org-mode集笔记、计划和写作功能于一身,这篇Blog就是在Org-mode下写成后直接发布到Wordpress中的(使用org2blog)。
todo.org
由于Org-mode超强的可定制性,几乎所有的时间管理流程都可以通过它实现。在网上也可以找到很多使用Org-mode实现GTD的文章。这里介绍的是我自己使用的方法。我自己只使用一个todo.org文件来管理及记录任务。
这就是我的todo.org文件大纲,在Emacs中打开后,移到每个大标题(*)后,按Tab可展开。
以上就是展开Projects及Reading两个分支后的结果。其中Projects项目中有四个二级标题(**),我将Technical English这个子项目展开,得到其中的三级标题(***)。这基本是一个已经完成的项目,所以里面的状态都是DONE了。Reading分支下的5个二级标题(**)都是Todo状态,表示我正在读的书。
下面是对各个一级标题的介绍:
- org-mode configuration
- 主要是对todo.org整个文件的一些配置。
- Inbox
- GTD中Inbox的概念,快速输入临时事件或突然的想法,释放头脑内存。
- Tasks
- 相当于GTD中的Todo-list,即那些一步就能完成的零散事件,如写这篇文章。
- Projects
- 各种需要多个步骤完成的项目,每个项目在里面是二级标题(**),由各种三级TODO标题(***)组成。当然也可能对项目进行再细分。
- Routines
- 一些每天都要进行的习惯。使用Org-mode可以很好地进行重复。
- Remind
- 需要提醒的事情,比如某个时间点上课。
- Reading
- 正在看的书。
- Weekly Review
- 每周要结束时进行Review,其中有一些代码段,用于进行当周的时间统计。
日程表
为了使用Org-mode的日程表功能,首先需要把todo.org加入到日程表文件中,在配置文件(~/.emacs)中写入:
; 将~/org/todo.org替换为todo.org实际路径 (setq org-agenda-files (list "~/org/todo.org"))
再绑定Org-mode日程表的快捷键。
(global-set-key "\C-ca" 'org-agenda)
这样按Ctrl-c a a就可以查看Org-mode的周日程表了。不过我一般看当天的,所以自己定制了一个Day Agenda。
有关Org-mode Agenda的具体用法可参考其他文章或官网的手册。简而言之,你可以设置TODO项的Schedule,该项在当日就会显示。我一般在每天开始浏览一下所有的TODO项目,将今天需要完成的任务Schedule一下。这样一天中剩下的时间只要看Day Agenda就行了。
计时
本文的重点是时间统计,我推崇Org-mode,最重要的一点即是它能够很方便地进行时间统计。在todo.org中,移到一个条目上,按Ctrl-c Ctrl-x Ctrl-i即可对该条目开始计时,Ctrl-c Ctrl-x Ctrl-o停止当前计时。如果在Agenda中,移到条目按I(大写)即可对该条目开始计时,O(大写)即可停止计时。对于已经对这些基本功能熟练的用户,还可使用以下技巧:
- 用global-set-key把org-clock-in, org-clock-out, org-clock-cancel这三个功能绑定到全局功能下,这样就不用专门跑到一个Org-mode的buffer里计时了。
- 加前缀(Ctrl-u)再按Ctrl-c Ctrl-x Ctrl-i,可快速查看最近计时项目,进行快速计时。
计时的重点是只计 纯工作时间 ,只要没在工作就停止计时。对于不在电脑时候的工作,可以先在纸上记录,电脑在手时再补录到todo.org的相应时间记录中。
我在todo.org的头部加入了#+PROPERTY: CLOCK_INTO_DRAWER t,这样,时间记录会放到一个名为LOGBOOK的抽屉(drawer)中,平时看项目时并不展开,所以记录再多也不影响日常操作。
Tag分类
为了便于统计,使统计信息有意义,有必要对任务进行分类。我用Tag实现分类,可在todo.org的文件头部写下该文件支持的Tag,如:
#+TAGS: { ACADEMIC(a) ENGLISH(e) SCHOOL(s) LEARNING(l) OUTPUT(p) OTHER(o) }
其中括号内代表简写(快捷键),对每个TODO任务,按Ctrl-c Ctrl-q即可赋符Tag,这样就完成了任务的分类。默认设置中,Tag是可以继承的,即子标题自动包含父标题中含有的Tag。
统计
在Day Agenda中,按R(大写)可打开Clockreport,查看当日计时统计,效果如下图所示。
不过这样有时略显繁琐,而且体现不出各类任务上所花的时间,为了实现类似柳比歇夫“第一类工作”时间类似的统计,我写了下面这个函数(org-clock-sum-today-by-tags)。
;; used by org-clock-sum-today-by-tags (defun filter-by-tags () (let ((head-tags (org-get-tags-at))) (member current-tag head-tags))) (defun org-clock-sum-today-by-tags (timerange &optional tstart tend noinsert) (interactive "P") (let* ((timerange-numeric-value (prefix-numeric-value timerange)) (files (org-add-archive-files (org-agenda-files))) (include-tags '("ACADEMIC" "ENGLISH" "SCHOOL" "LEARNING" "OUTPUT" "OTHER")) (tags-time-alist (mapcar (lambda (tag) `(,tag . 0)) include-tags)) (output-string "") (tstart (or tstart (and timerange (equal timerange-numeric-value 4) (- (org-time-today) 86400)) (and timerange (equal timerange-numeric-value 16) (org-read-date nil nil nil "Start Date/Time:")) (org-time-today))) (tend (or tend (and timerange (equal timerange-numeric-value 16) (org-read-date nil nil nil "End Date/Time:")) (+ tstart 86400))) h m file item prompt donesomething) (while (setq file (pop files)) (setq org-agenda-buffer (if (file-exists-p file) (org-get-agenda-file-buffer file) (error "No such file %s" file))) (with-current-buffer org-agenda-buffer (dolist (current-tag include-tags) (org-clock-sum tstart tend 'filter-by-tags) (setcdr (assoc current-tag tags-time-alist) (+ org-clock-file-total-minutes (cdr (assoc current-tag tags-time-alist))))))) (while (setq item (pop tags-time-alist)) (unless (equal (cdr item) 0) (setq donesomething t) (setq h (/ (cdr item) 60) m (- (cdr item) (* 60 h))) (setq output-string (concat output-string (format "[-%s-] %.2d:%.2d\n" (car item) h m))))) (unless donesomething (setq output-string (concat output-string "[-Nothing-] Done nothing!!!\n"))) (unless noinsert (insert output-string)) output-string))
并把它绑定到Ctrl-c Ctrl-x t按键上。可在当前光标处插入对当天各个分类进行时间统计(代码中的include-tags变量包含了参与统计的tags,可自行更改)。默认的效果是将当天非零的各分类时间统计显示出来。如:
[-ACADEMIC-] 01:24
[-OTHER-] 02:24
如果需要统计的是前一天的,可加前缀(Ctrl-u);如果要指定时间范围,可加两次前缀(Ctrl-u Ctrl-u)。这个函数在周统计中还会用到。我在一个日记文件中会插入每天的Clockreport以及上述分类统计。
周统计
周统计中我查看的内容之一还是Clockreport,在todo.org中任意位置(我是在Weekly Review下)按Ctrl-c Ctrl-x Ctrl-r即可插入一个Clockreport,不过参数需要做一些修改,我使用的是:
#+BEGIN: clocktable :maxlevel 5 :scope agenda-with-archives :block thisweek :fileskip0 t :indent t #+END:
改动之后,在BEGIN的位置再按一下Ctrl-c Ctrl-c就可以刷新报表了。同时我还查看每个tag的时间报表。参数和上面是一样的,最后加一个类似:tags “ACADEMIC”的参数即可。这些Clockreport,只需插入一次,以后每周用Ctrl-c Ctrl-c刷新即可。
同样的,这样的信息有时候太繁琐了,对于简报,我的做法是在todo.org中嵌入一段如下的Lisp代码:
#+BEGIN_SRC emacs-lisp :results value (setq week-range (org-clock-special-range 'thisweek nil t)) (org-clock-sum-today-by-tags nil (nth 0 week-range) (nth 1 week-range) t) #+END_SRC
同时,在配置文件中加入如下语句,使得在Org-mode可直接Evaluate上面的代码。
(org-babel-do-load-languages 'org-babel-load-languages '((emacs-lisp . t)))
这样,在刚才代码段的位置按Ctrl-c Ctrl-c即可获得各Tag的周时间统计。效果如下所示: