A Philosophy of Software Design
笔记
复杂性定义
系统的总体复杂度(C)由每个部分的复杂度(cp)乘以开发人员在该部分上花费的时间(tp)加权。在一个永远不会被看到的地方隔离复杂性几乎和完全消除复杂性一样好。
复杂性症状
变更放大、认知负荷、未知的未知
复杂性原因
依赖性和模糊性
工作代码是不够的
一些投资将是积极的。例如,值得花一些时间为每个新类找到一个简单的设计。而不是实施想到的第一个想法,请尝试几种替代设计并选择最简洁的设计。试想一下将来可能需要更改系统的几种方式,并确保设计容易。编写好的文档是主动投资的另一个例子。
最好的方法是连续进行大量小额投资 。我建议您将总开发时间的 10%到 20%用于投资。该金额足够小,不会对您的日程安排产生重大影响,但又足够大,可以随着时间的推移产生重大收益。
一开始,战术性的编程方法将比战略性方法更快地取得进展。但是,在战术方法下,复杂性积累得更快,从而降低了生产率。随着时间的流逝,战略方针会带来更大的进步
Facebook 作为一家公司已经取得了令人瞩目的成功,但是由于该公司的战术方法,其代码库受到了影响。许多代码不稳定且难以理解,几乎没有注释或测试,并且使用起来很痛苦。随着时间的流逝,该公司意识到其文化是不可持续的。最终,Facebook 改变了座右铭,即“以坚实的基础架构快速移动”,以鼓励其工程师在良好的设计上进行更多的投资。Facebook 是否能够成功清除多年来战术编程中积累的问题还有待观察。
好的设计不是免费的。它必须是您不断投资的东西,这样小问题才不会累积成大问题。幸运的是,好的设计最终会收回成本,而且比您想象的要早。
模块应该是深的
最好的模块是那些提供强大功能但具有简单接口的模块
深浅模块。最好的模块很深:它们允许通过简单的接口访问许多功能。浅层模块是具有相对复杂的接口的模块,但功能不多:它不会掩盖太多的复杂性。
模块深度是考虑成本与收益的一种方式。模块提供的好处是其功能。模块的成本(就系统复杂性而言)是其接口。模块的接口代表了模块强加给系统其余部分的复杂性:接口越小越简单,引入的复杂性就越小。最好的模块是那些收益最大,成本最低的模块。接口不错,但更多或更大的接口不一定更好!
诸如 Unix I/O 和垃圾收集器之类的深层模块提供了强大的抽象,因为它们易于使用,但隐藏了巨大的实现复杂性。
不幸的是,深度类的价值在今天并未得到广泛认可。编程中的传统观点是,类应该小而不是深。经常告诉学生,类设计中最重要的事情是将较大的类分成较小的类。对于方法,通常会给出相同的建议:“任何长于 N 行的方法都应分为多种方法”(N 可以低至 10)。这种方法导致了大量的浅类和方法,这增加了整体系统的复杂性。
信息隐藏在两个方面降低了复杂性。
首先,它将接口简化为模块。 其次,信息隐藏使系统更容易演化。
将系统分解为模块时,请尽量不要受运行时操作顺序的影响。这将使您沿着时间分解的路径前进,这将导致信息泄漏和模块浅。相反,请考虑执行应用程序任务所需的不同知识,并设计每个模块以封装这些知识中的一个或几个。这将产生带有深色模块的干净简单的设计。
通用模块更深入
通用方法最重要的(也许是令人惊讶的)好处是,与专用方法相比,它导致更简单,更深入的界面。如果您将该类用于其他目的,则通用方法还可以节省将来的时间。
参考:
https://book.douban.com/subject/30218046/
https://www.bookstack.cn/read/A-Philosophy-of-Software-Design-zh/docs-ch2.md