Blog

Blog

PHODAL

分层、分步与康威定律

最近,遇到几个有意思的案例,刚好与康威定律有关。于是乎,就决定简单写一篇文章做个记录。

"设计系统的架构受制于产生这些设计的组织的沟通结构。" —— M. Conway

简单来说,就软件架构与其开发团队存在等价的关系。于是,《黑客与作家》的作者 Raymond 举了个例子:If you have four groups working on a compiler, you'll get a 4-pass compile。简单来说,如果四个团队开发一个编译器,它的编译过程将是 4 步。后来,在一个新的例子里,这示例变成了:如果 N 个人开发一个 COBOL 编译器,他将变成 N - 1 步,因为还需要有一个 PM

手动 🐶 头:每个人都需要各思其职,才能完成工作。我们需要每个人都干点活,要不三个和尚没水喝。这也就是分工困难的地方,如果项目上只剩下四项 Todo,但是有五个人需要任务。在这时候,只能找到一个新的任务,诸如于从鸡蛋里挑骨头;又或者是将这种休息方式做进系统中,以进行休息上的轮换。而如果我们有 6 个任务,而只有四个人,它就变得简单得多。所以,我们总会把 4 步可以完成的过程,变成 N - 1 步。

从另外一个方面来说,对于一定规模的团队来说,更细致的步骤,适合于协作。当然了,它也会带来更多的效率问题。从某种意义上来说,规模和效率是一个不可能的平衡。 \n

N 个人如何完成一场技术分享?

我们的第一个例子是,在一场培训中,学员分组做分享。在这一个 20 分钟的演进里,需要每个人到讲一部分。在这种情况下,我们可以看到它的 AGENDA 基本上就是 N 步,因为需要每个人参与。根据不同的情况它可能是:

  • 按维度划分,诸如于 WHY-WHAT-HOW 等等。
  • 按演进次序划分,诸如于开始有一个总览,结束有一个总结。PS:虽然存在一定的重复,但是也是可以接受的。
  • 添加额外内容,当前的议程能划分的部分太少了,因此要添加一些额外的内容。
  • ……

每个人总是能找到一个合适的位置,要不无法证明自己的价值,哪怕是再小的一部分。所以,我们总是能将步骤划分到「沟通合理」的几部分 —— 经历过一次又一次地讨论。所以,哪怕来 20 个人,在 20 分钟里,我们也能完成一场分享。

而在一个 20 人的技术分享里,让每个人都有位置,并不是那么容易。而如果有一个人找不到位置,那麻烦就来了。

20 个人:超过两个披萨

在我们只有 7 个(两个披萨)的时候,我们并不需要一个 PM,因为这点沟通并不是问题。而现在,我们有 20 个人,我们怎么办呢?

在非工作时间里,要拉上 20 个人开会,并不是一件容易的事。只需要每个人说一句话,原来的 20 分钟的分享前准备讨论,也会变成 40 分钟。特别是,当 A 说起一个合理的观点,总有差不多一半的人不同意。所以呢,我们怎么办呢,划成 2 \~ N 个小团队吧。这里的 N 取决于, 我们的分享需要几步?

而我们的分享需要几步呢?天晓得,或许只有太上老君才知道。在不同的模式之下,都不一样,有的是三步,如 WHY-HOW-WHAT?,如 5W1H 等等。所以,我们需要一个 PM,或者不止有一个。

那么一个人呢?

众所周知,一个人也是能完成一场技术分享的。而遗憾的是,一个人是无法建成长城的。所以,在一定的范围内,一个人是远比一个团队要来得有效率的。

几层架构就是几步?

我们的第二个例子是,则是软件的分层模式。

在 Web 应用的传统 Controller-Service-Repository 三层架构之下,我们把它分为了三步:

  1. 在 Controller 处理请求与返回结果 。
  2. 在 Service 做一些业务逻辑上的处理。
  3. 在 Repository 在数据上进行处理。

而在 DDD 或者整洁架构的思想之下,它变成了四层分层,它并不代表数据处理是四步。只是呢,在我们编写代码的时候,它会变成三步。好在,我们并没有按四步四个人写的方式,来构建一个 Web 应用,因为这样的效率实在是太低了。

但是,在一些非 Web 应用的分层里,它的分层与架构就存在一定的关系。最典型的案例是在编译器领域,对于 IR 的不同处理,就意味着不同的阶段需要由不同的人来处。

语言的编译器

在 Rust 的编译器文档《Overview of the Compiler》 上,可以看到 Rust 的编译器是如何编译我们的 Rust 代码的:

  • Invocation
  • Lexing and parsing
  • HIR lowering
  • MIR lowering
  • Code generation

简单来说,我们可以将 Rust 编译过程分为上面的五步。而每一步都会有 IR (中间表示,代表源程序的语义和语法结构,读者可以简单视为模型)产出,HIR (高级中间表示)、THIR、MIR 等。而早期的 Rust 编译器里是不包含 THIR (Typed High-Level Intermediate Representation)的设计的,而从理论上来说,它需要一个这样的中间表示。

而在其它语言里,如 Java 的编译,就呈现的是另外一幅景象。

可视化引擎的层次

在最近,我刚好也在研究图形引擎的渲染,不同的图形引擎在考虑「复用」时,考虑的因素并不一样。也因此,呈现出了不同的抽象与步骤:从架构上来说,分层在必要时是可合并的 —— 取决于我们是否需要这样的抽象。更少的步骤,能减少分层,提升效率,也意味着维护性的降低。

从步骤上来说,大体可分为:

  1. 处理数据。
  2. 布局计算。
  3. 渲染引擎。

从模式上来说,Excalidraw、Drawio 所代表的是图形应用,所以在层次上显得有些杂乱,都是事件驱动的架构模式;而诸如于 mxGraph、Cytoscape 则代表的是图形库,拥有对应的层次与抽象。Mermaid 则是介于两者之间 —— 因为它所有一层图形即代码的抽象层。

诸如于 Cytoscape 考虑到不同的图形布局算法,如 Darge、CoSE 等,因此在「布局计算」上构建了一层,可具备算法上的可替换性化。而像 Mermaid 因为只采用 Darge 算法,所以并不需要这么一层,但是它在数据源上采用了 DSL 的设计,所以在「处理数据」需要一层抽象。而像基于 mxGraph 构建的 Drawio,即要运行在 Web 上,还要运行在 Electron,便需要构建一层 browser 的抽象。

而应对于这种抽象可替换化,虽然多一步就意味着多一个分层?而像 Excalidraw 就不需要这种层次性,而是以功能模块进行划分,诸如于 shapes、editor。

合理的抽象层,就需要让我们添加一步。

其它

观察团队与架构间的关系是一件非常有意思的事情。

我并不擅长于技术团队的管理,只是输出一些所见与所得。


或许您还需要下面的文章:

关于我

Github: @phodal     微博:@phodal     知乎:@phodal    

微信公众号(Phodal)

围观我的Github Idea墙, 也许,你会遇到心仪的项目

QQ技术交流群: 321689806
comment

Feeds

RSS / Atom

最近文章

关于作者

Phodal Huang

Engineer, Consultant, Writer, Designer

ThoughtWorks 技术专家

工程师 / 咨询师 / 作家 / 设计学徒

开源深度爱好者

出版有《前端架构:从入门到微前端》、《自己动手设计物联网》、《全栈应用开发:精益实践》

联系我: h@phodal.com

微信公众号: 最新技术分享

标签