整洁架构 《业务逻辑拆分模式》

taowen · January 18, 2021 · 99 hits
Topic has been selected as the excellent topic by the admin.

说的是 “架构” 吗?

我没有选择 “架构” 这样的词。因为 “架构” 代表了太多的含义,比如页面打开速度,处理吞吐,可用率,安全防御等。把这些东西都混在一起谈,一方面显然是超过了我的能力。另外一方面,我隐约感觉到造成打开速度的本质难题与造成安全防御难以做好的本质难题,可能是不一样的东西。业务逻辑拆分是 “架构” 的含义里非常狭小的一块,也是最没有硬技术含量的一块。选择专注于 “业务逻辑拆分”,使得我们可以更深入地分析是什么本质原因造成了 “业务逻辑拆分问题”。希望能够在《Domain Driven Design》和《Clean Architecture》这样的实践经典之外,补充一些有价值的观点和视角。

业务逻辑拆分问题是啥?

我所谓的业务逻辑拆分问题是指,如果没有做好业务逻辑拆分,可能在项目晚期造成以下三种问题:

  • 做一个需求要拉很多人,代码写进来了就删不掉了
  • 基础组件没有全局一致,导致改个 RPC 重试,要把所有的代码都刨一遍
  • 线上出了问题很难定位到谁引起的,本地做不了任何有意义的测试,反馈周期特别长

更抽象的说,这三种问题是

  • Autonomy 问题:多大程度可以保持每个模块的团队自主性
  • Consistency 问题:需求中如果有一致性的要求,这些一致性多大程度上可以被保证
  • Feedback 问题:获得反馈的难度和周期,包括技术故障这样的反馈,以及 “用户是否喜欢” 这样的反馈

为何随机选择了这三种问题并归纳为业务逻辑拆分问题呢? 因为我认为以上三种问题都是由同一个不易变化的本质约束所造成。这个本质约束就是人类的感知与沟通速度是难以大幅提高的。而 Autonomy,Consistency 与 Feedback 这三类问题都是关于如何利用好人类有限的感知和沟通能力,是材料约束引起的工程优化问题。

你说的东西可以落地吗?

我不是销售像 Angular 这样的可以直接 git clone 一份的代码框架给你。我也不是在销售 DDD 战术篇那样的可模仿的行为。我想分享的是我遇到过的一些实际的(或者虚构的)故事,以及我对于这些具体案例背后根本原因的思考。我希望你能够在面对 “什么叫一个 Service” 这样的问题时候,可以有一些自己的想法,而不是别人告诉你应该如何如何。

大部分人的日常工作都是维护一个已有的项目,没有几个人能够参与到 Greenfield 项目的初始设计阶段。这也是大部分读者所懊恼的地方,“我读你的东西有什么用,我这项目就已经烂成了这个样子了,我也改不了”。我希望对于 Autonomy,Consistency 和 Feedback 中三个问题能够出一些可度量的指标。这样对于现有的项目,我们可以拿这些指标去度量这些问题有多严重。

需要提前设计吗?

需求是不可预测的,提前过度设计往往都会导致做无用功,甚至产生副作用。Big Upfront Design 已经是臭大街的东西了。在过去的失败经验里,软件开发项目到了晚期总是有总总遗憾。比如说代码改不动呀,做一个需求总是需要拉上很多的模块负责人做需求评审。当我们去审视这些晚期的症状,发现要根治需要付出非常大的代价。总是慨叹一声,如果一开始做了 xxx 就好了。但是除非做过完全一样的项目,我们又如何能在最初就预知将来会遇到什么问题呢?

有两种办法,你真的做过一摸一样的项目(或者你以为是如此),然后针对之前的痛点进行针对性预防。相比性能和高可用,业务逻辑更多变,其实不太可能照搬经验。另外一种办法就是我们时刻去反思目前是不是有问题,最好是能够量化地去监测一些指标,促使我们不断地对现有的 “业务逻辑拆分” 进行修正。这也是《Building Evolutionary Architectures》所推荐的做法。

Autonomy

我们担心这样的症状:

  • 沟通多:做新需求很难,因为需要牵涉到很多的团队,要和大量的人去沟通才能把需求落地。
  • 需求做了就删不掉:一旦需求做进去了之后,即便愿意把这个功能下线也非常困难。遗留代码日积月累。

