前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何用 DDD 结合 TDD 的思想『分治』复杂问题?

如何用 DDD 结合 TDD 的思想『分治』复杂问题?

作者头像
Phodal
发布2020-03-26 03:02:18
5820
发布2020-03-26 03:02:18
举报
文章被收录于专栏:phodalphodal

PS:理论上,我应该在上个月 “交付” 这篇文章,自觉得有一些论据不够强有力。但是,因为疫情的原因,我离我的书架很远(电子书不方便翻阅)。所以回到杭州,搬完家后,我便继续补充这篇文章剩下的部分。

软件开发是一项复杂的集体活动,它涉及到一系列的行为和艺术,如项目管理、流程管控、知识转化、程序员心理学(狗头)等。从个体出发时,这些都是一些无关紧要的因素。作为一个 “螺丝钉”,我们所关心的是:如何去解决问题?当然了,我们把组织视为一个个体时,我们也只关心:如何去解决问题?

本文是我在写 Chapi 过程中的一个感悟与过程的思考,因为它具有一定的代表性,所以记录一下供大家参考。

TL;DR 版:没有,建议阅读全文。

问题的模式

通用问题的模式

所以,为了解决『如何解决问题』这个问题,我们开始尝试各种各样的解决方案,如 Cynefin 框架,还有 DDD(领域驱动设计),BDD(行为驱动开发),TDD(测试驱动开发)等等。我们所做的事情是寻找合理的原则与模式,以更好地解决问题,并记录这些实践,比如此文。

在一个团队、组织中,往往会强调文档和纪律的重要性 —— 你按文档上的过程来,不会出错(出错了,也不怪你)。因为前人总结了大量的经验,记录在案,告诉了你:遇到这样的问题,你应该这么做。顺便一提,这种做法各有利弊,不好的一个方面是:缺乏灵活性;缺少解决问题的能力。

回到,我们的元问题上,如何解决『如何解决问题』这个问题?

这个时候,我们可以尝试使用第一个模式,使用 Cynefin 框架。于是乎:

  1. 简单的问题,寻找最佳实践。
  2. 繁杂的问题,寻找最好的实践。
  3. 复杂的问题,探索、尝试,如转换为繁杂问题。
  4. 混沌,尝试采取行动,转向复杂问题。
  5. 失序。

最后,我们的问题就落到了:如何将复杂问题拆解到人能处理的范围?换句话来说,作为一个资深的管理者,又著程序员、Tech Lead,我们要做的事情就是将复杂问题拆解,并交给合适的人解决。顺便一提,合适这一点很难,因为合格的领导者阶除了要解决问题,还要考虑人的成长。

软件开发中解决问题的模式

回到软件开发的问题上来,在这个一领域,我们往往面对的都是复杂问题。除非,你遇到的问题是,你有一个亿但是你不知道做点什么,你却想做点什么,这个看上去就像是一个混沌的问题。总而言之,我们要解决的都是复杂问题,于是我们可以寻找一些合适的现成模式:

  1. 使用 DDD,将复杂问题转化为繁杂问题
  2. 使用 TDD,将繁杂问题转化为简单问题
  3. 在简单问题中,使用最佳实践

嗯,听上去就是这么简单。

将复杂问题转化繁杂问题:DDD

在软件开发这个行业里,人们已经总结了大量的模式和解决问题的手法。只是呢,因为你一直在加班 + 生活,可能没有时间去了解一些潜在的解决方案。于是,我们可以尝试的第一个方案就是使用 DDD(领域驱动设计)的方式来解决复杂的问题。

于是,我们开始了旅程:

  1. 提炼问题域
  2. 找到问题域中的第一个核心子域
  3. 对第一个核心子域进行战略设计
  4. 完善统一语言
  5. 视情况重复 2 ~ 5

过程中,我们所做的是聚焦、聚焦、再聚焦,解决核心的高价值问题,再逐一突破。

将繁杂问题转化简单问题:TDD

在我们分而击之之后,我们就回到一个小的问题上面,开始我们的编码。现在,我们就开始了我们的代码之旅。在不考虑一些技术细节的问题之后,我们的过程变成了:

  1. 拆解问题(Tasking)
  2. 红-绿-重构代码
  3. 重构模型以加深理解

步骤,我们很熟悉,那么怎么拆解问题呢?这个问题,又变成了一个复杂问题,我们需要识别出大部分的场景,而后针对每一个场景编写独立的测试。换句话来说,我们要重新尝试合适的切入点,而后再逐一解决问题,然后我们会形成最佳实战。

聚焦:核心域

如果把软件开发想象成是一场军事活动,那么核心域相当于是敌方(问题)的主力。我们所要做的就是,选择一个合适的方式来击溃敌军,以少胜多是我们一直追求的,但是没有银弹。所以,我们需要把关注力放置在核心域上面。

不同核心域

组织架构往往是金字塔式的层级架构。尽管,我们已经达到了组织所认为的关键核心所在。但是事实上,在这一个系统中,每个人所关心的核心要素都是有所不同的:

  • 组织统一核心域
  • 技术部分核心域
  • 代码中的核心域
  • 个人的核心域

每个人对于统一目标的想法,会影响整个的行动。所以,组织中往往会强调个人兴趣与组织目标的一种对齐。这样一来,才能真正有效地在核心域实施行动。所以,最后就会落到人的问题上。毕竟,每个团队都需要一些强有力的个人才能保障。

适应核心域的变化

