一个架构师十年架构感悟

Posted by 蔡超 on October 27, 2025

内容

1、“提出问题”难于“解决问题”

很多时候,公司里的一些矛盾就来自于工程师和产品经理之间,比如我们常常会说产品经理不懂技术,需求提得不够专业。但我们作为工程师也可以想一下,我们是不是应该把自己的位置再往前挪一点,去看看用户到底有哪些困惑,然后提出一个合理的需求去解决它;或者我们自己去体验一下用户的场景,然后提出一个全新的问题并解决它。

2、决定“不要什么”比“要做什么”更难

“People think focus means saying yes to the thing you’ve got to focus on. But that’s not what it means at all. It means saying no to the hundred other good ideas that there are. You have to pick carefully.I’m actually as proud of the things we haven’t done as the things I have done. Innovation is saying no to 1,000 things.”

3、非功能性需求决定架构

非功能性需求是非常重要的,甚至可以说是在你的架构设计中起到决定性因素的。架构设计完之后,少一个功能性需求,我们很容易就能看出来,未来也可以加上去,它对你的架构不会有本质上的影响。但如果我们忽略的是某一种非功能性需求,那在未来这可以说是一种灾难性的麻烦,很有可能你就需要重写了。比如你架构中的数据一致性问题无法解决,或者在设计的时候没有充分考虑性能问题,这样,所有的功能性的实现其实都没有意义。基本就是 Refactor 了,甚至不应该叫 Refactor,要叫 Recreate 或者 Rewrite,等于你要完全重写整个架构。

《面向模式的软件架构》这套书多年来一直是架构师的必读经典,书中很多架构都是从非功能性需求的角度展开去讲的,如果你想成为架构师,那就非常推荐给你去看。

4、“简单”并不容易

很多架构师都会提到保持简单,keep the simple,但很多时候我们会混淆简单和容易,简单是 simple,容易是 easy,我们是 keep it easy,而不是 keep it simple。

正如乔布斯所说,简单有时候要比复杂更难,需要你对问题、事物的研究非常地深入,你才能找到真正简单的方法。简单其实是蕴含着一种巧妙在其中的。例如我们熟知的布隆过滤器,是一个十分简单的高效重复数据过滤算法,它就非常巧妙地解决了一个问题。

回顾一下软件生命周期中各个阶段的成本消耗占比可以发现在整个软件生命周期中,成本消耗最高的并不是设计、编码这些阶段,而是维护阶段。也就是说,如果你让维护变得简单,这会是最有性价比的。

举例

我之前在一家国际公司工作过,主要是为移动运营商设计一个移动设备管理系统,运营商可以通过这个系统实现移动设备的自动注册,固件和软件的同步更新等。当时的移动设备还是摩托罗拉、爱立信之类早期智能手机的时代,打开手机会看到移动菜单或联通菜单,移动运营商就通过这些菜单跟你同步更新,也会对你的系统固件进行升级。这些工作是根据一些管理系统与移动设备之间预定义的协议来完成的,比如 SyncML。而电信专家们会根据业务场景及需求不断调整和新增这些交互协议。

刚开始设计系统的时候,我们也想着 keep it simple,就采用了一种看似简单的实现方式,团队里的软件工程师拿到电信专家设计好的协议后,把协议翻译成对应的程序语言,每一种协议对应一个程序语言。这时候每个程序语言都是一个插件,扩展也很容易,把这个语言实现的 Plugin 插到系统中,或者 Update 一个 Plugin,就可以支持一种新功能了。

这么看你可能觉得还行,反正也是插件结构,看起来也相当简单、直接,于是照着这个设计我们实现了一个系统:任何一个新业务过来,先由电信专家设计协议,再由工程师把协议转换为代码,然后将这个代码写成一个 Server 插件部署到 Server 端,这个协议就被支持了。

但很快,我们就发现事情没那么简单,这套系统的维护成本高到令人发指。为什么?原因其实可以用 Martin Fowler 的一句话来解释:

“I believe that the hardest part of software projects, the most common source of project failure, is communication with the customers and users of that software.”

