做了快十年程序员,见过不少架构------有的简洁到让人觉得「这也算架构?」,有的精巧到让人读不懂。好的架构不是设计出来的,是在每个阶段做了正确的决策才长出来的。
四阶段框架
我把一个项目的演进拆成四个阶段:能跑 → 跑得准 → 跑得稳 → 跑得快。
它们是递进的时间线,每进入一个新阶段,上一个阶段的能力还得保持。但每个阶段的核心矛盾不同,你要盯住的东西也不同。
| 阶段 | 核心问题 | 架构焦点 |
|---|---|---|
| 能跑 | 这东西能不能 work? | 简单优先,砍掉一切不必要的 |
| 跑得准 | 结果对吗? | 业务驱动,用数据验证 |
| 跑得稳 | 炸了怎么办? | 引入复杂度:容错、监控、灰度 |
| 跑得快 | 扛得住吗? | 只在瓶颈处动手优化 |
这个框架有一个大前提:项目不确定性高。你不知道要做什么、不知道能不能做成、不知道用户会不会用。这时候阶段演进是攒认知的过程,一步到位等于盲人摸象。
但如果需求很明确------业务方已经把需求拆到字段级别,数据量、并发量都有预估------你还按「能跑」来,就是浪费大家时间。确定性高的项目,前期设计要重,该想清楚的要想清楚,该预留的扩展点要预留好。区别不在于原则本身,在于每条原则的权重:
| 0→1 探索型 | 确定性交付型 | |
|---|---|---|
| 简单优先 | ★★★ 死守,复杂度是负债 | ★★ 保持节省,但要预留扩展点 |
| 业务驱动 | ★★★ 业务反馈验证方向 | ★★★ 同样重要,但业务目标是已知的 |
| 先跑通再优化 | ★★★ 先攒认知 | ★ 需求已经清楚,设计时就可以优化 |
核心不变:做当下信息量下最合理的决策。信息少的时候不瞎猜,信息多的时候不偷懒。
能跑:先证明想法不成立
「能跑」阶段最容易犯的错是想太多。表结构还没定,就开始琢磨分库分表;流量还没来,就把消息队列、微服务、K8s 全套安排上。
这个阶段只有一个目标:用最小的成本证明这个方向值得继续。
怎么做?三个字:砍、硬、短。
- 砍:砍功能。一个 MVP 需要的功能比你想象中少得多。用户管理?先用 admin 账号顶着。权限?先不做。通知?先不做。
- 硬:硬编码可以,写死配置可以。别在「能跑」阶段追求灵活性,灵活性是给「跑得稳」阶段准备的。
- 短:代码短,文件少,依赖轻。一个能跑的原型,1000 行代码能搞定的事不要搞成 10 个微服务。
「简单优先」不是偷懒------每多引入一个组件,就多一个可能出错的点,就多一份调试时的茫然。简单意味着更少意外。案例:早年做过一个数据同步工具,技术选型时在 Spark Streaming 和 Flink 之间纠结了很久。最后两个都没用------用 shell + cron 先跑了一周,发现瓶颈在源端 API 限流,跟计算引擎没关系。如果直接上流处理框架,这个真相要等到上线后才发现,而那时已经搭进去一整套基础设施。
退出信号:当你开始问「这样写对不对?」而不是「能不能跑?」的时候,该进入下一阶段了。
跑得准:别自己骗自己
「能跑」证明了能做出来。「跑得准」要证明的是做出来的东西是对的。
这个阶段技术人最容易掉进的坑:用技术指标替代业务指标。QPS 上去了,延迟下来了,觉得自己干得不错。但业务侧说「数据对不上」。
「跑得准」的核心是把业务结果当成唯一的验证标准。不是单元测试过了就算对,不是代码 review 过了就算对------是业务方看了结果点头才算对。
具体怎么做:
- 端到端对账:不是中间环节的日志对得上,是源端和终端的数对得上。中间环节再多都对,两头差一条就是不准。
- 业务方验收:不要自己定了正确标准然后自己做裁判,让业务方来验收。
- 别迷信测试:测试覆盖的是你知道的逻辑,线上出问题往往是你不知道的逻辑。测试只是兜底,不是验证。
退出信号:业务方不再来找你对账了。
跑得稳:该花的复杂度要花
到了这个阶段,系统已经在跑了、结果也对了。但你还睡不踏实。
这才是真正开始谈架构的阶段。前面的「能跑」和「跑得准」是在攒认知------你知道了系统的瓶颈在哪、业务的核心链路是什么、什么数据不能丢、什么延迟不能超。
「跑得稳」的核心矛盾是:你要引入复杂度保可靠性,但又不能把系统搞死。
几个必须花的复杂度:
容错。任何操作都要想「失败了怎么办」。重试?回滚?降级?不是每个环节都要三样都做,但每个环节至少要有一个兜底路径。
可观测。日志、指标、告警,这三样是「跑得稳」的基础建设。没有可观测性,系统炸了你都不知道炸在哪。
灰度/金丝雀。敢直接全量切,说明你对系统还不够了解。灰度发布不是胆小,是给自己留退路。
但也有不能花的复杂度:不要为了「万一」做架构。一个日活几百的内部系统,上微服务、分库分表、多活容灾------这些复杂度花出去,带来的不是可靠性,是维护负担。
案例:一个数据入湖链路,单机跑没问题,但数据量上来后就怕挂。方案是加 checkpoint 机制------挂了能从断点续跑,不用从头来。多写了几十行代码,换来的是凌晨三点不用爬起来手动重跑。
退出信号:你能安心睡觉了。
跑得快:别提前优化
性能优化有一条铁律:只在瓶颈处动手。
「提前优化」是人性的问题------你知道了某个地方可以更快,手就痒。你刚写完一段代码,脑子里已经在想「这个循环能不能少遍历一次」。忍住。
「跑得快」的正确姿势:
- 先 profiling,再动手。你不知道瓶颈在哪之前,所有的优化都是在正确的地方浪费时间。用火焰图,用慢查询日志,用 metrics------找到真正的热点。
- 优化有成本 。代码更快的代价往往是更难读。一个
for循环变成三个map/filter链式调用,快了 5% 但三个月后没人看得懂。这个买卖做不做,看 5% 在那个场景下值不值。 - 基础设施优先。很多性能问题不靠改代码解决------加个缓存、加个索引、调个连接池参数------效果比抠代码逻辑大得多。
案例:一个数据查询接口慢,第一反应是优化 SQL,折腾了半天。后来发现瓶颈不在 SQL,在每次查询都要从 S3 拉文件。加了本地缓存,延迟从秒级降到毫秒级。
退出信号:没人再抱怨慢了。
原则之间的关系
简单优先、业务驱动、先跑通再优化------这三条原则贯穿四阶段,但不是每条都平等地作用于每个阶段。
| 能跑 | 跑得准 | 跑得稳 | 跑得快 | |
|---|---|---|---|---|
| 简单优先 | ★★★ 死守 | ★★ 保持 | ★ 让位于可靠性 | ★★ 克制优化欲 |
| 业务驱动 | ★ 先跑再说 | ★★★ 唯一标准 | ★★ 业务链路优先 | ★★ 优化业务热点 |
| 先跑通再优化 | ★★★ 就是 MVP | --- | ★ 稳定了再谈性能 | ★★★ 但别提前 |
三条原则在你心里不是一个固定权重。不同阶段的优先级不一样,这才是「权衡」的真正含义。
收尾
架构能力不是你画了多少张图、用了多少种中间件决定的。是你在正确的时间做了正确的退让决定的。
「能跑」时你退让了完美,「跑得准」时你退让了技术自负,「跑得稳」时你退让了简单,「跑得快」时你退让了优化欲。
每个阶段都有一个你死守的东西,和一个你主动放下的东西。知道什么时候该守什么、放什么,比知道多少种设计模式都重要。
架构不是一次性的决策,是持续四阶段的循环。下一个需求来了,又是从「能跑」开始。