空间 (Space) 的定义
定义:空间是定义可能性的关注梯度(gradient of concerns)。 用数学的角度理解,如果空间是多维的,每一个维度对应一个关注点,那么空间 S 可以表示为一个向量空间: S = (c_1, c_2, ..., c_n) 其中 c_i 表示第 i 个关注点,n 是关注点的数量(维度)。
空间决定 (Space dictates)
空间会影响:
- 概念的呈现 哪些概念可以被讨论和表示。
- 可能的议题和解决方案 哪些问题可以被提出,哪些解决方案可以被考虑。
基于 CPP-Summit-2020 演讲,探讨系统架构与设计中的核心概念。重点阐述了‘空间’(Space)的定义及其多维性,区分了开发空间、架构空间与设计空间。分析了不同角色(新开发者、设计师、架构师)的关注点差异及随时间的变化。详细对比了 WHAT(需求)与 HOW(实现)的区别,强调不可混淆。介绍了过度规格化、需求、约束、偏好与能力的概念,以及如何在限制中平衡。最后讨论了自底向上与自顶向下的开发模式、复用策略及迭代反馈机制。
定义:空间是定义可能性的关注梯度(gradient of concerns)。 用数学的角度理解,如果空间是多维的,每一个维度对应一个关注点,那么空间 S 可以表示为一个向量空间: S = (c_1, c_2, ..., c_n) 其中 c_i 表示第 i 个关注点,n 是关注点的数量(维度)。
空间会影响:
空间通常是 N 维的,即多维的,每个维度对应一个不同的关注点。
# 定义一个空间 S,由多个关注点组成,每个关注点有权重
class Space:
def __init__(self, concerns, weights):
self.concerns = concerns # 关注点列表
self.weights = weights # 对应权重
assert len(concerns) == len(weights), "关注点和权重数量必须相同"
| 空间类型 | 定义 | 特点 |
|---|---|---|
| 开发空间 (Development Space) | 软件或产品开发相关的可能性空间 | 关注实现、功能、可行性 |
| 建筑空间 (Architectural Space) | 架构层面的可能性空间 | 关注系统结构、模块关系 |
| 设计空间 (Design Space) | 设计决策与创意的可能性空间 | 关注用户体验、创新方案 |
每个空间都有自己的关注点集合 S=(c_1,…,c_n),并且它们的维度、权重和排序方式可能完全不同。
作为开发者,我们在思考问题时,会用不同的'视角'来分析:
#include <iostream>
using namespace std;
// 语法规则:函数定义、循环结构
// 语义规则:变量作用域、类型安全
int add(int a, int b) {
return a + b; // 返回两个数的和
}
int main() {
int result = add(5, 3);
cout << "Result: " << result << endl;
return 0;
}
class Shape {
public:
virtual double area() = 0; // 子类必须实现
};
class Circle : public Shape {
double radius;
public:
Circle(double r) : radius(r) {}
double area() override {
return 3.1415 * radius * radius; // 面积计算
}
};
// 技术问题:计算精度、效率
double divide(double a, double b) {
if (b == 0) throw runtime_error("除数不能为零");
return a / b;
}
经验丰富的开发者,会进一步考虑 开发过程和团队协作:
// 定义问题空间的维度
struct ProblemSpace {
bool technicalConcern;
bool ergonomicConcern;
bool businessConstraint;
};
struct SolutionSpace {
bool algorithmicSolution;
bool architecturalDesign;
bool UIUXDesign;
};
从开发者角度:
定义 (def):角色是执行某个功能或承担某个部分的身份。 示例角色 (Example roles):
角色会决定:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// 定义角色及其关注点
struct Role {
string name; // 角色名称
vector<string> concerns; // 关注点列表
};
int main() {
Role developer = {"Developer", {"C++ features", "Technical solutions", "Implementation"}};
Role designer = {"Designer", {"Design approach", "System paradigms", "Code evolution"}};
cout << developer.name << " concerns:" << endl;
for (auto& c : developer.concerns)
cout << "- " << c << endl;
}
不同阶段的开发者角色关注点不同:
主要关注:
// 技术技能学习示例:了解 C++ 特性
int main() {
auto lambda = [](int x) { return x * x; }; // C++ lambda 表达式
cout << lambda(5) << endl;
}
主要关注:
主要关注:
// 技术复用示例:模板类复用算法逻辑
template<typename T>
class Repository {
public:
void add(T item) { data.push_back(item); }
T get(int index) { return data[index]; }
private:
vector<T> data;
};
int main() {
Repository<int> repo;
repo.add(10);
cout << repo.get(0) << endl;
}
| 角色 | 关注点 | 示例 |
|---|---|---|
| 新开发者 | C++ 特性、实现方法、最佳实践 | 技术技能获取 |
| 设计师 | 设计方法、编程范式、代码演进 | 解决设计问题 |
| 架构师 | 系统目标、技术选型、重用、组织发展 | 系统架构设计 |
公式表示各角色的关注空间: C_Developer = {C++特性,实现,技术解决方案} C_Designer = {设计方法,编程范式,代码演进} C_Architect = {解决方案空间,产品空间,组织健康,技术环境} 交互公式: Roles Interaction = C_Developer ∩ C_Designer ∩ C_Architect
所有角色的开发者都会关心 C++ 语言特性,但关注的重点因角色而异。
关注点:
#include <iostream>
#include <vector>
using namespace std;
// 新开发者关注:如何使用 C++ 特性完成任务
int main() {
vector<int> nums = {1, 2, 3, 4, 5}; // 使用 C++11 范围 for 循环 (range-based for) 特性
for (int n : nums) {
cout << n << " ";
}
cout << endl;
return 0;
}
数学上,新开发者关注的空间可以表示为: C_NewDev = {任务完成,最佳实践,语言特性使用}
关注点:
#include <iostream>
#include <memory>
using namespace std;
// 智能指针是 C++11 新增设计习惯
struct Node {
int value;
shared_ptr<Node> next; // 用 shared_ptr 管理内存更安全
};
int main() {
auto n1 = make_shared<Node>(); n1->value = 42;
auto n2 = make_shared<Node>(); n1->next = n2; // 安全连接节点
cout << n1->next->value << endl; // 输出 42
}
数学表示设计师关注的空间: C_Designer = {设计习惯,新问题解决方案,代码优雅性}
关注点:
#include <thread>
#include <vector>
#include <iostream>
using namespace std;
// 架构师关注:利用 C++ 多线程特性提升系统性能
void worker(int id) {
cout << "Thread " << id << " is running." << endl;
}
int main() {
vector<thread> threads;
for (int i = 0; i < 4; i++) {
threads.emplace_back(worker, i);
}
for (auto& t : threads) t.join();
return 0;
}
| 角色 | 关注点 | 目标 |
|---|---|---|
| 新开发者 | 如何完成工作,最佳实践 | 学会语言特性,解决日常开发问题 |
| 有经验设计师 | 新设计习惯,可优雅解决问题 | 改进设计模式,提高代码质量 |
| 架构师 | 系统架构、语言选择、硬件/软件协作 | 优化系统架构,提高性能和可维护性 |
公式表示整体交互空间: C_C++ = C_NewDev ∪ C_Designer ∪ C_Architect
问题 (Q):有经验的设计师 (Experienced Designer) 和架构师 (Architect) 有什么不同?
关注点:
#include <iostream>
#include <thread>
using namespace std;
// 架构师角度:考虑业务需求,决定使用多线程提升性能
void processTask(int id) {
cout << "Processing task " << id << " efficiently." << endl;
}
int main() {
thread t1(processTask, 1);
thread t2(processTask, 2);
t1.join(); t2.join();
}
关注点:
#include <iostream>
#include <memory>
using namespace std;
// 设计师角度:设计模式与资源管理
class Logger {
public:
static Logger& getInstance() {
static Logger instance; // 单例模式
return instance;
}
void log(const string& message) {
cout << message << endl;
}
private:
Logger() {}
};
int main() {
Logger::getInstance().log("Delivering quality technical solution");
}
关注点:
#include <iostream>
#include <vector>
using namespace std;
// 新开发者探索 C++ 特性
int main() {
vector<int> nums = {1, 2, 3};
for (auto n : nums) { // 范围 for 循环 C++11 特性
cout << n << endl;
}
}
| 角色 | 核心关注点 | 数学表示 |
|---|---|---|
| 架构师 | 业务方向、系统架构、组织演进 | C_Architect = {Business Direction, Solution Space, Product Space, Organizational Health} |
| 有经验设计师 | 技术交付、设计模式、代码演进 | C_Designer = {Technical Delivery, Design Patterns, Code Evolution} |
| 新开发者 | 学习语言特性、实现、探索 | C_NewDev = {Learning C++ features, Implementation, Exploration} |
公式关系:
在软件开发中,开发过程涉及一系列 工件 (Artifacts) 和 角色 (Roles),每个环节产生不同的成果:
struct Problem {
std::string businessNeed; // 业务需求描述
};
Problem problem = {"客户需要一个高性能数据处理系统"};
struct SystemAnalysis {
std::string technicalSolution; // 技术解决方案
std::string approach; // 分析方法
};
SystemAnalysis analysis = {"使用多线程处理数据", "C++11 线程库"};
#include <vector>
#include <memory>
struct Module {
std::string name;
std::vector<std::string> dependencies;
};
struct Architecture {
std::vector<Module> modules;
};
Architecture arch;
arch.modules.push_back({"DataProcessor", {"InputModule", "OutputModule"}});
#include <iostream>
using namespace std;
// 实现 DataProcessor 模块
class DataProcessor {
public:
void process(int data) {
cout << "Processing data: " << data << endl;
}
};
int main() {
DataProcessor dp;
dp.process(42);
}
#include <cassert>
int main() {
int result = 42; // 系统处理结果
assert(result == 42); // 验证满足业务需求
}
注意:在实际开发中,角色责任可能混淆,受到约束条件 (Constraints)、偏好 (Preferences) 和能力 (Capabilities) 的影响。
| 阶段 | 输出 | 主要负责角色 |
|---|---|---|
| 需求分析 (Requirements Analysis) | 系统应做什么 (WHAT) | 业务经理 (Business Managers) |
| 架构与设计 (Architecture & Design) | 提议架构和设计方案 (HOW) | 架构师 & 设计师 |
| 实现 (Implementation) | 构建系统 | 架构师 & 设计师 & 开发者 |
| 交付 (Delivery) | 系统可用 | 所有技术角色 |
f:系统分析 g:架构与设计 h:实现
'当你混合本不该混合的东西时,坏事情就会发生™'
注意:在任何阶段混合 WHAT 和 HOW,都可能导致需求不明确、架构设计错误或开发失败。
#include <iostream>
#include <string>
using namespace std;
// WHAT 阶段:定义系统需求
struct SystemRequirement {
string mustDo; // 系统必须做什么
};
// HOW 阶段:定义系统实现方案
struct Architecture {
string implementationDetails; // 系统如何实现
};
int main() {
// WHAT 阶段:不涉及 HOW
SystemRequirement req = {"处理用户数据并生成报告"};
// HOW 阶段:根据需求进行架构设计
Architecture arch;
arch.implementationDetails = "使用多线程处理数据,生成 PDF 报告";
cout << "Requirement: " << req.mustDo << endl;
cout << "Architecture: " << arch.implementationDetails << endl;
return 0;
}
注意:在 WHAT 阶段,不要写 arch.implementationDetails;在 HOW 阶段,不要重新定义 req.mustDo。
过度规格化是指给系统添加了不必要或错误的约束,这会带来负面影响。
定义 (def):
#include <iostream>
#include <string>
using namespace std;
// 系统目的:生成报告
struct SystemPurpose {
string goal = "Generate accurate business reports";
};
// 错误约束:规定报告必须使用特定字体和颜色(不必要)
struct OverspecifiedConstraint {
string font = "Arial"; // 不必要
string color = "Blue"; // 不必要
};
int main() {
SystemPurpose system;
OverspecifiedConstraint constraint;
cout << "System Goal: " << system.goal << endl;
cout << "Warning: Avoid overspecification like " << constraint.font << " font and " << constraint.color << " color" << endl;
}
注意:真正有价值的规格只需要满足
SystemPurpose.goal,字体和颜色是过度规格化的例子。
这些术语用于描述 系统交付中的'限制',帮助开发者理解系统设计和实现的边界。
定义 (def):
#include <iostream>
#include <string>
using namespace std;
// 系统需求
struct Requirement {
string description; // 必须完成的功能
};
int main() {
Requirement req;
req.description = "系统必须支持用户登录功能";
cout << "Requirement: " << req.description << endl;
}
定义 (def):
struct Constraint {
string limit; // 限制条件
};
int main() {
Constraint c;
c.limit = "响应时间必须小于 2 秒"; // 系统性能限制
cout << "Constraint: " << c.limit << endl;
}
定义 (def):
struct Preference {
string preference; // 偏好描述
};
int main() {
Preference p;
p.preference = "优先使用 C++17 标准特性"; // 开发团队偏好
cout << "Preference: " << p.preference << endl;
}
定义 (def):
struct Capability {
string ability; // 能力描述
};
int main() {
Capability cap;
cap.ability = "系统可以同时处理 1000 个并发用户";
cout << "Capability: " << cap.ability << endl;
}
这些术语在系统设计中形成不同层次的限制和指导: SystemLimits = Requirement ∪ Constraint ∪ Preference ∪ Capability
理解这些概念有助于避免混淆 WHAT / HOW、避免过度规格化,同时指导合理的系统架构与设计。
过度规格化 (Overspecification) 是一种痛苦的限制,但它只是系统限制的一种。 作为架构师 (Architect),你需要在 多种限制之间平衡。
struct Requirement {
std::string description;
};
Requirement req;
req.description = "系统必须支持用户登录功能"; // 强制性要求
// 放宽示例:协商更灵活的认证方式
bool relaxedRequirement = true;
struct Constraint {
std::string limit;
};
Constraint c;
c.limit = "响应时间必须小于 2 秒"; // 技术约束
// 放宽示例:使用更高效算法
bool alternativeTech = true;
struct Preference {
std::string tradeoff;
};
Preference p;
p.tradeoff = "优先使用 C++17 特性"; // 偏好限制
// 放宽示例:协商使用 C++14 或其他标准
bool relaxedPreference = true;
struct Capability {
std::string teamAbility;
};
Capability team;
team.teamAbility = "团队只能处理 1000 个并发用户"; // 放宽示例:培训团队,或者增加成员
bool enhancedCapability = true;
作为架构师,你需要平衡 Requirement, Constraint, Preference, Capability 四种限制: SystemLimits = RequirementLimit ∪ ConstraintLimit ∪ PreferenceLimit ∪ CapabilityLimit
| 限制类型 | 放宽方式 |
|---|---|
| Requirement | 协商需求或改变验收标准 |
| Constraint | 探索替代技术或方案 |
| Preference | 协商权衡顺序或优先级 |
| Capability | 培训团队或调整团队组合 |
数学表示放宽操作: Relax(Limit) = {Negotiate, if Requirement or Preference; Explore alternatives, if Constraint; Train or reallocate team, if Capability}
C++ 开发可以通过 抽象状态机 (Abstract State Machine, ASM) 来直接推理。开发者可以从 底层硬件 或 系统概念 两个方向进行开发。
开发者从 硬件 + C++ 保证 出发,逐步构建域类型、域算法、域子系统,最终形成系统。 流程:
int, double)定义领域相关类型#include <iostream>
#include <vector>
using namespace std;
// Step 1: 定义域类型
struct Temperature {
double value;
};
// Step 2: 实现域算法
double averageTemp(const vector<Temperature>& temps) {
double sum = 0;
for (auto t : temps) sum += t.value;
return sum / temps.size();
}
// Step 3: 实现域子系统
struct WeatherStation {
vector<Temperature> readings;
double getAverage() {
return averageTemp(readings);
}
};
int main() {
WeatherStation station;
station.readings = {{20.5}, {22.0}, {21.5}};
cout << "Average temperature: " << station.getAverage() << " C" << endl;
}
解释:开发从 基础类型 Temperature → 算法 averageTemp → 子系统 WeatherStation 构建系统。
开发者从 系统概念 → 域子系统 → 域算法 → 域类型,逐步实现具体系统。 流程:
#include <iostream>
#include <vector>
using namespace std;
// Step 1: 系统操作理论
// 系统目标:获取平均温度并报警
// Step 2: 实现域子系统
struct WeatherSubsystem {
vector<double> readings;
double getAverage() {
double sum = 0;
for (auto r : readings) sum += r;
return sum / readings.size();
}
bool alarmIfTooHigh() {
return getAverage() > 25.0;
}
};
// Step 3: 实现域算法 (可进一步定义域类型)
struct Temperature {
double value;
};
int main() {
WeatherSubsystem ws;
ws.readings = {22.0, 24.5, 26.0};
cout << "Average temperature: " << ws.getAverage() << " C" << endl;
cout << "Alarm: " << (ws.alarmIfTooHigh() ? "ON" : "OFF") << endl;
}
解释:开发从 系统概念 → 子系统 → 算法 → 域类型,逐步落实设计。
| 方法 | 出发点 | 流程 | 数学表示 |
|---|---|---|---|
| Bottom-Up | 硬件 + C++ 标准 | Domain Types → Domain Algorithms → Subsystems → System | Hardware → DomainTypes → DomainAlgorithms → Subsystems → System |
| Top-Down | 系统概念 | System Concept → Domain Subsystems → Domain Algorithms → Domain Types → Hardware | SystemConcept → DomainSubsystems → DomainAlgorithms → DomainTypes → Hardware |
核心问题:我们要构建什么系统?
struct SystemRequirement {
std::string description;
};
std::vector<SystemRequirement> analyzeSystem() {
return {{"支持用户登录"}, {"生成报告"}, {"高并发处理"}};
}
输出:一组需求集合,作为后续设计和开发的基础。
目标:定义系统的操作理论 (Theory of Operation),区分要构建的系统与不构建的系统
struct Prototype {
bool works;
};
Prototype testPrototype() {
Prototype p;
p.works = true; // 假设我们测试核心功能可行
return p;
}
// 如果原型不可行,回到概念化阶段
if (!testPrototype().works) {
// 重新设计概念
}
struct Subsystem {
void run() {
// 具体实现系统功能
std::cout << "Subsystem running..." << std::endl;
}
};
Subsystem s;
s.run();
void feedbackLoop(SystemRequirement &req, bool userSatisfied) {
if (!userSatisfied) {
// 迭代修改需求
req.description += " (更新需求)";
}
}
数学化流程表示:
数学表示: HardBarrierViolation ⟹ Cost↑ Risk↑ Quality↓ C++ 示例(错误做法,原型直接升到生产级别):
// 错误做法:将实验性算法直接部署到生产
int experimentalAlgorithm(int x) {
return x * x; // 未测试边界情况
}
int main() {
int result = experimentalAlgorithm(1000000); // 可能溢出
}
开发空间描述 开发过程中的状态与知识水平:
| 阶段 | 我们知道什么 | 状态 |
|---|---|---|
| Conceptualization | 系统要构建什么 | We Know Exactly |
| Haven't Started | 我们完全不清楚 | We Have No Idea |
| Development | 构建过程如何 | Started |
| Done | 系统完成 | We're Done |
架构空间描述 系统架构决策与业务需求对齐的状态:
| 阶段 | 核心参与者 | 关注点 |
|---|---|---|
| Conceptualization | Architects, Designers | 必须构思系统概念 |
| Haven't Started | Architects, Designers | 理解潜在和实际权衡 |
| Development Started | Developers | 实现设计 |
| Done | Architects, Designers, Business Managers | 系统完成并满足目标客户需求 |
| 轴 | 参与者 | 责任 |
|---|---|---|
| Conceptualization | Architects | 构思系统概念 |
| Conceptualization | Designers | 理解概念,提出设计方案 |
| Haven't Started | Architects | 理解潜在和实际权衡 |
| Haven't Started | Business Managers | 定义市场定位、战略目标 |
| Development Started | Developers | 实现系统 |
| Done | Architects, Designers, Business Managers | 系统完成,满足客户需求 |
核心思想:开发空间和架构空间是多维度的,每个角色在不同阶段承担不同责任,架构师必须控制'硬障碍',保持可行性与风险的平衡。
随着产品种类或目标客户的增加,复用动机也增加。
struct Product {
std::string name;
std::string version;
};
struct ProductLine {
std::vector<Product> products;
};
struct ProductFamily {
std::vector<ProductLine> productLines;
};
| 复用程度 | 范围 |
|---|---|
| 少 (Less Reuse) | 仅应用于特定应用 |
| 可复用 | 产品线内部 |
| 可复用 | 产品族内部 |
| 可复用 | 企业内部 |
| 多 (More Reuse) | 第三方可复用 |
数学化表示复用空间: ReuseLevel: {Application, ProductLine, ProductFamily, Enterprise, ThirdParty} C++ 示例(复用代码模块):
// 可复用于整个产品族的数学库
namespace ReusableMath {
double add(double a, double b) {
return a + b;
}
double multiply(double a, double b) {
return a * b;
}
}
// 产品线内部复用
struct ProductLineModule {
void process() {
/* 处理业务逻辑 */
}
};
正面效果 (Good):
负面效果 (Bad):
数学表示复用权衡: TotalCost = f(Consistency, Maintainability) - g(Innovation, Flexibility)
| 角色 | 关注点 |
|---|---|
| 管理者 (Managers) | 一致性和优先级排名 |
| 安全专家 (Security Professionals) | 库更新后的安全 |
| 第三方 (3rd Parties) | 可用性和接口一致性 |
| 创新者 (Innovators) | 灵活性和创新 |
| 大公司 (Big Companies) | 成本降低和规模经济 |
| 支持工程师 (Support Engineers) | 可维护性 |
核心思想:复用提供一致性和成本优势,但增加耦合和约束,需要在创新、成本、维护性之间平衡。
数学总结: ReuseDecision = argmax_{ReuseLevel} (Consistency + CostSavings) - (InnovationLoss + Risk)

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online