• 本博客已搬家至tonybai.com,后续该博客将停止更新,望各位朋友了解。

    再重申一下新博客的Feed地址为:feed.tonybai.com,欢迎订阅。

    凡bigwhite.blogbus.com以及下属子页面的访问请求都将会被重定向到tonybai.com,欢迎用tonybai.com的博客搜索页面找到你所需要的文章。

  • 2012-02-21

    Feed地址更改 - [我行我素]

    Tag:

    鉴于大巴博客设置中的Feedsky输出RSS不甚稳定,并且出于固定博客的Feed的需要,特将本博客的Feed地址改为: http://feed.tonybai.com ,烦请已经订阅本博客的朋友们重新订阅新的Feed地址;尚未订阅本博客的新朋友们请用新Feed地址订阅。

    BTW,原Feed地址将在一段时间后关闭。

  • buildc在发布0.1.0版时并没有做好安装脚本,当时的建议是直接下载0.1.0的源码包或svn export/checkout源码包,并手工将buildc目录位置加入到用户的PATH环境变量中。近期buildc计划正式投入到项目中使用,为了方便大家安装以及以后的统一升级维护,我花了些时间给buildc加上了setup脚本。

    Python有标准的程序分发方案,不过我对这些了解不多。buildc本身很简单,我觉得没有必要把安装做得很复杂,所以就自己动手编写了一个setup.py,不到100行,用于安装buildc。

    Python的标准安装脚本也叫setup.py,我这里也借鉴了这个名字。有了setup.py,buildc的安装就简单多了:
    * 下载buildc Release包(当前最新是buildc-0.1.1)
    * 解压发布包,在发布包路径下,执行setup.py install [--prefix=YOUR_INSTALL_PATH]

    setup.py默认将buildc安装到/usr/share/buildc下面,并在/usr/bin下建立一个到/usr/share/buildc/buildc脚本的符号链接(symbol link),当然这种安装是需要root权限的,但一旦安装好,host上的所有用户就都可以使用buildc了,日后统一升级buildc也十分方便;如果你不想在默认路径下安装,可以通过--prefix=XXX指定你自己的安装路径,这种情景下,setup.py不会建立什么符号链接,需要你手动将你的安装路径加入到你的PATH环境变量中,以便后续使用。

    卸载buildc也十分方便,执行一条"setup.py uninstall [--prefix=YOUR_INSTALL_PATH]即可。

    setup.py的安装原理很简单,就是利用shutil包的copytree将buildc目录复制到指定目录下。shutil的copytree在Python 2.6以后版本中支持ignore参数,可以有选择的将buildc目录下的文件和目录复制到目标目录,比如.pyc文件或.svn目录本不应该出现在目标目录下,我们就可以通过ignore参数指定一个ignore_patterns来过滤掉这些文件或目录:

    shutil.copytree(package_root, install_root, ignore = shutil.ignore_patterns('*.pyc', '.svn'))

    但在Python 2.6版本之前,ignore参数是不被支持的,所以这里也留下缺憾,那就是如果你使用svn checkout方式下载源码包,安装的时候.svn等目录也会被安装到目标目录下,看起来别扭,但不影响您对buildc的使用。

  • 当前任何一个组织 -- 无论是私企,还是国企,无论是政府还是民间组织,无论是在国内还是在国外 -- 都在强调提高效率。但"提高效率"不简单是一句口号,还需要脚踏实地的真正去做。

    说到"提高效率",大家首先就会想到工作的行为主体-人!促进人员能力的提升是提升个体工作效率的一个很好的办法。在软件开发领域也有一个公认的事实,那就是一个顶尖程序员的效率可以十倍甚至百倍于一个普通程序员。为此,很多组织都投入巨资引入各种针对个体能力提升的培训和咨询,试图以此提升全体人员的效率。我们不能否认这种方法的效果,但从实际情况来看,似乎效果有限,特别是对组织整体效率的提升效果有限,因为组织内不可能都是由领域顶尖人员组成的,即使接受培训,大部分人员也不会成为顶尖级,其水平还是处于平均线的。这就是摆在我们面前的一个现实,我所在的组织同样也面临着同样的问题,这也促使我进行了一些较为深入的思考。

    那么除了个体能力提升之外,我们还应当如何提升组织的整体效率呢?

    提高效率,首先要做好"认知",找到方向。即知道什么工作决策和行为是有利于提高效率的,什么样的决策和行为是无助于提高效率或是导致无用功。以现阶段比较火的物流快递行业为例,科学地选择送货路线无疑是提高整体效率的一个好方法,即能节省时间,还能节省交通燃油成本,缩短送货时间,提高服务质量。如果你作为快递公司的老总,你的决策应该是:建立一套高智能的选路系统,以帮助每个快递员快速完成送货任务。在软件开发领域,人们一直以来都在做着探索,努力地瞄准正确的方向前行。特别是近些年来,软件开发借鉴其他传统产业的生产经验,试图通过消除开发过程中的浪费来提升整体开发效率。什么是软件开发领域的浪费呢?广义的讲,对开发团队而言,不能卖钱的工作都是浪费;对于客户而言,不能给客户带来价值的工作都是浪费。传统行业(比如汽车制造业)用事实证明,浪费现象只能尽量减少,但无法完全杜绝。但浪费是否是完全没有意义的呢?有些"浪费“对组织的发展壮大还是有裨益的,比如建立企业内部知识库等。OK,我们似乎找到了软件领域提升组织整体效率的方向,那就是要尽量减少那些既不能给客户带来直接价值,也无法给我们自身带来经济利益,对组织的发展壮大也无多大贡献的浪费。

    提高效率,还要了解个体的行为特征。我们应该了解所在行业从业人员的行为效率曲线。理想的情况是让大家始终都能处于自己的高效率区间。俗话说,术业有专攻。快递员在挨家串户送货时效率是最高的;软件开发人员在设计、编码和调试时效率是最高的;文案人员在编写文档时的效率是最高的,等等。如果让每个快递员自己优化送货路线、让每个软件开发人员自己做集成构建,环境搭建、调试和测试、让文案人员自己负责后期的装订和印刷,那低效率就不可避免。说白了就是让大家都去做且一直在做自己最擅长的事情,这样才能尽量发挥出个体的效率,才有益于组织整体效率的提升。

    有了上面两个方面作为前提,我们就可以得到一种切实可行的提升组织整体效率的方法,那就是推进组织内部服务的建设。什么是"内部服务"?简单来说,就是组织内部一部分人员的工作就是为其他人提供服务,至于服务的内容因行业的不同而不同。"内部服务"可以从全局角度主动地推动个体效率提升。从个体行为上来看,内部服务可以剥离大多数个体所不擅长的事情,让大多数个体长期处在高效率区间,后期将这些大家不擅长的事情以服务或基础设施的形式科学地且用户界面友好地提供给大家,让大家可以高效地或自动化地使用。这就是"内部服务"的原理所在。注意,与在培训和咨询等过程中,组织内人员需主动学习和主动提高效率不同,通过内部服务的建设和提升,组织内人员是在不知不觉中"被提升了效率",也避免了因人员能力参差不齐,效果因人而异的问题,这是其最大魅力。

    个人觉得实施内部服务建设有以下几个关键要素:
    - 细分工作,识别出基础服务。即找出可以作为服务的工作内容。还是以软件开发领域为例,系统管理小组和版本构建小组的工作内容就可以作为提供给其他人的基础服务。

    - 按工作内容调整团队组织。即将组织划分为若干基础服务团队,以及其他非提供内部服务的产品团队;明确内部服务团队的职责范围以及与其他团队的接口方式。

    - 基于内部服务改造工作流程。将内部服务放入工作流程中,让成果物在各个团队间高效流动,甚至可以在一定程度上简化原有工作流程。

    在人员有限的前提下,内部服务团队也可以是虚拟团队,不过这样做就会导致内部服务工作的优先级在工作极其繁忙时被降低,可能会导致浪费现象在后续显现出来。内部服务的概念也是分工细化思想的延伸,也许它并不适合一些人员规模较小的startup,但却适合那些规模已经扩大但效率却没有明显提升的组织。

    在软件开发领域,我们很容易识别出很多基础服务,诸如服务器/虚拟化环境支持服务、公共库开发团队、测试工具的开发服务、构建与持续集成服务、自动化测试支持服务、文案服务等。越来越多的自动化框架和工具(比如puppetjenkinsbuildbot等)也让内部服务团队可以不必具有很大规模,而且可以使得服务团队自身的工作也颇为高效。另外内部服务团队还便于将一些致力于消除浪费、提高效率的思想(诸如持续交付DevOps)快速地转化为具体的工作方法和实践。

    总之,提高效率是一个极其重要的事,甚至是直接关乎于真金白银的事。一个组织应着眼于全局思考、规划和落实提高效率的具体措施。如果一个组织现在依然将提高效率停留在喊口号的层次上,那若干年后,这个组织剩下的也就仅是那句口号罢了。

  • 不知为何,一到秋天我就有了爬山的冲动。于是乎我和同事一行六人在一个秋高气爽的周末来到了位于丹东宽甸的天华山

    辽宁境内的山我爬过的不多,之前只是去过千山和关门山 。选择天华山也是再三考虑了同事们久疏于运动之后做出的决定,其实我个人更加向往征服另一座更为难爬的山峰 - 位于凤城的凤凰山 ,看来我的这个目标只能等来年再实现了^_^。

    景区的自费倒站车将我们送到了此次登山的起点-通天峡广场。一上来我们就要征服据说长达300多米的通天峡。所谓通天峡其实就是一道山体的裂缝,景区在裂缝内搭建了人类可以爬行的云梯,这么长的"山体裂缝"我还是第一次遇见,爬起来很是刺激。


    通天峡

    天华山让我感觉最好的地方就是可以手脚并用,而不仅仅是一直攀登石头台阶,这才叫真正的爬山。由于双手的介入,爬山过程中腿部感觉并不是很累,这点与爬千山、关门山有很大不同。

    这个季节天华山上已有些许枫叶变得红彤彤,一路之上我们也以发现红枫叶为最大的兴奋点,我们也的确收获了不少红叶美景。


    山中红叶

    忘记说了,爬天华山无论如何都不能缺少一种装备,那就是防滑手套。前面说过爬天华山最大的特点就是要"手脚并用",由于爬山过程较长,如果空手攀爬必然会对稚嫩的手带来一定的伤害,看看下面的照片你就能理解手套的功用了。


    登山天梯

    我一直走在最前面,一是为大家探探路,二是把握好爬山的节奏,激励大家爬山的斗志,最后就是在等待大家上来的那段时间独自远眺山景,充分体会大自然的壮丽。


    山景远眺

    天华山有多条游览路线,我们此行选择的目的地是天华山天台。天台应该不是整个景区的最高点,但却是名气最大的一处。天台,物如其名,就是山顶一处由山石构成的石台子,台子有一定倾角,但面积不小,可容纳几十号人。登上高台的瞬间感觉确实很棒,但在半山腰远观天台却更能凸显天台的无限魅力。


    天华山天台

    都说"上山容易,下山难",不过这次我们却没有这种感觉,下山的过程很顺利。呼吸着大山中纯净富氧的空气,我们一路说笑,每个人的脸上呈现出来的不是疲惫,而是无比地放松。

    回到通天峡入口,离集合时间尚早,我们没有选择坐倒站车,而是继续步行下山。我们沿着从"爱之源"流下的山溪而下,一路欣赏着天华山美丽的水景。现在似乎是枯水期,想必在富水期,这里的景色会更美。

    就这样,我完成了对天华山的征服^_^。

    附具体行程(散客拼团):
    - 早上4点多起床,5点集合。
    - 5点30奔赴天华山
    - 9点左右到达天华山景区
    - 9点半上山
    - 14:00下山
    - 14:30返城
    - 19:30回到温馨的家

  • 在Unix/Linux上,我们一般可以通过两种方法查看到一个可执行程序的版本信息,以下以Ubuntu中的Gcc为例。

    第一种方法:我们可以直接通过程序名字得到版本信息,例如:
    $ which gcc
    /usr/bin/gcc
    $ ls -l /usr/bin/gcc
    lrwxrwxrwx 1 root root 7 2010-08-21 00:18 /usr/bin/gcc -> gcc-4.4*

    可以看到我用的Gcc的版本号为4.4,但似乎这个版本信息还不够全,只包含了major和minor版本号,还不包括bugfix修订号。

    第二种方法,也是最常见的,获得版本信息最为详细的方法,它就是通过-v或--version命令行选项来查看可执行程序的版本号,绝大多数Unix/Linux下的程序都是支持这种方法的。比如:

    $ gcc --version
    gcc (Ubuntu 4.4.3-4ubuntu5) 4.4.3

    可能有人会认为无论是将版本信息放入程序名字中还是在程序内部加上版本信息,都不是神马难事儿,没有必要单写一篇文章来说明。没错,这些的确不是什么困难的事。

    在程序名字中放入版本号,通过Gcc命令即可完成:
    $ gcc -o foo-1.3.1 foo.c

    如果你使用Makefile来构建你的程序,你可以这样做:

    /* Makefile */
    TARGET = foo-1.3.1
    all: $(TARGET)
        gcc -o $(TARGET) foo.c

    而在程序内部加上版本信息的最简单方法莫过于在头文件中定义一个宏,然后在version函数中输出这个宏的内容:

    /* version.h */
    #define VERSION  "1.3.1"

    /* version.c */
    void version() {
        printf("%s\n", VERSION);
    }

    我相信很多朋友都是如是做的。

    如果大家真的都是这样做的,那么问题就出现了:"当可执行程序的版本信息发生变更时,我们需要修改两个地方"。又有人会说:"修改两个地方也不是很麻烦啊"。没错,但这绝不是吹毛求疵,而是实实在在发生的问题。实际开发中很多开发人员总是只记得修改一处,而忘记了另外一处,这样就导致了两处版本信息的不一致。

    我们不能完全依靠开发人员的细心和责任心来消除这一问题,我这里提供一种方法供大家参考:

    我们在Makefile中像这样定义一组版本信息相关的变量,最重要的是通过一个外部宏定义FOO_VERSION_INFO将版本内容传递到程序内部:

    # Makefile

    MAJOR := 1
    MINOR := 3
    BUGFIX := 1

    TARGET := foo-$(MAJOR).$(MINOR)

    CFLAGS = -DFOO_VERSION_INFO=\"${MAJOR}.${MINOR}.${BUGFIX}\"

    all:
        gcc -o $(TARGET) $(CFLAGS) foo.c

    /* foo.c */
    void version() {
        /* 这里直接使用Makefile中定义的FOO_VERSION_INFO宏 */
        printf("%s\n", FOO_VERSION_INFO);
    }

    int main() {
        version();
        return 0;
    }

    $ foo-1.3
    $ 1.3.1

    这样一来,即使版本号发生变更了,我们也只需修改Makefile这一处包含版本信息的文件即可。

    很多可执行程序的文件名中并不包含版本信息,像ls。如果是这样的话,一切就变得简单了。但是若像Gcc那样,在程序名以及程序内部都包含有版本信息的,我相信使用这个方法/技巧还是大有裨益的。

  • 果果在今年五月份就已经满一岁了,不过由于"档期"原因,果果一周岁的生日照直到六月份才拍上。再加上后期靓照制作过程中,我们与影楼就版面设计交流和修改过多次,这样果果的周岁靓照一直到上周才正式出炉!啥也不说了,上图^_^。

    现在小家伙儿有16个月了,很是淘气,胃口和爸爸一样好得很。我们说的生活用语似乎她都能听明白,也能照着做。但就是说话有些晚,到目前为止还不会叫爸爸呢:(。不过她的动手能力似乎还不错,目前已经会自己穿鞋子和短裤了。

  • Paul Graham不愧被誉为Lisp的超级推手,他的煽动力真的是很强悍。这不才刚刚看完一遍他编写的《黑客与画家》后,我就决定将Common Lisp作为今年计划学习的那门新语言,而且从现在就开始。

    去年曾囫囵吞枣般的学习过Haskell,一门通用且庞大的纯函数式编程语言。在惊叹于Haskell如此与众不同且功能强大的同时,也为Haskell Monad那魔鬼般的蹩脚语法所苦恼,而Monad的引入就是为了隔离副作用,并让你可以利用些过程式命令式语言解决问题的范式。

    原以为Common Lisp也是一门函数式编程语言,应该与Haskell很像,但在看了《ANSI Common Lisp》一书后的前几章后我才发现其实不是那么回事儿。Common Lisp设计初衷其实是一门支持多范式的通用语言。除了语法上更接近于函数式编程范式外,你完全可以用Common Lisp写出具有过程式特点的代码(而且看起来也很容易)。另外Common Lisp Object System(CLOS)还给你提供了OO范式的选择。与Haskell相比,对于我这个C程序员来讲,Common Lisp带来思维跳跃似乎更小些,更有利于后续的学习和使用。

    与Haskell的强类型和静态类型(即使你不显式指出类型,Haskell也会根据一些上下文的clue推导出类型,如果它发现类有不匹配,那么编译期间就会报错)不同,Common Lisp是动态类型和弱类型的,当然你也可以显式声明类型,但这么做也仅有利于编译器对代码的速度优化,并不能阻止什么。如:
    > (declaim (type fixnum count))
    > NIL
    > (format t count)
    *** - EVAL: variable COUNT has no value
    > (setf count "hello lisp")
    > "hello lisp"
    > (format t count)
    > hello lisp
    > NIL

    看到了吧,即使我们显式声明了count为fixnum类型,我们依然可以用字符串为其赋值。

    Lisp语法十分简单:万物皆在括号内,无论代码还是数据。Lisp一直因括号泛滥而被诟病,不过对于我来说还好,也许是因为在C语言中也没少使用括号的缘故吧。另外现在的编辑器都支持高亮括号匹配,这样只要你细心些,写代码时基本不会出现因括号不匹配导致的一些问题。

    编程语言影响思维习惯,但思维的转变不是一蹴而就的,也就是说用惯了C、Python等语言后,再去学习类似Common Lisp这类语言的确有些困难。遇到某问题时,或多或少还会首先以过程式的思维去考虑。另外Common Lisp也确实不是一门“小语言”,和Haskell一样,Common Lisp也很庞大,这也使得这些语言的学习曲线陡增。
      
    之前一直认为Lisp也是一门解释性的语言,类似Python采用解析器的方式执行,性能不会很快。后来经了解后才得知诸多编译器(如CLisp)都是将源代码编译为某种格式的字节中间码,这样不仅性能得到了提升,可移植性还得到了兼顾。当然Lisp性能与C比起来还是要差出至少一个数量级的。Common Lisp的编译器我装了两个:CLisp和SBCL,目前来看似乎后者的开发更活跃一些。我个人则更多地使用CLisp。

    这里必须得承认的是Lisp语言的应用还是比较小众的,甚至很多程序员都没有听说过有Lisp这门语言的存在。在实际商业开发中更是很少见到用Lisp实现的系统,这方面Haskell也有着同样的”感受“。不过近几年Lisp各种方言大有回升之势,Lisper们需要是耐心和时间。如果要想了解如何利用Common Lisp进行一些实际系统的开发,那么你就不能放过Peter Seibel于2005年编写的《Practical Common Lisp》一书。后来出版的《Real World Haskell》想必也是学习Peter Seibel试图为Haskell开发者们找到一条实际应用之道吧。

    但有关Common Lisp的入门书,我还是觉得Paul Graham的《Ansi Common Lisp》更适合,另外在这之前可以先拜读一下Paul Graham的文章"The Roots of Lisp",这将对Lisp的学习大有裨益。

    既然本文的主题为Hello,Common Lisp,那最后还是按学习新语言的惯例,在这里向大家展示一下用Common Lisp是如何编写Hello World的吧:

    ;; HelloWorld.lisp

    (defun hello-world ()
      (format t "hello, world!"))

    (hello-world)

  • 番茄工作法Pomodoro Technique ),你可能没有听说过,呵呵,它年纪也不小了,官方说它是在1980s时发明的一种时间管理方法,只不过它最近又被一些人“挖掘”了出来,并被大力推广了一番。特别是在软件开发圈子里,被包装后的番茄工作法披上了光鲜的外衣,拥有了不少粉丝(我还算不上粉丝,充其量算是个试用者 ^_^)。

    不过和历史上诸多的时间管理方法一样,番茄工作法不是银弹,它无法将你彻底地从每天纷繁芜杂的工作中解脱出来,甚至于:
    - 它不能告诉你今天应该去做哪些事情;
    - 它不能告诉你如何排定事情的优先级;
    - 它不能告诉你如何应对各种外界打扰;
          
    那这种方法的优点到底何在呢?别急,下面一一道来。

    简单!首当其冲的就是简单!番茄工作法的全部核心内容只有下面几句话(也是该方法的标准执行步骤):

    * 选择一个待完成的任务
    * 将番茄时间设为25分钟
    * 专注工作,直到番茄时钟响起,然后在纸上画一个x
    * 短暂休息一下(5分钟就行)
    * 每4个番茄时段多休息一会儿

    怎么样?看起来是不是与我们平时的工作方法没有太大区别呢?我们平时工作时也是一个任务接着一个任务的去做啊。没错!这种方法看起来似曾相识。不过细致挖掘后,你会发现这里每一步的描述中都没有废话。

    - 选择一个待完成的任务
    番茄工作法在这里没有给出如何进行任务选择的详细说明,我想这是因为在许多时间管理理论和方法中都针对这方面做了细致入微的讲解,如经典的四象限法等。再深入考量一下,你会发现番茄工作法执行前是需要你做一些准备工作的:你需要枚举出待办事项、识别出优先级别、将规模较大的Task拆分为small tasks,然后制定至少一天的番茄计划,设定每个番茄时间段(Promodora)对应的task。只有当你准备好这些,番茄工作法才能让你的工作更有效率。这里也可以理解成番茄工作法的开放性,可以让你与其他高效时间管理理论、任务分解方法充分结合,让效力倍增。

    - 将番茄时间设为25分钟
    从字面义来看,这就是一个定时器。没错,实际执行过程中,你的确需要一个定时器,物理的也好,软件实现的也好。可以支持自由设定番茄工作时间段,具备报时提醒功能。至于25分钟,我想这是发明者给出的一个经验值,你可以在初期按照25分钟设定,后续根据自己的需要自行调节。Google Chrome有一个名为ChromoDoro的番茄计时器插件很不错,我一直在用。有定时器和没有定时器,工作起来有啥分别呢?实践证明,在定时器下工作,你的潜意识中会涌出一种紧迫感,潜移默化的加强你提高完成效率的意识。

    - 专注工作,直到番茄时钟响起,然后在纸上画一个x
    别看这句不长,但我认为这句才是番茄工作法的精华。首先不得不提到的就是“专注”二字,这也是我理解的番茄工作法的第二个优点。专注,意味着迈向高效。长期使用番茄法可以大幅提高你的专注力,也间接的提升了你的效率。这个说起来容易,做起来难。不信你可以试试。其他外部干扰不说,你是否能在一个番茄时间段(25分钟)内专注于处理某件事情呢?你是否会走神(外面突然阴云密布,又要下雨了?)、是否会分心(昨晚巴萨赢没,梅西 进球了吗?真想打开 Browser看看结果)。哈哈,实践证明,在使用番茄初期,这些都会发生,起码在我身上就不断地发生过。为啥还要在完成时在纸上画个X,我理解这是个信心强化的小技巧,强调“完成”,提高完成的信心,久而久之,这种成功反馈会给你带来充足的自信。

    - 短暂休息一下(5分钟就行)
    工作也讲究节奏,适当的节奏会让你觉得游刃有余。反之,如果长时间专注,反倒会过损脑力,降低效率。另外适当的休息也避免了一些职业疾病发生的可能性。

    - 每4个番茄时段多休息一会儿
    我的理解,和上一条差不多。不过这里除了休息之外,还可以对之前的工作进行总结和反思。另外长时间专注于某一个项或一类工作后,也许要时间重新积蓄一些热情了。

    总而言之,番茄法更强调的是执行过程的专注以及工作节奏的把握,再结合适当的反馈技巧,可以让你的效率有提高,至于提高幅度因人而异了。

    在试用番茄法的过程中,我也总结了一些经验技巧,供大家参考揣摩:
    - 根据个人实际情况,合理设置自己一个工作日内的番茄时间段,尽量将重要的工作放在头脑高效的时段,比如上午8:30~11:00,下午15:00到17:00等。不一定所有工作都要纳入番茄时间段里,找到适合自己的工作节奏。
    - 做好准备工作,明确各个番茄时间内对应的任务,最好将任务简单写到纸质便签/日记本中,便于实施画X,强化反馈。
    - 每4个番茄时段内的task的上下文差别不要太大,尽量减少task间的切换成本(进入某个task的工作状态是需要时间的)。
    - 在番茄时间段内task没完成咋办? 这个估计经常发生,似乎只好在下一个番茄时间段里继续做了。其他task顺延。必要情况下加班完成。一旦出现这种情况,就需要你加强task划分能力,尽量做好task完成时间的预估,不断提升精确估计能力。
    -打扰是不可避免的。电话、邮件都可能打断你的工作。如果必要,可在你的番茄时间段中预留出一些处理打断的时间,比如25+5,预留5分钟。当然我们应该尽可能避免这种打扰,可用一些广为流传的技巧:比如在允许的范围内适当将mail接收的间隔延长;高挂“免战牌”,显式告知他人你已经“out of services”了;不启动即时通信工具,或设置即时通信工具的状态为外出或极其繁忙状态等等。

    再强调一点,番茄法不是孤立的,可以与其他时间管理方法(如GTD )结合使用。

    以上是个人小试番茄法之后的一些体会,图灵出版了《番茄工作法图解:简单易行的时间管理方法 》,是著名的Pragmatic Bookshelf系列,不过我还没有读过, 可能也不打算读,有些东西自己体会和感悟的更深刻,不是吗^_^。

  • 最近观察到这样一种情况,项目组内的两位比较资深同事似乎都习惯于这样来编码:他们可能会花上两、三周时间将一个模块的成百上千行代码一气呵成的编写完,然后再去与其他人编写的代码集成在一起编译,测试,最终提交。这种情况让我有些惊讶,因为我觉得一个良好的编码节奏不应该是这样的,原因有三:

    .这样的节奏不利于问题的早发现早解决

     我们都知道问题发现越早,其解决成本越小。如果只是一味地编写代码,甚至连一次编译都不做,又怎么可能尽早发现自己代码中的问题?怎么可能提早发现其他人的提交对你的模块可能带来的影响呢?这样下去的最终结果很可能是大量的返工或某个隐藏很深的问题,需要花费你较大力气去解决。

    .这样的节奏还可能会导致激情疲劳

     激情也会产生疲劳。想必很多朋友都有过类似的经历:一旦长时间投入在一件事情上,如若没有阶段性的成果或者中途遇到一些挫折,那激情也会疲劳,甚至是丧失。程序员都是很有激情的!你一定见过那些整天以方便食品度日,为了某个功能奋战N天N宿的蓬头垢面的程序员们。他们埋头于键盘与屏幕间,将用智慧加工后的字符输入到计算机中。但程序员也是人,如果一直这么下去,没有阶段性反馈,渐渐地,他们的效率就会降低,思维就会僵化,最终导致结果远不如预期。

    .这样的节奏不利于自身信心的建立

     在这样只有编码,没有编译,没有必要单元测试的情况下,你如何确保代码质量是没问题的呢?你是否敢于站出来对着大家说我编写的代码是牢不可摧的。显然你不能,因为你没有收到任何关于代码质量评估的反馈。甚至于你的代码是否可以正确地通过编译器的检查都未曾而知,你又哪里有对代码的那份自信呢?

    好了,说了这么多原因,那什么样的节奏算是良好的节奏呢?用一句话概括就是“小步快跑,迭代进行,循序渐进”。其主旨在于划大为小、快速完成、快速反馈(通过构建、单元测试)、快速调整,依此循环往复。划大为小是基础,也是一种任务分解的能力;快速完成和反馈能让你及早发现问题,包括自身的以及与他人集成过程中的;快速调整意为迅速应对发现的问题,及时变更设计、重构代码,直至满足。这样每轮下来,你会发现已经完成的任务都是相对健壮的,这种健壮同时也会给你一种正面的反馈,让你保持继续的激情和动力,同时也会给你带来充足的信心。这样一轮一轮下去,你就会持续不断地得到正反馈,这会促使你最终得到一个相对比较健壮的成果物,你的信心也会因此得到倍增。

    如果你和我的同事采用了同样的编码节奏,那你不妨尝试调整一下^_^。

  • 一般来说,只有周末我和老婆才有机会一起陪果果。我们就抓紧这段时间多陪果果到户外,现在是春末夏初,户外天气十分宜人,果果也十分喜欢到户外活动。这不今天又给果果拍了一组“写真”,我们称之为“花丛系列”^_^。


    花丛中-果果正面照


    花丛中-果果远景


    花丛中-果果近景


    可爱的果果

  • 市面上关于优秀编程风格和习惯养成的书籍还真不少,其中“叫好又叫座”的书诸如《代码大全》、《编程精粹:编写高质量C语言代码》、《编程匠艺》、《重构》以及《Clean Code》等。不过前些天我在网上下载了一本名为《The Elements of Programming Style》的电子书,看过此书后,我才知道开创编写优秀风格代码之路的鼻祖是谁(不知道是否还有比这本书更加古老的且系统地讲述优良编程元素的书籍了?)。

    这本书的两位作者来头都大得很。Brian W. Kernighan,K&R C中的那个“K”,C语言的鼻祖之一。 P. J. Plauger,《C标准库》一书作者,同样是大师级人物,说不准你现在使用的C标准库还是Plauger当初操刀实现的呢^_^。这本书的出版年份为1978年,Wow,Older Than Me!距今有30多年了,在编程领域算是一本“古书”了。其第一版则更早,于1974年出版。这本书的中心思想是计算机程序编写不应该只满足于编译器或者某些个体的编程风格,还要满足人们对程序的“可读性”的要求。据说当时这本书的出版让全天下的程序员们恍然醒悟,从此大家便知道了优秀编程风格是什么样子的,优秀的代码是应该这么写的。

    这本书我还没有全部看完,目前也只看完了前面的十几个条目和例子。本以为书中会用C语言做例子,没想到作者居然用了Fortran和PL/I,整本书“充斥”着用陌生的Fortran和PL/I语法编写的例子。后来我也想明白了:在那个年代,Fortran才是老大,C语言初出茅庐,还仅仅停留在Bell Lab中。不过也正因为如此,这本书看起来那叫一个费劲,让人头疼。于是我到网上搜出了这本书的所有条目列表。完整地看完一遍这些条目后,我甚感吃惊,吃惊的是这本古书中的大多数条目对我们今天的代码编写依旧具有着非凡的指导意义,甚至可以理解为编程领域的公理(至少在目前以及可预见的时间段内都是生效的)。另外当你看完这些条目后,你会发现有些似曾相识的感觉,原因也很简单。我们看到的《代码大全》、《重构》等“近现代”书籍可能都或多或少的从这本古书中继承了一些内容,并结合现代编程思想加以扩展和升华了!

    那《The Elements of Programming Style》这本“古书”是否还值得去读呢?毕竟我们已经有了像《代码大全》这样的百科全书了。我觉得至少应该过一遍这本书的条目列表,并且针对你感兴趣的重点条目去精读。三十多年前的古训也许更能还原出条目在当时所处的历史场景,这也许是当前一些书籍所不具备的。特别是如果你觉得《代码大全》太厚重,那么不妨可以先来聆听一下这本小书中的“古训”^_^。