程序员修炼之道(通俗版)——第二章

《程序员修炼之道》这本书中的内容挺不错,里面包含了很多精华,但一些句子很拗口,所以我就根据国人的阅读习惯,在不改变原意的情况下对词句稍加修改,标题中的“通俗版”就是这么来的。

1、我们觉得,可靠地开发软件、并让我们的开发更易于理解和维护的 唯一途径,是遵循DRY(Don’t Repeat Yourself)原则:系统中的每一项知识都必须具有单一、无歧义、权威的表示。
与此不同的做法是在两个或更多地方表达同一事物。如果改变其中一处,就必须记得改变其他各处。这不是你是否能记住的问题,而是你何时忘记的问题。

2、当我们拥有多个互相依赖的数据元素时,会出现一种较隐蔽的不规则数据。让我们看一个表示线段的类:

public class Line
{
    public int Start{get;set;}
    public int End{get;set;}
    public double Length{get;set;}
}

第一眼看上去,这个类似乎是合理的,线段显然有起点、终点和长度(即使长度为0)。但这里有重复,长度是由起点和终点决定的:改变其中一个,长度就会变化,所以最好让长度成为计算字段:

public class Line
{
    public int Start{get;set;}
    public int End{get;set;}

    private double _length;
    public double Length
    {
        get{return GetLength();}
    }

    private double GetLength
    {
        return End-Start;
    }
}

3、你可以对项目团队的正交性进行非正式地衡量,只要看一看,在讨论每个改动时需要涉及多少人。人数越多,团队的正交性越差。显然,正交的团队效率更高。

4、每次你编写代码,都有降低应用正交性的风险,除非你不仅时刻监视自己正在做的事情,也时刻监视应用的更大语境。否则,你就有可能无意中重复其他模块的功能,或再次表示已有的知识。
你可以将若干技术应用于维持正交性:

  • 让你的代码保持解耦。编写“羞怯”的代码——也就是不会向其他模块暴露任何不需要暴露的事情、也不依赖于其他模块的实现的模块。在此可以试一试德墨忒尔法则(迪米特法则):如果你需要改变对象的状态,让这个对象替你去做。这样,你的代码就会与其他代码的实现保持隔离,并增加你保持正交的机会。

  • 避免使用全局变量。每当你的代码引用全局数据时,它都把自己与共享该数据的其他组件绑在了一起。即使你只想对全局数据进行读取,也可能会带来麻烦(例如,你突然要把代码改成多线程的)。一般而言,如果你把所需的任何语境显示地传入模块,你的代码就会更易于理解和维护。在面向对象应用中,语境常常作为参数传给对象的构造器。换句话说,你可以创造含有语境的结构,并传递指向这些结构的引用。

  • 避免编写相似的函数。你常常会遇到看起来很相似的一组函数——它们也许在开始和结束处共享公共代码,中间的算法却各有不同。重复的代码是结构问题的一种症状,要了解更好的实现,请参考策略模式。

5、构建单元测试本身是对正交性的一项测试。要构建和链接某个单元测试,都需要什么?只是为了编译或链接某个测试,你是否就必须把系统其余的很大一部分拽进来?如果是这样,你已经发现了一个没有很好地与系统其他部分解耦的模块。

6、修正bug也是评估系统正交性的好时候。当你遇到问题时,评估修正的局部化程度。你是否只改动了一个模块,或者改动分散在整个系统的各个地方?当你做出改动时,它是因此修正了所有问题,还是又神秘地出现了其他问题?这是开始运用自动化的好机会。如果你使用了源码控制系统,当你在测试之后,把代码签回时,标记所做的bug修正。随后你可以运行月报,分析每个bug修正所影响的源文件数目的变化趋势。

7、正交性和DRY原则紧密相关。运用DRY原则,你可以使系统中的重复降至最小;运用正交性原则,你可以降低系统各组件间的相互依赖。这样说也许有点笨拙,但如果你紧密结合DRY原则、正交性原则,你将发现你开发的系统会变得更为灵活、更易于理解、并且更易于调试、测试和维护。

