空间 (Space) 的定义
定义:空间是定义可能性的关注梯度(gradient of concerns)。 用数学的角度理解,如果空间是多维的,每一个维度对应一个关注点,那么空间 S 可以表示为一个向量空间: S = (c_1, c_2, ..., c_n) 其中 c_i 表示第 i 个关注点,n 是关注点的数量(维度)。
空间决定 (Space dictates)
空间会影响:
- 概念的呈现 哪些概念可以被讨论和表示。
- 可能的议题和解决方案 哪些问题可以被提出,哪些解决方案可以被考虑。
空间的性质 (N 维性)
空间通常是 N 维的,即多维的,每个维度对应一个不同的关注点。
- 每个关注点可能 加权 (weighted): w_i * c_i 其中 w_i 是第 i 个关注点的权重。
- 每个关注点可能 排序 (ranked): 不同关注点的重要性可以通过排序体现。 代码注释示例(Python 表示空间及权重):
# 定义一个空间 S,由多个关注点组成,每个关注点有权重
class Space:
def __init__(self, concerns, weights):
self.concerns = concerns # 关注点列表
self.weights = weights # 对应权重
assert len(concerns) == len(weights), "关注点和权重数量必须相同"
空间的隐含性 (Space implies)
- 空间隐含了哪些问题和解决方案 可以讨论。
- 空间表示的领域是探索这些问题和解决方案的范围。
- 空间也隐含了 不可见的议题或解决方案:
- 正交问题 (orthogonal issue):某些问题与当前空间不相关,无法在该空间中讨论。
- 不可描述或不可解决问题:需要在另一个空间中管理。 数学上可以表示为: 如果 x ⊥ S,则 x 不在该空间的讨论范围内
开发空间 / 建筑空间 / 设计空间对比
| 空间类型 | 定义 | 特点 |
|---|---|---|
| 开发空间 (Development Space) | 软件或产品开发相关的可能性空间 | 关注实现、功能、可行性 |
| 建筑空间 (Architectural Space) | 架构层面的可能性空间 | 关注系统结构、模块关系 |
| 设计空间 (Design Space) | 设计决策与创意的可能性空间 | 关注用户体验、创新方案 |
每个空间都有自己的关注点集合 S=(c_1,…,c_n),并且它们的维度、权重和排序方式可能完全不同。
从开发者角度思考 (Think in Terms of Developers)
作为开发者,我们在思考问题时,会用不同的'视角'来分析:
1. 编程语言 (Programming Language)
- 我们思考的是 语法规则和语义规则
- 即:如何用语言的结构和意义来表达问题和解决方案 数学上可以表示为: L = {语法规则,语义规则} C++ 示例(语法与语义规则):
#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;
}
2. 编程范式 (Paradigm)
- 解释为:如何思考问题
- 帮助我们分解问题、组织逻辑 常见范式:
- 面向对象 (OOP)
- 函数式编程 (Functional)
- 面向过程 (Procedural) 数学表示问题分解: P = Problem ⟹ sub_problem_1, sub_problem_2, ... C++ 中面向对象示例:
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; // 面积计算
}
};
3. 问题 (The Problem)
- 对开发者而言,问题主要是 技术性的
- 需要解决的技术和人体工程学(ergonomic)问题 数学上可以表示为: Problem = {Technical concerns, Ergonomic concerns} C++ 示例(技术问题:计算与接口):
// 技术问题:计算精度、效率
double divide(double a, double b) {
if (b == 0) throw runtime_error("除数不能为零");
return a / b;
}
作为有经验的开发者 (As Experienced Developers)
经验丰富的开发者,会进一步考虑 开发过程和团队协作:
1. 开发过程 (Process)
- 包括传统和迭代的领域探索 (Traditional and Iterative domain exploration)
- 思考问题的空间随着过程变化而变化 数学上可以表示为动态空间: S_t = f(process at time t)
2. 角色 (Roles)
- 不同参与方的互动也会影响空间和解决方案
- 即开发空间是 多主体、多维度的交互空间
3. 空间的维度 (Dimensions defining the spaces)
- 空间的维度定义了:
- 问题被定义的范围
- 解决方案被表达的方式 用 C++ 类比:
// 定义问题空间的维度
struct ProblemSpace {
bool technicalConcern;
bool ergonomicConcern;
bool businessConstraint;
};
struct SolutionSpace {
bool algorithmicSolution;
bool architecturalDesign;
bool UIUXDesign;
};
空间的本质
- 开发空间 (Development Space):关注技术实现、编程语言、问题解决
- 架构空间 (Architectural Space):关注系统结构、模块关系
- 设计空间 (Design Space):关注用户体验、业务协调和约束管理 数学表示不同空间: Development Space S_D = {L, P, Technical Problems} Architectural Space S_A = {Structure, Modules} Design Space S_Des = {Business, UX, Constraints}
✓ 总结
从开发者角度:
- 语言层面:语法与语义
- 思维范式:如何拆解问题
- 问题本身:技术和人体工学 从有经验开发者角度:
- 开发过程:迭代与传统探索
- 角色和协作:多方互动
- 空间维度:问题和解决方案被定义与表达的空间 所有这些共同形成了 开发空间、架构空间、设计空间 的完整理解。
角色 (Role)
定义 (def):角色是执行某个功能或承担某个部分的身份。 示例角色 (Example roles):
- 开发者 (Developer)
- 设计师 (Designer)
- 域专家 (Domain Expert)
- 架构师 (Architect)
- 产品负责人 (Product Owner)
- 客户倡导者 (Customer Advocate)
- 经理 (Manager)
- 高管 (Executive Owner)
角色决定 (Role dictates)
角色会决定:
- 你关心什么
- 你负责什么 数学上可以用集合表示一个角色的关注点: C_role = {关注点_1, 关注点_2, ...} C++ 代码示例:
#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;
}
角色隐含 (Role implies)
- 每个角色的关注点是独特的(不同角色有不同的关注)
- 必须与其他角色交互(其他角色关心不同但可能重叠的关注点) 数学上可以表示为: Interaction(R_i, R_j) = C_R_i ∩ C_R_j (交集表示重叠关注点)
角色随时间变化 (Roles Change Over Time)
不同阶段的开发者角色关注点不同:
新开发者 (New Developers)
主要关注:
- C++ 语言特性如何工作
- 如何实现技术方案
- 哪种实现方式最好 特点:需要学习技术技能,探索空间很大。
// 技术技能学习示例:了解 C++ 特性
int main() {
auto lambda = [](int x) { return x * x; }; // C++ lambda 表达式
cout << lambda(5) << endl;
}
设计师 (Designers)
主要关注:
- 系统应采用哪种设计方法
- 使用什么编程范式(思考问题的方式)
- 代码如何演进以支持新的设计理念
- 如何解决过去遗留的问题 数学上,设计师关注的是 Design Space: S_design = {设计方法,编程范式,代码演进,新旧问题解决}
架构师 (Architects)
主要关注:
- 系统应该做什么
- 应该利用哪些技术来实现系统功能
- 代码和模块的重用
- 组织的技术演进 主要考虑因素:
- 解决方案空间 (Solution Space)
- 产品空间 (Product Space)
- 组织健康 (Organizational Health) 次要考虑因素:
- 外部技术环境(包括 C++ 语言的更新) 数学上可表示为多维度空间: S_architect = {Solution Space, Product Space, Organizational Health, External Tech Landscape} C++ 示例(架构师角度思考技术复用):
// 技术复用示例:模板类复用算法逻辑
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++ 语言演进 (Caring About C++ Language Evolution)
所有角色的开发者都会关心 C++ 语言特性,但关注的重点因角色而异。
1. 新开发者 (New Developer)
关注点:
- 如何完成我的工作?
- 关注具体语法和功能实现,解决日常开发问题。
- 最佳实践是什么?
- 关注如何使用最新语言特性以编写可靠且可维护的代码。 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 = {任务完成,最佳实践,语言特性使用}
2. 有经验的设计师 (Experienced Designer)
关注点:
- 现在有哪些设计习惯 (Design idioms) 可用?
- 关注新的 C++ 特性如何改变设计方式。
- 我现在可以解决哪些问题?
- 关注是否能用更稳健(robust)或更优雅(elegant)的方式解决问题。 C++ 示例(设计师视角):
#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 = {设计习惯,新问题解决方案,代码优雅性}
3. 架构师 (Architect)
关注点:
- C++ 语言特性如何影响系统架构?
- 例如,是否使用 C++ 优于其他语言(或硬件实现子系统)?
- 如何利用新的语言特性进行硬件/软件的最优组合?
- 考虑系统整体效率、可维护性和未来演进。 数学上可以表示为: C_Architect = {语言选择,硬件/软件结合,系统架构优化} C++ 示例(架构师视角,考虑语言特性与系统选择):
#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++ = C_NewDev ∪ C_Designer ∪ C_Architect
- ∪ 表示不同角色关注点的组合
- 各角色关注点可能有 重叠,也可能有独特关注
开发者视角下的角色 (Developer's Perspective of Roles)
问题 (Q):有经验的设计师 (Experienced Designer) 和架构师 (Architect) 有什么不同?
1. 架构师 (Architect)
关注点:
- 业务方向 (Business Direction) 架构师不仅关注技术实现,还要考虑整个系统与组织战略、业务目标的对齐。
- 关注 系统架构、技术选型、组织演进。 数学上可以表示架构师的关注空间: C_Architect = {Business Direction, Solution Space, Product Space, Organizational Health} C++ 示例(架构师关注业务和技术结合):
#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();
}
2. 有经验的设计师 (Experienced Designer)
关注点:
- 成功的技术交付 (Successful Technical Delivery)
- 设计师关注系统设计和技术实现的质量
- 如何使用新语言特性和设计方法保证系统可维护、可扩展 数学上可以表示设计师的关注空间: C_Designer = {Technical Delivery, Design Patterns, Code Evolution} C++ 示例(设计师关注设计与交付):
#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");
}
3. 新开发者 (New Developer)
关注点:
- 对各种'闪亮的技术点'感到好奇,但尚未能区分重要性
- 关注点比较分散,主要在理解语言特性和基础实现 数学表示新开发者关注空间: C_NewDev = {Learning C++ features, Implementation, Exploration} C++ 示例(新开发者探索语言特性):
#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} |
公式关系:
- 不同角色关注点可能重叠或独特: C_Architect ∩ C_Designer ≠ ∅ C_NewDev 可能重叠或独立于其他角色
开发概览 (Development Overview)
在软件开发中,开发过程涉及一系列 工件 (Artifacts) 和 角色 (Roles),每个环节产生不同的成果:
1. 问题空间 (Problem Space)
- 描述 业务需求,定义系统需要解决什么问题。
- 输出:需求文档 (Requirements Analysis / RFP) 数学表示问题空间: P = {Business Needs} C++ 示例(表示问题空间):
struct Problem {
std::string businessNeed; // 业务需求描述
};
Problem problem = {"客户需要一个高性能数据处理系统"};
2. 系统分析 (System Analysis)
- 从问题空间出发,分析系统应该如何工作。
- 输出:技术细节 (Technical Details),确定'如何解决问题'。 数学表示系统分析空间: S = f(P) = {Technical Details, Solution Approach} C++ 示例:
struct SystemAnalysis {
std::string technicalSolution; // 技术解决方案
std::string approach; // 分析方法
};
SystemAnalysis analysis = {"使用多线程处理数据", "C++11 线程库"};
3. 架构与设计 (Architecture & Design)
- 基于系统分析,提出 架构与设计方案 (Proposed Architecture & Design Proposal)
- 输出:架构图、模块设计、技术方案可交付成果 数学表示: A = g(S) = {Architecture, Design, Modules, Interfaces} C++ 示例(架构与设计阶段):
#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"}});
4. 实现 (Implementation)
- 根据架构与设计构建系统
- 参与角色:开发者 (Developers)、设计师 (Designers)、架构师 (Architects) 数学表示实现空间: I = h(A) = {Code, Tests, Executable System} C++ 示例(实现阶段):
#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);
}
5. 交付 (Delivery / Ship It!)
- 系统完成后交付使用
- 需要满足业务需求,行为符合预期 数学表示交付成果: D = deliver(I) 满足 P C++ 示例(交付后的验证):
#include <cassert>
int main() {
int result = 42; // 系统处理结果
assert(result == 42); // 验证满足业务需求
}
角色与责任 (Roles & Responsibilities)
- 业务领导 (Business Leadership):确定问题空间中的优先级
- 技术领导 (Architects & Designers):管理技术实现,确保架构与设计符合需求
- 开发者 (Developers):执行具体实现 公式表示角色与空间映射: Business Leadership → P Technical Leadership → S ∪ A Developers → I
注意:在实际开发中,角色责任可能混淆,受到约束条件 (Constraints)、偏好 (Preferences) 和能力 (Capabilities) 的影响。
'旧时代'开发流程 (The Olden Days)
| 阶段 | 输出 | 主要负责角色 |
|---|---|---|
| 需求分析 (Requirements Analysis) | 系统应做什么 (WHAT) | 业务经理 (Business Managers) |
| 架构与设计 (Architecture & Design) | 提议架构和设计方案 (HOW) | 架构师 & 设计师 |
| 实现 (Implementation) | 构建系统 | 架构师 & 设计师 & 开发者 |
| 交付 (Delivery) | 系统可用 | 所有技术角色 |
流程视图对比 (WHAT vs HOW)
- WHAT:需求分析 → 提供给架构师/设计师系统应该做什么
- HOW:架构与设计 → 系统分析 + 提议架构 → 实现 → 交付 数学表示: WHAT = P HOW = h(g(f(P))) = I → D
f:系统分析 g:架构与设计 h:实现
永远不要混淆 (Never Mix / Should Not Mix)
'当你混合本不该混合的东西时,坏事情就会发生™'
核心原则
- 有些事情 绝对不能混合 (NEVER MIX)
- 你必须 始终清楚自己在做'哪一件事'
- 如果发现不确定自己在做什么,立即停止并弄清楚
WHAT vs HOW
- WHAT (系统需求 / System Requirements)
- 描述 系统必须做什么
- 关注业务需求和问题定义
- 数学表示: WHAT = {Business Needs, Functional Requirements}
- HOW (架构与设计 / Architecture & Design)
- 描述 系统如何实现
- 关注技术实现、可行性和开发方案
- 数学表示: HOW = {Architecture, Design, Implementation Details} 重要原则: NEVER MIX(WHAT, HOW) 即不要在讨论'系统必须做什么'的同时,去考虑'系统如何实现',否则会导致混乱。
扩展注意事项
- 可行性 (FEASIBILITY)
- 在 HOW 阶段,才考虑技术可行性
- WHAT 阶段不要去做可行性分析
- 开发 (DEVELOPMENT)
- 构建系统的阶段
- 只能基于 HOW 进行,不应该在 WHAT 阶段做开发 数学流程表示: P_WHAT → f(P_WHAT) = S_HOW → h(S_HOW) = System
- P_WHAT:业务需求 / 系统需求
- S_HOW:系统分析 + 架构与设计
- System:最终实现的系统
注意:在任何阶段混合 WHAT 和 HOW,都可能导致需求不明确、架构设计错误或开发失败。
C++ 示例(概念映射)
#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。
总结
- WHAT = 系统必须做什么(业务关注)
- HOW = 系统如何实现(技术关注)
- 绝不可混合 Mixing WHAT and HOW ⟹ Confusion, Misalignment, Project Risk
小心:过度规格化 (Be Wary: Overspecification)
过度规格化是指给系统添加了不必要或错误的约束,这会带来负面影响。
1. 什么是过度规格化 (Overspecification)
定义 (def):
- 过度规格化 = 错误约束 (Erroneous Constraint)
- 错误约束总是提供负面价值 特点:
- 指定不必要的细节 (Specify unnecessary detail)
- 例如在系统设计中规定一些行为或实现细节,但这些并非系统本质需要。
- 假设不必要的行为 (Assume unnecessary behavior)
- 将某些行为视为必要,但实际上不影响系统目的。 数学表示: Overspecification = Constraint \ System Purpose
- \ 表示与系统目标不相关的约束。
2. 为什么 Spiral / Agile 避免过度规格化?
- Spiral / Agile 方法倾向于 跳过或延迟过度规格化阶段
- 原因:过度规格化会 伤害系统和开发者 关键机制:
- 不断回到'第一性原理 (First Principles)'
- 反复检查系统的 核心目的 (System Purpose)
- 任何与目的无关的假设都不是'真实'规格或约束 数学表示: ValidSpec = {Constraints c | c directly supports System Purpose} Overspecification = {Constraints c | c ∉ ValidSpec}
3. Agile 的真正目标 (A Real Problem™ That Agile Does Really Solve™)
- Agile 运动的一个核心动机是 避免过度规格化
- 通过 迭代开发 和 持续验证假设,确保系统规格紧贴业务目标,而不是被无关约束束缚 C++ 示例(概念映射):
#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,字体和颜色是过度规格化的例子。
4. 核心总结
- 过度规格化 = 错误约束 = 负面价值
- 避免策略:
- 回到第一性原理:Purpose → ValidSpec
- 使用迭代/Spiral/Agile 方法延迟细节决策
- 只指定与目的直接相关的约束
- 公式总结: Overspecification = {Constraints not required by Purpose} Value(Overspecification) < 0 ValidSpec = {Constraints that support System Purpose} Value(ValidSpec) > 0
回顾:限制系统的术语 (Review: Terms To Limit Your System)
这些术语用于描述 系统交付中的'限制',帮助开发者理解系统设计和实现的边界。
1. 需求 (Requirement)
定义 (def):
- 需求 = 被强制的规格 (A mandated specification)
- 系统必须满足的条件或功能 数学表示: Requirement = {Must-do constraints for the system} C++ 示例(需求概念):
#include <iostream>
#include <string>
using namespace std;
// 系统需求
struct Requirement {
string description; // 必须完成的功能
};
int main() {
Requirement req;
req.description = "系统必须支持用户登录功能";
cout << "Requirement: " << req.description << endl;
}
2. 约束 (Constraint)
定义 (def):
- 约束 = 可能性的限制 (A limit of possibility)
- 描述系统实现、设计或运行中不可逾越的边界 数学表示: Constraint = {Limits on system design, implementation, or operation} C++ 示例(约束概念):
struct Constraint {
string limit; // 限制条件
};
int main() {
Constraint c;
c.limit = "响应时间必须小于 2 秒"; // 系统性能限制
cout << "Constraint: " << c.limit << endl;
}
3. 偏好 (Preference)
定义 (def):
- 偏好 = 排序备选方案的倾向 (An expressed bias to rank alternatives)
- 表示对某种实现方式或设计方案的倾向性选择,并非强制 数学表示: Preference = {Ranking or bias among alternatives} C++ 示例(偏好概念):
struct Preference {
string preference; // 偏好描述
};
int main() {
Preference p;
p.preference = "优先使用 C++17 标准特性"; // 开发团队偏好
cout << "Preference: " << p.preference << endl;
}
4. 能力 (Capability)
定义 (def):
- 能力 = 系统或团队交付某项功能的能力 (An ability to deliver)
- 描述实际可以实现或提供的功能,不是需求或偏好 数学表示: Capability = {Ability of system or team to deliver functionality} C++ 示例(能力概念):
struct Capability {
string ability; // 能力描述
};
int main() {
Capability cap;
cap.ability = "系统可以同时处理 1000 个并发用户";
cout << "Capability: " << cap.ability << endl;
}
总结公式
这些术语在系统设计中形成不同层次的限制和指导: SystemLimits = Requirement ∪ Constraint ∪ Preference ∪ Capability
- Requirement → 必须满足
- Constraint → 不可逾越
- Preference → 可选择的倾向
- Capability → 可实现的能力
理解这些概念有助于避免混淆 WHAT / HOW、避免过度规格化,同时指导合理的系统架构与设计。
理解你的系统限制 (Understand Your System-Limits)
过度规格化 (Overspecification) 是一种痛苦的限制,但它只是系统限制的一种。 作为架构师 (Architect),你需要在 多种限制之间平衡。
1. 需求限制 (Requirement Limit)
- 定义:你受制于 强制性规定,即系统必须做的功能或条件。
- 如何放宽 (How to relax):
- 协商需求或'验收标准 (Acceptance Criteria)'
- 判断哪些需求可以灵活处理 数学表示: RequirementLimit = {Mandated specifications for system} C++ 示例:
struct Requirement {
std::string description;
};
Requirement req;
req.description = "系统必须支持用户登录功能"; // 强制性要求
// 放宽示例:协商更灵活的认证方式
bool relaxedRequirement = true;
2. 约束限制 (Constraint Limit)
- 定义:你受制于 技术或物理可能性 (limits of technology or physics)
- 如何放宽:
- 探索替代技术
- 重新设计以突破原有限制 数学表示: ConstraintLimit = {Limits of technology or physics} C++ 示例:
struct Constraint {
std::string limit;
};
Constraint c;
c.limit = "响应时间必须小于 2 秒"; // 技术约束
// 放宽示例:使用更高效算法
bool alternativeTech = true;
3. 偏好限制 (Preference Limit)
- 定义:你受制于 偏好或权衡 (bias expressing preferred tradeoffs)
- 如何放宽:
- 协商不同的权重或偏好
- 优化决策顺序 数学表示: PreferenceLimit = {Preferred tradeoff rankings} C++ 示例:
struct Preference {
std::string tradeoff;
};
Preference p;
p.tradeoff = "优先使用 C++17 特性"; // 偏好限制
// 放宽示例:协商使用 C++14 或其他标准
bool relaxedPreference = true;
4. 能力限制 (Capability Limit)
- 定义:你受制于 实现团队的能力 (what team can deliver)
- 如何放宽:
- 培训团队
- 调整团队组合
- 提供额外支持或工具 数学表示: CapabilityLimit = {Team availability and capabilities} C++ 示例:
struct Capability {
std::string teamAbility;
};
Capability team;
team.teamAbility = "团队只能处理 1000 个并发用户"; // 放宽示例:培训团队,或者增加成员
bool enhancedCapability = true;
5. 总结:架构师的多限制平衡
作为架构师,你需要平衡 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++ 开发看起来像什么 (Using C++ Looks Like…)
C++ 开发可以通过 抽象状态机 (Abstract State Machine, ASM) 来直接推理。开发者可以从 底层硬件 或 系统概念 两个方向进行开发。
1. 底向开发 (Bottom-Up)
开发者从 硬件 + C++ 保证 出发,逐步构建域类型、域算法、域子系统,最终形成系统。 流程:
- 定义域类型 (Domain Types)
- 从基础类型(如
int,double)定义领域相关类型 - 保证行为明确 (Well-Defined Behavior)
- 从基础类型(如
- 实现域算法 (Domain Logic / Algorithms)
- 基于域类型实现算法
- 实现域子系统 (Subsystems)
- 基于域算法构建子系统 数学表示: BottomUp: Hardware → C++ Guarantees → DomainTypes → DomainAlgorithms → Subsystems → System C++ 示例(底向开发):
#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 构建系统。
2. 顶向开发 (Top-Down)
开发者从 系统概念 → 域子系统 → 域算法 → 域类型,逐步实现具体系统。 流程:
- 定义操作理论 (Theory of Operation)
- 描述系统行为、目标和约束
- 实现域子系统 (Domain Subsystems)
- 将理论映射为子系统
- 实现域算法 (Domain Algorithms)
- 子系统内部的算法实现 数学表示: TopDown: SystemConcept → DomainSubsystems → DomainAlgorithms → DomainTypes → Hardware C++ 示例(顶向开发):
#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;
}
解释:开发从 系统概念 → 子系统 → 算法 → 域类型,逐步落实设计。
3. 总结比较
| 方法 | 出发点 | 流程 | 数学表示 |
|---|---|---|---|
| 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 |
- Bottom-Up 优势:更易保证类型安全和行为明确
- Top-Down 优势:更易对齐系统目标和操作理论
开发轴 (Development Axes) 与自由度 (Many Degrees Of Freedom)
- 系统开发包含许多自由度和选择
- 现实开发阶段 (Real-World Development Stages) 帮助我们理解 应该期待什么,以及 每个阶段的目标和输出
1. 系统分析 (System Analysis)
核心问题:我们要构建什么系统?
- 目标:
- 确定业务需求
- 明确系统功能
- 回答'我们为什么被雇佣?' 数学表示: SystemAnalysis: Identify {Requirements, Constraints, Capabilities, Preferences} C++ 概念示例:
struct SystemRequirement {
std::string description;
};
std::vector<SystemRequirement> analyzeSystem() {
return {{"支持用户登录"}, {"生成报告"}, {"高并发处理"}};
}
输出:一组需求集合,作为后续设计和开发的基础。
2. 概念化 (Conceptualize / Theory of Operation)
目标:定义系统的操作理论 (Theory of Operation),区分要构建的系统与不构建的系统
- 可行性 (Feasibility):
- 技术问题必须在系统理解前被回答
- 通过 原型 (Prototype) 验证系统是否可行 数学表示: Feasibility = Check if system can be built given technology and constraints C++ 概念示例(原型验证):
struct Prototype {
bool works;
};
Prototype testPrototype() {
Prototype p;
p.works = true; // 假设我们测试核心功能可行
return p;
}
// 如果原型不可行,回到概念化阶段
if (!testPrototype().works) {
// 重新设计概念
}
- 注意:原型可以与可行性阶段合并,如果已有类似系统或技术,可跳过。
3. 开发阶段 (Development / Build It!)
- 任务:
- 实现操作理论 (Implement Theory of Operation)
- 编码/实现设计 (Code / Implement Design)
- 验证 (Validate):确保需求被满足,技术行为正确 数学表示: Development = Implement(SystemConcept) → Code → Subsystems → Validate → System C++ 概念示例:
struct Subsystem {
void run() {
// 具体实现系统功能
std::cout << "Subsystem running..." << std::endl;
}
};
Subsystem s;
s.run();
4. 部署阶段 (Deploy)
- 任务:
- 交付系统给生产或客户
- 更新文档
- 培训支持人员
- 系统可用性交付 数学表示: Deploy(System) = Make system available to end-users
5. 迭代与反馈 (Feedback Loop)
- 后期阶段的反馈可以反向影响早期阶段
- 这与 Spiral / Agile 方法类似,形成循环迭代 数学表示: Feedback: LaterPhase → EarlierPhase C++ 概念示例:
void feedbackLoop(SystemRequirement &req, bool userSatisfied) {
if (!userSatisfied) {
// 迭代修改需求
req.description += " (更新需求)";
}
}
6. 总结流程 (Real-World Development Flow)
数学化流程表示:
- SystemAnalysis → 2. Conceptualize/Feasibility → 3. Development/Implementation → 4. Deploy → Feedback → 1
- System Analysis:定义要构建什么
- Conceptualize / Feasibility:定义操作理论、验证可行性
- Development:实现理论和设计
- Deploy:交付系统
- Feedback:后期反馈指导早期调整
1. 唯一的'硬障碍' (The Only 'Hard Barrier')
- 架构师必须在考虑'闪亮的新技术 (sparkly new things)'时保持理智,扮演'成年人'角色。
- 绝不能将可行性 (Feasibility) 阶段直接放大成开发 (Development) 阶段,否则会带来严重问题:
- 成本大幅增加
- 在未经验证的实验上投入生产级资源
- 风险放大
- 部署级问题可能造成严重影响
- 质量下降,开发者困惑
- 实验与生产混合,导致低标准实验与高标准生产混乱
数学表示: HardBarrierViolation ⟹ Cost↑ Risk↑ Quality↓ C++ 示例(错误做法,原型直接升到生产级别):
// 错误做法:将实验性算法直接部署到生产
int experimentalAlgorithm(int x) {
return x * x; // 未测试边界情况
}
int main() {
int result = experimentalAlgorithm(1000000); // 可能溢出
}
2. 并行与概念进展 (Parallel & Concept Progression)
- 并行进展 (Parallel Progression)
- 不同阶段可'同时进行',例如 Feasibility、Conceptualization、Development
- 概念进展 (Concept Progression)
- 随阶段演化:
- Requirements → Conceptualization → Development
- 允许响应意外:
- 关键客户改变需求
- 目标用例改变
- 业务方向改变
- 随阶段演化:
- 开发进展 (Development Progression)
- 随阶段演化:
- Feasibility / Prototyping → Development → Productization
- 意外情况:
- 迁移新平台/操作系统
- 迁移新编译器/工具链
- 更换或添加第三方子系统
- 可能原因:
- 快速变化市场
- 收购、兼并或合并
- 随阶段演化:
3. 两种开发模型 (Two Development Models)
- 正式开发 (Formal / Waterfall Model)
- 顺序阶段:需求分析 → 设计 → 实现 → 测试 → 部署
- 迭代开发 (Iterative / Spiral / Agile Model)
- 通过原型、反馈循环不断调整需求和设计
- 允许更灵活应对市场变化 数学表示: Waterfall: Requirements → Design → Implementation → Verification → Deployment Spiral/Agile: IterativeCycle(Requirements, Design, Implementation, Feedback)
4. 开发空间 (Development Space)
开发空间描述 开发过程中的状态与知识水平:
| 阶段 | 我们知道什么 | 状态 |
|---|---|---|
| Conceptualization | 系统要构建什么 | We Know Exactly |
| Haven't Started | 我们完全不清楚 | We Have No Idea |
| Development | 构建过程如何 | Started |
| Done | 系统完成 | We're Done |
- 问题:在尚未开始或开发阶段,团队不确定如何操作
- Spiral / Agile 的做法:通过迭代减少未知
- Waterfall 的做法:严格按阶段执行
5. 架构空间 (Architectural Space)
架构空间描述 系统架构决策与业务需求对齐的状态:
| 阶段 | 核心参与者 | 关注点 |
|---|---|---|
| Conceptualization | Architects, Designers | 必须构思系统概念 |
| Haven't Started | Architects, Designers | 理解潜在和实际权衡 |
| Development Started | Developers | 实现设计 |
| Done | Architects, Designers, Business Managers | 系统完成并满足目标客户需求 |
- 目标客户 (Target Customer):
- 系统需求和期望可能多维、多目标
- 架构师和设计师需要处理短期和长期目标,以及市场定位 数学表示: DevelopmentSpace: Conceptualization → Development → Done ArchitecturalSpace: Conceptualization → Architects, Designers → Development → Developers → Done
6. 谁在每条轴上? (Who is found on each axis?)
| 轴 | 参与者 | 责任 |
|---|---|---|
| Conceptualization | Architects | 构思系统概念 |
| Conceptualization | Designers | 理解概念,提出设计方案 |
| Haven't Started | Architects | 理解潜在和实际权衡 |
| Haven't Started | Business Managers | 定义市场定位、战略目标 |
| Development Started | Developers | 实现系统 |
| Done | Architects, Designers, Business Managers | 系统完成,满足客户需求 |
核心思想:开发空间和架构空间是多维度的,每个角色在不同阶段承担不同责任,架构师必须控制'硬障碍',保持可行性与风险的平衡。
7. 总结:开发 vs 架构空间
- 开发空间 (Development Space):
- 聚焦 构建过程与状态
- 角色:开发者、架构师、设计师
- 架构空间 (Architectural Space):
- 聚焦 概念设计、权衡、业务需求
- 角色:架构师、设计师、业务管理者
- 两者相互依赖:
- 开发空间提供实现反馈
- 架构空间提供设计决策和业务指导
1. 产品线复用动机 (Motivation for Reuse)
- 产品 (Product):可交付的单元
- 产品线 (Product Line):一组相关但独特的产品
- 产品族 (Product Family):一组相关但独特的产品线
随着产品种类或目标客户的增加,复用动机也增加。
- 市场差距分析 (Market Gap Analysis):
- 每个'相关但独特'的产品都鼓励某种架构复用
- 通过分析市场中所有产品族位置,确定哪些可以复用 数学表示: ReuseMotivation ∝ Variations in Product Offerings C++ 概念示例:
struct Product {
std::string name;
std::string version;
};
struct ProductLine {
std::vector<Product> products;
};
struct ProductFamily {
std::vector<ProductLine> productLines;
};
2. 架构空间中的物理维度 (Physical Dimensions in Architectural Space)
- 复用等级 (Levels of Reuse):
| 复用程度 | 范围 |
|---|---|
| 少 (Less Reuse) | 仅应用于特定应用 |
| 可复用 | 产品线内部 |
| 可复用 | 产品族内部 |
| 可复用 | 企业内部 |
| 多 (More Reuse) | 第三方可复用 |
- 复用相关考虑事项:
- 用户界面 (UI)
- 子系统配置 (Subsystem Configuration)
- 系统配置 (System Configuration)
- 业务逻辑不变量 (Business Logic Invariants):
- 类型 (Types)
- 处理模型 (Processing Models)
- 控制流 (Control Flows)
- 数据流 (Data Flows)
- 可维护性 / 支持接口 (Serviceability / Support Interfaces)
- 域特定数据处理 (Domain-Specific Data Handling)
- 日志 (Logging)
- 序列化 (Serialization)
- RPC / 分布式处理模型 (RPC, Distributed processing)
数学化表示复用空间: 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() {
/* 处理业务逻辑 */
}
};
3. 复用的成本与收益 (Cost and Benefits of Reuse)
正面效果 (Good):
- 促进一致性
- 所有开发者都知道'统一工作方式'
- 低成本创建新系统,提供规模经济
- 对安全和维护有益
- 库更新后,每个开发者均可获益
负面效果 (Bad):
- 强制同一解决方案应用于不同问题
- 减少创新
- 可能减慢开发进度
- 库更新可能导致所有系统等待
- 增加耦合度,提高复杂性、时间和风险
- 无法单独在某个系统中快速修复
数学表示复用权衡: TotalCost = f(Consistency, Maintainability) - g(Innovation, Flexibility)
4. 谁关心复用? (Who Cares About Reuse?)
| 角色 | 关注点 |
|---|---|
| 管理者 (Managers) | 一致性和优先级排名 |
| 安全专家 (Security Professionals) | 库更新后的安全 |
| 第三方 (3rd Parties) | 可用性和接口一致性 |
| 创新者 (Innovators) | 灵活性和创新 |
| 大公司 (Big Companies) | 成本降低和规模经济 |
| 支持工程师 (Support Engineers) | 可维护性 |
核心思想:复用提供一致性和成本优势,但增加耦合和约束,需要在创新、成本、维护性之间平衡。
5. 总结:复用战略 (Reuse Strategy)
- 动机:产品/产品线/产品族数量越多,复用价值越高
- 复用等级:从应用级 → 产品线 → 产品族 → 企业 → 第三方
- 关键权衡:
- 正面:一致性、降低新系统成本、规模经济
- 负面:降低创新、增加耦合、维护复杂性
- 决策者:架构师、管理者、开发者、安全专家、支持工程师等
数学总结: ReuseDecision = argmax_{ReuseLevel} (Consistency + CostSavings) - (InnovationLoss + Risk)

