7

这旨在作为 RESTful API 的后续问题:我应该在哪里编写我的工作流程?问题的简短摘要(适合我的问题更好一点)将是这样的:

每个域对象都包含与特定有界上下文 (X) 中的特定对象相关联的业务逻辑。REST API 包含将查询或命令的结果转换为通过网络发送的数据(例如 JSON)的逻辑。在使用 HATEOAS 和超媒体时,我们希望使用链接对资源之间的关系进行建模。但是为了确定 REST API 应该返回哪些链接,通常需要求助于业务逻辑/规则。问题是,这些“工作流程规则”在 DDD 应用程序中属于哪里?它们可能处于仅处理工作流规则的不同有界上下文中(可能与 X 处于类似“伙伴”的关系中)还是属于 X BC?

4

3 回答 3

1

我不是 DDD 专家(仅通过 Eric Evan 书中的 100 页),但我可以告诉您在我们的电子商务目录案例中发生了什么。

最初,我们基于数据和请求用户的角色/权限在应用程序的相同有界上下文中拥有这样的业务流程,我们更改了状态转换(你说的是链接,但这实际上是它的核心,链接只是呈现的一种方式状态转换)呈现给用户。这工作正常,但是执行了很多重复的逻辑。然后我们添加了一个搜索应用程序,它是一个不同的有界上下文,因为它呈现相同的数据但在不同的集合/分组中,我们不希望它们不同步。

我们转向了 CQRS 实现,因此我们的许多业务逻辑都是“预先计算的”,因此它处于类似于“合作伙伴上下文”的状态,作为我们从写入模型到读取模型的投影的一部分。我们不专门存储链接,而是在数据上标记允许的行为。目录应用程序和搜索应用程序都使用此读取模型及其行为标志来确定要呈现给客户端的状态转换。

有些事情会在请求资源时即时发生,几乎是在序列化步骤中。我们的目标是尽可能将这些移动到预先计算的位置,但是我们无法预先计算(仅因为规模)是专门基于用户的东西。就像推荐的搜索,它使用搜索引擎中的 BI 数据返回结果。我们可以为每个用户预先计算出这个数字,但对于我们的系统来说,这个数字现在太大了。因此,我们发送主应用程序计算的资源(来自主上下文)并将其传递给另一个合作伙伴上下文以进一步完善事物。

另一个用例是一些链接只提供给经过身份验证的用户,因此对匿名用户隐藏。我们在主应用程序上下文中执行此操作,但它开始有点障碍,因为它们的存在表明请求背后的用户可以在其他应用程序中执行什么操作(例如更改密码),而我们的上下文并不是真正的权限用户可以在其他一些应用程序中执行。将资源交给他们的上下文并让他们在我们将其返回给用户之前对其进行处理会更好。我们为此使用的一个简单解决方案不是深度链接到外部上下文中的函数,而是链接到该上下文的根资源并允许它呈现状态转换。这意味着有 2 个请求,但它清理了逻辑的位置/权限。

于 2015-05-26T23:10:56.630 回答
0

工作流实际上由领域知识和仇恨基础设施组成。

如果应用程序不是用超媒体设计的,你甚至可能不需要 hatoas 部分。但是领域知识仍然存在,它们只是存在于最终用户的脑海中。您需要领域知识来验证用户的命令,以防他们忘记它。

所以对于hateoas,我将工作流实现分为两部分:领域模型和hateoas 基础设施。

领域模型告诉领域知识。
另一方面,hateoas 基础设施是 hatoas 特定的,将它们排除在域之外。

这是一个使用 springframework-hateoas 的 java 示例。我将工作流放在将域模型映射到资源的过程中。

@Component
public class OrderResourceAssembler extends ResourceAssemblerSupport<Order, OrderResource> {

    @Override
    public OrderResource toResource(Order model) {

        OrderResource resource = mapToResource(model);
        resource.add(orderResourceHref(model).withSelfRel());//add self link
        if (model.isAvailableToCancel()) { //let the model tell
            //add cancel link
            resource.add(orderResourceHref(model).withRel("cancel")); 
        }
        if (model.isAvailableToPay()) { //let the model tell
            //add payment link
            resource.add(new Link("http://www.restfriedchicken.com/online-txn/" + model.getTrackingId(), "payment")); 
        }
        //etc


        return resource;
    }
    // omitted codes
}

如果模型无法自行判断,您可以引入规范对象来完成这项工作。

于 2015-05-27T09:55:27.727 回答
0

资源所在的位置与需要编组访问它的位置相同。

假设您有一个具有三个有限上下文的更大系统:员工管理、客户吸收和服务供应。

从员工管理部门获取员工信息?决定是否显示可用于发布或删除角色的链接由员工管理层决定。

从客户接收处获得一份新提交的服务合同?决定是否显示可用于 PUT 修订或 POST 后续详细信息的链接由客户决定。当然,员工管理层负责分配处理新服务合同所需的角色,但客户接收负责了解需要哪些索赔和其他条件,并最终确保一切顺利。

同样,从服务供应中获取物理安装的软件配置文件?服务配置需要确保在提供可以放置的链接之前,一切都与其他服务/上下文(客户帐户已付清,当前用户担任网络服务角色,设备未锁定以进行维护)保持一致新的服务质量规范。

这些“工作流程”决策对于每个上下文都是不可或缺的——它们不应该被拆分到其他地方。

于 2015-06-10T01:29:52.843 回答