完整课程 · No. 03
一门面向已经在写代码、但想学会做架构决策、向团队和业务解释这些决策、并看见系统全貌的工程师的课程。
24 个模块 · 用 trade-off 取代教条 · 把专业词汇讲成大白话
架构师和 senior engineer 的区别,不在于他懂更多技术。他为"决策在时间维度上的后果"负责。
架构师以年为单位思考
工程师造一座明天就有车开过去的桥。架构师则问:等卡车开始上桥会怎样、等隔壁起了一个新城区会怎样、等维修费比桥本身还贵会怎样。
工程师通常解决被提出来的那个问题。架构师则先检查这个问题有没有被提对。这不是清高,也不是想"聊点高深的"。只不过一个架构决策,通常比一行代码更难改、改起来更贵。
脑子里最关键的那个转变:你不再只问"我该怎么做 X",而开始问**"我们为什么需要 X、有哪些备选、会失去什么、三年后它会是什么样"**。
架构师的责任是系统的形态,而不是代码
木匠把搁板装歪了,你能挪。设计师把承重墙放错了位置,房子要带着这个错误活上几十年。
架构师没有义务亲自做每一个技术决策。但他有义务为那些"定下系统形态"的决策负责:service boundary、数据模型、集成协议、scaling 策略、安全、observability、迁移路径。
这里有用的区分是 reversible decisions(可逆决策) 和 irreversible decisions(不可逆决策)。可逆决策一天或一周就能改:一个日志库、一个按钮颜色、一个小模块的内部结构。不可逆或难以撤销的决策,会改变系统的轨迹:数据库、tenancy 模型、一个 API contract、event 的存储方式、service boundary。
- 我们真正在解决的是什么问题? - 如果负载涨 10 倍,什么会变? - 这里哪些决策可逆,哪些几乎不可逆? - 一年后 谁来维护这套东西?
架构师不造"最正确的系统"——他造一个能在现实里存活下来的系统。
架构里没有免费的决策。每个选择都用一个属性的代价,买来另一个属性。
脱离 context 的 best practice 是坏建议
泥泞路上 SUV 赢轿车。城里轿车赢 SUV。要是只走三个街区又没地方停车,自行车赢过两者。
你没法脱离 context 去评判一个架构决策。REST、GraphQL、Kafka、PostgreSQL、Kubernetes、microservices、monolith——全都是带价格的工具。一个 trade-off 是一次有意识的交换:latency vs throughput、consistency vs availability、time-to-market vs 可维护性、简单 vs 灵活。
架构师不说"Kafka 比 RabbitMQ 好"。他说:"我们需要按 key 的 event ordering、高吞吐、replay,以及一个持久化的 log;作为交换,我们付出 Kafka 的运维复杂度。"专业的语言,听起来就是这样。
复杂度是一种税
每一个新抽象,都像房子里多出的一个房间。房间可以有用,但它得打扫、供暖、维修,还得向客人解释。
当复杂度买来一个重要属性时,它是有用的:故障隔离、独立发布、安全、scaling、可测试性。但"为了将来"的复杂度,通常变成一笔永久的税。
over-engineering 和 under-engineering 这两个词,只有放在一起才有用。over-engineering:复杂度在真正的痛出现之前就来了。under-engineering:系统已经撞到了极限,而架构没留出生长的余地。架构师的活儿不是去挑一个极端——而是守住中间。
- Architecture: The Hard Parts — Ford, Richards, Sadalage, Dehghani
- Software Architecture in Practice — Bass, Clements, Kazman
- Martin Fowler: Is Design Dead?
技术债不总是坏事。坏的是那种偶然背上的、没写下来的、压根没打算偿还的债。
债是一笔贷款,不是垃圾
一笔买设备的贷款能加速一桩生意。一笔办派对的贷款,只留下宿醉和利息。
技术债 是一个让我们现在加速、却制造了未来"改动成本"的决策。有时这是对的:你要试市场、赶 deadline、留住一个客户。问题始于团队把一切都贴上债的标签:烂代码、缺测试、混乱的依赖、过时的库。
一个有用的模型是 Martin Fowler 的四象限:deliberate / inadvertent(刻意 / 无意)与 prudent / reckless(审慎 / 鲁莽)。deliberate-prudent 的债:"我们暂时跳过 multi-region,因为我们只有 200 个用户、一个市场。"inadvertent-reckless 的债:"我们当时不知道需要事务。"
债要付利息
如果路坏了,每一趟都多花五分钟。一个月后它不再是一个坑——而是对整座城市征的税。
技术债的利息,是每一次后续改动的减速。团队越频繁地碰某个区域,那里的债就越贵。这就是为什么"热点领域"里的债,比一个很少用的后台面板里的债更危险。
架构师会谈定一套偿还策略:到底什么算债、它制造了什么风险、我们什么时候回头重审这个决策、什么信号在说"该还了"。没有这些,"技术债"就成了一个情绪化的论点,而不是一个被管理的工具。
- 我们为什么接下这个折中,记在哪里了?
- 我们每个 sprint 在付多少利息?
- 要发生什么,这笔债才会变成一个 blocker?
- 有没有还款计划,或者至少有个回头重审的触发条件?
一个没人装得进脑子的系统,就算配上强工程师,也会出问题。
架构必须装得进一个人的脑子
地铁图有用,不是因为它画出了隧道里的每一颗螺栓。它画的是线路、换乘和行进方向。这就够做决策了。
Cognitive load(认知负荷) 是一个系统向工程师索取的脑力。有 intrinsic load(内在负荷):领域本身的复杂度。有 extraneous load(外在负荷):来自烂架构、不直观的关联、偶然的例外和"魔法"的额外复杂度。架构师没法移除业务复杂度,但有义务削减偶然的复杂度。
一个好模块能被单独看懂。一个好的 bounded context 有自己的语言和自己的 invariant。一个好团队拥有一块"装得进它脑子"的领域。
Conway's Law 不是玩笑
如果三个部门彼此不说话,他们的产品几乎总会长成三个产品硬拼进一个菜单的样子。
Conway's Law(康威定律) 说:一个组织设计出的系统,会映照出组织内部沟通的结构。如果架构边界和团队边界对不上,团队就会不停地踩进别人的地盘。
Team Topologies 引入了一些有用的标签:stream-aligned team、platform team、enabling team、complicated-subsystem team。这不是 HR 的时髦——而是一个架构工具。有时候,系统的正确拆分,要从责任的正确拆分开始。
一个大系统,只有当你能沿着对的边界去切它时,才变得可管理。
可以按层切、按领域切,或按数据流切
屠夫不会随便乱切一头牲畜——他在关节处下刀。好的拆分,也在寻找那些天然的断点。
拆分不是"归进文件夹"。它是在选择责任在哪里结束。High cohesion(高内聚) 意味着一个组件内部的一切都关于同一件事。Low coupling(低耦合) 意味着这个组件对别的组件知之甚少。
横切给你的是层:UI、application、domain、infrastructure。纵切给你的是 feature 或 bounded context:billing、identity、catalog、comments。真实系统两者都需要,但拿一个去冒充另一个,很危险。
坏边界会在变化里露馅
如果换厨房水龙头要把卧室拆了,问题就不在水龙头。
坏拆分的一个迹象:一个小改动在五个模块里激起涟漪。另一个迹象:一个模块出于不同的原因而变化——今天因为产品,明天因为数据库,后天因为一个集成。
DDD 的术语 bounded context 恰恰在这里有用。它是一条边界,在边界以内,词只有一个含义。billing 里的"Customer"和 support 里的"Customer"可以是不同的 model。硬把它们塞成一个,往往造出一个脆弱的"万能"model。
业务逻辑应该依赖业务规则,而不是依赖 framework、数据库或 HTTP。
依赖应该朝着中心流动
地基不该取决于窗帘的颜色。如果取决于了,那这房子是反着设计的。
Clean Architecture、Hexagonal Architecture 和 Onion Architecture 讲的是同一件事:重要的逻辑属于中心,细节属于外圈。HTTP、SQLAlchemy、Next.js、Kafka、Redis、Stripe——这些是细节。它们重要,但不该定义业务规则。
Dependency Inversion Principle 说:高层逻辑依赖抽象,实现从外部插进来。落到代码里,这就是 ports and adapters:service 收进一个 PaymentGatewayProtocol,而不在自己内部构造一个 StripeClient。
抽象是为了吸收变化,不是为了好看
插头真的不一样时,adapter 才该出现。如果你只因为喜欢 adapter 就给每个插座都装一个,房子反而更不安全。
不是每个 class 都需要一个 interface。但任何触及外部世界、时间、随机、网络、文件系统或数据库的东西,都应该在测试里可替换。否则你测的不是业务逻辑——你是在一个 unit test 里启动了一个小型生产系统。
一个层的代价,是更多文件、更多文字。它的回报,是可测试性、可替换的 infrastructure、干净的边界。如果没有回报,这个层就是死重。
API 是一个承诺。打破承诺很容易;重建客户端的信任,很难。
contract 比 transport 更重要
护照检查不在乎门是什么牌子。要紧的是接受哪些证件、适用哪些规则、出了岔子怎么办。
REST、GraphQL、gRPC 和 WebSocket 是不同的对话方式。REST 适合面向资源的 API 和简单缓存。GraphQL 在不同客户端需要不同读取形状时有帮助。gRPC 适合带类型的 service 间通信。WebSocket 用于实时的双向 event。
transport 的选择是次要的。要紧的是 contract:schema、错误、幂等性、versioning、向后兼容、deprecation policy。
幂等性把你从现实世界里救出来
如果你按十次电梯按钮,电梯不该来了又走十次。它该明白:意图只有一个。
Idempotency(幂等性) 意味着一个重复的操作产生同样的最终效果。在网络系统里,重试不可避免:timeout、retry、重复的 webhook、worker 重启。如果创建一笔支付、订单或消息不是幂等的,系统迟早会多干点什么。
架构师在 contract 层面就设计幂等:idempotency key、unique constraint、安全的重试、清晰的 status。
代码会被重写。数据会迁移好多年。这就是为什么数据模型是最昂贵的架构决策之一。
数据比应用活得久
外墙一周就能重刷。地基浇错了,会在建筑的整个生命周期里提醒你。
语言、framework、UI 可能换好几遍。但表、event、key、关系和历史记录会留下来。数据模型里的一个错误,往往变成产品每一个未来版本里的错误。
normalization(规范化)减少重复和分歧的风险。denormalization(反规范化)加速读取、简化读模型。OLTP 系统为事务优化,OLAP 为分析优化。你没法把一个 model 设计成"既完美服务事务、又完美服务分析"。
event sourcing 是一个强工具,不是一种宗教
银行流水不只存当前余额——它存操作的历史。这才让你能解释余额是从哪来的。
Event sourcing 把变化存成一串 event,并从中重建当前状态。当历史、审计、状态恢复和 replay 重要时,它有用。代价很高:event schema 演进、查询复杂度、eventual consistency、对工具链的高要求。
CQRS 把写模型和读模型分开。它能极大地简化复杂的读系统,但加上了同步和延迟。只因为"听起来很架构"就引入 CQRS,是一种昂贵的、把一个问题变成两个的方式。
状态是住在某处的复杂度。真相的副本越多,出错的方式就越多。
single source of truth 不等于单一数据库
一家公司可以有很多报表,但必须有一份官方的工资册。否则发薪日就变成一场表演。
Single source of truth 意味着:对每一个重要事实,你都知道权威版本住在哪。cache、search index、read replica、materialized view——这些是派生的副本。它们可以有用,但不该假装自己是首要真相。
stateful 组件持有状态,需要照料:事务、locking、恢复、备份。stateless 组件更容易 scale 和替换,但它们仍然依赖"状态住在别处"。
cache 是第二份真相,有时会撒谎
冰箱上的日程表很方便,直到有人在手机日历里挪了那场会议。
cache 用新鲜度的代价买来速度。最难的 cache 问题不是"怎么放进去",而是"什么时候让它失效"。TTL、显式 invalidation、write-through、write-behind、cache-aside——这些是复杂度、新鲜度和负载之间的不同折中。
当两个操作争抢同一份状态时,race condition 出现。optimistic locking 说:"冲突很少,我们在写入时检查 version。"pessimistic locking 说:"冲突很危险,我们提前锁住。"在不同条件下,两者都对。
分布式解决规模的问题,却制造出时间、顺序和"对网络的信任"的问题。
网络不是一根线,而是不确定性的来源
单体是同一个房间里的对话。分布式系统是不同时区的人之间的通信——信有时会丢、会到两次,或者迟到。
在分布式系统里,你没法只是"调一个函数"。service 之间有网络、timeout、retry、partial failure、不同的时钟、不同版本的代码。在单体里曾是本地事务的东西,变成了一个协调协议。
CAP 定理常常被总结得很糟。实用版是:在网络分区期间,你在 consistency 和 availability 之间做选择。PACELC 补了一句:就算没有分区,你仍然在 latency 和 consistency 之间做选择。
consistency 有好几种口味
两个人看同一个 Google Doc,几乎瞬间看到同样的内容。两个人看一笔银行转账,可不能将就于"几乎"。
strong consistency 给你新鲜的真相,但付出 latency 和 availability。eventual consistency 容忍暂时的分歧,但往往 scale 得更好。causal consistency 保住因果:如果 event B 依赖 A,B 就不该在 A 之前变得可见。
saga pattern 把一个长业务事务拆成一些带补偿动作的步骤。two-phase commit 给跨资源的原子性,但在真实分布式系统里既昂贵又脆弱。架构师挑的不是"最严格"的 model,而是对这份风险"足够"的那个。
微服务修不好烂设计。它们把本地问题,变成分布式问题。
modular monolith 常常被低估
如果反正是同一个快递员在之间往返,一个组织良好的仓库,比十个小仓库更快。
单体不是骂人话。坏单体是一团肮脏依赖的乱麻。好的 modular monolith 有严格的内部边界、分开的领域、显式的 interface,以及单一的部署单元。对一个小团队,它往往是最好的起点。
当你需要独立发布、自治团队、不同的 scaling 画像、故障隔离,或不同的技术栈时,微服务有帮助。代价:网络调用、observability、分布式事务、DevOps 开销、versioning、service 间的安全。
distributed monolith 是两头最差的组合
就像住在分开的公寓里,却为了拿一把勺子就得跑去隔壁。
distributed monolith 看着像微服务,但 service 并不自治:共享数据库 schema、同步调用链、只能一起发布、改动需要去碰所有人。团队付了分布式的代价,却没换来独立性。
Strangler Fig pattern 让你能小心地迁移:包住旧系统,逐步抽出能力,沿着真实业务边界来切,而不是沿着表来切。
同步在时间上耦合系统。异步打破这种耦合,却带来延迟、重复和 ordering 的复杂度。
打电话要求双方现在都有空。信可以稍后读——但它可能丢、可能迟到,或者要求一个回复。
同步调用很容易推理:发出去,拿到答案。但如果接收方慢或不可用,发送方就受罪。通过 queue 或 pub/sub 的异步,让你能扛住故障和负载峰值,但它要求一个不同的心智模型。
queue 通常把活儿分给多个 consumer。pub/sub 把一个 event 广播给许多订阅者。Kafka、RabbitMQ、SQS、Redis Streams——不同的工具,有不同的 ordering、durability、replay 和运维模型。
exactly-once 几乎总是营销话术
如果一封信被寄了两次,像样的会计不该把工资发两遍。
实践中,你按 at-least-once delivery 加上一个幂等 consumer 来设计。一条消息可能到两次;handler 必须扛得住。dead letter queue 用来装那些在合理次数的尝试后仍处理不掉的消息。
backpressure 是"接收方跟不上了"的信号。没有它,系统会优雅地照单全收,然后从内部死掉。
"让它快点"不是一个需求。一个需求听起来是:latency、throughput、percentile,以及一个负载画像。
平均响应时间几乎总在撒谎
如果九个人一分钟内拿到了饭,第十个人等了一小时,平均值看着还能忍。第十个人不同意。
latency 是单个操作的延迟。throughput 是系统单位时间处理多少操作。percentile 展示分布:p50 是中位数,p95 意思是 95% 的请求比那个值快,p99 是尾部。
用户感受不到平均值——他们感受到的是尾部。tail latency 在"一个屏幕依赖多个后端调用"的系统里尤其要命:慢响应的概率会叠加起来。
先 profile,再优化
不带 profile 就修性能,像是看着病人鞋子的照片去给他治病。
先测量,再优化。N+1 查询、多余的 round trip、坏 index、序列化、lock contention、GC pause、冷 cache——它们看着都像"慢",但治法各不相同。
Amdahl's Law 提醒你:加速的上限,受限于你真正优化的那部分。Little's Law 帮你思考队列:同样吞吐下 latency 更高,意味着更多在制品堆在系统里。
可扩展性是"在负载和功能上生长,而不必把系统从头重建"的能力。
纵向和横向 scaling 买的是不同的东西
你可以买一辆大卡车。也可以买十辆小卡车。前者更简单,后者更灵活——但需要一个调度员。
纵向 scaling 是把一台机器变更强。简单,只要还有余量。横向 scaling 是加更多实例。更灵活,但需要一个 stateless 的应用层、负载均衡、一套共享状态策略,以及 observability。
数据库比应用更难 scale。read replica 帮的是读,不是写。sharding 拆分数据,却逼你挑一个 shard key。一个坏的 shard key,把 scaling 变成负载失衡。
scale 功能,和 scale 负载一样重要
一座城市不只靠人口增长。它靠学校、医院、道路和规则增长。
系统必须吸收的不只是更多流量,还有更多产品面。如果每个新 feature 都要去重写一个共享的 God-service,系统在组织上就不可 scale。
scaling cube 是个有用的模型:X 轴是克隆,Y 轴是按功能拆分,Z 轴是按数据或 tenant 分区。
可靠的系统不是"什么都不会坏"的系统。可靠的系统知道:坏的时候该做什么。
没有策略的 retry,是对自己的攻击
如果门没开,敲一次合理。每秒敲一千次,现在就成了门和邻居的问题。
retry 是用于瞬时故障的。但 retry 需要上限、timeout、exponential backoff 和 jitter。否则一次局部宕机,会变成一场 retry storm。
circuit breaker 暂时停掉对一个卡住的依赖的调用。bulkhead pattern 隔离资源:如果一个下游死了,它不会把你所有的 worker thread 和连接池一起拖走。
SLO 把可靠性变成一份契约
"我们尽力"不是一张火车时刻表。时刻表说清楚:什么算正常,什么算故障。
SLI 是你测量的东西:成功率、latency、新鲜度。SLO 是目标:30 天内 99.9% 的请求成功。SLA 是对客户的承诺,附带后果。
error budget 告诉你:你被允许花掉多少不可靠。如果预算烧光了,团队就停下追 feature,去修可靠性。那是"工程质量"的业务语言版本。
你没法在发布前才加上安全。它必须被建进访问模型、数据、infrastructure 和流程里。
authentication 和 authorization 是两回事
护照证明你是谁。门票证明你被允许去哪。一个替不了另一个。
authentication(认证)回答"这是谁?"。authorization(授权)回答"他被允许做什么?"。把它们搞混很危险:一个用户可以正确登录,却仍然无权读别人的发票。
RBAC 通过 role 授予权限。ABAC 考虑属性:资源 owner、tenant、region、对象状态。session-based auth 更容易撤销;JWT 更容易在不查数据库的情况下验证,但更难撤销。选择取决于威胁和生命周期。
threat modeling 是专业的偏执
好架构师像攻击者一样思考,不是因为他不信任人,而是因为他信任现实。
STRIDE 帮你寻找威胁:spoofing、tampering、repudiation、information disclosure、denial of service、elevation of privilege。defense in depth 意味着好几层防护:输入校验、authz、加密、audit log、rate limiting、最小权限。
secrets management 不是"把 key 放进 env 然后忘掉"。你得理解 rotation、access、audit、blast radius,以及泄漏时会发生什么。
看不见的东西修不了。系统必须讲出它自己的状态,而不必到代码里做考古。
monitoring 告诉你哪里出错。observability 帮你理解为什么
"check engine"灯有用,但机械师仍然需要仪表、历史和诊断工具。
observability 的三大支柱:logs、metrics、traces。structured logging 让日志可查询。metrics 展示聚合。distributed tracing 追踪一个请求穿过各 service 的路径。
correlation ID 是个小东西,却能救命:一个 request ID 流过 gateway、service、queue、worker 和下游。
对症状告警
用户不在乎 CPU 到了 92%。他们在乎的是 checkout 不工作了。
一个好告警说的是用户的痛:error rate、latency、失败的支付、过期的数据。一个坏告警说的是一个可能完全正常的原因。如果告警很吵,团队就不再信任它们。
runbook 回答"凌晨三点该做什么"。post-mortem 回答"我们怎么确保这事不再发生"。blameless;目标是改进系统,而不是找出该怪谁。
一个没被记下的架构决策,会和它作者的 context 一起消失。
ADR 胜过记忆
口头约定很好,直到第一次休假、第一次离职,或半年后的第一次争论。
一份 Architecture Decision Record 记下 context、decision、alternatives 和 consequences。ADR 不必是一部小说。一份好的 ADR 回答:我们当时在解决什么问题、我们选了什么、为什么没选备选、我们什么时候回头重审。
文档不是给审计的——它是给下一次改动的。一个新工程师不只要理解"怎么做",还要理解"为什么"。
一张图是工作工具,不是装饰
地铁图不画电线或螺栓。它画线路和换乘。这就够你不迷路了。
C4 model 给你四个层级:Context、Container、Component、Code。前三个通常就够了。当交互的顺序重要时,sequence diagram 有用。完整的 UML 很少需要;单独的几张图,需要。
living documentation 住在代码旁边,在 PR 里更新,并被 review。一份躺在被遗忘的 wiki 里的文档,很快就变成历史小说。
架构师要跟工程、产品、业务、安全和法务对话。每个听众听的是一种不同的语言。
把风险翻译成听众的语言
医生不会只对病人念拉丁文名字。他解释哪里会疼、要治多久、要避开什么。
你可以对工程师说:"我们的 payment callback 上没有幂等性。"业务需要听到的是:"如果 webhook 重试,我们可能重复扣款、或重复发货;那是财务和声誉的风险。"
stakeholder mapping 帮你看清谁在乎什么:产品要 time-to-market,安全要降低风险,财务要可预测的成本,support 要可理解的行为,工程要可维护性。
RFC 给一场争论降温
白板前的争论,常常被嗓门最大的人赢下。一份书面提案,逼着论点和嗓门分开站。
一份 RFC 描述问题、约束、选项、选定的方案、风险,以及 rollout 计划。一份好 RFC 在决策变成 policy 之前,就邀请批评。
disagree and commit 只有在一场诚实的讨论之后才管用。如果团队没被听见,那不是 commit——那是压制。
架构师往往仍是一个 individual contributor。他的权威,来自思维的清晰、信任,以及把团队变强的能力。
没有职权的影响力
指挥不演奏每一件乐器,但没有他,乐团很快就变成一群各演各曲子的天才。
架构师不该在每个决策上都变成 bottleneck。他的活儿是设定原则、解释边界、培养人,并在"出错代价高"的地方介入。
架构师的带人不是"照我做"。它是教那些问题:你见过哪些备选、你放弃了什么、你打算怎么验证风险、责任在哪里结束。
授权不等于转移 ownership
船长可以把舵交出去,但他不能说船的航向不再是他的问题。
一部分架构决策应该由团队来做。否则架构师就变成一个队列。但必须有 guardrail:原则、review、ADR、平台约束、quality gate。
当一个决策不可逆、破坏系统 invariant、制造安全风险,或影响多个团队时,架构师才介入。
架构只有放在业务目标的 context 里才有意义。否则它就是昂贵的工程美学。
非功能性需求也是业务需求
对一家店来说,"黑五时 checkout 能用"不是技术细节——是钱。
性能、可用性、安全、合规、可运维性——这些不是"技术上的想要"。它们是产品属性。架构师把它们翻译成业务影响:损失的收入、监管风险、support 成本、上线的速度。
cost of delay 帮你讨论的不只是做这件事的成本,还有等待的成本。有时需要一笔没有即时 ROI 的架构投资,因为没有它,接下来的 feature 会开始变得更贵。
build vs buy 不是面子问题
不是每家公司都该为了开灯,自己造一座发电站。
自建给你控制力和差异化。购买给你速度、并降低运维负担。vendor lock-in 是个真实的风险,但它本身不是反对购买的理由。问题是:如果 vendor 改价、改 API 或改质量,退出的代价有多大?
架构师帮产品看清 capability map:哪些能力是业务的核心,哪些更适合买。
当代码由 agent 来写时,架构师的价值移向了规格、架构思维和质量控制。
规格质量成为 bottleneck
如果施工队快了十倍,约束就不再是砌砖的速度。它变成了图纸的质量。
AI agent 加速实现,但它们不移除架构。一个没框好的任务,只是更快地变成烂代码。Specification-driven development 意味着首要的产物,是对行为、边界、invariant、测试和验收标准的规格。
在一个 AI-native 的流程里,架构师写更少的底层代码,写更多精确的散文。他 review diff、测试、架构边界,以及与规格的对齐。
agent 的输出,值得和人类 PR 一样的纪律
一个每小时写一千行的快手初级工程师,仍然需要 review。速度不会让代码正确。
你不能因为 agent 代码能编译就接受它。你需要测试、eval、import 边界、type check、安全 review。scenario evaluation 尤其重要:系统必须通过真实案例,而不只是 happy path。
一个 AI-native 的组织,赢的地方不是"人人都在 vibe-coding",而是有强规格、小迭代、自动化检查,以及架构 ownership。
架构师之所以危险,恰恰是因为他听起来很有说服力。认得这些陷阱,能省下好几年。
ivory tower 架构师
有人在山上画了一座完美的城,却从不走下来看看人们实际往哪走。
ivory tower(象牙塔)架构师在远离代码、运维和团队的地方做决策。他的图很漂亮,但实现遭殃。解药很简单:读 PR、看事故、跟工程师聊、自己走一遍改动路径。
resume-driven development 与 cargo cult
因为能让邻居刮目相看就买一辆消防车,挺怪的——如果你既没有水,也没有消防员。
resume-driven development 为简历上的一行字挑技术。cargo cult engineering 抄走别人决策的形,却没有那个原因。NIH 综合症逼你自己写,而一个成熟的外部工具本来会更好。
另一个陷阱是技术完美主义。一个从没到达用户的完美架构,输给一个能发布、能演进的"够好"的系统。
架构是一场无限游戏。技术会变,但"提对问题"的能力只会越来越强。
向系统学习,而不是向 hype 学习
厨师变强,不是靠看刀具广告,而是靠理解食材、火候、时间和味道。
新技术值得通过问题来研究:它们解决什么问题、引入什么代价、在哪里已经翻过车、有哪些备选、要什么成立它们才变得有用。
T-shaped 技能给你一个领域的深度,加上对邻居的广度。M-shaped 技能出现在一个成熟的架构师身上:好几根深柱子——数据、分布式、安全、产品、AI 工具。
公开学习加速成熟
当你用文字解释一个决策时,你思维里的缺口,会在生产环境发现它们之前先暴露出来。
写 ADR、RFC、工程笔记、post-mortem、决策的简短拆解。向比你强的架构师学习——不只是学他们选了什么,而是学他们怎么推理的。
人们会去模仿的那个架构师,通常不是懂术语最多的那个。而是那个让团队在他身边开始提出更好问题的人。
- 我能不带 ego 防御地说出一个决策的 trade-off。 - 我明白系统里 source of truth 住在哪。 - 我分得清可逆 决策和不可逆决策。 - 我能用不同的话,把架构解释给工程、产品和业务。 - 我把决策写得一年后仍然能被看懂。 - 我不把复杂度藏在"best practice"这几个字后面。
架构师是一个学会"在后果变成事故之前就看见它们"的工程师。