程序员修炼之道

第1章 注重实效的哲学

1 我的源码让猫给吃了


在所有的弱点中,最大的弱点就是害怕暴露弱点
——J. B. Bossuet,Politics from Holy Writ,1709


为你自己和你的行为负责的这一观念,是注重实效哲学的一块基石。 注重实效的程序员对他自己的职业生涯负责,并且不害怕承认无知或错误。这是说在出了问题的时候我们必须诚实和坦率——可以为成绩和能力自豪,也必须对无知和错误诚实。

负责

责任是你主动担负的东西。
你承诺确保某件事情正确完成,但是你不一定能直接控制事情的每一个方面。这里面有两点:1)超出了自己控制范围的风险,有权不去为之负责;2)确实同意要为某件事情负责,就应切实负起责任。
如果是自己需要负责的事情出现了风险,应该提供各种选择而不是寻找蹩脚的借口。如果一定要说,就先对你的猫说。没有解决方案的借口没有任何好处,还会影响在别人心中的形象。

2. 软件的熵

不要容忍破窗户

通过不容忍”破窗户“的方式来控制软件系统的熵。

灭火

优秀完整的代码,及时灭火的时候大家也不想弄脏他。所以不仅不要破窗,还要保持窗户的干净整洁。

3. 石头汤与煮青蛙

石头汤是指”3个士兵通过煮石头调动了周围村民的热情,齐心合力的做了一顿最好吃的饭“。煮青蛙是指”任谁煮青蛙“。
煮石头的故事首先告诉大家如何去调动资源。通过核心人物、事情做出成果,然后吸引更多的人来加入。要做变化的催化剂,在这个过程中,可以考虑”请求原谅比获取许可更容易“。
与煮青蛙相比,煮石头对村民是带了了好处。但是很多时候煮青蛙式的变化,会导致人民忽略变化,而使事物发展超出控制。所以在起变化催化剂的时候,需要关注大图景

起变化的催化剂,但是不要像青蛙一样,要留心大图景。要持续观察周围发生的事情,而不只是你自己在做的事情。

4.足够好的软件


欲求更好,常把好事变糟。
——李尔王 1.4


让你的用户参与权衡

  1. 系统的范围和质量应该作为系统需求的一部分规定下来。

使质量成为需求问题。

知道何时止步

不要因为过度修饰和过于求精而损坏完好的程序,让你的代码凭着自己的质量站立一会。

5. 你的知识资产


知识上的投资总能得到最好的回报。
——本杰明·富兰克林


知识是一种资产,但是它是一种有时效性的资产。随着你的知识的价值降低,对你的公司或者客户来说,你的价值也在降低。

你的知识资产

关于计算技术和所工作的应用领域的全部事实、以及他们的所有经验视为他们的知识资产。

可以发现程序员的知识资产分为3中:1)计算机相关技术;2)在某个业务领域的知识;3)其他的经验等技能。所以不能把资产只看做技术这一块。

管理知识资产和管理金融资产非常相似:

  1. 严肃的投资者定期投资——作为习惯。
  2. 多元化是长期成功的关键。
  3. 聪明的投资者在保守投资和高风险、高回报的投资之间平衡他们的资产。
  4. 投资者设法低买高卖,以获取最大回报。
  5. 应周期性的重新评估和平衡资产。

经营你的资产

  • 定期投资。必须定期投资,即使投资了很小习惯自身也和总量一样重要。
  • 多元化。你知道的不同事情越多,你就越有价值。底线是你需要知道你目前所用的特定技术的各种特性。但是不要止步,掌握的技术越多,越能更好的进行调整——不会信息过载,更好的可以赶上变化。
  • 管理风险。
  • 低买高卖。在新技术刚出现的时候学习它可能和找到被低估的股票一样困难。
  • 重新评估和平衡。计算机是一个非常动荡变化的行业,所以需要及时评估。

定期为你的知识资产投资。

目标

前面介绍了何时以及增加什么到你的知识资产中 ,现在你已经拥有了一些指导方针,那么什么是获得智力资本、从而为你的资产提供资金的最佳方式呢?这里有一些建议。

  • 每年至少学习一种新语言。不同语言以不同的方式解决着相同的问题。通过学习不同的方法,可以帮助你扩宽思维,并避免墨守成规。
  • 每季阅读一本技术书籍。刚开始阅读与项目有关的书籍,后续拓宽范围阅读一些与你项目无关的书籍。
  • 也要阅读非技术书籍。记住计算机是由人——你在设法满足需求的人——使用的,这十分重要。不要忘了等式中人这一边。

