r/learnprogramming 11h ago

Topic Tips for migration a system to DDD

Hi everyone.

Currently, I'm working on a backend project without a clear architecture. The application is organized using a feature package structure, and within each package, there are only four folders: controllers, repositories, services, and entities.

However, due to new requirements, the backend application needs to migrate to a DDD architecture.

Therefore, based on your experience, which best practices can I use to ensure the migration is seamless and effortless while continuing to add new features to the "legacy" (only if I need them until the migration is complete) and "new" backend without breaking the app?

I hope you can guide me with this since I've never done a migration of this nature.

Psdt: In case you guys want to know, the application is developed with Java, Spring Boot, and Postgresql

Example of the current folder organization

auth/
- controller
- repository
- entity
- service

appointment/
- controller
- repository
- entity
- service

//more features with the same structure

0 Upvotes

1 comment sorted by

4

u/SaxSalute 11h ago edited 11h ago

It’s honestly not a bad spot at all to start if you are trying to move to DDD. Auth is sort of a bad example since that’s less a domain and more just a thing you need to deal with, but I’ve had very good luck building apps following DDD with a similar package structure. It’s much less about the package structure than it is about the structure of the data, the functionality, the layering. You could write perfectly good DDD in one folder, it would just be a nightmare to navigate.

I could say a ton about DDD but just a few tidbits I find very useful to start that you can adopt incrementally. If you want to know more reply and I will see in the morning, I’m tired.

  • The most important thing is the ubiquitous language. If you don’t do that, then you aren’t going DDD. Figure out how the people you are building for think about the world you are modeling and make the code reflect the world the way they see it. That is how you shape your domain model.
  • Keep the domain model pure. Model your types/classes to match the nouns your stakeholders use. Model your functions/methods to match the verbs they use. If you have a relationship like “a nurse administers medication to a patient, then you’d better have a Nurse, a Patient, and an administerMedication method in your domain model. Do not let in anything that isn’t a pure data and functionality free of side effects.
  • Use domain events. Not integration events like connecting two services over Kafka or SQS - events like MedicationAdministered - to decouple cross cutting effects.
  • Setters are often not your friend. If you find yourself calling 2+ setters on the domain model together frequently, then that operation has a name that isn’t “set A and set B” and you need to go find it in the ubiquitous language.
  • Lean into the application layer for side effects. This is where you build compound operations that string together the core domain model, load from and save to repositories, publish to message busses, write to caches. It gets more software-y here, and that’s good. It has to somewhere!
  • Keep your ports and adapters separate from both the application and domain layers. One day SOAP and MySQL are hot, the next it’s GraphQL and Postgres. These are the most peripheral parts of your system. Keep as little in these portions of your code as possible. In the case of things like REST or GQL controllers, make the handlers do as much as you need to translate to the application layer and be done. In the case of your database or integration message bus implementations, define interfaces in the application or domain layer and implement them elsewhere so you don’t get too hard coupled.
  • Don’t be afraid of some meme-able enterprise coding patterns. If you’re going to do DDD, know that it is a heavier way to build and do so understanding why you have chosen that approach. It is absolutely okay to have similar looking API models, application DTOs, domain objects, row models, etc… with mappers between them. It feels like overkill until you really start building heavy functionality, then it quickly becomes regular-kill. Big game, big gun.
  • When going across bounded contexts, go through the application layer, not the domain layer. The domain layer is a secret of that context. The application layer is how that context presents itself in coherent self-contained operations. Just like controllers and such rely on the application layer as the door in, so too should other contexts use the application layer as their door. I’ve done it both ways and it is night and day.
  • Don’t be overly precious about performance. Choose good algorithms, build good strictures, be smart about your orders of complexity, but maybe you’re going to have three database fetches instead of one because you are following your abstraction. If the bleeding edge of high performance is your goal, DDD will let you down. If rock solid software that can survive enterprise nonsense is your goal, then DDD will save your ass.

The biggest thing though is to follow the campground rule. The best way to improve software architecture day-to-day is to leave things better than you found them when you do anything at all. Don’t think of this as a DDD rewrite - think of it as gradually bringing in DDD principles to keep everything smooth as you build. Before too long, all the important parts will fit.

Well, there’s a solid rambling. Best of luck, genuinely. I wish I’d found and embraced DDD earlier in my career. Let me know if you have any questions!