如何将系统分解成模块
如何将系统分解成模块
原文:https://medium.com/hackernoon/how-to-decompose-a-system-into-modules-796bd941f036
自从我读了 DDD 的书之后,我就认为模块是我代码中的“一等公民”。找到模块边界可能是继找到服务边界之后第二重要的事情。
DDD 的模块
书中突出了最重要的部分,它们是:
选择能够讲述系统故事并包含一组连贯概念的模块。这通常会导致模块之间的低耦合,但是如果不是这样,请寻找一种方法来改变模型以理清概念,或者寻找一个被忽略的概念,它可能是以有意义的方式将元素集合在一起的模块的基础。在可以相互独立理解和推理的概念意义上寻求低耦合。细化模型,直到它根据高级领域概念进行划分,并且相应的代码也被解耦。
和
除非真正打算将代码分布在不同的服务器上,否则将实现单个概念对象的所有代码放在同一个模块中,如果不是同一个对象的话。
嗯,难怪那里写的只是“你的代码应该是松散耦合和高度内聚的”。这本书缺少的是如何定义一个模块的例子。对错误方法的描述也很棒,但是没有。
大卫·帕纳斯论分解
但是最近我偶然发现了大卫·帕纳斯的一篇论文,名为《关于将系统分解成模块的标准》。嗯,这个名字很有描述性,所以不需要详细说明它是关于什么的。有一个例子(我没有完全理解),但更重要的是,有一个错误的(也是最流行的)识别模块边界方法的例子:使用你的软件必须作为模块经历的步骤。它完全违背了面向对象的方法,是程序性思维的一个例子。
识别模块的过程化方法
这里有一个简单的例子。假设您的系统涉及在线交易处理。所以你的(程序性)思维可能是这样的:
- 好的,首先我需要验证输入数据;
- 然后我想检查我的业务专家强加的业务规则;
- 然后我想在支付系统中发送一个请求;
- 之后,我想根据我从支付系统收到的响应来保存或更新一些实体。
因此,您的模块很可能是:
- 验证器;
- 商业规则;
- 协议;
- “商业逻辑”。
那么,为什么它是程序性的呢?因为业务专家使用的概念知识遍布于整个代码库中。验证器知道什么数据是可接受的。业务规则阻止您发送不应发送的请求。业务逻辑模块接受从支付系统收到的数据,并简单地执行数据库插入或更新,因此模块名称中有引号。所以从概念上讲,这些模块只不过是一组处理输入数据并进一步传递数据的过程。这些过程的名字经常以-er "或"-或"【T1 "结尾,因为它们对输入数据做一些事情,但是必须假装成一个名词:Validator、PaymentApplicationIsExpiredChecker、PaymentRequestSender、TransactionSaver。
识别模块的面向对象方法
我们有什么概念?显然,我们有一个支付申请和支付交易。如果你跟随这个例子,你可以识别更多:它们是客户通知、重复注册、保存的用户卡等。代表这些概念的实体知道什么数据适合它们,并且知道它们可以在什么条件下操作。他们知道需要执行什么样的业务逻辑以及何时执行。嗯,其实他们是业务逻辑。我认为领域概念的这种内在独立性使得基于这种概念的模块松散耦合。 这就是帕纳斯对他的模块识别方式的看法:
相反,我们建议从一系列困难的设计决策或可能改变的设计决策开始。每个模块都被设计成对其他模块隐藏这样的决定。
这些概念本身不太可能改变。但是它们的实现是。 还有
[……]根据流程图开始将系统分解成模块几乎总是不正确的。
因为它本质上是程序性的。
这真的非常重要:模块不是你的编程语言的一项技术能力。它是对您的系统的更高层次的描述,刻在您的代码库中。再一次,OOP 被证明是业务-IT 一致性的体现。