1、简介
我们不必修改中央系统/平台来实现针对不同用例的变体行为。我们应该能够从外部插入这些行为,以自定义整个系统行为的特定部分。通过提供功能和可定制性的强大组合,这将使我们的系统更加耐用。
问题:
假设您正在构建一个供其他多个团队使用的中央系统。根据系统提供的复杂性的类型,一个或多个客户可能会要求针对其用例的原始行为的变化。我们可以轻松想象在B2B软件中出现的这种情况,其中每个客户都需要原始功能的某些自定义变体。
我们如何适应这些情况?
当然,最明显的方法是构建它!构建系统的团队还根据任何客户的要求在功能中构建自定义项。如果这些请求很少(因此团队可以轻松地为其分配时间)或过于复杂(这是唯一可以做到的团队),那么这是有道理的。但是,如果不是这种情况,原始团队将成为多个团队的瓶颈,因为它无法节省时间来处理所有传入的自定义请求。
第二种方法是要求客户团队进入代码库并自己进行更改。这消除了带宽瓶颈。客户开发人员通常可以在给定足够足够的工具/文档和指南(代码审查等)的情况下进行更改。但是随着时间的流逝,这几乎总是导致代码质量下降和所有权模糊。由于每个人都在进行更改,因此很难让任何一个团队对系统的质量负责。根据变更的性质/复杂程度,所需的监督和沟通可能会很多。同样,如果客户团队在组织外部,因此无法授予代码访问权限,则该模型实际上是不可能的。
2、系统边界是团队边界
康韦定律,团队拓扑和其他各种思想流派已经非常清楚地表明,组织的软件体系结构反映了其通信体系结构。因此,构建定制的问题可以概括为定义客户团队如何交互和影响拥有系统的团队的问题,从而影响系统的设计。
如果多个团队想要使用和扩展同一个系统,我们需要定义一个模型以在它们之间进行协调。在我看来,此模型必须至少实现两个目标:
我们应该能够独立开发软件,而不会陷入通信开销的泥潭。在此基础上排除了上面讨论的第一种方法,因为它使拥有团队处于所有变更路径上。客户必须乞求/欺凌/说服他们为他们做出改变。
我们应该能够做到这一点而不会降低代码库的质量。由此排除了上面讨论的第二种方法。如果任何人都可以(预期)对您的代码进行更改,则几乎不可能保持代码质量和卓越的操作。
因此,我们需要一种方法来定义系统边界和更改过程,以便其他人可以独立进行更改而不会影响我们的代码质量。如果我们可以允许人们“了解”系统的内部决策点并修改其用例的行为,则可以执行此操作。这就是史蒂夫·耶格(Steve Yegge)在他传奇的平台rant(您可以在这里阅读我的redux )中所说的“外部可编程性”,并且在“吃自己的Dogfood”旁边,这是构建平台的第二个基本原则。
3、外部可编程性
外部可编程性的思想是识别应用程序中我们认为应该可定制的部分,将它们变成用于可变功能的钩子,然后在外部公开这些钩子。然后,客户可以插入这些钩子并触发自定义行为或基于自定义逻辑做出决定,而不必进入系统代码库。结果,系统的行为不是完全由拥有团队实现的逻辑决定的,而是由核心逻辑和定制钩子的共同影响决定的。
从某种意义上说,这种样式是多系统级别的OCP,与内部修改方法相比,具有明显的优势。
1.客户确切知道如何挂接到自定义行为,因为系统的设计使其变得明确。它们没有进入系统内部并被错误破坏的风险。
2.这也使客户端的更改速度更快,因为他们不必学习如何在新的代码库中工作。它们从外部通过定义明确的界面进行集成,并且自定义项本身是在他们选择的技术环境中实现的。这就像能够告诉另一个微服务在哪个步骤要调用哪个API而无需修改其代码。
外部可编程性将系统的内部决策转换为开放接口,系统用户可以根据需要对其进行修改。从系统设计的角度来看,这意味着系统接口的“关闭”比您通常期望的要少得多。变成外部可定制钩子的内部部分可能将一组API转换为决策和动作的协作相互作用。我们刻意公开许多系统内部信息以进行自定义,这样我们就不必将整个系统暴露于侵入性的变化中。
如果我们看一下传统的分层体系结构样式,则控制总是从较高层流向较低层。但是,在外部可编程性创建的平台体系结构中,控制上游和下游系统(客户端系统被认为是上游,而平台系统是下游)之间的来回控制。新兴的协作系统体系结构可以更好地可视化为系统的3维网格,而不是二维堆栈。上游和下游部分仍然存在,但它们之间的界限更加流畅。
4、我们怎么去那里?
一种实现方法是将所有业务逻辑(甚至是原始业务逻辑)外部化为核心应用程序之外的工作流。因此,核心变得非常非常轻巧,所有逻辑都移入了业务流程层。这样,客户可以完全控制他们想要做什么。他们随心所欲,然后视需要调用核心系统的简单API。这提供了最终的自由和控制权的反转-客户无需修改现有内容,而是可以编写他们想要的任何内容。
这里的问题是,剩下的核心通常会被剥夺所有业务语义,而几乎根本不会成为产品!客户不仅需要构建一些现有行为的自定义,还需要一遍又一遍地构建整个功能。域边界完全破裂。无法知道在哪里执行用于处理某种订单的逻辑,因为该逻辑完全位于核心外部,并且我们无法系统地了解发生在哪里的情况。
另一种方法是实现基于回调的系统。原始系统识别出它认为控制流的哪些部分是可定制的(由于不能由客户端修改,其他部分根据定义成为核心),并通过API公开它们。这些API允许客户端定义规则,在该规则下应触发其特定的自定义以及应如何触发它们(执行对客户端系统的API调用)。
一旦在主系统中“注册”了这些自定义项,每当客户端A调用功能X时,客户端A都会按照默认行为执行所有未覆盖的点,但会执行已注册的覆盖项,以实现为客户端A定制的端到端结果客户A。
通过这种方法,针对某个问题的所有交互都会到达同一中央系统,并且我们可以从该位置确定我们想要做什么。客户端要么使用系统的默认行为,要么他们将向自定义回调注册专用钩子。在这两种情况下,都容易找到控制流,因为所有分支都发生在众所周知的分歧点上。结果,仍然存在一个多孔的技术领域边界,并且在边界内运行着许多业务逻辑,但是偶尔的定制又回到了堆栈中,直到客户端系统。我们的核心系统仍然是可以追溯所有业务逻辑的地方。
注意,在这种方法中,我们不需要区分内部团队和外部团队。所有客户团队都跨越一个多孔的系统边界进行通信,该边界定义了清晰的接口和协议,但除此之外,两个团队都独立运作。拥有系统的团队和使用该系统的团队实际上是通过允许彼此深入彼此的系统以创造业务价值来共同构建一个更大的系统。
关注苏州程序大白,持续更新技术分享。谢谢大家支持
转载:https://blog.csdn.net/weixin_46931877/article/details/117248639