"架构"是技术人员最熟悉的词汇之一,但深究起来,大多数人并不能准确回答。本文开始系统梳理系统与子系统、模块与组件、框架与架构三组概念,并给出软件架构的精确定义。
维基百科定义:系统泛指由一群有关联的个体组成,根据某种规则运作,能完成个别元件不能单独完成的工作的群体。
三个关键词:
| 关键词 | 含义 | 示例 |
|---|---|---|
| 关联 | 个体间有联系,堆在一起≠系统 | 发动机+PC 不是系统,但发动机+底盘+轮胎+车架 = 汽车 |
| 规则 | 个体按规则分工协作,不是各自为政 | 发动机产生动力→变速器→传动轴→车轮,驱动汽车前进 |
| 能力 | 系统能力 ≠ 个体能力之和,产生了新能力 | 汽车能载重前进,但发动机、变速器各自都不具备这个能力 |
子系统也是由一群有关联的个体所组成的系统,多半会是更大系统中的一部分。
系统和子系统的定义本质相同,区别在于观察角度——同一个系统,放在更大的背景下就成为子系统。
以微信为例:
微信(系统) ├── 聊天子系统 ├── 登录子系统 │ └── 防刷子系统、验证码子系统…… ├── 支付子系统 └── 朋友圈子系统 ├── 动态子系统 ├── 评论子系统 │ ├── 防刷子系统 │ ├── 审核子系统 │ ├── 发布子系统 │ └── 存储子系统 ← 不再是业务子系统,而是技术组件(MySQL/Redis)
这两个概念最容易混淆。维基百科的定义读完之后依然一头雾水:
软件模块(Module)是一套一致而互相有紧密关连的软件组织…… 软件组件(Component)是自包含的、可编程的、可重用的、与语言无关的软件单元……
关键在于看问题的角度不同:
| 角度 | 划分得到的单元 | 目的 |
|---|---|---|
| 逻辑角度(业务边界) | 模块(Module) | 职责分离 |
| 物理角度(技术实现) | 组件(Component) | 单元复用 |
"组件"的英文 Component 可理解为"零件"——物理概念,独立且可替换。
从逻辑角度拆分(按业务职责):
学生信息管理系统 ├── 登录注册模块 ├── 个人信息模块 └── 个人成绩模块
从物理角度拆分(按可部署单元):
学生信息管理系统 ├── Nginx(反向代理 / 静态资源) ├── Web 服务器(处理业务逻辑) └── MySQL(数据存储)
两者都对,只是视角不同:
逻辑拆分(模块)→ 告诉开发者"系统做什么" 物理拆分(组件)→ 告诉运维"系统怎么部署"
模块向虚(逻辑),组件向实(物理)。
框架(Framework)和架构(Architecture)关联性强,容易混淆。先看定义:
框架:
软件框架通常指的是为了实现某个业界标准或完成特定基本任务的软件组件规范,也指提供规范所要求之基础功能的软件产品。
两个关键点:
@Controller 注解、Spring Security、Spring JPA 等)架构:
软件架构指软件系统的"基础结构",创造这些基础结构的准则,以及对这些结构的描述。
核心区别:
| 框架(Framework) | 架构(Architecture) | |
|---|---|---|
| 关键词 | 规范 | 结构 |
| 回答的问题 | "这套代码该怎么写?" | "系统由什么组成,如何组织?" |
| 示例 | Spring MVC、Django、Rails | 业务架构、物理架构、开发架构 |
以学生信息管理系统为例,从不同角度拆分,得到不同的"架构":
业务逻辑角度(如何分工):
学生信息管理系统 ├── 登录注册模块 ├── 个人信息模块 └── 个人成绩模块
物理部署角度(在哪运行):
学生信息管理系统 ├── Nginx(负载均衡) ├── 应用服务器集群 └── MySQL 主从
开发规范角度(用什么框架):
采用 Spring MVC 框架 → 标准 MVC 架构
三种都是正确的架构,只是视角不同——这正是 IBM RUP 提出 4+1 视图的原因。
参考维基百科定义,作者给出更精准的描述:
软件架构指软件系统的顶层结构。
看似简单的一句话,却串起了所有概念:
"系统是一群关联个体组成" → 个体可以是:子系统、模块、组件 → 架构要回答:系统包含哪些个体 "个体按规则运作" → 架构要回答:个体如何协作 "顶层结构" vs "基础结构" → 避免将系统架构和子系统架构混淆 → 顶层 = 最上层,避免层次混乱
系统 ├── 子系统 │ ├── 模块(逻辑拆分) │ └── 组件(物理拆分) └── 框架(开发规范) ↓ 架构 = 顶层结构
| 概念 | 回答的问题 |
|---|---|
| 系统/子系统 | 整体与局部的关系 |
| 模块 | "这块做什么业务?" |
| 组件 | "这个零件用什么技术实现?" |
| 框架 | "代码该怎么写?" |
| 架构 | "系统的顶层结构是什么?" |
以下程序模拟学生信息管理系统的模块与组件划分,直观展示逻辑拆分与物理拆分。
python#!/usr/bin/env python3
"""
student_sys.py - 演示学生信息管理系统的模块与组件划分
逻辑视角(模块):按业务职责划分,每个模块对应一类业务功能
物理视角(组件):按技术实现划分,每个组件对应一个可替换的技术单元
"""
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Protocol
# ─────────────────────────────────────────────
# 组件层(物理视角,可独立替换的"零件")
# ─────────────────────────────────────────────
class StorageComponent(Protocol):
"""存储组件接口——物理视角的"零件",可替换"""
def save(self, key: str, value: bytes) -> None: ...
def load(self, key: str) -> bytes | None: ...
def delete(self, key: str) -> None: ...
class DatabaseStorage:
"""MySQL 存储组件"""
def save(self, key: str, value: bytes) -> None:
print(f"[MySQL] INSERT key={key}, size={len(value)} bytes")
def load(self, key: str) -> bytes | None:
print(f"[MySQL] SELECT key={key}")
return b"student_data_mock"
def delete(self, key: str) -> None:
print(f"[MySQL] DELETE key={key}")
class CacheStorage:
"""Redis 缓存组件"""
def save(self, key: str, value: bytes) -> None:
print(f"[Redis] SET key={key}, size={len(value)} bytes")
def load(self, key: str) -> bytes | None:
print(f"[Redis] GET key={key}")
return b"cached_data_mock"
def delete(self, key: str) -> None:
print(f"[Redis] DEL key={key}")
class SearchComponent(Protocol):
"""搜索组件接口"""
def index(self, doc_id: str, content: str) -> None: ...
def search(self, query: str) -> list[str]: ...
class ElasticSearchComponent:
"""ElasticSearch 搜索组件"""
def index(self, doc_id: str, content: str) -> None:
print(f"[ElasticSearch] INDEX id={doc_id}")
def search(self, query: str) -> list[str]:
print(f"[ElasticSearch] SEARCH query={query}")
return ["doc1", "doc2"]
# ─────────────────────────────────────────────
# 模块层(逻辑视角,按业务职责划分)
# ─────────────────────────────────────────────
@dataclass
class Student:
sid: str
name: str
grade: float
class LoginModule:
"""登录注册模块(逻辑视角)"""
def __init__(self, storage: StorageComponent):
self.storage = storage
def login(self, sid: str, pwd: str) -> bool:
key = f"session:{sid}"
self.storage.save(key, f"session_data:{sid}".encode())
print(f"[LoginModule] sid={sid} login OK")
return True
class ProfileModule:
"""个人信息模块(逻辑视角)"""
def __init__(self, storage: StorageComponent):
self.storage = storage
def get_profile(self, sid: str) -> Student | None:
print(f"[ProfileModule] fetching profile for sid={sid}")
return Student(sid=sid, name="Alice", grade=85.5)
class GradeModule:
"""个人成绩模块(逻辑视角)"""
def __init__(self, storage: StorageComponent, search: SearchComponent):
self.storage = storage
self.search = search
def query_grade(self, sid: str) -> float:
print(f"[GradeModule] querying grade for sid={sid}")
self.search.index(f"grade:{sid}", f"student:{sid}:grade:85.5")
return 85.5
def search_grades(self, keyword: str) -> list[str]:
return self.search.search(keyword)
# ─────────────────────────────────────────────
# 系统组装(演示逻辑 vs 物理)
# ─────────────────────────────────────────────
def build_system() -> dict[str, object]:
"""
组装学生信息管理系统。
从物理视角:组件可以是 MySQL、Redis、ElasticSearch
从逻辑视角:模块对应登录、个人信息、成绩三个业务域
"""
# 物理组件实例(可替换)
mysql = DatabaseStorage()
redis = CacheStorage()
es = ElasticSearchComponent()
# 按逻辑职责组装模块(每个模块内部依赖具体组件)
login_mod = LoginModule(storage=mysql)
profile_mod = ProfileModule(storage=redis) # 个人信息用缓存,读快
grade_mod = GradeModule(storage=mysql, search=es) # 成绩用 DB + 搜索
print("=" * 50)
print("系统组装完成")
print("逻辑视角(模块):", [login_mod, profile_mod, grade_mod])
print("物理视角(组件):", [mysql, redis, es])
print("=" * 50)
return {
"login": login_mod,
"profile": profile_mod,
"grade": grade_mod,
}
if __name__ == "__main__":
system = build_system()
print("\n--- 业务操作演示 ---")
system["login"].login("S001", "pass123")
p = system["profile"].get_profile("S001")
print(f" → 姓名: {p.name}, 成绩: {p.grade}")
g = system["grade"].query_grade("S001")
print(f" → 成绩查询: {g}")
results = system["grade"].search_grades("math")
print(f" → 搜索结果: {results}")
运行效果:
bash$ python3 student_sys.py
==================================================
系统组装完成
逻辑视角(模块): [<LoginModule>, <ProfileModule>, <GradeModule>]
物理视角(组件): [<DatabaseStorage>, <CacheStorage>, <ElasticSearchComponent>]
==================================================
--- 业务操作演示 ---
[MySQL] INSERT key=session:S001, size=18 bytes
[LoginModule] sid=S001 login OK
[ProfileModule] fetching profile for sid=S001
[Redis] GET key=session:S001
→ 姓名: Alice, 成绩: 85.5
[GradeModule] querying grade for sid=S001
[ElasticSearch] INDEX id=grade:S001
→ 成绩查询: 85.5
[ElasticSearch] SEARCH query=math
→ 搜索结果: ['doc1', 'doc2']
LoginModule / ProfileModule / GradeModule 各自封装一类业务行为DatabaseStorage(MySQL)、CacheStorage(Redis)、ElasticSearchComponent 是可替换的"零件"ProfileModule 用 Redis(读快),GradeModule 用 MySQL + ES(存+搜)