我们一般说的架构既包括架构的设计过程,又包括设计的产出物,可以是各类设计文档、设计图,也可以是一些技术验证代码、Demo或其他相关程序。
文档的目的在于准确记录我们的思维产物,在软件尚未实现时,作为指导蓝图,尽量精确地描述清楚软件。
在软件的实现过程中,可能随着我们的深入研究,根据具体情况对文档做出局部的调整和修改。
在软件已经实现以后,部署运行的软件实例和代码只能说明软件目前是什么状态,却无法告诉我们这个软件系统是如何从开始设计,慢慢变成现在看到的样子的,这个思维的过程和中间做出的很多决策的信息丢失了。
一个软件系统的长期稳定发展,必然需要一个可靠的、随着软件本身的维护不断同步更新的文档作为每次变更的出发点。这样我们可以随时沿着架构相关的文档逆流而上,了解这个软件系统从整体到具体的设计思路。
同时,文档作为结项或交接的一部分,也是整个软件项目的产出物的一部分,成为公司IT资产的有机组成部分。其中一个架构图的例子如图所示。
文档是设计的载体,代码是系统功能实现的载体,技术和业务最终都有很大一部分体现在代码里(技术的另外一部分是部署运维,即如何最终把这些代码应用到设备上;业务的另外一部分是操作流程,即如何应用到系统与人的交互上)。
广义上来说,代码和代码里的注释都可以认为是文档的一部分。技术社区有一种观点:结构良好的、可读性强的代码,是最好的“文档”。
那么怎么才能写出好的代码呢?
关键在于两个词:经验、重构。GoF的23个设计模式是在面向接口的编程环境中,处理一些常见问题的代码编写经验。通过灵活应用这些模式,我们就可以在处理各种一般问题时进行抽象和总结,进而写出结构良好、可读性强,并具有一些灵活性的代码。
如果是面向企业应用领域的系统,那么企业应用架构模式可以供我们参考。如果是面向多个系统的集成领域,那么企业集成模式和各种中间件可以帮助我们更好地处理问题。
技术性工作里存在一个“一万小时理论”:在一个领域里需要持续实践一万个小时,才可能成为该领域的专家。
编程也是一个这样的领域,随着我们代码写得越来越多,维护性的代码改得越来越多,我们就能总结和沉淀出很多经验,变成自己的编码风格和习惯。
在这个过程中通过实践和思考,不断地提升和发展自己的技能,进而反馈到代码中,我们可以认识到以前代码的不合理之处,不断地重构和改善既有的设计与实现。
从代码里,我们可以很直观地了解到,程序做了什么、不能做到什么、能做到什么程度,以及其与相关的文档(包括业务文档和技术文档)是否一致。
但是代码不适合作为唯一的“文档”,只有代码没有其他文档,就像是一部只有结尾没有开头和过程的电影。我们只能了解这个系统的一个时间点的切面影像。
所以,在设计类文档和代码注释里,很多时候描述清楚为什么(Why)和怎么样(How)比单纯描述是什么(What)重要得多。一个具体问题的技术选型,实现一个业务模块的某个具体功能点,其实都是在做技术相关的选择(Choice),而我们做一个技术选择的时候需要考虑:我们面临的问题是什么,有几种可行的方案,各有什么优势和劣势,选择哪个方案最适合目前的形势,并可以兼顾一下未来一段时期的发展等。
如果我们没有留下来任何思考的痕迹,那么这些思想过程的智慧就会在软件的创造过程中丢失。随着时间的流逝,我们只能看到系统最终的样子。这种信息缺失对于目前大规模软件开发的协作过程非常不利。
例如,我们看到一个8年前的遗留系统里,有一“坨”代码非常烂。我们改了一下,过段时间发现运行不正常了,回过头来再细细分析,发现业务逻辑需要优化,框架也需要调整,不然这个地方的代码会很别扭。
很多时候,我们要是直接能看到以前文档描述了当时做的选择和权衡,就可以避免很多的“坑”,降低很多沟通成本,特别是涉及团队成员的变动和跨团队的协调成本。