领域驱动设计将产研从阅读理解中解放出来

软件开发的真理?

我最早接触编程是小时候玩的 GBasic 和 Logo,正式学习是大一的 C 语言课,这都是典型的面向过程语言。对于我那个年代计算机专业的人来说,一般都是从面相过程的语言起步。因为他符合我们做事的方式,容易理解。等工作后,如果你做的是企业级开发,那么多半用的是 Java,少半用的是 C#(当然,如今的开发语言要丰富得多),这就都是面向对象语言了。于是就诞生了一个经典的笑话,用面向对象的语言编写面相过程的代码。

在我工作一年多的时候,突然有一天我顿悟了软件开发的真理,发现软件开发的过程其实就是处理数据的过程,无外乎就是对数据增删改查的排列组合而已。只要我们弄清楚业务中各类数据的关系,以及流转规则,就可以很好地完成软件的开发。我相信有很多很多开发人员都会有这样的经历,甚至从此以后以数据驱动的开发模式就完全扎根于他的心中了,而且根深蒂固。

至此,一个广为使用的开发模式,既用面向对象语言编写过程式的代码来操作数据以实现需求的开发模式,诞生了,而它在代码上的表现形式一般为传统三层架构模式。

该模式的使用方法为:

  1. 分析需求,明确都有什么数据,以及数据之间的关系,以及工作流程
  2. 建表,逐个字段与需求对应,而工作流程一般体现为各种状态字段。
  3. 绘制流程图,将数据表与流程图相对应(此步骤也可在建表之前)
  4. 复制一份以前的项目,删掉原有代码,开始开发
    • 对应每张数据表,都建一个数据类,里面只有对应表字段的属性 getter、setter 方法
    • 对应每个数据类,都建一个 dao 类,用来做数据库的增删改查
    • 对应每个 dao 类,都建一个 service 类,写业务逻辑,主要就是调用 dao 的增删改查
    • 对应每个 service 类,都建一个 controller 类,用来写对外接口

至此,项目开发完毕。

为了简洁,以上过程写得有些极端,但是我相信,有很多很多开发人员,就是用这种方法,做了很多很多项目,而且做得还不错。

我的需求很简单

但是随着业务复杂度的提高,我们时常会遇到这样的情况,产品提出一个需求变更,他觉得这是一个很简单的改动,应该很快就能上线,从逻辑来说也确实是个简单的改动,可是开发的时候就是反反复复出问题,怎么也改不好。什么原因呢,牵一发而动全身嘛。一个点的改动牵连了很多其他功能,稍有不慎就会发生关联的影响。

可为什么产品预见不到这种尴尬的局面呢,为什么产品确实认为是个简单的改动呢?因为产品与技术的模型不匹配,在产品模型中,这就是一个简单的改动,但是在技术模型中,这却是一个关联了多个功能的操作,只不过在以前的需求下,从结果来看是满足业务需求的。

这是一个很常见的,但又很严重的问题,因为它直接导致项目无法按照产品的节奏迭代,这对于很多项目,尤其是互联网项目,是致命的。因为业务的压力就在那里,做不完就会带来极大的损失,而这又进一步导致产研增加很多临时性的补救措施,解决短期问题,却留下长期隐患。而解决这些隐患的常见方式,就是换一拨人重构。

我们如今在技术及质量管理上有很多方法来避免这种情况的发生,而我见过的最好的方法就是“领域驱动设计”。我之前简单介绍过领域驱动设计,它是软件核心复杂性应对之道 。上面所说的开发方式,算是一种数据驱动的方式。但真实世界除了数据,还有很多事件、规则等是无法用一般的关系型数据来表达的。而领域驱动设计,则能更好地描述真实世界,真正发挥了面向对象编程的优势,让程序与需求形成更严谨的对应关系。

