代码大全读后感3

发布时间 2023-10-31 22:16:45作者: 千恒

软件构建的定义:包括编码与调试、单元测试、规划构建、集成等,没有给出一个明确的定义。

软件构建的重要性:软件构建是编写大型项目最重要的、不可或缺的部分。 

对软件开发地隐喻不是明确的标准,而是微妙的启发,所以不要被隐喻限制而远离“不符合”隐喻的方法。可以将不同的隐喻结合启发自己构建代码。

一个好的隐喻是将代码构建比作珍珠的生长(accretion),从外在吸收材料并慢慢成长的过程。代码的构建应该是增量式的,从一个基础的框架开始每次增加一点点。假如一开始的代码没有完整的功能,也应该用dummy class搭起一个基本的框架,然后逐一替换成细致可用的代码。这个思想与《程序员修炼之道》中的“曳光弹”思想一致。

另一个好的隐喻是将代码构建比作建筑。

首先,越大的架构修正错误的消耗越大,所以需要从一开始就仔细地设计框架。然而对代码的设计不应该过于细致,应该始终保持解耦,细节随时可以在后期更换。

另外,代码构建可以引用第三方库,也可以根据需要自己编写库。

最后,不同的项目需求所需要采取的构建方式可以是截然不同的。

根据数据,引入错误到发现错误的时间越长,修正错误的消费越大。进行充分的前期准备可以将需求、设计上的错误扼杀于萌芽。

软件大致分三种:商业系统、使命攸关的系统、使命攸关的嵌入式系统。

我们的项目属于商业系统,推荐采用敏捷的、增量式的开发,计划、管理可以非正式,需求可以非形式化,设计可以和编码同时进行,测试可以较少。

我有一点异议:尽管是商业开发,也应该有较正式的计划管理、形式化的需求与经常的测试,只是由于商业开发解决错误的消耗较少,所以这些不用过分冗余。

迭代式开发中,需求发掘、构建、设计等工作较为重合,伴随整个编码过程,检错修正的成本在过程中逐次交付。序列式开发中,各工作较为独立,每一个工作依赖于前一轮工作。对两种开发方式,前期准备均可以大大降低成本。对于需求稳定、设计理解透彻、开发者熟悉相关领域、项目风险小、需要长期可预测性、后期更改代码消耗很大的项目,推荐采用序列式开发。反之,推荐迭代式开发。问题定义:需要用自然语言、从用户的角度定义,并不涉及具体的解决方式。需求:明确的需求可以避免程序员错误地理解需求、避免开发者之间的争论。需求不是稳定的。如何处理需求的变更:经常评估需求的质量;确保每一个人都知道变更需求的代价以免心血来潮;在新需求过多的情况下建立变更控制程序;使用能适应变更的开发方法。架构:本书没有将过多笔墨花在架构上,但私以为架构很重要。架构的典型组成:

程序组织:各构造块的分工与合作;主要的类;数据设计;业务规则;UI;资源管理;安全性;性能;可伸缩性;互用性;国际化/本地化;IO;错误处理,及相关约定;容错性;架构可行性;是否需要冗余;使用第三方库还是自己构建,以及为何这么做;是否复用;应对变更的策略;总体质量。

关键的“构建”决策

 选择编程语言:熟悉的语言比不熟悉的语言生产力高;高级语言(java, c++, python, perl…)比低级语言生产力高。编程约定,如变量命名、类命名、函数命名、格式、文档等。在技术浪潮中的位置:浪潮后期可以稳定持续地编写新功能,而浪潮前期需要耗费更多时间应对不完善的技术。Working in a language vs. working into a language,Working in a language意味着对一种语言不够了解,被语言本身的逻辑限制;working into a language意味着在了解已有语言的基础上,由思想确定使用的语言及使用语言的方式。选择主要的构建方法,如编码约定、团队工作方式、质量保证措施、各种工具等。设计是一个“险恶”的问题:只有通过解决或至少部分解决,才能明确地定义它。设计中会有很多错误和修正的过程。设计有诸多限制,要针对限制与需求进行取舍。设计是不确定的,是启发式的过程,是自然而然的。管理复杂度:把任何人在同一时间需要处理的本质复杂度减小到最小(模块化、分工),不要让偶然复杂度无谓地增长(封装、良好的问题处理机制)理想的设计特征:

复杂度最小(可以为此牺牲算法的精巧);易于维护;松散耦合;可拓展;可复用;高扇入,即让某个特定的类被大量调用,意味着更好地利用低层次的工具类;低扇出,即让某个特定的类尽可能少调用其它的类,减少依赖关系;可移植性;精简性;层次性;标准化。设计层次:系统层次分解为子系统或包,常用的有业务规则、用户界面、数据库访问、系统依赖性。对子系统之间的交互关系要加以限制到最简,一个常用原则是应该无环。分解为类分解为子程序子程序内部设计。一些帮助设计的启发式方法:找出现实世界中的对象:辨识对象及其属性,定义可对对象执行的操作,定义对象可对其它对象执行的操作,如继承、包含,定义对象哪些属性对其它对象可见定义每个对象的接口。

形成一致的抽象。基类就是一种抽象。可以忽略不必要的细节。用封装实现细节。

当集成能简化设计时要继承。

信息隐藏,隐藏复杂度及隐藏变化源。要避免循坏依赖。不要因为考虑性能放弃信息隐藏,应该在后期寻找性能瓶颈。信息隐藏很有价值,要养成问自己“我应该隐藏什么”的习惯。

找出容易改变的区域,用封装将它与其它区域隔离。如:业务规则,硬件依赖性,IO,非标准的语言特性,困难的设计区域,状态变量,数据量的限制(如数组大小,用宏定义、const替代),。

标准:规模,耦合越小越好;可见性,接口应该公开;灵活性。

其它,如:高内聚性,一组代码在支持同一目标上的紧密程度;分层结构;严格描述类契约;分配职责;为测试而设计;考虑并避免失误;有意识地选择绑定时间;“唯一一个正确位置的原则”:每一段代码应该只在一个地方能看到,也只在一个地方能进行维护和修改;考虑暴力算法;画图;保持模块化。自上而下:从高抽象层次向下逐层增加细节的层次,简化问题的复杂性

自下而上:从具体需要执行的工作出发,进行分类、组合

二者实际没有矛盾,应该配合使用。

构建原型(同样在《程序员修炼之道》中提到过):用最简单的方式写出仅用来试用某个功能、隐藏细节的代码,随时可以丢弃合作设计记录设计成果,方式如将设计文档写入代码、Wiki、总结邮件、数码相机、设计挂图、索引卡片、uml图