0

I'm refactoring a application to DDD, and so far so good but i got a doubt about some responsibility and what are the best approaches to solve it.

The application is a web app that call center agents use, with CRM features, the backend is a REST API.

The use case is as follows: The agent calls to a customer and need to collect some information / offer promotions etc. After calling the customer and talked to him, he needs to fill some information for this contact attempt, some of that information is combo box with data filled from the database, and it sends a POST with the IDs of the entities to a endpoint to register it.

So we have a endpoint contactAttempt that receive the data, customerId, agentId, some combo box info (subjectId, reasonId, extraInfo1, extraInfo2), the extra info doesn't call that, but just to simplify.

That information is deserialized to a DTO object that is passed to a application service, which consult the respective repository to check if the ids are valid and return the Entities, if the entities are not found, it throws a exception that the controller catches and answer the client with a message.

If all the entities are valid, there are some domain rules, like if is the first contact with the customer, sends a welcome e-mail, and other stuff.

My doubt is with this steps of fetching entities from the Repository, it should be like that or should i fetch it in the controller, and if all that i need is present, then i pass to the domain service with just the logic needed to apply the business rules?

  • What are the pros and cons of the mentioned approaches?
  • Is there other approaches?
  • In the context of a MVC, what is the responsibility of the Controller?
Kennedy Oliveira
  • 2,141
  • 2
  • 20
  • 25
  • Mvc is not *compatible* with DDD. – Constantin Galbenu Sep 25 '17 at 15:30
  • Also, what kind service are you refering to? Domain service? – Constantin Galbenu Sep 25 '17 at 15:32
  • About the mvc, ok, just consider a controller that will receive a request, I'm talking about where to put the logic of fetching entities from dB, controller, app service or domain service – Kennedy Oliveira Sep 25 '17 at 16:03
  • 2
    @ConstantinGalbenu Why DDD isn't compatible with DDD? This sounds weird to me... – rascio Sep 25 '17 at 16:03
  • @rascio The idea is that mvc is more fitted for the presentation layer than the domain layer. There are other architectures that work well with the DDD approach. You could however use any architecture that keeps the domain layer free of any dependencies and without any IO calls. – Constantin Galbenu Sep 25 '17 at 16:11
  • @ConstantinGalbenu if i use a controller as an application service, for orchestrating the domains would that be interesting? – Kennedy Oliveira Sep 25 '17 at 16:51
  • Yes. This would work. – Constantin Galbenu Sep 25 '17 at 17:03
  • @ConstantinGalbenu, i see, so the controller can access repositories and fail fast, if it not find the entities it need. If i need to replicate this logic to different parts of system, say you can request something via rest or via message, a facade encapsulating the behavior of the controller with DTOs would be ok? – Kennedy Oliveira Sep 25 '17 at 17:46
  • @KennedyOliveira yes but be carreful about the controller stealing logic from the domain as you seem to be very interested about it. For example, the domain should decide what a "non-existent" aggregate means and not the controller. There are cases where a command can be sent to a newly instated aggregate route (i.e. `beginSell`). – Constantin Galbenu Sep 25 '17 at 18:31
  • @ConstantinGalbenu can you elaborate more on the "the domain should decide what a "non-existent" aggregate means ", because i'm trying to don't let the controller steal the domain logic, thats my doubt, for example, in my case, the controller would just report that one of it parameters are invalid, like an ID that doesn't exist in the data store (repository), is it correct? – Kennedy Oliveira Sep 25 '17 at 19:07
  • @KennedyOliveira but then you let the controller decide that if an Aggregate was not created in the past then it should not receive that command and this is domain logic. For example, the `CreateOrder` command; this command **would** fail because, by your logic, the ID would not exist but it **should** not fail - that is how entities are created, by receiving an initial command and you *let* the controller decide what is that initial command when in fact the Aggregate should decide that. – Constantin Galbenu Sep 26 '17 at 01:38
  • So, that `if the entity was not created in the past then fail this command` should stay in the entity because is domain logic – Constantin Galbenu Sep 26 '17 at 01:41
  • @ConstantinGalbenu I don't quite understand your point, how the aggregate would know that the entity was not created in the past? Could you show a sample code? – Kennedy Oliveira Sep 26 '17 at 01:47
  • Just to speak the same language: Aggregate root is an entity so when I say Aggregate I'm refering to Aggregate root. – Constantin Galbenu Sep 26 '17 at 02:00
  • I gave you an example. Would your controller permit the `createOrder` method on an order that was not created in the past (its ID does not exist in the DB yet, right?)? – Constantin Galbenu Sep 26 '17 at 02:02
  • @ConstantinGalbenu i understand your point Reading some posts, i guess my doubt wans't clear, in my use case, the aggregate root needs 4 entities to do its job, of creating a contact attempt, some of this entities are Just options that the client chooses in the ui and send its ids to the endpoint, based on your explanation, the controller should Just pass a command to a command handler that Will fetch the data from the repository and check if exists, failing if not and calling the correct aggregate root with its needed information? – Kennedy Oliveira Sep 26 '17 at 03:08
  • @KennedyOliveira no, the aggregate root check this otherwise you break its encapsulation. – Constantin Galbenu Sep 26 '17 at 05:24
  • "then i pass to the domain service with just the logic needed to apply the business rules" - this will definitely lead to an anemic domain model – Constantin Galbenu Sep 26 '17 at 06:01
  • @ConstantinGalbenu so, I basically pass nulls to the aggregate? – Kennedy Oliveira Sep 26 '17 at 11:35
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/155327/discussion-between-constantin-galbenu-and-kennedy-oliveira). – Constantin Galbenu Sep 26 '17 at 11:43
  • @ConstantinGalbenu I disagree with DDD not being compatible with MVC. You can have your Model layer contain all your DDD layers -- domain services, aggregates, factories, entities, etc. Then, your Controller simply passes the Commands to an app service which deals with the domain. The View is obviously independent of all that. (Sorry for the late comment, just bumped into this question.) – ishegg May 22 '19 at 15:34
  • @ishegg read the 5th comment (which is mine) – Constantin Galbenu May 22 '19 at 16:02
  • @ConstantinGalbenu I did, and that's true for an incorrect implementation of MVC. A Controller shouldn't deal with a Repository at all. In that case, I agree that you're leaking domain logic. I think the Controller should just pass the Command to the app service, which deals with the aggregates and repositories (i.e. an ID not being found). (Just saw your edit, this was an answer to *your* 5th comment). So I guess you're saying MVC is "not the most appropriate" for DDD rather than "not compatible"? – ishegg May 22 '19 at 16:07

1 Answers1

1

The MVC is responsible to deserialize the HTTP request in a message for the "application layer".

So it should get from the querystring/body/headers all the values needed and pass to a service as immutable values (command). This because the application service (handler, whatever) should execute the command transactionally, and if the entities (so, the behavior) are accessed outside the application layer, you can't assure that no modification happens outside the application layer.

rascio
  • 8,968
  • 19
  • 68
  • 108