先讲个小故事
如果给你一间两室一厅的毛坯房,让你设计属于你自己的世界,相信你一定有非常多的想法:
- 不同的区域可以有完全不同的设计
- 家具摆放要兼顾美感和实用性
- 储物空间要满足未来不断买买买的需求
- 电源插座个数、位置要满足现在市面上不断出现的新的电子化产品
- ……
装修完毕,住进去的感觉真的是非常棒,一切都是按照自己的想法设计的,完美。
随后,新需求来了,你结婚了,这个房间新增了一位主人。TA的想法可能和你的不完全一样,TA也有很多东西要放,也有自己喜欢的生活方式,于是你的设计有一部分开始改变了原有的用途,甚至可能要重新装修。
随着人数的增加,需求也会不断变化。你有了自己的宝宝,开始买大量的婴儿用品,奶粉、纸尿裤、婴儿床等等。以现在年轻人的工作节奏,大概都会叫双方的老人过来帮忙带孩子,老人的加入也会给房子的使用增添更多新的需求。
即使你很早就想到了这些,相信你也无法抵挡新增的需求带来的冲击。你一定遇到过想找个东西怎么也找不到,翻开衣柜和床底下的储物空间,里面乱的让你无法忍受的场景。
架构混沌的表现
软件架构就像我们的房子一样,随着各种各样的需求增加,我们划分出来的各种组件都变得不再如最初设计的那么简单,变得混乱,复杂。通常可能有以下几种表现形式:
系统稳定性差
架构的腐化最初的表现大都是从用户体验侧来反应出来的,比如不断收到用户的抱怨,不断被吐槽功能无法正常使用等等。用户的这种感觉就像在一个大且杂乱的储物空间中找一个物品,不仅需要花费很多时间和体力,找到还不确定能正常使用,体验非常差。
当软件设计变的复杂时,架构设计、数据质量以及数据关系都变得复杂。甚至你会惊讶地发现前端一个请求过来,后端需要十几个服务通力配合,通过几十次的跨服务调用才能完成,这种情况下的性能和稳定性对于用户体验的影响都是致命的。
系统可扩展性差
对于开发团队而言,上面提到的接口可能成为梦魇,几乎没人敢碰,因为谁也不知道改了会不会有新的问题。
这个问题原因有很多,比如服务之间存在循环依赖,服务冗余过多数据需要同步更新,还有些服务承担了很多边界之外的职责,也有因为设计不合理导致的多个服务合在一起才能完整处理一个业务,数据一致性问题频频发生。
这些设计的复杂度对扩展性影响非常大,牵一发而动全身,最后变得谁也不敢改动,只能推倒重来。就像同样的户型,不同的设计和使用会让结果完全不同。如果储物空间设计的不合理,功能区域划分不合理,到处都堆满了东西,老是觉得空间不足,最后也懒得收拾,也没法再新增物品和家具,只能寄希望于换一个大点的房子,重新好好设计,但这往往是一厢情愿的奢望。
数据准确性差
数据是业务的核心,业务是各种数据变化迁移的逻辑组合,数据质量和一致性直接影响到业务的准确性,在分布式系统下,要做到这一点并不容易:
- 相关集成系统的数据流入质量差,脏数据多,导致流程很多无法走下去
- 业务逻辑设计复杂,导致一个操作要同时更新很多数据,在没有分布式事务等特殊手段保证时,很容易导致一个服务的数据已经更新,其他服务的数据没有更新而引起业务异常。
系统可用性差
系统集成也是出问题最多的场景之一,一个第三方集成系统出问题,经常会引起一系列的连锁反应,导致系统的关键业务无法正常工作。遇到这种问题,既冤枉又无奈,但说到底还是没有从设计上隔离其他系统对自己的影响。
各个系统面对的用户不一样,所以对系统的要求也不一样。对于要求更严格的系统,它需要保证的响应时间和并发数可能都远高于其他系统,当请求量较大时支撑系统很可能无法提供及时响应,导致核心业务系统也无法正常提供服务,这是常见的现象。另外基础设施层面的异常也是让系统可用性下降的非常直接且关键的原因之一。
怎么就混沌了呢?
上面的问题是任何一个架构师也不希望面对的,然而架构逐渐变得复杂难以维护,从长期来看是个必然的趋势,但到底是哪些原因让这个趋势不可逆转呢?
这里我们抛开人员能力的问题,虽然这个问题也不容忽视,但在讨论当前这个话题时,我们假设团队的开发人员都是尽了自己最大的努力来保证架构和代码的整洁的,然后看看还有哪些因素是导致架构逐渐变的混沌复杂的,进而可以采取一些措施延缓架构的腐化。
上下文丢失造成的低认知
可以想象,当一个系统中只有一个服务,几万行代码,任何一个开发人员都可以花一段时间理解且记住逻辑的细节,当业务需求变更,开发人员可以不进行任何调研就设计解决方案,甚至可以马上和其他开发一起讨论方案的合理性。
再试想,当业务不断增长,系统逐渐变的复杂,服务扩充到几十个甚至上百个,相信没有一个开发人员可以说的清所有的逻辑细节,甚至很难找到一个开发人员可以说清其中一个他最熟悉的服务的所有实现细节。因为当业务变得复杂,都需要多个服务配合才能完成,逻辑链条很长,而人的脑容量毕竟有限,系统不断增长的知识会逐渐超出人类所能记忆的范围。
对于一直在这个软件系统上工作的开发人员尚且如此,那么对于新加入的开发人员,可想而知,业务和系统的知识会更少,更难理解原有逻辑设计的上下文和决策原因。项目人员的更替是无法避免的,这种更替会让团队人员对于上下文知识变的越来越少,这种趋势也是不可逆的。
上下文不足,对系统的认知有限,那么做出的设计和决策很容易出现问题,也就加快了系统复杂的速度。
系统大但边界不清
设计系统的架构受制于产生这些设计的组织的沟通结构。—— 《康威定律》
随着软件系统逐渐变的复杂,服务越拆越多,但如果工作在这个系统上的开发人员还是一个团队,根据康威定律,这个系统的架构也会趋向于一个整体,而不会像预期的各个服务各司其职那样边界分明。
这就好像在自己的房子里,房子的主人可以随意的摆放自己的东西;而在一个合租的房子里,一定是有边界的,即便有公共空间也有公共空间的规则,超越边界会变得非常棘手。
因此,当一个系统逐渐变大、变得复杂,如果系统的各个组件之间没有做到很好的隔离,只能让各个组件之间的边界变得更加模糊,也就增大了组件之间的耦合度,让系统变的更加复杂,这跟负责这个系统的组织结构有很大关系。
做项目而非做产品
软件系统的开发和演进有很多驱动因素,但多数场景导致系统更加复杂的是按照特定需求开发特定功能,也就是类似做项目的方式,每次都有明确的目标,而且这个目标的方案多数也是设计好的。
做项目的方式对系统最直接的影响就是需求的一致性,多个不同的项目作用在同一个系统上,为了解决不同的问题,单纯的叠加功能,缺少对这个软件系统的整体认知和规划。而不像做产品,每一款产品都有一个愿景和核心要解决的问题,任何不符合愿景或者无法帮助解决核心问题的需求都是伪需求,不应该被添加到这个系统中。
因此,以做项目的方式推进的软件系统,随着项目不断的推进,多个不相关或没有经过深思熟虑的需求叠加到系统中,也会不断加剧软件系统的复杂度。
小结
就像开篇讲的故事一样,软件系统就像一个不断有人居住的房子一样,随着需求的不断增加,会变得复杂和混乱,这个趋势是无法避免的,这种混沌的状态会直接影响到系统的使用者和维护者,不管作为用户还是作为开发者,体验都是非常差的。但当我们意识到了上面这些能够让系统变的复杂的因素,还是可以采取一些措施,尽量避免这些因素的发生,或者反过来利用这些因素采取一些逆向的措施,让系统能够更长久的保持健康状态。