最近逐渐开始写一些简单且稍微务虚的文章。原因有挺多,其一是,自己的工作内容和企业的内部情况绑定的更加深入了,许多信息如果要在互联网上分享,需要考虑在很多地方做加工;其二是,过分拘泥于非常深度的技术挖掘,可能只能涉及到一些特定的领域,不利于技术博客的持续运营,并且从读者的视角,形式简单但内容富有思考的干货,才是真正有价值的产出。
因此,今天这篇文章,就从笔者自己的角度,谈一下代码架构治理的四层境界,把读者自己最深层的思考内容给解剖出来。希望这篇文章能够帮助到一些在代码架构治理工作方面,感受到痛点的同行们,让大家可以通过文章提到的一些思维工具,去解决实际工作中代码架构治理方面的问题。
这四层境界分别是:
- 套设计模式
- 自上而下需求拆解
- 自底向上模块抽象
- 网状概念聚类分层
第一层境界是套设计模式。犹记得刚开始接触代码工程架构的时候,我们都被灌输了很多设计模式相关的概念,小到工厂、责任链,大到DDD、BDD。这些看起来很高大上的名字,它们的实质是什么?是工具,是最为基础的代码架构思维工具。一个工具要有用武之地,必然有其背后合适的业务场景。理论上来讲,大多数的代码架构问题,通过套设计模式,遵循基本的重构原则,都是可以解决的。
设计模式不能解决的问题是什么呢?答案是:未知的领域。通俗地理解,设计模式就是前人已有的经验,在某类业务或者技术场景之下,沉淀出来的一套代码范式。但面对未知的领域,以前的设计模式是否可以起作用,哪些设计模式最为适合,都不是能够直接无脑确定的。未知的领域背后,本质上是未知的概念联系,如果直接套用某类设计模式,那么将来如果引入新的需求场景,既往的设计模式不适用,就会出现重构成本。
现今有很多技术同行的简历或者PPT上,都可能写通过DDD、BDD的思想,解决了某类技术问题。从笔者的角度认为,不同领域的概念模型其实是五花八门的,如果真的某类场景用了经典方法解决,要么是这类场景已经被研究透了,架构层面缺乏创新潜质,要么是自身实力不足,对技术缺乏独立思考,没有能力去灵活调配代码的架构,只能通过既有的思维去生搬硬套。如果有意识在简历或PPT重突出这类信息,这样的人才,假使面对未知的业务或技术领域,一定很难有能力去cover住代码架构。套设计模式的是一类人,如今,套GPT的也是这一类人。
第二层境界是自上而下需求拆解。需求拆解可以解决未知领域代码建模的问题,弥补纯设计模式的不足。做代码架构,本身即是对某类业务或技术场景的建模,当我们需要解决某些具体的问题时,一个最简便的办法是对需求本身做拆解,比如用金字塔模型,把大的问题划分为小的问题,然后分而治之。这样的一个好处是,我们很容易去构建出模块化、低耦合的代码架构模型,因为每一个需求的子问题都可以用单独的一套代码去解决。并且,在协同开发场景下,还能够保证各司其职,互不干扰,形成一套很完善的开发体系。
自上而下需求拆解,解决不了的问题是什么?答案是:认知的一致性。在先前的一篇文章里,通过一个自动化框架的例子就说明了这个道理,需求拆解是自上而下的,但技术实现是自底向上的。为什么要自底向上,其本质诉求就是在工程初始化环节,把最基础的认知概念给统一抽象起来,认知的一致性越多,代码需要受迫维护的内容就会越少。如果在工程代码开发方面,无脑通过需求拆解的方式构建不同的模块,那么必然会出现很多具备重复意义的代码。久而久之,就会形成技术债。
因此,要解决这个问题,我们需要踏入第三层境界,自底向上模块抽象。当需求自上而下拆解完成后,还有一个重要步骤是,把最底层需求涉及的共性概念给抽象出来,构建成一套公用基架。这套基架不仅是提升了代码的易维护性,而且更重要的,是决定了这个领域的基本概念认知。以游戏开发为例子,一个客户端研发团队,除了业务Gameplay研发的成员之外,一定还有部分成员会专攻游戏引擎的研发,去做好整块客户端代码的基架。有了这个基架,就不容易出现你实现一套,我实现一套的问题,从而让整个工程架构的底层逻辑都通顺起来。
对于一些小的研发团队,或者是个人开发者,在工程代码的呈现方面,很容易出现踏入第二层境界,但无法踏入第三层境界的情况,导致工程能力不能长久迭代。解决这个问题的方法就是,下手慢一拍。如果是在时间紧张的情况下,需要注意在写完demo期代码之后,顺便构思好代码重构的路径,留有后手。做出10分,交付7分,这样就能够保证工作产出的弹性。
当然,自底向上模块抽象,也有解决不了的问题,那就是概念分层。如果一味陷入共性抽象,一味通过【加一层】的方法解决技术问题,就容易出现层次冗余,难以重构的情况。一套抽象下来,看起来代码可读性不错,但整个工程的内在结构太复杂,就会导致可读性不高。虽然每块代码的责任是分明了,但不同模块之间的关系很不清晰。A调了B,B调了C,C又调了A,从而导致代码之间出现循环依赖的风险。然后,哪天项目需要升级了,要么就是弄个V2,要么还往原来的层次上加,这样就会降低整个项目的可迁移可复用能力。
要解决这个问题,我们就需要踏入第四层境界,网状概念聚类分层。我们需要了解一个本质是,不论是那种业务或技术领域,底层概念之间的关系,都是网状结构的。通过纯代码的方式,不可能模拟网状结构的概念,但是我们可以通过聚类分层的方式,把一些同质的概念放到相同的层次,并且同时保证层次的数量尽量少,从而在尽可能简明工程架构的同时,达到需求预期的效果。
那么,如何去把聚类分层这个事情给做好呢?一个重要的关键点就是,根据不同的视角,来划分不同的层次。举个例子,一个后端服务,从服务框架的视角,可以分出来handler/service/dal/util几个层次;从业务视角,可以在service内部,分出来app/core/3rd等几个层次(当然,微服务的话,可以把3rd提到外面,app跟core都不要)。基本上一个后端项目,代码最多3~4层就可以解决问题,如果还存在需要加一层的情况,就从更高的服务架构维度去解决,而不是再拘泥于已有的代码项目。
分清每块代码的责任很重要,但如何构建每块代码的层次梯度也很重要。解决了低耦合问题,也要解决高内聚问题,这样才能让整个代码的架构变得游刃有余。