1

I'm building a Use Case for creating blog posts, this Use Case has its own "DTO", which is basically a parameter object with only primitive data, as follows:

Use Case's DTO (Parameter Object):

export class CreatePostInput {
  public id: string;
  public slug: string;
  public title: string;
  public authorId: string;
  public platform: string;
  public tags: string[];
  public images: string[];
  public content: string;
  public createdAt: string;
}

inside my Use Case, I have to create an entity that is built with most of the data of the Use Case's DTO, the "problem" is that most of the entity's properties are typed with Value Object's, for example:

Post Entity

export class Post {
    private id: PostId;
    private slug: Slug;
    private title: Title;
    private authorId: AuthorId;
    private platform: Platform;
    private tags: Tag[];
    private images: Image[];
    private content: string;
    private createdAt: Date;
}

Use Case:

export class CreatePost {

  public async create(CreatePostInput: CreatePostInput): Promise<CreatePostOutput> {

    if (CreatePostInput.images.length > 0) {
      // do something...
    }

    // some more logic using typed data

    const PostEntity = new Post(CreatePostInput);
    // ...
    // return CreatePostOutput
  }

}
  1. Should the Use Case be responsible for creating the entity's Value Objects or transforming its primitive data into something else? if so, is there a problem with instantiating the Value Objects inside the Use Case?

  2. If I happen to have more entities and more Value Objects in this use case, how should i organize all this creation? builder pattern?

8
  • Is this some completely new meaning of "Use Case" that I'm not aware of?
    – Simon B
    Commented Jun 17, 2021 at 8:46
  • sorry, i do not follow? Commented Jun 17, 2021 at 12:00
  • To me, a Use Case is a text document, containing a written description of how a user would interact with the system being designed, in order to achieve a specific goal. A bit like a User Story, but much more detailed. Use Cases are written before you've written any code, as they are part of the requirement analysis phase. What you're describing here is nothing like that.
    – Simon B
    Commented Jun 17, 2021 at 12:42
  • i'm sorry, is that because i over-simplified my example? sure, it could be more complex if you will, but I'm talking about the concept of "Use Case" of Uncle Bob's book "Clean Architecture" Commented Jun 17, 2021 at 15:31
  • 1
    @SimonB he isn't mixing it up. The idea behind it is, that you have functionalities that your code implements - use cases. So if the use case is the thing that have to be implemented, why not give them a class which implements it. From my understanding Bob views a use case as normal flow and exceptional flows, stripping all the overhead of the traditional use case that has all sorts of additional information.
    – Blaž Mrak
    Commented Jun 20, 2021 at 13:45

3 Answers 3

1

First, allow me to distinguish client request from use-case input which is considered to be a boundary object. The former by nature consists of primitives (you called it "input" in your example) while the latter is only required if you choose to reflect client request as a set of value objects (at least for some client properties).

How to create an entity out of an input object (be it client request or boundary object) - that should be achieved using a factory or, for a simple entity, directly through entity's constructor. Either way, I find it more appropriate to have input's properties (those relevant to the entity) passed to the factory/constructor, rather than pass input object as a whole.

I would recommend to transform client request into input object. Should this transformation take place in UI layer (e.g. web api) or inside use-case? I personally prefer the UI layer, in order to increase isolation level of application layer, that is make it more technology-ignorant, more domain-focused.

As for massive creation of entities and values objects, it is possible to use builder pattern in some cases, especially for complex value objects (plenty of articles on web). It is also OK to use good old methods to update an entity (and of course apply necessary validations/rules inside those methods).

0

As far as I can see, the use case should just delegate the calls to other objects, that should be responsible for things. Move your creation of the object into a separate factory method - your use case should look something like this:

export class Post {
  // ...

  public static fromInput(input: CreatePostInput): Post {
    // creation logic here
  }
}

export class CreatePost {

  public async create(createPostInput: CreatePostInput): Promise<CreatePostOutput> {
    const PostEntity = Post.fromInput(createPostInput);
    // ...
    // return createPostOutput
  }
}

13
  • I see, but in that case, my Post entity is tight couple to the CreatePostInput, which I don't think is a good thing for my entity to know about, what if I have different use cases? Commented Jun 20, 2021 at 14:49
  • It isn't, because factory method is responsible for converting CreatePostInput into a Post entity. fromInput is a static method. It is the equivalent of PostFactory.fromInput()
    – Blaž Mrak
    Commented Jun 20, 2021 at 14:55
  • i see, does it belongs to the use case's layer or the entity's? because let's say the CreatePostInput has information for others Entities that I'm going to use in the same use case, should I have a factory for each entity in the use case layer? Commented Jun 20, 2021 at 16:40
  • @Thiago What you should do is create the parameters on the use case that you want to receive. You then create a factory for each entity yes. I think you have a problem with thinking about the layers. The use case is an entry point into your domain layer. There is only one layer, that is split into different domains. Basically all the factories, use cases, entities live in the same layer, but different domain (like sales, warehouse, etc).
    – Blaž Mrak
    Commented Jun 20, 2021 at 16:55
  • The DTO lives on the API layer, so the parameter of the use case should not be a DTO, but some object that you define when creating the use case (your domain layer should not know about the outside layers). You can indeed then use the same object in the API layer as a DTO, but that is incidental. I hope I'm clear enough in what I am trying to say.
    – Blaž Mrak
    Commented Jun 20, 2021 at 17:00
-1

Someone has to convert for example a string containing an id into a PostId, and s complete CreatePostInput into a PostEntity. The question is: Who does it? Obviously either the code calling your “use case”, or the use case itself, or whatever code your “use case” calls.

Your caller would likely know a CreatePostInput and can create one and fill it in, but it knows nothing about a PostInput and shouldn’t, so it cannot do the conversion. The code called by your use case would likely know a PostEntity but not a CreatePostInput, and it shouldn’t, so it cannot do the conversion either.

Either CreatePostEntity or PostEntity would have code for the conversion. I would assume that PostEntity would be at a lower level and more stable, so I would put the conversion into CreatePostInput (but that’s up to you). And it is all called by your use case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.