构建:
用隐喻来更充分地理解软件开发和架构
隐喻:不是从错误-->正确;而是从不太合适-->更好。
前期的项目准备需要良好的问题定义
架构师消化需求,设计师消化架构,软件开发师消化设计。
软件的首要技术使命:管理复杂度。
编程思路决定你使用什么编程工具和语言,而不是编程语言决定你的编程思路。当然,决定了编程语言需就要调整自己的编程思路去最高效地使用编程语言的特性来完成目标。
设计:
人类更易于理解许多项简单的信息,而不是一项复杂的信息。所有的软件设计技术的目标都是把复杂问题分解成简单的部分。我们每次只关注一小部分,最后再连接起来。
理想的设计特征:
最小的复杂度,易于维护,松散耦合,可扩展性,可重用性,高扇入(让大量的类使用某个给定的类),低扇出(让一个类少量或适中地使用其他的类),可移植性,精简性,层次性,标准技术(标准化,常用的,减少别人的理解难度)
设计的层次:
1)软件系统;2)子系统和包;3)包中的类;4)类中的数据和子程序;5)子程序内部。
封装填补了抽象留下的空白。抽象可以让你从高层的细节来看待一个对象,而封装说除此之外,你不能看到对象里的任何其他细节层次。
隐藏信息细节:编写类和子程序时,要问一下自己我要隐藏什么细节。如:即使只是一行代码 g_id++,如果很多地方用到,g_id的递增实现可能会改变,就封装到一个newId()的函数里,既方便更改,也隐藏细节;id类型用typedef,若要修改数据类型,只要改一个就可以了。
隐藏复杂度,隐藏变化源。
隐藏信息的障碍:信息过度分散;循环依赖;
保持松散的耦合:函数传入参数尽量简单,数量少
启发设计的方法总结:
1)寻找现实世界的对象
2)画一个图
3)为测试二十几
4)高内聚性
5)保持松散耦合
6)藏住秘密
构建:
子程序
子程序名字:动宾结构,可带返回值描述,9~15个字母,
子程序长度:一页,200行以内。太短太长都容易出错。
子程序参数:7个以内,C是4个以内,参数顺序是输入-修改-输出-状态
宏定义即使是空宏也应该加上括号
宏定义的替代方案很多,如const,typedef,inline,enum,template,函数等。少用定义工程或函数的宏。
防御式编程
断言,是处理不应该发生,且小概率,但发生了后果严重的一种方法。一般用断言来检查前条件和后条件。对于高建壮性的代码,应该先使用断言再处理错误。
错误处理技术:(换,记,返,解,关)返回中立值,换用下一个正确的数据,返回与前一次相同的数据,换用最接近的数据,显示错误,把警告信息记录到日志文件中,返回一个错误码,用子程序处理错误,关闭程序。
异常:在恰当的抽象层次抛出异常;不能透露过多的异常信息以免不法利用;尽量及时处理异常,不要老推卸责任往上抛;避免使用空的catch语句。
隔离:隔栏外先用错误处理技术对数据做判断处理,隔栏内再用断言检测错误。
辅助调试代码:尽早引入调试代码,采用进攻式编程及早暴露错误和异常,宁要开发时惨痛失败,不要发布时输得惨烈。使用内置的预处理器debug。多设几级debug级别。
保留防御性代码:保留(检查重要错误代码,让程序稳妥崩溃的代码,为技术支持人员记录错误信息的代码,友好提示错误代码);去掉(检查细微错误代码,导致程序硬性崩溃代码)
总结:1.正确性与健壮性相矛盾,要想处理错误返回正确信息,就会牺牲一定的健壮性,如可能会关闭程序退出,或重新执行;要在遇到错误仍能继续执行下去,就会牺牲一定的正确性,用一定换数据方法继续下去。 2.采用进攻式编程达到防御式编程,以攻为守。 3.对防御式编程采取防御的姿态。
伪代码辅助编程
作用:伪代码可以在更高层次构建子程序,而不用受细节语法的约束和干扰。
步骤:创建类的总体设计-->创建子程序【添加子程序注释-->创建伪代码(检查先决条件和后条件,定义子程序要解决的问题,为子程序起名字,决定如何测试子程序,在标准库找可用,考虑出错处理,考虑效率问题,研究算法和数据类型,编写伪代码,检查伪代码)-->检查伪代码-->分解伪代码】-->用最终代码在伪代码下填充-->编译子程序(打开最高警告,在调试器中逐步执行代码)-->消除错误-->检查子程序(接口输入输出,设计质量,变量名字和类型,逻辑和流程,格式布局,文档和注释)。
伪代码替代方案:1)测试先行开发;2)重构;3)契约式设计。
变量
初始化原则:在声明变量的时候初始化,在靠近第一次使用变量的位置声明和定义该变量;在可能的情况下用final或const。
作用域和生命周期:尽量小和短,少用全局变量,变量的使用尽量放在一起,不要分隔太开以缩小跨度。
持续性:有时候数据没有你想象中的那么有持续性,可能回收机制或某些难以预料的事情发生,避免方法:断言,附上null。
绑定时间:编码时绑定(直接赋值常量),编译时绑定(宏定义),加载时绑定(函数读取),即时绑定(重绘窗体时读取数据)。
变量用途:单一。不要复杂。少用temp命名。
代码改善:
调试
BUG的作用:让你深入理解自己的代码;及时反馈;重新审视问题的解决方法;审视自己修正缺陷的方法。
禁忌:胡乱猜测;不理解问题就开始乱改;把问题归咎于别人或机器。
指导思想:1)把错误稳定下来,收集错误;2)构造假说;3)设计方法证明或反证假说;4)证明或反证假说;5)重复上述步骤;6)修补缺陷;7)再次重复测试。
做法:
头脑风暴把可能的假说都列出来。
缩小嫌疑代码范围。
找不到问题时,扩展嫌疑代码范围。
检查最近修改过的代码。
同他人讨论。
休息一下。
短时间尝试蛮力调试,不行就要设计周全的调试。
检查警告,不要忽略编译器第二条出错信息。
增强警告级别。
分而治之 。
找没有配对的注释。
多用工具,如对比不同的工具diff,检查语法的工具lint.