本文是一篇强调实践、注重实效、轻量级、面向开发者的软件架构指南。你将从中学到:
在不同的人眼里“架构”一词的意思大相径庭,互联网上对架构的定义也多如牛毛。过去几年里我问过上百人同一个问题,在他们看来“架构”意味着什么。得到的答案概括如下(排名不分先后):
模块、连接、依赖和接口; 大局观; 改变成本很高的事情; 难以改变的事情; 更加兼顾全局的设计; 接口而非实现; 审美(比如:艺术般的整洁代码); 概念模型; 满足非功能需求/质量属性; 每件事都有“架构”; 沟通能力(抽象、语言、词汇); 计划; 一定程度的严格和可靠性; 蓝图; 系统、子系统、交互和接口; 管理; 战略决策的产出; 必要的约束; 结构(组件和交互); 技术方向; 战略和愿景; 结构单元; 实现目标的过程; 标准和准则; 整个系统; 工具和方法; 从需求到最终产品的道路; 指导原则; 技术领导力; 构成产品的元素之间的关系; 对环境约束和限制的意识; “基础; 抽象的观点; 把问题化整为零的过程; 产品的骨架、支柱; ...
还可能包括:
系统的形态(例如,客户端-服务器、基于Web、原生移动客户端、分布式、异步,等等); 软件系统的结构(例如,组件、层、交互,等等); 技术选择(即编程语言、部署平台,等等); 框架选择(例如,Web MVC 框架、持久性/ORM 框架,等等); 设计方法/模式选择(例如,针对性能、可伸缩性、可用性等的方法); ...
难怪找不到一个合适的定义!好在还可以分为名词和动词两大类。无论我们谈论的是建造一个物理建筑或一个软件系统,都适用。
架构作为名词来解释时,概括起来都与“结构”有关:将产品分解为一系列组件、模块和交互。 这需要考虑整个产品,包括:
架构作为动词来解释时,包括了:
所有这些都要以需求为基础,因为需求驱动架构 。
关键在于,架构是关于交流愿景以及引入技术领导力的,这样参与构建产品的每个人都能理解这个愿景,并为产品的成功做出积极贡献。
不管你是构建软件系统、网络还是数据库,任何成功的方案都需要你:
不论何种领域的架构,其实主要就是结构和愿景 。
软件架构需要考虑诸如:面向对象的原则、类、接口、控制反转、重构、自动化单元测试、代码整洁和其他不胜枚举的技术实践:
有时你需要退一步,远离代码和你的开发工具。这并不意味着低层次的细节不重要,因为可用的软件最终还是要靠交付可运行的代码。细节同样重要,但就大局而言,对软件的整体视角可以确保你的代码符合整体愿景而非背道而驰。
下面是我认为构成软件架构角色应有的内容。注意,我这里说的是“角色”;它可以是一个人,也可以由团队共同扮演。

在古代和中世纪的历史中,大多数建筑设计和建设都是工匠完成的:下至石匠和木匠,上至建造大师。 尽管石匠大师受人尊敬、通常也很富有,然而在达到行业顶峰之前,他必须经历石匠、监督的历练来证明自己的价值。石匠大师为将要建造的东西设计结构、美学和象征等方面的特性,组织后勤,还要评定工作的优先级并决定它们的顺序。
优秀架构师的重要特征是抽象思维能力,也可以理解成不把所有时间都耗在细节里的能力。这没错,但你画的那些框框线线终归要形成代码。

编码为架构师提供了一种与团队分享软件开发经验的方式,从而帮助他们更好地理解如何从开发的角度看待架构。一个写代码的软件架构师会更有成效也更快乐。你不应该因为“我是架构师”,就把自己排除在编码之外。
让建筑行业的人直观地传达建筑物的架构,您将看到场地平面图、平面图、立面图、横截面图和详细图。相反,如果让软件开发人员使用图表来传达软件系统的软件架构,您可能会得到一团乱麻的方框和线条……不一致的符号(颜色编码、形状、线条样式等)、模棱两可的命名、未标记的关系、通用术语、缺少技术选择、混合抽象等。

