2

We have divided our app into vertical slices, by feature, each of which contains domain/data/application/ui layers which has increased cohesion. However there is still some coupling because feature B might use value objects (or things associated with the value objects) from other features. For the sake of the example let's say that we have an app that allows user to book restaurants.

We could have features / vertical slices / subdomains like:

  • manage_account
  • manage_restaurant
  • restaurant_catalog
  • book_restaurant

To me it is fine if there is some dependencies like the Account entity might be defined in the manage_account feature, it's pretty obvious that it's going to be found there. However there are some value objects that might be found in multiple features and do not inherently spawn from any feature. For example OpeningHours, which might have all sorts of things associated with it: localization, ui stuff, etc. Another example would be geography things like Position, repositories, ui map stuff.

It is not immediately clear to me where the DDD community stands on that. Because those are not really features but they are part of the domain. I do not think the concept of a shared kernel / shared folder where we put every other thing is really a good solution in this instance, neither would be duplication. I'd prefer individual modules for those things that are not features and won't change depending on the context.

My question is: would modules for those tiny domains fit better in infrastructure, features or something else ? It seems that neither of those two is a good place to put those. I undertand this might be a judgment call, I'm more interested in going by the book though.

4
  • What's the problem with encapsulating the domain into a library and making this a dependency of any feature?
    – Laiv
    Commented Sep 22, 2022 at 9:37
  • @Laiv That's the idea, I'm just not sure where to put that library. Making choices is hard.
    – Ced
    Commented Sep 22, 2022 at 15:31
  • The library is everywhere. It's reusable code. Domain has no concrete infrastructure adapters. Whoever depends on this library will have to implement them. The implementation of the adapters can be a written in a different library. Basically, you have an "api-lib" and an "api-imp-lib" that can be mixed for code reuse, or not, in the same "feature". Or inject only "api-lib" and leave the feature to craft all the required adapters. The main problem is slicing the domain to hide specific knowledge among features. That might lead you to dependency hell. Overall if libs are versioned.
    – Laiv
    Commented Sep 22, 2022 at 15:48
  • Another option is making your domain the "sum" of all the features. Each feature implements its own domain (DDD) and they correlate domains only by references, never by concrete elements or components. Feature A points to a domain element of Feature B, but knows nothing about B. When it needs to know something, it sends a request to B and uses only what's necessary. If A doesn't need to know the whole of B's genome to get his name. Right?
    – Laiv
    Commented Sep 22, 2022 at 16:01

2 Answers 2

2

First, I'm sorry to say, there's no such thing as "going by the book". Everything is up to interpretation, which in DDD's case has unfortunately a very wide deviation. Even Eric Evans seem to have revised some stuff since the book. Which is fine actually, we all learn continuously.

TLDR: Using other "features" is fine, influencing the other feature back is not fine.

For example you are using a logging library. That is using something that you obviously will not be changing (I hope). Using an "opening hours" feature is also fine though for the same reason.

Not ok is when you have a "manage_account" slice, sometimes people do "accounts" (plural), or similar. It's because as soon as you, as another slice have some need for some data in an account, you'll influence the account to have that data. You'll have physical dependency on "manage_account", but "manage_account" will also have a semantic dependency on your module.

In other words, if somebody would look at "manage_account" in itself, there would be questions like: Why is this here? It is never used! It's there because someone else uses it. For something. Or does it?

It causes a circular dependency of sorts. Which is bad for understanding and maintaining the module.

Not every feature needs to be persistent. So yes, "OpeningHours" could be a "feature". I would call it more of a "library" thing actually, but I don't think the categorization matters that much. :)

In short:

  1. Storing stuff is not a feature. It is at most a technical part of a feature.
  2. Using features is fine. As long as rule #1 is not violated, i.e. it's not used for storing data, instead you're genuinely using separately defined, meaningful (in business-sense) functions.
5
  • Thank you however you say that having "manage_account" is not fine. It is my understanding that it's better to divide the application in slices that have business meaning, or in a broader sense have a close aggregate of use cases in that slice. That is what is being done here, ence why there is a feature named "manage_account" which could be using the file_upload infrastructure library for instance. Am I understanding you clearly when you say that it's better to have an overall account feature in that case ?
    – Ced
    Commented Sep 22, 2022 at 15:18
  • Having an example of the folder structure you'd use here would help. There is not many example I found of vertical slices. I know there is no answer by the book, but there are people like yourself with a lot of experience in that aspect and their answer here on stack exchange seem to be often on point, so following those steps seems worthwhile to me. Even if it's to find flaws.
    – Ced
    Commented Sep 22, 2022 at 15:29
  • Having functionally closed vertical slices with business meaning is great. "Getting" accounts, listing accounts, getting stuff from accounts, however, is not business. Obviously I don't know your case in detail. If you're not doing that, then ignore my comments about it. However, "manage_account" sounds a lot like infrastructure in disguise, not a vertical slice. Commented Sep 22, 2022 at 18:38
  • In our case the account_management contains every layer from ui to the repositories to create, view and update an account. So yeah you might be spot. We end up in the end with a bunch of x_management module which might not be optimal. I might be mixing some concepts here, idk.
    – Ced
    Commented Sep 22, 2022 at 19:05
  • Also to quote you "Why is this here? It is never used! " <= this is starting to appear too.
    – Ced
    Commented Sep 22, 2022 at 19:11
0

Yes, it is perfectly OK if the Domain appears in the Infrastructure layer. You are being Domain-centered. Domain objects are under your control, validated and talk the company language. What would have been a problem is polluting your domain with infrastructure or other domain.

That said. The Domain - Infrastructure separation seems a bit like Hexagonal Architecture (a.k.a. port and adapters) that goes quite good with DDD. But you can be DDD without this architecture.

Anyway. In this case I would recommend using immutable domain objects that the infrastructure won't be able to break.

One example. A Repository interface may be Domain but its implementation using a database would be infrastructure. It can receive an Account to save it and the implementation can transform it to something that can be saved by the database.

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.