软件开发的53条黄金法则:从质量到效率的实践指南 #
引言 #
在软件开发领域,有一些经过时间检验的核心原则和最佳实践。本文将通过51条实用建议,系统性地探讨如何提升代码质量、优化开发流程、提高团队效率。
最近在读《软件开发的 201 个原则》,书内容不多,但是每一页都看的很仔细,好像往往这种言简意赅的书更让人有静下心来仔细阅读的欲望。在我看来,读书的作用本来就不是解答所有的困惑,而是激发人更加深入地学习的动力。
如果看这本书的时候,你会主动搜索文献或者资料,去了解更多的信息,那说明这本书就已经帮助了你。话不多说,抛砖引玉,本文和大家分享下我的"读后感"。
01. 质量第一 #
编程一定要把质量放在首位,没有可商量的余地。当你被要求要为质量做妥协时,要直接说不。质量必须可量化。
02. 质量与效率的权衡 #
对质量要求越高,开发效率就越低。越是强调提高开发效率,最终的质量就越低,bug 的密度就会增加。
03. 提高软件质量的方法 #
- 让客户参与
- 在全面开发之前验证需求
- 保持设计简单
- code review
- 雇佣最优秀的人
04. 尽早交付产品 #
在需求阶段,无论你多努力了解客户需求,都不如给他们一个产品,让他们使用后确定自己的真实需求。可以在开发过程的早期构建一个快速且粗糙的原型,交给用户,收集反馈,然后确定真正的需求。最终产品也就更有可能让客户满意。
05. 与客户沟通 #
永远不要忽视开发软件的原因:满足真正的需求,解决真正的问题。解决真正需求的唯一方法就是去跟有真正需求的人沟通,让他们参与进来。
06. 开发者与客户目标一致 #
从客户的角度出发,按优先级对需求排序,确保不要 delay。
07. 开发正确的原型 #
有两种原型,一次性原型和演进式原型。
- 一次性原型:用快速粗糙的方式构建,交给客户来获得反馈,得到反馈后废弃,然后获取正规的需求后再开发。
- 演进式原型:用高质量的方式构建,交给客户获取反馈,然后进行整改。
如果对大多数功能都不了解,应该首先构建一个一次性原型,然后从零开始构建一个演进式原型。
注意 #
- 开发一次性原型要快,不用担心质量,可以使用任何工具任何语言,只需要开发那些没有充分理解的特性。
- 开发演进式模型时,从小的可用系统开始,只实现少数功能,然后逐步扩展,覆盖更多的功能子集,这样可降低风险。
08. 为变化做好准备 #
开发过程中的变化是不可避免的,可能体现在新的代码、新的测试计划、新的需求或需求变更等,不要抱怨,积极应对,做好准备。
09. 简短的用户手册 #
即简短的文档,文档内容越少,软件质量越高,这里不是说要少写文档,而是要做高质量的软件,让用户尽量少看文档就能使用明白。
10. “知道何时"比"知道如何"重要 #
一个工程师要了解更多的技术,要知道什么时候使用什么技术,要知道什么项目使用什么项目。
11. 跟风要小心 #
当学习新技术时,不要轻易接受与之相关的不可避免的炒作。
12. 不要忽视技术 #
不要固步自封,紧跟技术潮流,每年努力参加 1-2 个关键会议。与参会者的交流,很可能比会议报告更重要。
13. 使用文档标准 #
如果你的项目、组织或客户要求遵循一套文档标准,那就要遵循它,理智的执行。
14. 承担责任 #
软件有任何问题时,不要找任何借口,要承担责任,要么做好,要么就不做。
15. 先确定问题,再写需求 #
先明白要解决的是什么问题,再提出相关的需求。
16. 修复需求规格说明中的错误 #
- 如果错误保持到系统设计阶段,定位和修复要多花 5 倍的代价
- 如果保持到编码阶段,要多花 10 倍的代价
- 如果保持到单元测试阶段,要多花 20 倍的代价
- 如果保持到交付阶段,要多花 200 倍的代价
17. 记录需求为什么被引入 #
记录每个需求的动机。
18. 给需求排列优先级 #
并非所有需求都是同等重要的,要明确需求的优先级,先做哪个需求,后做哪个需求,或者在关键阶段哪个需求可以暂时舍弃掉。
19. 明确环境超出预期时的系统行为 #
当环境超出为其定义的任何约束时,在软件需求规格说明中应明确声明预期的系统响应。用我们开发者的话说就是,做好边界处理。
20. 评估备选方案 #
设计架构或者某个解决方案时,最好详细列出多种方法,明确优缺点,在这些方法之间权衡分析,最终选择一种。
21. 做好封装 #
面向对象的一种思想,对某一需求做好抽象,做好封装,做好信息隐藏。
22. 不要重复造轮子 #
程序员经常一次又一次的重新发明组件,却很少修补已有的组件。
23. 保持简单 #
构建软件设计有两种办法,一种办法是使它简单到明显没有缺陷,另一种办法是使它复杂到没有明显的缺陷。
24. 保持概念一致 #
这是高质量设计的一个特点,方式一定要统一,包括模块如何向调用方通知错误,软件如何向用户通知错误,如何组织数据结构,模块通信机制,文档标准等等。
25. 使用耦合和内聚 #
尽量做到高内聚低耦合。高耦合意味着,当修改一个组件时,很可能需要修改其他组件。低内聚意味着,难以分离出错误原因或者难以判断为满足新需求而要修改的位置。
26. 为变化而设计 #
需要选择合适的架构、组件和技术来适应不断的变化,设计需要做到:
- 模块化:产品由独立部分组成,每一部分都可以单独升级和替换,对其他部分造成最小的影响。
- 可移植性:产品应该很容易修改以适应新的硬件和操作系统。
- 可塑性:产品可以灵活适应预期外的新需求。
28. 软件的通用性和灵活性 #
通用性体现在,在不同的场景下不做任何修改就能执行预期功能。灵活性体现在,它很容易被修改,以在不同的场景下执行其功能。
29. 使用高效的算法 #
了解算法复杂度是成为优秀软件工程师的必要前提。高效的算法和低效的算法可能会相差几个数量级。
30. 避免使用特殊技巧 #
很多程序员喜欢编写比较 trick 的代码,然而这种程序让别人很难理解,也很难维护,这种特殊技巧被频繁使用的理由有很多:
- 程序员都非常聪明,他们想展示这种聪明
- 维护人员在最终搞清这些特殊技巧如何生效时,不仅会认识到原来的程序员有多聪明,也会意识到自己有多么聪明。
- 职业安全感。
32. 避免使用全局变量 #
全局变量写代码很方便,但是如果此全局变量访问出现问题,很难确定问题具体出现在哪个模块,所以,可以将重要数据封装在对应模块中,做好封装。
33. 编写可自上而下阅读的程序 #
有助于读者理解。
34. 使用有意义的别名 #
确保每个变量,每个函数的命名都有意义,尽量做到代码即文档,代码即注释。
35. 程序首先是写给人看的 #
程序的功能以及效率固然重要,但程序也是写给人看的,要提升程序的可读性,以免在这个过程中对相关人员造成负面影响。
36. 先确保正确,再提升性能 #
不要担心优化问题,每个项目都有很大的进度压力,在这种情况下,任何时候一个组件要是能够按时完成并且可靠运行,都值得庆祝,先保证完整功能,然后再去考虑做性能优化。
37. 先写文档后写代码 #
也可以理解为,不要上来就埋头写代码,要先想清楚代码应该怎么写,然后再动手。
38. 代码审查 #
即 code review,一定要做 code review,code review 大约会消耗 15% 的研发资源,可以将总成本减少 25%~30%。
39. 避免嵌套太深 #
即圈复杂度不要太高,不过过多的 if-else,switch-case 之类的嵌套,考虑做优化。
40. 编程语言不是接口 #
如果你是一个好的程序员,对任何一种编程语言来说你都应该是一个好程序员。
41. 编程语言的知识没那么重要 #
一个真正优秀的程序员很好的理解和赞赏高质量编程的概念,而不只是了解某些编程语言的语法和语义特性。为一个项目选择语言的首要驱动力应该是什么语言更适合,而不是说我们只知道 C 语言。
42. 格式化代码 #
使用标准的 format 规则,可大大提高程序的可读性。选择遵循哪种规则不重要,但一旦选择了,就要保持一致。
43. 不要太早编码 #
即在编码之前,要确认需求和设计都是正确且合适的,即想清楚再编码。
44. 为代码做单元测试 #
老生常谈了,自己写的代码自己都不测试就去提测,那得多坑啊。
45. 好的管理比好的技术更重要 #
好的管理可以激励人们做到最好,糟糕的管理会打击人们的积极性。
46. 人是成功的关键 #
具备合适经验能力的人,是在预算内按时完成满足用户需求软件的关键。
47. 几个好手要强过很多生手 #
对于关键任务,最好只安排少数有足够经验的工程师,而不是安排许多没有经验的工程师。
48. 不要设定不切实际的 deadline #
要设定合理的 deadline,然后严格踩住。
49. 知晓风险 #
在开始项目时,要熟悉经常导致软件灾难的情况,并制定降低风险的计划:
- 人员短缺
- 不切实际的排期
- 不理解需求
- 开发糟糕的用户界面
- 没有控制需求变化
- 缺乏可重用或接口化的组件
- 糟糕的响应时间
- 试图超越当前计算机技术的能力
50. 预先了解风险 #
在项目计划的早期阶段,要梳理与你的项目相关的最大风险列表。
51. 有时重新开始会更好 #
有时候从头开始设计和编码可能是更好的选择。
52. 回归测试 #
每次改动后都要进行回归测试:这个相信大多数程序员都会遵循的一个原则,代码改动后需要验证它是否能够正确的运行。
53. 性能分析 #
在优化前先进行性能分析:先做性能分析,拿到性能数据进行性能分析后再考虑做优化,80-20 原则,80% 的 CPU 周期将被 20% 的代码消耗,我们应该找到那 20% 的代码,然后对它们做优化。