这个点非常重要,以人为本。

  • 上课。在学院、大学或者展会上寻找有趣的课程。
  • 参加本地用户组织。不要只是去听听,而是要参与。与世隔绝对你的职业生涯可能是致命的,打听一下你们公司以外的人都在做什么。
  • 试验不同的环境。用惯了windows可以换个Linux等。
  • 跟上潮流。订阅商务杂志和其他期刊。选择所涵盖的技术与你当前的项目不同的刊物。
  • 上网。

持续投入非常重要。要把学到的知识进行使用,及时没有使用该技术也可以借鉴一些想法,思想的“异化授粉”非常重要。

学习的机会

即使站在了所有突破性进展的前沿,当别人问你问题你却回答不上来时,也需要坦然承认,然后去寻找答案。
可能自己通过上网、图书馆等无法找到问题,但是一定有人可以知道答案。
在学习上面,不仅不能止步,而且还要随时学习。

批判的思考

批判性的思考你读到的和听到的,你需要确保你的资产中的知识是准确的,并且没有收到供应商和媒体操作的影响。

**批判地分析你读到的和听到的,要为自己的知识资产负责。

6 交流


我相信,被打量比被忽略要好。


问题不是你有什么,而是看你怎样包装它。

知道你想要说什么

先梳理好大纲,问自己“这是否讲清了我要说的所有内容?”。而不是坐下来就写“1.介绍”。

了解你的听众

只有当你在传达信息时,你才是在交流。为此,你要了解听众的需要、兴趣、能力。
图1.1显示WISDOM离合诗可能会有帮助。

程序员修炼之道_第1张图片
离合诗

选择时机

需要弄清楚听众的“轻重缓急”,这样才可以事半功倍。

选择风格

调整你的交流风格,让其适应你的听众。

让文档美观

你的注意很重要,它们应该以美观的方式传递给你的听众。

让听众参与

尝尝发现,与制作文档的过程相比,制作出的文档最后并没有那么重要。如果可能,让你的读者参与文档的早期草稿的制作。获取它们的反馈,汲取它们的智慧。

做倾听者

如果你想要大家听你说话,你必须使用一种方法:听他们说话。通过鼓励大家提问来交谈,或是让他们总结你告诉他们的东西。把会议变成对话,你将能更有效的阐明你的观点。

回复他人

你说什么和你怎么说同样重要。

交流越有效,你就越有影响力。在回复他人时需要做到及时——即使是“稍后回复”,而且还要在发送前做检查,以达到准确。

在发送前检查一定要做,尤其现在智能输入法的情况下,很容易出现错别字。如果平时聊天还好,在稍微重要的场合就非常尴尬。

第2章 注重实效的途径

7. 重复的危害

因为知识会随着需求、环境、政策等的变动而变动,所以知识是不稳定的。当知识散落在应用的各处时,维护就是一场噩梦。

系统中的每一项知识都必须具有单一、无歧义、权威的表示。要遵守“RRY”——不要重复你自己的原则。
我刚开始对DRY原则的理解是不要做重复的事情,这样可以提高开发效率,忽略了其中最重要的一点:在有重复的情况下,发生变更的时候就是噩梦。

重复是怎样发生的

  • 强加的重复。开发者觉得无可选择。
  • 无意的重复。开发者没有意识到他们在重复。
  • 无耐性的重复。开发者偷懒。
  • 开发者之间的重复。同一团队的人重复了同样的信息。

强加的重复

信息的多种表示。同一种信息被以多种方式表示,例如支持不同语言的代码,这种情况可以抽象成一个元数据,根据元数据用代码生成多语言信息。
代码中的文档。程序员一直被要求写注释,但是没人告诉他们为什么写注释:糟糕的代码才需要注释。DRY原则告诉我们,低级知识放在代码中,把注释留给高级说明。
文档与代码。例如需求变更之后,应该测试代码也需要发生变更。
语言的问题。有些文件会在源码中强加客观的重复。

无意的重复

有时,重复来自设计中的错误。
例如一个线段类如下:

class Line{
  public:
    Point start;
    Point end;
    double length;
}

第一眼看上去,这个类似乎是合理的:一个线段有起点、终点和长度。但是长度是有起点和终点决定的,所以最好让长度是成为一个计算字段:

