就其核心内容而言,软件开发是关乎创建并管理复杂系统的工作。
早期的时候,计算机程序都比较简单。那时,程序也许仅用于抛物线轨迹计算或数值分解。世界上首个计算机程序是由Ada Lovelace(爱达·洛芙莱斯)在1843年设计的,用于计算一个Bernoulli(伯努利)数的序列。100多年后,第二次世界大战刚结束不久,人类就发明了电子计算机用于破解加密的代码。随着这项新发明的潜力被不断发掘,越来越多的复杂运算功能和系统被设计出来。编译器和高级语言等工具使其能力不断增强,硬件的快速发展使得越来越多的功能得以实现。这样很快就催生了一类需求,即管理软件开发过程中日益增长的复杂性,并将一致性工程原则应用于其中。
在计算行业诞生50多年之后,我们所拥有的软件工具已经变得令人难以置信地多样和强大。我们可以站在巨人的肩膀上构建自己的软件。现在可以利用高级语言和API,或者使用开箱即用的模块和软件包,用相对较少的付出迅速地增加许多软件功能。伴随着这种大幅增长的能力,也带来了对其爆发性增加的复杂性的管理责任。
简而言之,软件架构决定了一个软件系统的结构。通常,在项目的早期阶段这种架构会逐步成型。在系统规模变大并出现某些需求变更之后,仔细考量软件架构的需求也变得越来越重要。随着系统规模的进一步增长,其架构也变得很难进行调整,这样就会影响后续的工作。遵循系统架构来实现系统功能调整相对容易,逆架构而行则不然。
让某些功能调整难以实现并不一定总是坏事。实现起来比较困难的功能调整可能涉及需要由不同团队监督的因素,也可能涉及那些影响外部客户的因素。虽然重点在于创建一个将来易于有效调整的系统,但聪明的架构设计会根据需求在难易程度上做一些适当的权衡。在本章后面,我们将研究安全有关的问题,并以其为例清晰地说明在何时需要保持某些操作难以实现。
由此可知,软件架构的核心要义是着眼于宏观,关注系统未来的发展方向,能够将这一设想具体化,但同时也要对当前的状况有所帮助。在开发过程中,在短期便捷和长期可维护性之间的选择非常重要,最常见的情况是不当选择所导致的技术负债(technical debt)。软件架构主要用于处理长期影响。
软件架构需考虑的因素相当多,需要在其间做出取舍,例如:
❍ 商业愿景 ,如果系统将用于商业化环境,就需要考虑这一因素。这可能包括来自市场、销售或管理层等利益相关者的要求。商业愿景通常是由客户驱动的。
❍ 技术要求 ,比如要确保系统可扩展且可应对特定数量用户的访问请求,或者系统对其应用场景来说要足够快。对一个新闻网站来说,它所需要的更新时间与一个实时交易系统是不一样的。
❍ 安全和可靠性 ,其重要性取决于应用程序和所存储的数据面临的风险大小或关键程度。
❍ 任务划分 ,允许专注于不同领域的多个团队,以灵活的方式同时在同一个系统上工作。随着系统的发展,将其划分为半自主的、更小的组件的需求变得更加迫切。小项目采用“单块”(single-block)或单体(monolithic)架构的方式可能会存活得更久。
❍ 使用特定的技术 ,例如,允许与其他系统集成,或利用团队现有的知识。
这些考虑因素将影响系统的架构和设计。从某种意义上说,软件架构师负责实现应用程序的预期目标,并使其与用于开发的具体技术和团队相匹配。这使得软件架构师成为业务团队和技术团队之间,以及不同技术团队之间的重要中介。沟通是从事这项工作的关键性内容。
为了实现有效的沟通,一个好的架构应该设定各方面的界限,并明确分配其责任。软件架构师除了定义清晰的边界外,还应该推动系统组件之间接口通道的创建,并跟进其实施细节。
理想情况下,软件架构设计应该在系统设计的起始阶段进行,根据项目的需求进行周密的设计。这是本书介绍的一般性方法,因为它是最易于用来阐明不同选择和技术的方法。但这并不是现实环境中最常见的场景。
软件架构师的主要挑战之一是,在需要调整的现有系统环境下开展工作,既要让系统朝着更好的方向渐进式发展,同时又不中断维持业务运行的日常操作。