作为一个行业,我们确实有统一建模语言 (UML)、ArchiMate 和 SysML,但询问这些是否提供了一种有效的软件架构交流方式通常是无关紧要的,因为许多团队已经将它们抛弃,转而支持更简单的“盒子和线”图。放弃这些建模语言是一回事,但也许在敏捷性的竞赛中,许多软件开发团队已经失去了视觉交流的能力。
C4 模型是绘制软件架构图的“抽象优先”方法,基于反映软件架构师和开发人员如何思考和构建软件的抽象。

在 C4 模型中,软件系统由一个或多个容器( Web 应用程序、移动应用程序、桌面应用程序、数据库、文件系统等)组成,每个容器包含一个或多个组件,而这些组件又由一个或多个代码元素实现(例如类、接口、对象、函数等)。

一个人代表您的软件系统的人类用户之一(例如演员、角色、角色等)。
软件系统是最高级别的抽象,它描述了为用户提供价值的东西,无论他们是不是人类。这包括您正在建模的软件系统,以及您的软件系统所依赖的其他软件系统(反之亦然)。

在许多情况下,软件系统由单个软件开发团队“拥有”。
不是码头工人!在 C4 模型中,容器代表应用程序或数据存储。容器是为了使整个软件系统工作而需要运行的东西。实际上,容器类似于:
服务器端 Web 应用程序:在 Apache Tomcat 上运行的 Java EE Web 应用程序、在 Microsoft IIS 上运行的 ASP.NET MVC 应用程序、在 WEBrick 上运行的 Ruby on Rails 应用程序、Node.js 应用程序等。 客户端 Web 应用程序:使用 Angular、Backbone.JS、jQuery 等在 Web 浏览器中运行的 JavaScript 应用程序。 客户端桌面应用程序:使用 WPF 编写的 Windows 桌面应用程序、使用 Objective-C 编写的 OS X 桌面应用程序、使用 JavaFX 编写的跨平台桌面应用程序等。 移动应用程序:Apple iOS 应用程序、Android 应用程序、Microsoft Windows Phone 应用程序等。 服务器端控制台应用程序:独立(例如“public static void main”)应用程序、批处理等。 无服务器函数:单个无服务器函数(例如 Amazon Lambda、Azure 函数等)。 数据库:关系数据库管理系统、文档存储、图形数据库等中的模式或数据库,例如 MySQL、Microsoft SQL Server、Oracle 数据库、MongoDB、Riak、Cassandra、Neo4j 等。 Blob 或内容存储:Blob 存储(例如 Amazon S3、Microsoft Azure Blob Storage 等)或内容交付网络(例如 Akamai、Amazon CloudFront 等)。 文件系统:完整的本地文件系统或较大网络文件系统的一部分(例如 SAN、NAS 等)。 Shell 脚本:用 Bash 等编写的单个 shell 脚本。 ETC

容器本质上是一个上下文或边界,在其中执行一些代码或存储一些数据。每个容器都是可单独部署/可运行的事物或运行时环境,通常(但不总是)在其自己的进程空间中运行。因此,容器之间的通信通常采用进程间通信的形式。

“组件”一词在软件开发行业中是一个非常重的术语,但在这种情况下,组件是封装在定义良好的接口后面的一组相关功能。如果您使用 Java 或 C# 之类的语言,考虑组件的最简单方法是它是接口后面的实现类的集合。诸如这些组件如何打包(例如,一个组件与每个 JAR 文件、DLL、共享库等多个组件)等方面是一个独立且正交的问题。

这里需要注意的重要一点是,容器内的所有组件通常都在同一个进程空间中执行。 在 C4 模型中,组件不是可单独部署的单元。
软件架构角色同时也是技术领导的角色,“软技能”或“交际能力”也极其重要。
Simon Brown. “程序员必读之软件架构。” 关于 C4 model:https://c4model.com/