前言
近期有幸参与了一个现有系统进行全盘重构,接触的系统架构设计相关概念较多,同时也看了几本相关书籍,比如《架构整洁之道》。对此理解更深刻了些,有所收获,就在这里分享一下读书笔记(因为全是引用)吧。欢迎各位交流探讨。
一般来说,描述一个事物,要先说“是什么”,再说“为什么”,但我偏不。
为什么需要架构
我们为什么需要设计架构,一个好的软件架构的目标是什么呢?
在软件开发工作中,实现需求的目的是“提高销售”,这里的“提升销售”是个笼统概念,泛指软件系统的业务目标,对于一些不盈利的软件系统,比如公益app,“提升销售”则是指系统功能可以帮助到特定人群。而功能开发需要有成本,开发的人力成本,部署的机器成本,系统的运维成本等,而系统设计的目的是“降低成本”。
引用《架构整洁之道》书中的话:
就像我之前描述过的:软件架构的终极目标是,用最小的人力成本来满足构建和维护该系统的需求。一个软件架构的优劣,可以用它满足用户需求所需要的成本来衡量。如果该成本很低,并且在系统的整个生命周期内一直都能维持这样的低成本,那么这个系统的设计就是优良的。如果该系统的每次发布都会提升下一次变更的成本,那么这个设计就是不好的。就这么简单。
有没有发现,上面描述的大多是架构对开发时期的影响,但却没有提到运行时期呢?其实是这样的。但很多有经验的人也会不自觉将两者混在一起讨论。比如,谈系统间交互时,有可能被性能蒙骗,而做出不合理的决策:
“你发消息的时候,将价格字段放消息体里带过来给我呗?省的我再调一次接口,增加耗时啊。对了,按照我们PM的需求,要是没有库存的话,需要将价格置为0给我。”你想了想正好能拿到数据,还能让下游更低成本接入,加了!
一个月后,你接了个需求:另外一个接入方要求能接收到没有加工过的原价...
两个月后,你接了个需求:另外一个接入方要求能接收到计算最大优惠后的价格...
什么是架构
相信不少同学和我之前有一样的想法,认为架构是神秘的、高大上的,只有传说中的架构师才能够对其谈笑风生、随意拿捏。也有很多技术人以成为一名优秀的软件架构师为目标。
其实架构的定义不复杂,不过这种事最好交给专业的来:
软件架构这项工作的实质就是规划如何将系统切分成组件,并安排好组件之间的排列关系,以及组件之间互相通信的方式。而设计软件架构的目的,就是为了在工作中更好地对这些组件进行研发、部署、运行以及维护。——《架构整洁之道》
通俗点翻译一下就是:做架构设计就是将系统拆分成一块一块的,小块放在一起组成大块,并且安排一下谁和谁之间要产生联系。
这么简单?
是的,这就算架构设计了,我们平时无意中做的就是架构设计。但是架构也分好坏,我们自然是讨论怎么做一个好的架构。
觉得自己总是在维护一座屎山的举手
其实,我们深知,好的架构可以帮助我们降低成本;也深知各类设计模式、编码规范,并且希望能将其全部应用到自己在维护的系统里,好让系统变得优雅、高性能、可扩展,可配置。但却依旧过不好这一生在屎山上拉屎?
对此,我认为有两个主要原因:1. 没有时间做架构;2. 做不好架构
没有时间做架构
在当今互联网,时间就是金钱,抢占市场比什么都重要。我相信绝大部分系统都是一开始野蛮生长,为了快速发展,不断堆砌人力、加班赶工......逐渐的,系统变得臃肿混乱,难以维护,产出再也不能抹平投入。
一般来说,人都要经历重大变故才会做出彻底改变。有的人平时暴饮暴食、作息不规律,不幸真得大病了,就会开始注重养生。软件系统也一样,不到不可忍受的地步,怎么会花费时间去重构?
在之前,我对这种现状是感觉无力、沮丧的,不知何时会有所改变。这就是明显的只挑毛病不行动。其实我们是可以尽自己的努力,去影响团队,影响Leader、影响业务的。短期需求的交付效率固然重要,但是,”让软件系统长期的迭代效率提高“也是软件开发人员的工作职责,所以我们必须从公司长远利益出发与其他部门抗争,否则,当系统变得臃肿,交付效率变慢时,被质疑的还是研发团队。
做不好架构
建造一个稳固的房子,应当采用坚硬、规则的砖块;想要构建一个好的软件系统,就应该从写出易理解、整洁、可复用的代码开始。
于是你开始去学习:《阿里爹爹编码规范》、《就是你小子还不懂SOLID设计原则?》、《软件设计奥义:23种设计模式》、《学会这一套MVC框架,大厂都抢着要》。却发现还是在代码屎山上蹦跶。
是因为这些编码规范、设计原则都没用吗?当然是有用的,且还具有很大的参考价值,引用《架构整洁之道》中的话来解释:
今天的软件与过去的软件本质上仍然是一样的。都是由if语句、赋值语句以及while循环组成的。哦,你可能会抗议说我们现在有更好的编程语以及更先进的编程范式了。毕竟,我们现在都是用Java、C#、Ruby语言编写程序,并且大量采用面向对象编程方式。这没错,但是最终产生的代码仍然只是顺序结构、分支结构、循环结构的组合,这方面和20世纪60年代甚至50年代的程序是一模一样的。如果深入研究计算机编程的本质,我们就会发现这50年来,计算机编程基本没有什么大的变化。编程语言稍微进步了一点,工具的质量大大提升了,但是计算机程序的基本构造没有什么变化。
这就是秘密所在:计算机代码没有变化,软件架构的规则也就一直保持了一致。软件架构的规则其实就是排列组合代码块的规则。由于这些代码块本质上没有变化,因此排列组合它们的规则也就不会变化。
那问题出在哪了呢?
达成共识
十个985、211科班毕业的,有三、五年大厂工作经验的工程师,聚在一起协同开发一个系统,都很有可能出现屎山代码。是他们技术能力不强吗?是他们只会嘎嘎CV,不会抽象复用吗?显然都不是的,原因在于没有达成一致。
软件系统开发,是极其灵活的,完成一个稍微复杂点的功能,十个人绝逼能写出十种不一样的代码。这些个代码,单拎出来都非常简洁、优雅、高性能,但整合到同一个系统中,可能就出现坏味道了。职责分层不一致、模块划分不一致、命名规则不一致,等等这些,都会让一个系统的变更、维护成本日益增长,并伴随各种风险。
有一种特殊的情况,如果是只有一个人在维护一个系统,无论代码风格多么差,他也能快速地读懂代码,并进行高效的开发工作。因为系统内代码的风格是统一的,这才是重点。
我认为对于一个软件系统,很重要很重要的一个特性应当是“高度统一”:职责分层标准一致、模块定义标准一致、错误处理标准一致,等等。 而无规矩不成方圆,这就要求团队内需要设立各种规范,且需要团队内成员都认可,且愿意去遵守、维护。
而市面上流行的这么多设计模式、设计原则、开发框架,则可以帮助我们更容易达成这个目标——通过约束我们的行为。它们的意义更多在于,让协同开发的工程师,劲往一处使。只要团队内成员的认知都能达成一致,系统的风格高度统一,那么日常的变更迭代,不会是一件很困难的事情。哪怕是有些不合理的地方,也都能以较低的成本去优化。
架构看护
制定一个好的架构并不难,而这只是走了第一步,真正困难且重要的是怎么将架构持续维护下去。其实就是防止和定义好的架构有冲突。什么情况会出现冲突呢,比如:
- 原有架构不合理 / 不能满足业务了 / 团队有人员不认可。这时候重新进行架构设计和评审即可。注意最好留有各方案的决策记录,让后来人知道当初的设计原因,避免踩坑。
- 规范执行不到位。可以加强技术方案评审和代码CR环节。如果能有自动化工具帮忙进行检查和约束,那将是极好的。
一些建议
再分享一些在系统重构过程中,学习到的知识吧,因为学艺不精,所以也给不出系统的方法论来。
1. 明确目标
进行架构设计之前,需要明确目标,这一点看似废话,但却很重要,也是我们最容易忽略的一点。优秀的工程师都太习惯性的关注各类系统问题了,有代码洁癖的我们,总想将一切碍眼的代码统统干掉。好不容易逮到机会重构,桀桀桀...😏
但是!我们的精力是有限的,系统问题有轻重缓急,应该把精力花在刀刃上,对于不在优化目标内的问题,就不要过多关注了,甚至都不需要引起集中讨论。做够用的架构,不是做高大上的架构。
2. 懂得取舍
在架构设计过程中,你会发现很多”这样也行,那样也行“的方案,列出来所有优缺点,还是达不成一致,总是引起反复激烈的讨论。比如:
有人认为做依赖倒置很有必要,它能够让系统分层更清晰;有人认为没有必要,到这个项目黄了也不可能把MySQL换掉,那写个接口层干啥?
这时候需要架构师站出来,拍一个结论,大家遵守就好了,避免无休止的争论。为什么这样肯定可行?1. 因为充分讨论过了,所有可选方案都算”合适“;2. 决策后,就算后期发现需要更换方案,成本也是可控的,因为团队内”达成了一致“。
3. 白纸黑字
讨论的过程和结论,需要留有记录。在头脑风暴中,想法是繁杂的,需要将有价值的信息(重要的想法、决策的过程)记录下来,帮助我们进行回溯和分析。结论就不用多说了,表示大家都认可,之后要遵守的。
4. 共同参与
架构师需要让大家都参与进来,目的是提升团队成员的架构水平。做架构不是架构师的一言堂,经验再丰富的架构师也会有考虑不周的情况。团队成员架构水平的提升,可以更好地帮助系统进行架构升级演进,同时可以减轻架构师的负担。
总结
一个好的软件架构,能够降低系统的迭代的成本,长远来看是符合公司利益的。这需要我们在任何时候都特别注意,不要为了一时方便,让架构变得糟糕。
架构是实用、优美、巧妙的,每个技术人都应该花时间去了解、实践。