8、与我们开发软件的速度相比,需求、用户以及硬件变得更快。假定在项目初期,你决定使用A提供的关系数据库。过了很久,在性能测试过程中,你发现数据库简直太慢了,而B提供的对象数据库更快。对于大多数传统项目,你不会有什么运气。大多数时候,对第三方产品的调用会缠绕在代码各处。但如果你真的已经把数据库的概念抽象出来——抽象到数据库只是把持久作为服务提供出来的程度,你就会拥有“中流换马”的灵活性。
与此类似,假定项目最初采用的是C/S模型,但在开发的后期,市场部门认为服务器对于某些客户过于昂贵,他们想要单机版。对你来说,那会有多困难?因为这只是一个部署问题,所以不应该要很多天。如果所需时间更长,那么你就没有考虑过可撤销性。另外一个方向甚至更有趣,如果要以C/S或n层方式部署你正在开发的单机产品,事情又会怎样?那也不应该很困难。
错误在于假定决策是浇铸在石头上的——同时还在于没有为可能出现的意外事情做准备。要把决策视为是写在海滩上的,大浪随时可能到来,把它们抹去。

9、有许多人会设法保持代码的灵活性,而你还需要考虑维持架构、部署以及供应商集成等领域的灵活性。
你正在开发UNIX软件?哪一种?你是否处理了所有可移植性问题?你正在为某个特定版本的Windows做开发?哪一种——3.1、95、98、NT、2000?支持其他版本有多难?如果你让决策保持软和和柔韧,事情就完全不困难。如果代码中有着糟糕的封装、高度耦合以及硬编码的逻辑和参数,事情也许就是不可能的。
不确定市场部门想怎样部署系统?预先考虑这个问题,你可以支持单机、C/S、n层模型——只需要改变配置文件。
通常你可以把第三方产品隐藏在定义良好的抽象接口后面。事实上,在我们做过的任何项目中,我们总能够这么做。但假定你无法那么彻底地隔离它,如果你必须大量地把某些语句分散在整个系统中,该怎么办?把需求放入元数据,并且使用某种自动机制——比如Aspect或Perl——把必须的语句插入到代码自身中。无论你使用的是何种机制,让它可撤销。如果某样东西是自动添加的,它也可以被自动去掉。
没有人知道未来会怎样,尤其是我们!所以要让你的代码学会“摇滚”:可以“摇”就“摇”,必须“滚”就“滚”。

10、语言的界限就是一个人的世界的界限。

11、把高级命令语言直接嵌入你的应用是一种常见的做法,这样,它们就会在你的代码运行时执行。这显然是一种强大的能力:通过改变应用读取的脚本,来改变应用的行为,却完全不用编译。这可以显著地简化动态的应用领域中的维护工作。

12、通过学习估算,并将此技能发展到你对事物的数量级有直觉的程度,你就能展现出一种魔法般的能力,确定它们的可行性。当有人说“我们将通过ISDN线路把备份发给中央节点”时,你将能够知道那是否实际。当你编码时,你将能够知道哪些子系统需要优化,哪些可以放在一边。
在某种程度上,所有的解答都是估算。只不过有一些要比其他的更准确。所以当有人要你进行估算时,你要问自己的第一个问题就是,该问题的语境是什么?他们是需要高度的准确性,还是在考虑球场的大小?
如果你的奶奶问你何时抵达,她也许只是想知道该给你准备午餐还是晚餐。而一个困在水下、空气就快用光的潜水员很可能对精确到秒的答案更感兴趣。
π的值是多少?如果你想知道的是要买多少饰边,才能把圆形花坛围起来,那么“3”可能就足够好了。如果你在学校里那么“22/7”也许就是一个好的近似值。如果你在NASA,那么也许要12个小数位。

13、关于估算,一件有趣的事情是,你使用的单位会对结果的解读造成影响。如果你说,某事需要130个工作日,那么大家会期望它在相当接近的时间内完成。但是,如果你说“大概要6个月”,那么大家知道它会在从现在开始的五到七个月内完成。这两个数字表示相同的是时长,但“130天”却可能暗含了更高的精确度。我们建议你这样表述估算的时间:

时长报出估算的单位
1~15天
3~8周
8~30周
30+周在给出估算前努力思考一下

14、在面对大型应用开发的各种复杂问题与反复无常的情况时,普通的估算规则可能会失效。我们发现,为项目确定进度表的唯一途径常常是在相同的项目上获取经验。如果你实行增量开发,重复下面的步骤会有奇效:

  • 检查需求
  • 分析风险
  • 设计、实现、集成
  • 向用户确认

一开始,你对需要多少次迭代。或是需要多少时间,也许只有模糊的概念。当你完成了初始功能的编码与测试,并将此标记为第一轮增量开发的结束时,基于已有的经验,你可以对迭代次数、每次迭代所包含的内容进行提炼。提炼会变得一次比一次好,对进度表的信心也将随之增长。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

changuncle

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值