class Line{
  public:
    Point start;
    Point end;
    double length(){
      return start.distanceTo(end);
    };
}

在以后的开发过程中,你可以因为性能原因而选择违反DRY原则。例如每次都计算length很耗费时间,可以使用字段进行存储。如下:

class Line{
  private:
    bool changed;
    double length;
    Point start;
    Point end;

   public:
    void setStart(Point p){ 
      start=p;
      changed=true;
     }

    void setEnd(Point p){ 
      end=p;
      changed=true;
     }

    Point getStart(void)  {return start;}
    Point getEnd(void)  {return end;}

    double getLength(){
      if(changed){
        length = start.distanceTo(end);
        changed=false;
      }
      return length;
    };
}

这个例子说明了像Java或C++这样的面向对象语言的一个重要问题:在可能的情况下应该总是用访问器函数读写对象的属性,这将使未来增加功能(比如缓存)变得更容易。

使用了访问器,那么类有没有这个私有属性不重要。即getLength()方法里面可以直接计算,也可以为了缓存增加length这个字段。
这里特意强调是因为在写代码的时候用了lombok的注解,导致潜意识中把私有变量和访问器变成了对等的,实际上他们是完全可以独立的。

8.正交性

什么是正交性

正交性是一个数学用语,在计算机中表示某种不相依赖性或解耦性。如果两个或更多事物中的一个发生变化,不会影响其他事物,这些事物就是正交的。

正交的好处

消除无关事物之间的影响

我们要设计自足的组件:高内聚(独立、具有单一、良好的目的)。
如果你编写正交的系统,有两个主要好处:提高生产率和降低风险。

提高生产率

  • 改动得以局部化,所以开发时间和测试时间得以降低。
  • 正交的途径还能够促进复用。如果组件有明确而具体的、良好定义的责任,就可以用其最初实现着未曾想过的方式,把它们与新组件组合在一起。
  • 如果你对正交的组件进行组合,生产效率会有相当微妙的提高。例如做M件事的组件和其正交的做N件事的组件结合,那么就会有MxN件事情,如果非正交就有重合的部分。

降低风险

  • 正交的途径能够降低任何开发中固有的风险。
  • 有问题的代码区域被隔离开来。某个模块有毛病,不会扩散到系统的其余部分。
  • 所得系统更健壮。对特定区域做出的改动与修正,所导致的任何问题都将局限在该区域中。
  • 正交系统很可能得到更好的测试。
  • 你不会与特定的供应商、产品或是平台紧绑在一起。

项目团队

设计

不要依赖你无法控制的事物属性。

工具箱与库

引入工具箱和库的时候,要注意保持系统的正交性。

编码

  • 让你的代码保持解耦。编写“羞怯”的代码——不会没有必要的向其他代码暴露任何事情、也不依赖其他模块的实现模块。
  • 避免使用全局数据。每当你使用全局数据时,它都会把自己与共享该数据的其他组件绑在了一起。
    单例模式是确保特定类的对象只有一个实例的一种途径,许多人也把singleton对象用作某种全局变量,使用时要小心,可能会造成不必要的关联。
  • 避免编写相似的函数。你常吃会遇到看起来全都很像的一组函数,使用策略模式。

测试

正交地设计和实现的系统也更易于测试,因为各个系统的各组件间的交互是形式化的和有限的,更多的系统测试可以在耽搁的模块级就行。

9.可撤销性

如果某个想法是你唯一的想法,再没有比这更危险的事情了。

可撤销性

不存在最终决策。要做到“中流换马”。

灵活的架构

灵活性不仅指代码,还有架构、供应商等等。
如果你必须把大量的某些语句分布在代码中,该怎么办?把该需求放入到元数据,并且使用某种自动机制——例如Aspect——把必要的语句插入代码。可以自动插入就可以自动消除。

10.曳光弹

一种是在黑暗中通过精确计算得到位置击中目标;一种是用曳光弹。普通子弹可以击中的曳光弹也可以。

黑暗中发光的代码

用户对自己不清晰的时候,如果通过传统的方式把未知元素、各项需求、限定环境一一列举,那么工作量非常大。但是可以通过曳光弹得分方式,先动起来。

  • 用户能够及早看到能工作的东西。及早反馈。
  • 开发者构建了一个他们可以在其中能够工作的结构。
  • 你有一个集合平台。
  • 你有了可用于演示的东西。
  • 你将能够看到工作进展。

你可能感兴趣的:(程序员修炼之道)