当然,这一切也比数据驱动要复杂得多,我看了很多书,也在真实项目做了尝试,但到目前为止,并没有一个可以长期领域驱动的项目,我也没法系统化体系化地来介绍这门学问。庆幸的是,去年发现了张逸老师的一门课程,讲领域驱动设计的战略设计,让我受益匪浅,解开了我很多困惑。这门课程是国内一线的软件开发设计者,学习实践领域驱动设计后,归纳终结出的自己的知识体系。

因为我自己也会写技术文章,所以我知道,把学到的知识归纳整理成自己的知识体系,这是很难的,张老师让我着实佩服。课程一开始并没有急于介绍具体的设计方法,而是拿出很大篇幅来介绍软件的复杂度,这一点我表示非常赞同,因为复杂度才是问题的根源。程序员在工作学习中,很常见的一个问题就是陷于技术细节,而对目标和问题置若罔闻。

比如,我以前介绍过另外一门学问,REST 架构风格,很多人学习时就只关注了 RESTful 接口的设计与实现,而忽略了 REST 对整个互联网软件架构的深远影响与期望。在学习领域驱动设计的过程中,复杂度就是我们要解决的根本问题,更进一步的话,还可以加上时间,领域驱动设计是一个可以长期解决软件复杂度问题的方案。

软件复杂度

张老师在介绍软件的复杂度时,将复杂度分为技术复杂度和业务复杂度,这个划分本身,算不上什么独创性的见解,但是在软件设计中,只要你有了这个分类的概念,就能帮助你思考具体的问题,这个分类概念就是很多开发者所缺少的。进而他再讲形成复杂度的原因,包括:

  • 理解力
    • 规模(问题域过于庞大而复杂,使得从问题域中寻求解决方案的挑战增加)
    • 结构(开发人员将业务逻辑的复杂度与技术实现的复杂度混淆在一起)
  • 预测能力
    • 变化(随着需求的增长和变化,无法控制业务复杂度和技术复杂度)

这些分类概念,都给开发者提供了很好的分析问题的思路。

img

本图依据课程内容绘制

把问题分析明白了,才可能给出好的解决方案。对应前面的分类,将技术复杂度与业务复杂度区分对待,并让两类解决方案形成正交的关系,这样就能避免两类复杂度相互混淆产生更加复杂的影响。至于具体的解决方案,就是领域驱动设计中经常提到的通用语言、限界上下文、六边形架构等概念了。

img

本图依据课程内容绘制

摆脱阅读理解

我最近参加的一场需求评审,逻辑有些复杂,而产品文档并不是很清晰,让我产生了一种,产品经理带着研发做阅读理解的错觉,整个评审下来大家都觉得有些力不从心。我后来仔细分析了整个需求,逻辑虽然有些繁杂,但如果建立好对应的模型,其实产研双方都更容易理解。而建立模型的过程,就是分解软件复杂度的第一步。当然,这也需要花费更多的时间。

我这里说的模型就是领域模型,它一方面为研发提供了规则、逻辑、模型,同时也为产品提供了很好的需求表达形式,最重要的是产研可以通过领域模型达成统一。在未来长期的需求迭代中,都可以基于领域模型达成的共识,让整个产研团队高效地生产出高质量的成果。这也是我学习领域驱动设计过程中,想达到的终极目标。我之前谈论过的敏捷技术指南,也都是为了实现这个目标。

想达到这一目标,领域驱动设计是很好的工具,但它并不简单。最关键的是,它不是一个人的工具,而是团队的工具,还是整个产研团队的工具。所以,在未来的工作中,我也会有意识地向团队输出领域驱动设计的相关思想,希望整个团队都能充分理解如何站在公司的角度上,去保持一个项目长期高质高效的迭代。同时,我也会不定期分享我的学习实践心得。

最后再次向大家推荐张逸老师的领域驱动设计课,希望对大家有所帮助。

img

img

img

陈浩 wechat
欢迎扫描上面二维码,关注我的公众号“就浩这口”
感谢您的支持,我会创作更多更好的内容