Search code examples
design-patternsarchitecturemicroservicesdomain-driven-designdomain-model

DDD and Microservices - data flow and structure


I'm trying to create a simple blogging platform and at the same time learn more about DDD and Microservices, so I wanted to ask you about two advises in this context:

  1. One of the business rules I assumed in my project is that only users in roles Publicist and Administrator are able to create posts, but posts created by Publicist have to be approved by Administrator first before they go public. In my understanding this is a part of a Posts.Domain, so in Post aggregate (and at the same time entity) I encapsulated changing the post's status into methods like SetPublishedStatusBy that take User (requestor) data as parameters and evaluate above rule (+ create domain events). However now I'm having some doubts whether information about requestor is really a part of the Posts.Domain. Maybe requestor should be evaulated in a different place, like Posts.API or some other service and SetPublishedStatus would be then called without parameters after it is already done?
  2. Let's stick to above context. Despite Posts microservice, I'm also developing independent Users microservice responsible for storing the users and providing some tools for Administrator to manage them. What would be then the proper data flow when a user wants to publish a new post? I'd imagine this in a following way:
  • Client sends PublishPost command with a post ID to the gateway
  • Gateway authenticates user from HTTP request (probably done via cookie with JWT)
  • Gateway sends a PublishPost command to Posts microservice
  • Posts microservice calls Users microservice to get relevant user data from DB
  • Posts microservice retreives post from DB by ID
  • All business rules are evaluated through the Posts.Domain and status is changed to Public
  • Posts microservice updates DB if everything goes fine and notifies Gateway that sends Success HTTP response

Solution

  • My thoughts ...

    For DDD, you're best served by taking guidance from the Ubiquitous Language of the domain when discussed with a domain expert.

    The term "SetPublishedStatusBy" probably wouldn't come up in that discussion.

    I think the most likely outcome of that discussion would be:

    • An Administrator and publish a post.
    • A Publicist can submit a post that an Administrator must approve before it is published.
    • An Administrator can approve a submitted post that has been Submitted by a Publicist, which will result in the post being published.
    • An Administrator can reject a submitted post.

    My Post aggregate would then end up looking something like:

    class Post
    {
        void Submit()
        {
            this.Status = Submitted;
        }
        void Publish()
        {
            this.Status = Published;
        }
        void Approve()
        {
            if (this.Status != Submitted) throw "This post is not pending approval.";
            this.Status = Published;
        }
        void Reject()
        {
            if (this.Status != Submitted) throw "This post is not pending approval.";
            this.Status = Rejected;
        }
    }
    

    When creating the post, the UI would either be calling Publish or Submit in your API, depending on the context. The API would then check that current user can perform the requested Publish or Submit.

    Two other options:

    1. Introduce an Aggregate called PostRequest that Publicists have permission to create and only create a Post when that is approved by an Administrator.
    2. If you want the rules to be more dynamic, i.e. a user just hits 'Publish', whether they are a Publicist or an Administrator and then the outcome is either a published post or a submitted post depending on the rules of the day, then you'd want an orchestration / saga / task layer in between your API and the Aggregate which can interact with User service to decide whether the the first call to the Posts service should be a "Submit" or a "Publish".