Design Patterns – Why Are So Many Classes Needed?

design-patternsdomain-driven-designsource code

I am junior developer among seniors and am struggling a lot with understanding their thinking, reasoning.

I am reading Domain-Driven Design (DDD) and can't understand why we need to create so many classes. If we follow that method of designing software we end up with 20-30 classes which can be replaced with at most two files and 3-4 functions. Yes, this could be messy, but it's a lot more maintainable and readable.

Anytime I want to see what some kind of EntityTransformationServiceImpl does, I need to follow lots of classes, interfaces, their function calls, constructors, their creation and so on.

Simple math:

  • 60 lines of dummy code vs 10 classes X 10 (let's say we have totally different such logics) = 600 lines of messy code vs. 100 classes + some more to wrap and manage them; do not forget to add dependency injection.
  • Reading 600 lines of messy code = one day
  • 100 classes = one week, still forget which one does what, when

Everyone is saying it's easy to maintain, but for what? Every time you add new functionality, you add five more classes with factories, entities, services, and values. I feel like this kind of code moves a lot slower than messy code.

Let's say, if you write 50K LOC messy code in one month, the DDD thing requires lots of reviews and changes (I do not mind tests in both cases). One simple addition can take week if not more.

In one year, you write lots of messy code and even can rewrite it multiple times, but with DDD style, you still do not have enough features to compete with messy code.

Please explain. Why do we need this DDD style and lots of patterns?

UPD 1: I received so many great answers, can you guys please add comment somewhere or edit your answer with the link for reading list (not sure from which to start, DDD, Design Patterns, UML, Code Complete, Refactoring, Pragmatic ,… so many good books), of course with sequence, so that I can also start understanding and become senior as some of you do.

Best Answer

This is an optimization problem

A good engineer understands that an optimization problem is meaningless without a target. You can't just optimize, you have to optimize for something. For example, your compiler options include optimizing for speed and optimizing for code size; these are sometimes opposite goals.

I like to tell my wife that my desk is optimized for adds. It's just a pile, and it's very easy to add stuff. My wife would prefer it if I optimized for retrieval, i.e. organized my stuff a bit so I can find things. This makes it harder, of course, to add.

Software is the same way. You can certainly optimize for product creation-- generate a ton of monolithic code as quickly as possible, without worrying about organizing it. As you have already noticed, this can be very, very fast. The alternative is to optimize for maintenance-- make creation a touch more difficult, but make modifications easier or less risky. That is the purpose of structured code.

I would suggest that a successful software product will be only created once but modified many, many times. Experienced engineers have seen unstructured code bases take on a life of their own and become products, growing in size and complexity, until even small changes are very difficult to make without introducing huge risk. If the code were structured, risk can be contained. That is why we go to all this trouble.

Complexity comes from relations, not elements

I notice in your analysis you are looking at quantities-- amount of code, number of classes, etc. While these are sort of interesting, the real impact comes from relations between elements, which explodes combinatorially. For example, if you have 10 functions and no idea which depends on which, you have 90 possible relations (dependencies) you have to worry about-- each of the ten functions might depend on any of the nine other functions, and 9 x 10 = 90. You might have no idea which functions modify which variables or how data gets passed around, so coders have a ton of things to worry about when solving any particular problem. In contrast, if you have 30 classes but they are arranged cleverly, they can have as few as 29 relations, e.g. if they are layered or arranged in a stack.

How does this affect your team's throughput? Well, there are fewer dependencies, the problem is much more tractable; coders don't have to juggle a zillion things in their head whenever they make a change. So minimizing dependencies can be a huge boost to your ability to reason about a problem competently. That is why we divide things into classes or modules, and scope variables as tightly as possible, and use SOLID principles.

Related Topic