五十年前,软件工程大神 FrederickP.Brooks 在《人月神话》一书中提出一个观点:没有一种能够解决软件工程中所有问题的技术或方法。即没有“银弹”能杀死软件本身的复杂性这头可怕的“人狼”。五十年后,AI 技术的突破又激起了各界的想象与期待,AI 会是那枚银弹吗?在某乎上有一篇很有意思的问答,问题是“为什么我觉得 AI 写代码纯属添乱?” 有几个高赞的回答都不约而同地提到,AIGC 工具确实可以大大提高日常的开发效率,但并不能解决软件设计中的核心问题。因为随着时间的推移,软件需求的变更、模块间的调用关系、软件体系架构都会使得软件系统的复杂性不断累积。如果开发人员自身都无法掌控软件的复杂性,那么他也无法向 AI 准确描述问题,所以 AI 不是银弹。要从根本上解决软件系统的复杂性问题,程序员应当掌握软件设计的底层逻辑。《软件设计的哲学(第 2 版)》这本经典之作,就揭示了一系列在软件设计时应当遵循的原则,这些原则在 AI 时代仍然是适用的,也是助力程序员获得职场成功的基本“哲学”。▼点击下方,即可购书
我们先来探讨一个问题,为什么技术工具发展得如此强大了,软件开发还是会失败?在软件工程的早期阶段,瀑布模型盛极一时,它的主要思想是将软件开发过程分成若干独立的阶段,例如需求分析、设计、编码、测试等。上一阶段工作全部完成,就进入下一阶段。这个过程看起来和建筑工程类似,建筑图,就可以预估材料、人力、施工进度等,然后在统一的管理下逐步推进实施。但遗憾的是,软件开发的历史上充斥着失败的案例,其中不乏拥有巨额投入的明星团队,这是为什么?一个显著的原因,是瀑布模型难以适应软件需求的灵活变更。书中有一个很精彩的譬喻,就是建筑架构师不会轻易给一个盖好的高楼挖个地下室,但是软件架构师却经常干这样的事。所以业界有识之士在反思后,基于实践经验提出了敏捷软件开发理念,这是一种增量式方法,通过对功能的不断迭代,使得软件逐渐成型。软件的设计、编码、测试、发布贯穿整个生命周期。这意味着开发者要时刻思考软件的设计,并降低软件的复杂性。《软件设计的哲学(第 2 版)》就是讲述如何在软件的整个生命周期中,利用复杂性来指导软件设计。第一,描述软件复杂性的本质;
第二,介绍在软件开发过程中可以将复杂性最小化的技术。
本书作者 John Ousterhout 是斯坦福大学计算机科学系的教授,为了探索软件设计的教学方式,他向学生提出一套软件设计原则,然后学生们通过一系列项目来吸收和实践这些原则。在课程中,学生从零开始构建一个大型软件,在开发过程中会进行大量的代码评审并找出设计问题,学生则会遵循设计原则去修改他们的项目以解决问题。Ousterhout 教授将多次授课经验复盘整理后,提炼为这本《软件设计的哲学(第 2 版)》。Ousterhout 教授不仅在学界硕果累累,还曾是一名业界老兵他在耶鲁大学获得了物理学学士学位,后在卡内基梅隆大学获得了计算机科学博士学位,他是 Tcl 脚本语言的创建者,并且以在分布式操作系统和存储系统中的工作而闻名,曾创办了 Scriptics 和 Electric Cloud 这两家公司。Ousterhout 教授还是美国国家工程院院士,各种专业大奖更是拿到手软,包括 ACM 软件系统奖、ACM Grace Murray Hopper 奖、美国国家科学基金会总统年轻研究者奖和 UC Berkeley 杰出教学奖。我们现在就来跟随 Ousterhout 大神的脚步,吃透软件设计的哲学。本书探讨的一个核心问题,就是如何通过将复杂的软件系统分解为可独立实现的模块(如类和方法),来降低复杂性并提高开发效率。根据书中内容,可以分为五个方面来学习,下面逐一拆解这些软件设计原则。书中指出软件复杂性的原因在于依赖关系(dependency)和模糊性(obscurity),随着复杂性的增加,会导致变更放大、认知负担增加和不知道未知的增加。
在确立软件开发的基本原则时要认识到,能工作的代码是不够的。书中细致说明并对比了战术性编程与战略性编程两种思维方式,提出以“投资-回报”的眼光来看待战略性编程,并给出了建议实施方案。
这部分帮助读者学会识别复杂性,并树立起基本的软件设计原则。
模块化是降低软件复杂性的核心技术。书中指出模块化设计的目标就是尽量减少模块之间的依赖关系,然后解释了接口和抽象的概念,并区分了深模块与浅模块,认为模块应该深。
信息隐藏(information hiding)是实现深模块的重要技术之一,在将系统分解为模块时,要避免时序分解,从而造成信息泄和浅模块。然后进一步讨论了如何通过增加模块的通用性来实现更好的信息隐藏,还讨论了“不同层,不同抽象”的规则。
这些块化设计的核心原则,从系统结构层面给读者提供了消除复杂性的指导。
接下来就是代码设计,探讨了合并代码与分开代码的决策因素,还对另一部经典之作《代码整洁之道》中的函数拆分原则进行剖析,展示了更层次的思考。
对于异常处理,作者的观点独到,提出“定义错误不存在”原则,并提供了避免处理异常的诸般策略。书中还提出,对于重要的设计决策多给一次机会,设计两次。
这些具体的代码设计原则和实践方法,能帮助开发者在编写代码时做出更明智的选择。
代码写出来要让人看得明白才好维护,所以作者首先就批驳了不写注释的四大理由,并提出注释的指导原则:注释应描述代码中不明显的内容。然后详细了讨论编写有效注释的原则和实践方法。
另一件重要的事情,就是要精心为类、方法和变量取一个好名字,书中列举了好名称的特点,并给出了一些指导原则。接着强调代码设计要遵循一致性的原则,开发者要为此付出努力。
这部分探讨了过去几十年来软件开发中流行的几种趋势和模式,包括面向对象编程、敏捷开发、单元测试、测试驱动开发、设计模式等,读者可以纵览软件开发的演进过程。
对于软件性能设计,书中探讨了分析性能瓶颈的方法,并提出了优化性能的方法,通过一个 Buffer 性能设计的实例,证明简洁的设计与高性能是可以兼容的。
从模块设计、代码设计和维护,到性能设计,这些大道至简的软件设计思想,真的是软件开发者前行的指路明灯。
AI 技术的发展,还会继续提升软件开发的效率,但在当前看来AI 还不是银弹。作为一名软件开发者,仍然有必要掌握好那些能够消除软件复杂性的设计原则。《软件设计的哲学(第 2 版)》应该是每一名开发者的案头必读书。本书的一大特点在于不仅提供了一系列设原则和技术解决方案,更重要的是,它强调了设计思维的重要性。书中的原则和警示信号帮助读者识别和解决设计问题,同时也鼓励读者在实践中发展自己的观点和方法。John Ousterhout 教授以多年教学经验为基础写成此书,教导读者如何识别软件中的复杂性,如何思考代码的设计——这种深层次的思辨能力对于任何希取得成功的软件开发者来说都是至关重要的。本书的另一个显著特点是它的实用性。书中的每一个原则和建议都基于实际的软件开发经验,而丰富的实战示例进一步增强了其实用价值,这意味着读者可以直接将这些原则应用到自己的工作中。本书适合广泛的读者群体,包括软件工程师、计算机科学专业的学生、教育者、对软件设计和开发感兴趣的自学者以及技术管理者。无论是新手还是资深开发者,都能从本书中获得宝贵的知识和深刻的见解。看懂《软件设计的哲学(第 2 版)》,你就能深刻理解软件复杂性的来源,掌握软件开发的成功之道,成就卓越软件工程师之路!
▼点击下方,即可购书
在留言区参与互动,并点击在看和转发活动到朋友圈,我们将选1名读者获得e读版电子书1本,截止时间11月30日。