Autonomy 的愿景就是尽量减轻上述的症状,让拆分出来的代码更独立(更具有 Autonomy)。从而新需求需要的沟通可以更少,不需要的功能也可以比较容易被干掉。 假定业务逻辑肯定要拆分,拆分成

  • 文件
  • 文件夹
  • Git 仓库

以 Autonomy 为目标的话,我们可以很容易判断 Git 仓库是主要的着手点。为了减少沟通,每个块业务和产品经理,应该有个对口的 Git 仓库。不选择文件和文件夹的主要原因是 Git 仓库一般对应了编程语言的 Package 的概念,如果是 JavaScript 的话,对应的有 package.json 文件。使用 Git 仓库比较容易依赖编译器进行依赖检查。而选择了文件或者文件夹,则很容易变成表面上拆开了,但是仍然有调用关系,实际上仍然和写在一起没有区别。

但是拆分成多个 Git 仓库不是免费的。拆分之后就有组合的问题。怎么能把多个 Git 仓库又集成回去呢? 这个装配应该拿什么描述。

我们又如何能度量在 Autonomy 这个维度,现在的问题有多严重。或者换句话说,当我们做出了一些改进,如何度量有改善呢?

Consistency

我们担心这样的症状:

  • 难以改全:改一下 RPC 重试策略,需要把所有调用 RPC 的地方都改一遍
  • 用户体验不一致:一个 APP 有 4 中不同的 date picker 组件,做的都是选日期这个事情
  • 不知道该抄谁:要做一个新界面了,发现类似的界面布局有用 css flexbox 的,有用 grid 的,也有自己拿 margin 算的
  • 找不到:可复用的组件也不是我写的,我怎么能知道需要复用你呢?

Consistency 的愿景是尽量减轻上述的症状,使得需求中的一致性可以很好地被落实到实现代码里,也通过复用减少了工作量。

需要注意的是,我选择的词汇是 Consistency 而非 Reuse。 我对这两个词的感觉是,Reuse 是从所有代码中找重复,然后努力抽取出可复用的东西。 Consistent 则是我先定义了一个标准,比如说 UI 规范,然后强制要应用到所有的页面上。如果没有应用上,那就得说明理由,引入的不一致是有意为之,还是偶然的设计失误。 Consistent 隐含了先有共识(Consensus)的含义,就是产品和开发团队达成了什么是必须一致必须复用的共识。 而 Reuse 总有开发团队一厢情愿的意味在里面,依赖了每个人做新需求的时候去主动地消除重复。

那么根据过往经验,常见的需要强制 Consistency 的场景有哪些呢?

我们如何能度量在 Consistency 这个维度,现在的问题有多严重。或者换句话说,当我们做出了一些改进,如何度量有改善呢?

Feedback

我们担心这样的症状:

  • 故障定位慢:线上出了 bug,要花很长时间才能定位出问题的代码以及对应的开发者。
  • 获得真实反馈慢:代码写完了要等苹果审核发版,错过了这个版本又要等一个月公司才会发下个版本。
  • 本地测试难:稍微有点价值的测试都不是本地可以用 JUnit 写出来的。
  • 听不见炮火:管你前线洪水滔天,我这后台模块是管不着的

Feedback 的愿景是尽量减少获得反馈的摩檫力。业务逻辑拆分为什么会影响到 Feedback 呢?这仍然是要归结为人的沟通效率问题。能用标准化的方式解决的,就可以减少沟通。能尽量减少信息传递次数的,就可以有效减少传递过程中的信息衰减。

那么针对这些常见症状,有没有什么对症的药方呢?

我们如何能度量在 Feedback 这个维度,现在的问题有多严重。或者换句话说,当我们做出了一些改进,如何度量有改善呢?

未完待续: https://github.com/taowen/modularization-examples

飞书群

「软件匠艺社区」旨在传播匠艺精神,通过分享好的「工作方式」,让帮助程序员更加快乐高效地编程!

seabornlee mark as excellent topic. 18 Jan 22:38
You need to Sign in before reply, if you don't have an account, please Sign up first.