沟通往往是导致软件项目失败的主要问题,的确是这样。这个系统最大的问题是在上线后的运行维护阶段,电信专家和工程师之间会不断地就新的协议修改和增加进行持续的沟通,但是他们之间的领域知识和词汇都有很大的差别,对彼此专业领域的理解有限,结果就大大影响沟通的效率。这期间系统修改每次都十分艰难,不仅协议更新上线时间慢,而且很多问题由于工程师对于电信协议理解程度有限,都要在开发完成,实际使用后才能被电信专家发现。导致了很多的交换和反复,也造成了很多客户的抱怨。所以,这个系统只是表面上看起来简单,最终整个过程演变得没那么简单。

那什么才是真正的简单?发现上面提到的这些问题,以及背后的原因是沟通后,我们开始重新思考解决的方法。后来我们和电信专家一起设计了一种协议设计语言 DSL,Domain Specific Language。DSL 是用电信专家熟悉的词汇来进行描述的,我们还提供了可视化工具,让电信专家能非常轻松容易地使用。然后这个协议会通过一个类似于编辑器的工具,将电信专家定义好的协议模型转换为内存中的 Java 结构,在线上进行运行。这样整个项目的运行和维护就变得更加简单高效了,省去了低效的交流和不准确人工转换。

5、永远不要停止编码

作为架构师,我们可能设计了一个非常 high-level 的架构,但代码是软件的最终实现形态,每一个程序员在架构落地过程中的实现,都可能会影响架构的最终呈现。另外,如果你放弃编码,最大的影响不是说你代码的技术落后了,或者是敲代码变慢了,最大的影响是你会逐渐丧失对编程的敬畏,忘记作为程序员的感受,特别是编码过程中的那些痛苦所在。你会有一些不切实际的幻想,做出一些不切实际的设计,这才是最大的问题。

6、风险优先

先思考一个问题,我们为什么要做架构设计?在我看来,架构设计最主要的功能就是转化、降低、避免整个开发过程中的风险。而架构师很大的一个职责就是在早期识别出系统可能存在的风险,并通过你的设计来转换它、去除它。

我们常说的原型方式,或者架构切片的快速迭代方式,其实也是从另一个角度在早期尽量去测试风险,去测试我们的架构能不能解决相关问题,尤其是那些非功能性需求实现的风险,这些风险往往没有功能性需求这么容易在初期被发现,但修正的代价通常要比修正功能性需求大非常多,甚至可能导致项目的失败。

这里再给大家推荐一本书《Just Enough Software Architecture(恰如其分的软件架构)》,这是最近非常流行的一本架构书籍,书中强调,架构设计的目的就是为了化解软件实现中的风险。如果你项目中所有的风险都可以通过未来重构来解决的话,那你根本就不需要进行架构设计,直接等着重构就可以了。这也是我非常赞同的观点,风险优先。

7、从“问题”开始,而不是“技术”

作为技术人员,我们非常乐意学习一些新技术,并且学了之后,我们还会非常有热情去应用这个技术。我经常会有这样的感觉,感觉在某一时刻被某个技术上身,特别想去实践它,以至于忽略当前手上的问题用这个技术来解决是不是最合适的,不知道你有没有相同的感觉。

冷静的时候,其实我们每个人都知道,要从实际出发,从需求出发,从用户的问题出发,而不要从技术出发,但在实际工作中,我们却常常不自觉地忽略这一点。就像手里有了一把锤子,看到什么都是钉子。

8、过度繁忙使你落后

在这个高速发展的时代,如果因为过度忙碌,导致你没有时间学习和更新自己的知识,那必然会让你落后。

我们在一个领域工作了一段时间,比方说三五年之后,会对这个领域的业务越来越熟悉,解决问题越来越顺手,但相应的,能学到的知识和技能也就会越来越少。有些人会说这是进入了舒适区,要逃离舒适区,换一个领域,我倒觉得不必如此。本质上来说,换一个领域其实是促进你进一步学习一些新的知识,你在原来的领域也可以这么做。你可以有意识地摆脱那种麻木,挤出时间来重新学习,然后即使做的是相同的事情,也可以用不同的方式更好更高效地完成它。你会发现,即使在同一个领域,你也完全可以做和别人不一样的事情。

所以,每个技术人员都要保证充足的学习时间,否则很容易成为井底之蛙。