《程序员应该知道的97件事》样章

谨慎行动

Act with Prudence

勒布·罗斯Seb Rose

 

无论你承诺了什么,都得小心处置,顾及后果
                                  ——无名氏

在一次迭代开始时,各项任务看上去安排得张弛有度,但仍无法避免在某段时间会承受到巨大进度压力。当你发现必须在干得好干得快之间作出抉择时,一般都会选择干得快,并提醒自己将来再来返工。你对自己、团队和客户许下这个承诺的时候,确实是想这样做的。但经常会出现的情况是,下一轮迭代自有其新问题,你只好把工作重点转移到新问题上。这类久拖不决的工作任务就是所谓的技术债务(technical debt),它可不是你的好朋友。Martin Fowler在他的技术债务分类法里把它叫做蓄意技术债务(deliberate technical debt1,有别于无意技术债务(inadvertent technical debt)。

技术债务就像一笔贷款。在短期内,你能从中得到好处,但是,在清偿之前,你要付出利息。代码里的捷径使得新功能更难于加入,也会影响到代码重构。它们是软件缺陷和失败测试用例的滋生地,放任它们的时间越长,情况就会越糟糕。当你有一天终于想兑现之前的承诺,对它们进行修改时,会发现代码已经难以重构和更正。事实上,往往是情况变得不可收拾时,你才不得不对它们进行修正,而那时你已没有足够的时间,也承担不起由此带来的风险。

难免有几次为了赶上最后期限,或要为一项特性做个简化版本,不得不背上技术债务。请尽量不要陷入这样的境地,如果实在是形势逼人,那就勇敢地去承担。但是(注意,这是加重语气的但是),必须时刻追踪这笔技术债务,尽快地或者当情况急剧恶化的时候,立即将其偿还。每当你迫不得已欠下了技术债务,就要立刻记录到任务卡上或者登记到问题跟踪系统里,以保证其不会被遗忘。

如果在下一轮迭代里偿还了这笔债务,其代价就会减少到最小,如果总是不还,利息就会日益累加。每笔利息都应该被跟踪到,使其代价显而易见。这一措施彰显出技术债务对项目的商业价值的负面影响,从而给还贷一个适当的优先级。利息的计算和跟踪方法因项目不同而互有差异,但是,这类跟踪是必须做的。

尽快偿还你的技术债务吧,否则你会为你的轻率而后悔。


函数式编程原则的应用

 

Apply Functional Programming Principles

爱德华·加森Edward Garso)

 

函数式编程最近又在主流编程社区里火热起来了,其部分原因是计算机芯片工业正在向多核发展,函数式范型(functional paradigm)的特性恰好能应对多核时代的挑战。函数式编程在这方面的应用固然重要,但这并非本文把它推介给你的原因。

掌握函数式编程范型(functional programming paradigm)能极大地提高你的代码质量,不管是在哪类应用环境下。如果你能深入领会并熟练运用函数式范型,那么你的设计就会显示出更高的引用透明性(referential transparency)。

引用透明性是一个非常重要的属性:它意味着函数不管在何时何地被调用,都保持一致的行为,同样的输入得到同样的输出结果。也就是说函数的输出值很少——理想的情况下根本不会——受制于由多变的状态值带来的副作用。

过程式代码(imperative code)最突出的缺点就是状态变量众多。每一个读到这段话的人都曾经有过这样的经历:一些值在某个特殊的位置会变得跟预想的不一样。可见性语义(Visibility semantics)有助于去除一些隐蔽的错误,或者能极大地缩小发生问题的根源范围,但是,罪魁祸首可能还是因为在设计思想里使用了太多变化莫测的状态值。

在原来的思路上,我们当然无法再获得多少帮助。因此,需要引入面向对象编程来提升此类设计,因为在经常展示的面向对象例子里,关联的长寿命对象(long-lived objects)之间可以方便地调用状态因子方法(mutator method——这可能也会有危险。然而,在灵活的测试驱动设计里,特别是当确信要模仿角色,不用对象Mock Roles, not Objects1时,不必要的易变性就能被排除在外了。

最终解决办法是实现一种设计,其典型特征是负责分配数量更多、粒度更细的函数,这些函数依据传入的参数做相应的处理,而不是依赖于易变的成员变量。这样不仅能减少差错,并且在将来也容易调试,因为在这些设计中定位奇怪变量要比在特定场景推断出错误的赋值要容易得多。这样在引用透明性上就提高了一个层次,没有什么能比学习一门函数式编程语言更能使这种感受深入人心了,在函数式编程里,这种计算模型就是标准。

当然,这种方法不是在所有情景下都是最好的选择。举例来说,在面向对象系统里,针对此类问题,领域模型开发(domain model development)(比如用一系列协作来分解复杂的业务规则)好过基于用户界面的开发。

掌握了函数式编程范型之后,你可以把从中学到的知识应用到其他领域。对象系统(举个例子)将会从引用透明性的优点中获益良多,比你所相信的更加符合它们的功能属性。事实上,甚至有些人断言说函数式编程和面向对象的顶点相互映照,如同计算形态里的阴阳两面。

 



1  http://martinfowler.com/bliki/TechnicalDebtQuadrant.html.

1  http://www.jmock.org/oopsla2004.polf.

posted @ 2010-10-12 22:19  博文视点  阅读(498)  评论(0编辑  收藏  举报