-
2009-08-13
《程序员修炼之道》 第二章 注重实效的途径 - [新知随笔]
版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://liuyangsl.blogbus.com/logs/44090177.html
1. 重复的危害
软件系统中所使用的知识,是会不稳定变化的。比如市场环境的改变,政府决策的变化。
当知识变化的时候,软件系统的基础就出现了错误,这时就需要维护。
维护不应该只存在于软件的发布阶段,而是应该贯穿于开发过程的始终。
如果系统中对同一个知识进行了重复,那将给维护带来无法估计的麻烦。
因此应该避免在多个地方表达同一事物,这就是DRY原则(Don't repeat yourself)。(不管是代码还是文档)
重复的出现有以下几种:
(1)强加的重复:
因为代码结构的约束而不得不出现的重复,有以下几种。
<a>信息的多种表示:
跨越不同子系统使用同一知识结构。可以使用一个生成器,在多种语言的环境下,利用数据库中的元数据来构造出符合条件的结构体。
<b>代码中的注释:
注释应存在于高级结构中,以防止在低级应用中出现注释重复。
<c>文档与代码:
当代码改变后,文档往往没有时间更新。不妨用文档来驱动代码,先更新文档,再根据文档来操作代码。
<d>语言问题:
尤其是在面向对象语言中,会强加很多重复,比如接口及其实现,函数重构等。这种情况只能在编译时,仔细考察头文件和实现文件之间的差异。
(2)无意的重复:
在设计中,由于对象设计不合理,会产生重复:
<a>不同对象类型中,出现重复的属性。(比如:{a,b,c} {a,d,e})
<b>一个对象中,一个属性的改变会使另一个属性也需要改变。(比如:{start,end,length})
对象中的属性,应该使用访问器(get、set)来操作。
(3)无耐性的重复:
开发人员为了节省开发时间,产生的重复。但是往往欲速而不达。
(4)开发者之间的重复:
在开发人员开发自己的独立模块时,很可能生产出一些重复的基本逻辑处理函数。
应鼓励开发者互相进行主动的交流。比如新闻组和论坛。
集中存放实用例程和角本。以便找到可复用的东西。
阅读他人代码和文档,互助复查。
---------------------------------------------------------------------------------
2. 正交性
两个直线相互垂直成为正交。在坐标上表现为,当X值变化时,Y值不变。
也就是说两个或多个事物中一个变化,不会影响到其他。(不依赖性、解耦性)
正交系统的设计就是消除无关事物之间的影响。设计独立、自足的组件。
正交可以提高生产效率、降低风险、便于测试和修改Bug。
团队任务的划分也应该注意正交性。
将基础设施与应用分离。
先按照基础组件(数据库、通信接口、中间件、等)划分子团队。
再根据应用功能和成员能力进行调整,尽量降低子团队之间的偶合性。
设计正交系统:
系统由一系列相互协作的模块组成,每个模块实现不依赖于其他模块的功能。
模块可以被分为很多层,每层提供一级抽象,每层只使用下面一层的抽象。
当一个模块的功能变化时,只需要调整这个模块和它下一层的接口即可。
“对象持久模型”(object persistence scheme)
正交性也体现在:面向方面编程(AOP)
在使用外部工具或库的时候,也应该注意正交,这样可以很容易地更换提供商。
文档也可以使用正交。
正交编码:
<a> 让代码保持解偶:除非必须,不要向外部模块暴露任何事情,也不去依赖外部模块。
<b> 避免使用全局数据。应该把需要的东西显式地传入模块而不是在模块中去访问共享。
<c> 避免编写相似的函数。
---------------------------------------------------------------------------------
3. 可撤销性
不要过于依赖某一个事实,以至于当它改变时已经没有其他的解决办法。
我们在项目初期会做出一些重要决策,随着项目的进展,可选择的余地会越来越小,这些决策变得不能逆转。
一些方法可以帮助我们避免做出不可逆转的决策,DRY原则、解耦、使用元数据等等。
最重要的就是充分预计决策的可能变化,使项目保持灵活。
灵活性:代码、架构、部署、供应商集成。
在设计系统的时候应该注意:
<a> 考虑到单机结构、C-S结构、n层结构的简单转换。
<b> 应该把第三方产品隐藏在定义良好的接口后面。
<c> 注意系统兼容性。
---------------------------------------------------------------------------------
4. 曳光弹
在夜间战争中,射击往往使用曳光弹和子弹交错的形式,一发曳光弹一发子弹。如果明亮的曳光弹打中了目标,那么子弹也就会打中。这种反馈很即时,因为曳光弹处于和子弹同样的环境中,降低了外部影响,并且非常快速地接近目标。
当要构建一个从没有构建过的东西时,基本上已知的东西很少。含糊不清的需求、不熟悉的算法、技术、语言、库。这时候我们需要能在黑暗中发光的代码。
曳光代码是简单功能的试探,通过实现一个和项目相似的简单功能,就可以快速地判断可行性、找出困难。
之后,曳光代码将被扩展、完善,做为最终项目的一部分。
因此,曳光代码需要完整的错误检查、结构、文档、自查。
曳光代码的优点:
<a> 用户可以及早看到实例,并通过直观的对比来纠正需求上的错误。(重新构造曳光代码)
<b> 开发者构建出一个可行的工作结构。
<c> 以曳光代码做为平台,每天的工作结果都可以集成上去,成为一个可用的集成测试原型。
<d> 可以演示。
<e> 非常直观的工作进展情况。
曳光代码不同于原型。
原型可以是一个片面功能的示意,比如用户界面演示,而曳光代码则是一个可用的简单整体架构。
原型制作应该放在曳光代码之前,做为对目标侦察和试探。
---------------------------------------------------------------------------------
5. 原型与便签
原型是为了分析和揭示风险。
原型可以使多种形式的,只要能够准确地表达开发者的理解,并回答一些问题。
对以下工作建议制作原型:
架构、已有系统中的新功能、外部数据的结构或内容、第三方工具组件、性能、用户界面。
原型的价值在于通过它获得的经验教训。
原型应该尽量掩盖细节,把注意力集中在希望获得解答的问题上。
从原型中寻求解答:
主要组件的责任以及主要组件之间的协作关系。
耦合最小化。估计重复的潜在来源。
接口定义、约束关系、数据访问。
原型往往是用过就扔的,并不完整,也不代表任何工作进度。
但原型很容易被人误解,以为工作已经进行了很大一部分,如果需要避免这种误解,最好使用曳光代码。
---------------------------------------------------------------------------------
6. 领域语言
对于一个业务,可以用文字描述。可以用编程语言来实现。也可以定义小型的领域语言并编写解释器,制作专用的代码。
一个项目中会涉及到不同领域,使用不同的领域语言来描述项目,有助于专心解决该领域中的问题,忽略琐碎的细节。
数据语言:
产生某种数据格式供程序使用。比如软件配置文件中特殊的数据格式,只有软件自己定义的解释器才能将其编译为可用的数据结构。
命令语言:
自定义一些命令语句,并构造解释器。比如脚本就是一种命令语言,可以直接执行。
嵌入式语言:
把高级命令语言直接嵌入到程序中。在程序运行的时候,加载不同的外部脚本就可以使程序进行不同的行为,不用重新编译,方便灵活。
这些领域语言的文法大多简单易懂,但真的做到能够运行,却需要花很大力气来做解释的工作。
但是这种努力可以使高级语言更易懂,易于维护,为后期开发带来越来越多的回报。
---------------------------------------------------------------------------------
7. 估算
估算是为了避免发生意外。
估算的准确程度:不同的人对估算结果的准确性的要求有所不同。
估算的方法:
<a> 基本方法:去询问已经做过这件事的人。
<b> 理解提问内容:想要了解问题的范围,再去进行思考。
<c> 建立系统模型:需要一些源数据做为前提,开发一种普遍适用的计算方法。
<d> 把模型分解为组件:考察组件之间的关系,和它们对结果的影响。
<e> 给每个参数制定值:关注于那些对结构影响大的参数,保证尽量正确。
<f> 计算结果:通过调整参数,考量结果是否符合期望。
<g> 用实际结果来验证并改进估算方法。
估算项目进度:
在项目的开始,估算是模糊的。
在开发进行了一部分之后,通过这部分工作的实际情况来进行重新估计。
随着项目的进行,在多次迭代估算之后,估算的结果将趋向于正确。
在被要求估算时,告诉他:“我等会儿回答你。”多花一点时间来思考细节,会得到更好的结果。随机文章:
《程序员修炼之道》 第八章 注重实效的项目 2009-08-19《程序员修炼之道》 第七章 在项目开始之前 2009-08-19《程序员修炼之道》 第六章 当你编码时 2009-08-19《程序员修炼之道》 第五章 弯曲或折断 2009-08-18《程序员修炼之道》 第四章 注重实效的偏执 2009-08-17
收藏到:Del.icio.us







