如何提升软件工程的质量
date
Jul 14, 2025
slug
how-to-increase-quality-of-a-software-engineer
status
Published
tags
Code
summary
type
Post
当一个软件项目成长为“工程”,它通常意味着更长的周期、庞大的代码库和更多的协作者。在这种规模下,如果我们不能有效把控代码质量,那么前期迭代得再快,后期维护也将是一场无尽的噩梦。
在小团队中,质量相对容易控制,因为每个成员都有机会熟悉项目的方方面面。然而,当团队和业务规模迅速扩张时,情况会变得复杂。需求的堆积速度超过了团队的处理能力,导致项目陷入混乱的“抢占式”开发模式。此时,任何人都可能被指派去修改一个陌生的模块。
依赖僵化的流程来保证质量是不现实的。因为,在混乱的快速扩张中,一个稳定的流程是不可能存在的。团队内的每个人都应当懂得如何提升软件工程的质量,依赖共识而非流程来实现工程质量的提升。
提升软件工程的方法有很多,最为根本也最为重要的便是模块化。仔细想想,软件之所以可以变成一个庞大工程,也正是因为模块化。模块化并不是简单的设计接口命名,也不是将一个大项目拆成多个小文件,而是根据代码所期待达成的功能,将项目分解成各司其职的多个模块,再将它们以得当的方式对接。
我们来看一个简单的例子
上面这段仅有三行的代码就是糟糕的模块设计。该模块的功能是将状态设置为关闭,乍一看似乎没有什么问题,还挺简洁的。多想一想,会发现,当isOpen的值已经为false时,调用该函数会使得isOpen的值变更为true。也就是说,该模块的职责虽为将状态设置为关闭,其的实现却依赖于isOpen当前的值,该模块的职责能否得以实现实际上取决于isOpen在该模块调用时的值。模块化于此也就失败了,虽然接口看起来语义明确,但是却是完全的不可靠。
对于有一定小型工程经验的朋友,一个场景一定不会陌生,那就是更改了一处代码,出现了意想不到的bug,辛苦排查后发现这bug并不是我们所写的新代码导致,而是项目中原有的与本处代码耦合的其他模块所导致。这种情况真的很蛋疼,除非对整个项目都非常熟悉,不然真的很难避免。我们能做的,就是在自己写模块时遵循良好的模块设计。刚刚的例子揭示出模块设计最重要的法则:语义明确,确保履职,尽可能减少不必要的外部依赖,不做职责之外的事。
所谓语义明确,除了函数名、变量名等简单易懂,在自己已经丢失记忆的情况下仍然能看懂之外,还要注意尽可能少用各种花哨的语法,可读性比技巧性更为重要,在技巧无法带来显著提升的地方,技巧甚至应当被禁用。当然啦,开发人员必须要熟悉语言的惯用法,才能够判断什么属于技巧,什么不是技巧。
确保履职,则是提升模块内的稳定性,使其在外部环境波动的情况下仍然能够正确行使职责,在实在难以应对的条件下及时的抛出异常,优雅退出。确保履职的前提是职责明确,而职责明确很大程度体现在语义是否明确上。但是反过来,语义明确并不是职责明确的充分条件,最根本在于模块设计者在编写模块时是否想清楚自己正在将代码模块化,为何将这块代码模块化,是否有必要模块化,以及本模块化应该如何良好实现,既考虑到外部依赖,又有扎实的内部锻造功底。
实际上,确保履职,不仅仅是保障模块调用时功能的正确执行,也包括模块卸载时资源的正确清理,而这是经验不足的程序员最容易忽略的地方之一,毕竟太过依赖GC,使得我们忘记了资源清理这回事。组件卸载时的待清理资源并不仅仅是内存资源,还包括组件所修改的状态,组件引起的副作用……当我们在底层看计算机所发生的一切,调用模块就是一个压栈的过程,而模块退出则是一个出栈的过程,有压栈必有出栈。
尽可能减少不必要的外部依赖,在vibe coding盛行的今天非常容易被忽略,大量开发者正在往工程中添加自己都看不懂的代码,正如引入不熟悉的包一样,都是非常危险的行为。外部依赖不仅仅是registry平台上的包,还包括项目内的代码引入。毕竟,庞大的代码工程,其内部可以拆分出多个相距甚远的模块,而只要距离足够远,无关从何而来,称其为外部依赖便是很合理了。尽可能减少不必要的外部依赖,能够使得如预期履职的稳定性进一步提高。
良好设计的模块,不仅要尽可能减少不必要的外部依赖,还要注意尽可能不做职责之外的事。
很多时候我们无法确保也没有时间去了解整个系统,在内部的流水线中上游可能已经处理好了我们所需要的数据,我们并不知道这回事,保险起见,我们会在模块内重复处理一遍。即使在不考虑性能的情况下,我们为什么仍然要避免看似安全的“多次质检”呢?跳出模块本身来思考,我们之所以会做重复的处理,是因为我们不够了解上游模块,这使得我们无法明确设计所开发模块的职责,将会引入潜在的风险,即使多次质检本身可能是安全的。说的粗俗一点,我们做模块时不要过度帮外部“擦屁股”。
好啦,软件工程是个同时具备想象力空间和现实约束的事,期待再次聊到这个话题。