软件开发总成本=开发成本+维护成本;软件维护成本=理解成本+修改成本+测试成本+部署成本。——KenBeck在设计框架和系统架构时,可扩展性是人们想要追求的特性之一。从技术社区的文章中,我们可以看到大量的相关词典,比如“通过配置和定义可扩展”,或者“业务流程”的可扩展性,以及各种“插件”和“可扩展的扩展”点”等。实际上,从我们经历过的大多数项目来看,这些系统的扩展性并没有那么好。有的,可能在设计系统的时候,能满足当前的需求,不适合未来的场景——那就是另外一回事了。这是因为架构师在设计系统时缺乏对边界的考虑。边界约束的另一种解释是,系统在开发过程中实现了可扩展性,却忽略了维度周期带来的问题。在软件开发周期中,维护成本往往占据成本的主要部分,正如KenBeck开篇所言。这时候,人们不禁又开始思考起来。不是为维护而设计的系统真的具有可扩展性吗?该架构真的可扩展吗?在很多系统中,开发就像它的设计一样,具有很好的可扩展性。只是它的扩展性在运维的时候可能会失去作用。DDD系统损坏的谣言这是一个DDD谣言,尚未经过严格验证。在一书中,EricEvans根据自己在项目中的重构经验,给出了领域驱动设计的系统方法,并结合了一系列领域特定的相关实践。我们相信Eric在重建这个系统的架构时,经过了一系列好的设计。十几年过去了,这个系统的架构已经变成了一个大泥球,已经很难看出当初的精心设计了。人员的流动和知识传承的流失,让制度逐渐腐败——这几乎是大多数制度的通病。OSGi模块化回归测试OSGi是一个有趣的模块化和插件化解决方案,Eclipse是最广为人知的应用场景。在可扩展性方面,OSGi有很多优点:比如在不停止服务的情况下动态加载、更新和卸载模块,可以实现系统的模块化和版本化。在微服务架构流行之前,其可插拔的能力对于大型系统来说是非常有吸引力的。当发布一些新功能时,我们不需要发布整个系统,而只发布其中一个bundle(插件)。只是基于OSGi构建的web应用会变成一个可怕的单体,每个bundle都可能被构建成一个“微服务”,bundle之间存在相互调用——在微内核架构中,我们不允许这样的存在。这样,一旦我们更新了bundle,我们倾向于发布整个系统而不是单个bundle。此时,我们还需要对整个系统进行回归测试。低代码生成的遗留代码这是“遗留代码”,指的是难以测试的低代码平台。这里的低代码平台是指通用的低代码平台。在那篇无代码编程文章中,DSL被认为是核心元素,一种精心设计的领域特定语言/类编程语言(不是JSONDSL)。基于DSL设计,可以为系统提供良好的可测试性和持续集成能力,这是普通JSON所不具备的。而一旦我们生成的低代码无法测试,就可能成为遗留代码——这取决于平台构建的自动化测试机制和自动化版本迁移的设计。“复杂性,就像力一样,不会消失,也不会凭空产生。它总是会从一个物体转移到另一个物体,或者从一种形式转移到另一种形式。”如果框架本身不考虑可测试性和质量的问题,那么就得有人重新考虑了。灵活性的另一面在过去,PL/SQL是我见过的最灵活的系统,“人不用写代码就可以做任何事情”。我们可以把它看成是一种DSL,类似于我们遇到的配置系统,通过简单的“配置”就可以快速实现。这种灵活的“配置”非常有趣。我们可以在测试环境中重复地、可预测地手动测试它们。在追求自动化和稳定性的今天,这种不稳定性变得异常可怕。在移动端,消息推送是以配置和接口的形式进行的,我们经常可以收到测试人员向生产环境发送消息推送。从某种意义上说,这种灵活性应该更多地被视为一种补救措施,而不是系统设计的核心部分。反思软件开发是一项团队活动。越是天马行空的甜头在大系统中蔓延,破窗效应就越明显——一旦一个人不按规范执行,就会有越来越多的人违反规范。这个问题源于相关规范没有通过流程或者工具没有固化。比如没有严格的代码检查流程,缺少自动化的架构守卫工具。比如为了一个团队,临时修改了底层库的接口,开了个坑。从而导致后续其他团队需要新的开孔,导致底层库偏离原来的设计。因此,在增加新的临时接口之前,要考虑系统迁移和演进时会遇到的问题。我们允许这种临时解决方案存在(紧急在线永远存在),发生后我们应该重新设计并填补相关问题。缺乏自动化保障在不考虑调试的情况下,对于配置等具有灵活性的系统,很难实现功能的自动化测试,也不可能进行持续集成和持续部署。对于中大型软件系统,将成为维护(开发+运维)工作的噩梦。尤其是一旦配置的系统缺少版本管理机制,就会给软件回滚带来新的挑战。在可扩展性+灵活性的条件下,软件开发需要的一系列因素要重新分析。缺少本地测试环境,遇到了一些复杂的bug。无论是Serverless,还是声明式和配置方式,都需要和其他开发系统联合调试。我们需要搭建一个本地环境,快速重现bug,然后才能修复。基于现有平台场景,需要在云端进行调度和测试。不过,这种混高的格局,在《云端开发时》流行之后就会发生变化。为维护建立秩序最近在写《 Architecture 3.0》的时候,我和同事@NoaLand一直在讨论架构的秩序,期望建立一个秩序模型来解决部分维护问题。在今天的场景下,除了解决上述问题,可能还需要以下几个方面。正视问题的复杂性正如你所看到的,问题本身是复杂的,只有正视它才能带来真正的突破。设计思想的定期交流众所周知,软件开发团队成员的流动性会影响系统的稳定性。每隔几年,团队成员就会更新一次——比如在互联网行业,三年就是老员工。系统的相关知识会随着人员的流动而遗忘在角落,新加入的团队成员也不了解系统的原设计。在我们尝试过的众多方法中,比较有效的一种是:在新员工进来一段时间(比如三个月)之后,让他们谈谈系统的架构。在这个过程中,纠正他们对系统的一些认知偏见。及时解决技术债实施过程需要不断为技术债腾出时间——老问题了。在一系列的解决方案中,持续更新依赖是一个非常简单有效的策略,详见《管理依赖的 11 个策略》。当然,还有其他技术债。其他待续...
