不仅如此,支配也变得困难,而且为新开拓职员进入代码库创造了一个糟糕的学习曲线。这些都是不可取的,许多创造自己处于这种情形的人开始阅读并理解基于做事架构(SOA)的上风。问题是 - 单体monolith变得越大,越难分解。
虽然事情是很难的,但却不会变成不可能。话虽如此,我们仍旧在感性上觉得到这是不可能,由于从一个混乱的单体直接转到SOA是不太可行的。必须有某种中介状态,这样可以更随意马虎地开始打破。
这个中介状态虽然仍旧是一个单体,但是由业务领域进行组织的,而不是原始代码库的纠缠或薄弱的状态。一旦我们达到这一阶段,对付我们的运用程序的未来再做出决定就要随意马虎得多,特殊是关于决定分解哪些做事,哪些部件该当保持在一起。

在这篇文章中,我们将先容领域驱动设计(DDD),然后再通过三个步骤,将一个缭乱的单体转化为刚刚描述的有组织的中间状态。
领域驱动设计
在开始任何重构之前,我们必须弄清楚我们运用程序的业务领域。最大略的方法是将运用程序分解成可以根据业务逻辑来阐明的组件。例如,在结算运用程序中,某些领域可能是地址验证,运输,税收和支付处理。在软件中,这种分解或构建您的代码是根据业务逻辑而进行组织的行为称为领域驱动设计(DDD)。
DDD的紧张观点之一是在一些有界高下文环境中通过子域来组织您的代码职责功能。在我们的结算运用程序的示例中,结算是一个较大的电子商务平台内的有限高下文,而运输和税收将分别是结算高下文中的子域。
上图左侧,所有逻辑都在一个进程中处理,造成相互依赖的关系。在右边,所有的职责功能都是由不具有交叉点的域分解出来的。
领域驱动设计可以帮助我们实现SOA的缘故原由在于,通过将代码分解成单个的领域,我们实际上已经创建了类似于做事的部件。
然后,如果须要,这些类似做事的部件可以被分解成紧张运用程序所哀求的相应的微做事。或者,如果您决定保留单体架构,您现在可以在易于迭代的状态下轻松理解运用程序中发生的情形。
至此,我们可以采纳下面一些步骤来组织我们的代码。
步骤1-根据领域“检疫”您的业务逻辑,以肃清相互依赖关系
“检疫”一词在这里是有目的选择的一个词语,由于它不仅意味着隔离。通过隔离,我们不但是将功能分离身分歧的文件,我们希望进一步,乃至不让它们打仗运用程序的其他部分,除非我们特殊要通过注入一个依赖关系。
在构建运用程序时,常日情形下,您的逻辑将触及许多不同的领域。让我们再考虑电子商务运用程序中的结算流程。单个结算涉及验证送货地址,打算税率,从运营商处获取运送用度,验证库存是否可用,...有很多步骤。这些完备可以在一个过程中处理所有的结算步骤,但这只会使您的代码难以掩护,险些不可能进行测试。相反,我们要完备分离所有与这些部分干系的逻辑,使它们完备不相互打仗。
保持您的运用程序逻辑按领域排序,是建立基于做事架构的第一步。
如果您拥有掌握器或实用程序文件,具有不同功能的抓取包,请先分开它们并通过职责功能进行组织,并删除每个功能的相互依赖关系。
步骤2 - 定义您的接口,并隐蔽所有其他内容
在一个单体代码库中事情的缺陷之一是新的开拓职员有一个巨大的学习曲线。当他第一次看到代码库时已经被巨大单体代码的气势压倒,犹如面对一座大山或巨石,统统逻辑都混在一个地方,你不知道谁调用谁和在哪里调用。所有的逻辑都在一个地方,你不知道从哪里开始。
作为开拓职员,我们不应该理解运用程序的其他部分的内部事情,这样才能方便快速进入代码库事情。
DDD为我们带来的上风之一是它许可我们从业务逻辑的角度考虑我们的运用程序。
每个领域中的所有逻辑都该当由一个单一的接口来表示,这个接口可以用来理解隐蔽在个中的统统功能。
以下是打算订单税率的界面示例。
// iTaxCalculator.phpinclude ValueObject\Address;include ValueObject\TaxRate;interface iTaxCalculator{/ @throws InvalidArgumentError @return bool/public function setTaxNexus(array $addresses);/ @return bool/public function setDestination(Address $address);/ @return bool/public function setShippingOrigin(Address $address);/ @return \ValueObject\TaxRate/public function getTaxRate();}
只要看这个接口,我们就可以推断出它的事情事理,乃至不用看代码。它利用目的地地址,运输来源和商店的税务关系来得到订单的税率。纵然在一个单体代码库中,这种在单个接口背后隐蔽所有细节的做法也是一个很好的习气。
步骤3-利用不可变值工具
本日许多盛行的编程措辞,包括我紧张利用的两个:PHP和JavaScript,使得很随意马虎利用关联数组或工具作为容器通报信息。毁坏我们的代码库的实质便是大量的数据流过我们各种新的组件并将它们流粘在一起。
实在,只是通报大略的普通工具就可以了,如果有某种合约能解释每个子域中的内容以及将要从中退出的内容,那将是很好的。如果这些工具是不可变的,那么也是很好的,只有在明确定义了setter时才可以显式变动这些工具。
这便是利用值工具的地方。值工具不是模型实例,它们没有ID。它们是具有定义属性的不可变信息容器,它们的状态完备取决于其值。这是一个例子:
//TaxRate.phpclass TaxRate{/ @var float/private $tax_rate;/ @var string add|base|instead/private $rate_type;public function __construct($tax_rate, $rate_type){$this->tax_rate = $tax_rate;$this->rate_type = $rate_type;}/ Get the tax rate/public function getTaxRate(){return $this->tax_rate;}/ Get tax type/public function getTaxType(){return $this->tax_type;}}
起初看起来彷佛是很乏味的,但这使我们有信心在税率上运行的系统中,我们将始终利用这个税率值工具,而不是随机的一堆blob值包装,可能有也可能没有我们须要的领域。
概要
从单体代码到SOA是一项艰巨的任务,不可能一步完成。如果您创造自己的代码库变得太大,无法快速迭代,请立即开始考试测验将其分解或破解。利用本文中描述的DDD观点将您的单体组织架构分解到明确的子域中。一旦做到这一点,再开始将代码分解为单独的微做事将变得更加随意马虎。