核心域并非一成不变的,它会随着业务中心的转移发生迁移。因为核心域会随着市场门槛的降低,慢慢变成通用域。

也因此,我们需要寻找新的核心域。而原先我们的支撑域,可能因为种种原因,转变为核心域。一个有意思的故事是牛仔裤的故事,原生它只是淘金者 Levi Strauss 的支撑域,核心域是淘金,随后它凑成变成了 Levi's 的核心域。不同公司、不同项目的核心域往往有可能相同的。

重新聚焦核心域

这一点,实现上是对于个人而言。尽管你是一个系统的核心部分,但是你做的事情,是不是依旧核心,这就是一个非常有意思的问题了。因为随着焦点的转移,你做的事情可能对于你来说价值不大。

拆解:驱动开发

我们已经有太多的关于驱动开发的模式:

  • 测试驱动开发
  • 行为驱动开发
  • 验收驱动开发

它们以不同的视角来尝试拆解一个复杂的问题,从一个用户故事的验收开始,考虑一个个的用户场景,再落到某一个函数的实现。随后,通过这一个个的用例完善促成整个用户故事的完整性,以实现代码的价值。

分解任务,分离关注点

标题即内容。

从无序分解到有序实施

开始的时候,你并不是一帆风顺的。尝试一个新技术、框架的时候,我们总是一点点领悟出来的,所以我们会从一个大方向正确,但是小小的走弯,直到正确的抽象出特定的模式。以 Chapi 语法解析作为示例,尝试了不同的方案之后,最后出现了一个统一的步骤和模式,如:

  1. 解析依赖
  2. 解析 data struct
  3. 解析 function name
  4. ……

这样一来,当我们遇到不同的语言时,我们都可以尝试这样的 solution。不过解决方案并不是通用的,还会遇到一些特殊的情况。

模式:持续改进

没有什么设计可以一次设计到位。举个最简单的例子,在我毕业的这 6 年里,我搬过 5 次家,住过 10 年或者是 20 年前设计的老房子,我经常看到一些设计不足:

  • 20 年前的房子,房间的插座不够,客厅大到离谱,房间很小。
  • 10 年前的房子,房间的插座够了,但是它在每个房间有个电视,还有网线。而我们用路由器和电脑(含平板)。
  • ……
  • 1 年前设计的房子,可能考虑不到在家办公的需求,所以疫情期间要买各种设备。

因为种种原因,比如家有老小,所以你可能像我一个同事一样在厨房办公,它又大又安静。

所以啊,你设计的系统能满足未来一年的变化,已经非常了不起了。我们能所做的就是预留空间、引入创新文化,以便持续改进。

完善:领域模型重构

慢慢地,当我们接入越来越多的需求时,会发现模型会发现一些变化,所以我们需要一些重构才能支撑起新的业务场景。如在 Chapi 中,我们遇到的第一个挑战是,有的语言它是基于函数的,如 Go等,而有的语言是基于类的,如 Java。

所以,我们需要对模型进行重构以及设计改进。

模式:演进的统一语言

如上。

回顾:缺失的地方

回顾,设计中缺失的地方,以便下次吸取一些经典(当然了,不要过度地预先设计):

  • 模型的适用性。在设计的过程中,我假定了不同的编程语言使用的是同一个模型,但是模型缺少边界。
  • 如何从代码中显现概念?毕竟代码上可能只有一个字段,一行注释。我所应对的一种方式是测试、查看调用方,还有知识共享的方式。

好了,这篇文章又写得太长了。

结论

事实上,你并不需要上述的驱动开发方式,你所需要的是:如何有序地解决一系列的复杂问题?

同时,你所归纳出来的这个方法,可以被快速地大规模复制。一个启发的文章是《驱动方法不能改变任何事情》,如文章所说,你需要创造出吸引人的基因(朗朗上口):

框架

它的承诺

吸引人的文化基因

TDD

你的产品将几乎没有可见的 bug,同时除了必须的代码外,不会生产过多的代码。

红 - 绿 - 重构,单元测试

BDD

你将 TDD 与功能需求关联起来

Given, When, Then

DDD

应用的架构完全反映现实业务,因此后续需求的实现将非常自然;没有变通方法,没有秘密路径,只有纯粹的、不受影响的以及独立的模型。

组成部分(Building Blocks),无歧义的语言(Unambiguous Language)和策略设计(Strategic Design)

顺带吐槽一句,从这个基因来看,DDD 有点复杂。

如果没有的话,那么使用别人总结的方法,是一种更省事的方式。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 phodal 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题的模式
    • 通用问题的模式
      • 软件开发中解决问题的模式
        • 将复杂问题转化繁杂问题:DDD
        • 将繁杂问题转化简单问题:TDD
    • 聚焦:核心域
      • 不同核心域
        • 适应核心域的变化
          • 重新聚焦核心域
          • 拆解:驱动开发
            • 分解任务,分离关注点
              • 从无序分解到有序实施
              • 模式:持续改进
                • 完善:领域模型重构
                  • 模式:演进的统一语言
                  • 回顾:缺失的地方
                  • 结论
                  相关产品与服务
                  项目管理
                  CODING 项目管理(CODING Project Management,CODING-PM)工具包含迭代管理、需求管理、任务管理、缺陷管理、文件/wiki 等功能,适用于研发团队进行项目管理或敏捷开发实践。结合敏捷研发理念,帮助您对产品进行迭代规划,让每个迭代中的需求、任务、缺陷无障碍沟通流转, 让项目开发过程风险可控,达到可持续性快速迭代。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档