225

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.

user1318496
  • 1,767
  • 4
  • 9
  • 11
  • 7
    Note that this particular way of writing code is not a problem with patterns but with the people writing the code. You can write a rich software with a lot of patterns and maybe 40 or 50 classes; easy. But if you overengineer things... well, then you end up with 20 classes for something that could have been done with 3 classes or with 4 to 5 procedural functions. The important skill is recognizing when a class is about to get too big an break it down so that it does not become a god class. – marstato Apr 10 '18 at 16:30
  • 3
    I find your math around lines of code and their understantability to be quite comical. I would really like to see detailed writeup of your reasoning behind numbers you use. – Euphoric Apr 10 '18 at 16:40
  • 84
    I think there is a good question here but it's hiding behind hyperbole and frustration. @user1318496, you might benefit from rephrasing your question a bit. – MetaFight Apr 10 '18 at 16:42
  • 3
    @user1318496 This *is* a duplicate of the above question. You are just unaware of what you are actually asking. The essence of your question really has nothing to do with OO vs functional programming or design patterns and everything to do with organization. The question to which you actually desire an answer is, "Why separate code into distinct atomic units?". Now, although many developers may think the answer to this is self-evident, I believe this is a very valid question. One that many developers struggle with in one form another as they are just getting started. – user3347715 Apr 10 '18 at 18:46
  • 50
    At the risk of stepping on toes, because your language sucks. Don't take that for more than it is: a sucky language is often the correct technical choice for a variety of reasons, but that doesn't make it non-sucky. As for your actual question, correctness is more important than readability. Or to put that slightly differently: readability matters insofar as in enables reasoning about correctness. So which is easier to test, your 100 classes or your monolithic god class? I'm betting 100 simple classes. – Jared Smith Apr 10 '18 at 19:27
  • 89
    "Yes this could be messy, but its a lot more maintainable and readable.". If its messy, how can it be readable and maintainable? – Polygnome Apr 10 '18 at 19:56
  • 38
    @Polygnome: I was about to type the exact same comment. Another choice comment characteristic of junior developers is "I feel like this kind of code moves a lot slower then messy code." It does you no good to run as fast as you can if you spend half your time running into walls! Slow is smooth, smooth is fast. – Eric Lippert Apr 10 '18 at 20:07
  • 1
    We really don't need them... – Vector Apr 10 '18 at 22:48
  • 5
    @user1318496 - you don't need to worry, there a lot of successful companies which share your opinions. And they hiring all the time, because need more developers to maintain code which was quickly written.. :) – Fabio Apr 10 '18 at 23:29
  • 16
    Am I the only one who thinks that maybe using 20-30 classes with `EntityTransformationServiceImpl`s to solve a simple problem is heavily over-engineering? I'm guessing you're referring to Java, whose culture is to throw design patterns at design patterns until the code base is unintelligible... – Reinstate Monica Apr 11 '18 at 01:31
  • 9
    In OPs defense, a good example of what he might be referring to is replacing simple switches over 3 or 4 low value conditions with State pattern everywhere. I have seen this happen and the result really can be a hundred classes instead of a hundred lines of code. Maintenance is compromised too. – Sentinel Apr 11 '18 at 05:33
  • 41
    You don't, unless you're doing Java. When all you have is Java, everything looks like a class. – hobbs Apr 11 '18 at 06:27
  • 5
    Put simply, it is more difficult and takes longer to write elegant code, so people settle for incohesive but highly-structured code. – Karl Bielefeldt Apr 11 '18 at 12:49
  • 1
    I am starting to feel the same way about classes in general as user1318496. Perhaps its more of a personal preference thing than anything else. – Graham Apr 11 '18 at 15:41
  • @Graham Language features are to a certain degree personal preference, but that is orthogonal to this question. Functional code can just as well be written for easy creating vs easy modifying. – R. Schmitz Apr 11 '18 at 15:58
  • 6
    It should be noted that OOP is not a universal best tool, so solving every (part) of the problem by adding more classes, especially with inheritance, may and does lead to poor, unnecessarily complicated designs. The problem is that coming up with a good design takes time and an experienced developer, and both are costly. Business is often ok with a messy design if it works _right now_. – 9000 Apr 11 '18 at 16:01
  • 7
    OOP is oftentimes an anti-pattern, and pure OOP is almost always an anti-pattern. OOP tends to bleed into all sorts of places in your code, especially testability. Design patterns make use of the hammer (OOP) to drive in all these nails you scattered about with overuse of OOP. If you have a class with the name `Provider`, `Entity`, or `Processor`, you are likely overusing OOP, but you can surely find plenty of people who have figured out how to OOP that nail. – Rich Remer Apr 11 '18 at 21:49
  • 5
    @Theodoros Chatzigiannakis: That's just a religious conversion. The problem is the unthinking worship of a software development methodology. You just change the deity, but keep the unthinking adherence to rituals. – jamesqf Apr 11 '18 at 22:43
  • Perhaps one should [revisit](https://www.youtube.com/watch?v=QM1iUe6IofM) [one's](https://www.youtube.com/watch?v=IRTfhkiAqPw) [convictions](https://www.youtube.com/watch?v=V6VP-2aIcSc)? – Peter Mortensen Apr 12 '18 at 09:35
  • 2
    @9000 I think what you are talking about would be called COP - "Class-oriented programming"? If you're adding classes without giving a hoot about actually having objects, you're not doing OOP... – R. Schmitz Apr 12 '18 at 09:50
  • 3
    Can't believe no-one has mentioned the Single Responsibility Principle (which, if you follow it, tends to lead to the production of numerous classes) and SOLID principles in general. – Paul Suart Apr 12 '18 at 11:27
  • Are those classes concepts that exist in your domain? If not, why do they exist? If they do, then they have business value, right? What future flexibility do you loose if you write 600 lines of messy code vs 20-30 classes that represent domain concepts? – Rob Crawford Apr 12 '18 at 15:15
  • 6
    Decades ago I worked in a shop where we upgraded from (I think) DOS 2.0 to DOS 3.0. In the first version, there was only a single directory with everything in it. In the latter, subfolders had been introduced. My boss asked, "Why do we need all these subfolders? Why can't I just put everything in one folder so I know where to find it?" Good times. :) – Don Branson Apr 12 '18 at 15:51
  • "Reading 600 lines of messy code = one day". That's wrong...The time it takes for me to read a class increases exponentially, will all the branching and branch misprediction etc... At 600 lines I am at the edge of my comfort zone. At 1000 it normally takes me about a month to fully understand the class.... – ArTs Apr 13 '18 at 10:42
  • 1
    The F22 Raptor wasn't built by taking an IKEA warehouse of fixtures and pouring them into a aeroplane shaped mould. – ArTs Apr 13 '18 at 10:47
  • 3
    Some of these answers and comments are talking past each other. I think it might help to think about two distinct questions, e.g. "Why use DDD/design-patterns/etc. rather than 'simple' code *in general*" (testability, decoupling, etc.) and "Why is *this particular codebase* using so many more classes than I would expect?" (over-engineering, language-specific workarounds (e.g. no lambdas), outdated style (e.g. Java now has lambdas), cargo-culting, tech debt, etc.) – Warbo Apr 13 '18 at 11:06
  • Design patterns isn't just about maintainability, but it's also about reusability. – O.Badr Apr 13 '18 at 12:07
  • 1
    @jamesqf Perhaps you see it as a religious conversion. I see it as a function of type `Religion -> Religion`. – Theodoros Chatzigiannakis Apr 13 '18 at 13:05
  • 1
    @Jared: "Which is easier to test?": As always, that depends on what kind of test. If you have 100 trivial classes and all the system behaviour is in how they're linked together, then generally speaking the resulting system is no easier to write integration and QA tests for than was the naive monolith. You do have 100+ unit tests which assert, "you have not changed your design", but so what? The OP may have exaggerated and/or the code may be fine, but if the ratio really is 1 class per 6 lines of naive code to solve the same problem then there are grounds to consider if it's over-engineered :-) – Steve Jessop Apr 13 '18 at 13:22
  • And by "solve the same problem" I of course mean fully solve, which is another area the OP might have failed to see what the authors of this code base see. 600 lines of code that sort of work most of the time is not the same as 100 classes sitting in a framework that externally proves useful theorems that allow you to deduce that the code *actually* works! – Steve Jessop Apr 13 '18 at 13:33
  • @SteveJessop yes, testing the *system* is equally complex in both cases. Perhaps even more so in the multiple classes case. The difference is this: with the monolith while it might be easier to find *where* to make a change, there's potentially unbounded time fixing the stuff that might break from making it. Finding the correct piece of code in the split-up codebase is harder but a known quantity, and making the change is trivial. I'd rather be confident than roll the dice, but YMMV and one size does not fit all. For anything less than a 10k lines, I *might* prefer the monolith. Maybe. – Jared Smith Apr 13 '18 at 13:39
  • 9
    This question is rather like asking "why do we need so many parts to build a window? There's all this jargon with sashes and sash cords and double hung and triple glazed casements and it's too confusing. If I want to see through a wall I just get a drill, drill a hole in the wall, done. Why do window makers want to make everything so complicated when I can do it so simply?" – Eric Lippert Apr 13 '18 at 15:25
  • @EricLippert: if the code with the 100 classes has features easily explained to the user of the software, that the naive code doesn't, then yes that's a great analogy. I think the difference between a hole in the wall and a glazed window is pretty easy to classify as, "the naive solution is not in fact a solution since it doesn't satisfy our real user requirements". So, if the hacked-together code works in a day but cannot be integrated into the software stack that runs your actual user-facing services, then that'd be an example slam-dunk argument for writing more classes. – Steve Jessop Apr 13 '18 at 15:53
  • @Jared: you already bet above that the 100 classes are easier to test than the monolith. I was only responding to that claim. The ease of changing the code is a whole different argument against monoliths :-) – Steve Jessop Apr 13 '18 at 15:55
  • 1
    @Rob Crawford: Re "...600 lines of messy code vs 20-30 classes...", you've got two unrelated things here. It's perfectly possible to write 600 lines of clear, well-commented code, just as it's possible to convert that into 20-30 messy classes. – jamesqf Apr 14 '18 at 04:58

11 Answers11

351

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.

candied_orange
  • 102,279
  • 24
  • 197
  • 315
John Wu
  • 26,032
  • 10
  • 63
  • 84
  • 110
    I would note, however, that an overabundance of classes and indirection does NOT help either understanding NOR maintenance. And nor does convoluted control flows (aka, callback hell). – Matthieu M. Apr 11 '18 at 08:33
  • 10
    @JohnWu this explanation is way the best and easier to understand one that I ever read. – Adriano Repetti Apr 11 '18 at 09:04
  • 15
    Well written, but is it maybe missing why "created once but modified many, many times" is important? (If all the code is in `EntityTransformationServiceImpl`, you are forced to learn _how the whole thing works_ before you can fix it - but if e.g. something is wrong with the format and a `Formatter` class handles that, you only need to learn _how that part works_. Plus reading your own code after ~3 months is like reading a stranger's code.) I feel like most of us subconsciously thought of this, but that might be because of experience. Not 100% sure about this. – R. Schmitz Apr 11 '18 at 14:48
  • 17
    I'd go for the full 10×10=100 for the combinatorial: those functions could well be recursive, and in particularly poor code, not necesarrily obviously so. – KRyan Apr 11 '18 at 15:06
  • 34
    "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 take issue with the implicit notion that more classes = more maintainability. In particular, scattering logic across many classes often makes it difficult to find the overarching logical concepts in the code (especially without a very intentional eye on ensuring the concepts are very visible), which degrades maintainability enormously. – jpmc26 Apr 11 '18 at 17:51
  • 3
    My go-to example of this has recently become [NuGet's restore command](https://github.com/NuGet/NuGet.Client/tree/dev/src/NuGet.Core/NuGet.Commands/RestoreCommand). The restore has three basic steps: read in the list of packages, download them, and then extract them onto disk. While each of those steps certainly has complexities, it is inordinately difficult to track down where those are implemented in the code, in part due to the relatively large number of objects and in part due to the fact that revealing these concepts doesn't appear to have been a priority in the naming and organization. – jpmc26 Apr 11 '18 at 17:51
  • 6
    When I was first learning to code I wrote a program all within one class, it worked well but got to the point where making a simple change would introduce 4 or 5 bugs that would take me a couple days to fix. I started researching design and broke everything out into about 10 classes and my maintenance problems disappeared. I made many changes with 0 bugs introduced after this refactor. I think this a lesson one has to learn the hard way to really understand why it's worth it. – reggaeguitar Apr 11 '18 at 18:16
  • @jpmc26 "I take issue with the notion that more classes = more maintainability." Depends, of course, on what the operand of "more" is. In this case, it is "50K LOC messy code." So I'm not sure I agree, in the specific context of the OP's post. – John Wu Apr 11 '18 at 18:19
  • 2
    A good answer, but with a glaring omission: it is highly likely that "600 lines of messy code" cannot be tested properly, and that alone is a deal breaker for the approach advocated in the OP. – skomisa Apr 11 '18 at 19:14
  • @jpmc26 What would be an example of non-trivial OOP program (say >10k loc) that uses a minimal number of classes and is easy to maintain and read? Also I'll have to disagree on the complexity of reading the code. Even without loading the code into an IDE it seems pretty easy to follow along from `RestoreRunner.RunAsync` to `RestoreCommand` and so on. The problem I think is that you missed that NuGets are not a simple list but a tree with `PackageReference` these days which throws a wrench into your mental model. – Voo Apr 11 '18 at 19:16
  • 2
    @Voo I had trouble figuring out which object started the command; that's all obfuscated with the OO approach to command line parsing. Once you figure out it's `RestoreRunner`, you try to trace through how its "requests" are created, which leads you down through about 4 method calls culminating in a call to a provider object, if I'm reading it right. Finding a tree is not surprising, but just finding it involves far too many layers. I'm not clever. I like code that's carefully crafted to reveal the intention behind it, and the object centric approach there exacerbates the poor abstractions. – jpmc26 Apr 12 '18 at 01:00
  • 7
    Nuget is probably not a great example, since its modularity may be driven more by external requirements than architect's overenthusiasm-- it is, after all, an extensible framework for managing extensible frameworks, that runs as a PowerShell commandlet inside a Visual Studio extension. Now that I think about it, if all those things were written monlithically, Nuget couldn't even exist.. . – John Wu Apr 12 '18 at 01:13
  • @Voo that depends on the definition of “minimal number of classes”. We have an application consisting of thousands of classes, still, I know if we used certain commonly used frameworks and “best practices” we had twenty times that number… – Holger Apr 12 '18 at 08:40
  • @R.Schmitz that’s an interesting point. “created once but modified many, many times” might be important *because* the software is designed in a way that makes creating horribly expensive, hence we have to keep and maintain it until we reach the point that this entirely outdated, patched mess has to die. Not everyone follows this pattern. There are companies were the release of a software is also always the day when the development of the new version starts, written from scratch, incorporating all lessons learned from developing the previous version, as well as newly arrived technologies. – Holger Apr 12 '18 at 08:48
  • 1
    @Holger No, because when adding new code, the previous code is not as important as your writing standards. If _the software_ makes it horribly expensive to add code, then that's just messy code. You can have a perfectly modular project, but add some quick and easy code. You can also have a whole program in one god class, but spend some thought on how to make your addition maintainable later on. Concerning those companies you speak of, I only heard of one and [it was called Netscape](https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/). – R. Schmitz Apr 12 '18 at 09:37
  • 3
    @R.Schmitz did you know that all browsers of that time were based on the original mosaic, including, e.g. the Internet Explorer, to name one that still exists? What do you think, how many of today’s browsers are still based on it? Today, there are only browsers which either, have been rewritten from scratch (more than one time) since then or do not even exist that long. In a theory world, that first browser could have been written in a modular, extensible, future-proof way, being ready for whatever changes the future will bring. In reality, not. Requirements and technologies change too much. – Holger Apr 12 '18 at 09:50
  • 2
    @Holger So when did Mozilla stop adding new features to Firefox for several years to completely rewrite their browser? They didn't. Sure you can replace parts of the code and there's a natural evolution but a complete rewrite is poison (the other company that did that was MS between IE6 and 8.. didn't work that much better for them than Netscape) – Voo Apr 12 '18 at 10:20
  • @Holger If a company creates a new product that's not REwriting a code base, that's _creating_ it in the first place. Otherwise you're arguing that today's AutoCAD and 3DSMax etc are just "rewrites" of 1968 UNISURF and Call of Duty: Modern Warfare 3 is just a rewrite of DOOM. Also I'm not saying that it doesn't happen, just that in those cases it would have turned out better if it didn't. – R. Schmitz Apr 12 '18 at 11:19
  • @R.Schmitz so you’re saying it would be better *if* “Call of Duty: Modern Warfare 3” was based on Doom’s source code and that it is a sign of Doom’s poor software design that it isn’t? Or are you actually confirming my point that old software will be replaced by new one, as infinitely updating the old one is an illusion? – Holger Apr 12 '18 at 12:59
  • @Voo I don’t see where I claimed that all software developers do that. Maybe you’re right and Firefox never got redesigned from scratch after it started its life as redesigned-from-scratch replacement for Netscape. Perhaps that’s a sign of how well Firefox has been designed. Or perhaps, you are just about to start a flamewar, as Firefox’ quality is perceived really controversial. Don’t open that can of worms. – Holger Apr 12 '18 at 13:03
  • @Holger Your interpretations of what I said as well as of what a rewrite is are wrong. Call of Duty is **not** a rewrite of DOOM. It's a completely different product by a completely different developer. Sure, you might say every piece of code is just a rewrite of the first piece of code ever written, but the word just loses any practical meaning and you should probably [post a question here](https://philosophy.stackexchange.com/) then. – R. Schmitz Apr 12 '18 at 13:51
  • @R.Schmitz it seems you are completely missing the point. It doesn’t matter whether new software is a “rewrite” of an old one or an entirely new product. The point is, it is *new* software to which it doesn’t matter how easy the maintenance of the old one is. Do you get it now? Old software will die. Old software will get replaced by new one. That’s an inevitable fact. You can only influence whether that new one is yours or that of your competitors. But you can also optimize your software for maintenance, making development of new software expensive, and try avoiding to write new one forever… – Holger Apr 12 '18 at 14:04
  • 2
    @Holger You claim that today "only browsers which either, have been rewritten from scratch or do not even exist that long". This is patently false. I doubt you'll find any popular product that was rewritten from scratch and is still as successful as it was before (since the example you mentioned isn't true, I doubt you know a better one). The only browser vendor who did something similar since Netscape was Microsoft after IE6. And they went from 90% majority to a minor player and that despite bundling the browser with the most popular operating system on the planet... great success that. – Voo Apr 12 '18 at 16:14
  • 2
    Rewriting from scratch and second system syndrome are a surefire way to kill a product, which is why nobody still around is doing it. What you're doing is improving the existing code while implementing new features. Or you might decide to rewrite small parts of the application based on a need basis (security or performance usually, very rarely maintainability). But a rewrite from scratch? The Joel article gives many, many reasons why this is such a bad idea. – Voo Apr 12 '18 at 16:17
  • @Voo exactly, Microsoft was the only one having rewritten their browser from scratch. Now, name *any* browser besides that from Microsoft which existed at that time (Netscape 4 or earlier) that still exists today (without having a major rewrite, in other words, still being based on Mosaic code). Well, actually Netscape did a rewrite too, but outsourced it to the Mozilla foundation, which led to the development of Firefox. So rewriting “killed” the product because it gave birth to the new one. Do you think a Netscape browser based on the old code could still exist today? Mozilla disagreed. – Holger Apr 12 '18 at 16:36
  • 3
    @Holger In my post I discuss two possible optimization goals. Certainly you can optimize for other goals too-- e.g. to "minimize number of rewrites" (which is very similar to optimizing for maintainability) or to "maximize ease of rewrite," which is similar but not the same as optimizing for ease of product creation (there are additional requirements such as backward compatibility and feature parity). I don't prescribe a goal, I simply wish to highlight the differences, as a means of explaining the rationale for careful design. – John Wu Apr 12 '18 at 17:03
  • @JohnWu your way of describing optimization a function of varying goals is very good, I’m not objecting that. It’s a really good answer. – Holger Apr 12 '18 at 17:11
  • 5
    Great answer but..: _The alternative is to optimize for maintenance_ implies this is the only one and the one OP is complaining about. There also is _optimization to find design patterns by all means and at all cost religiously_. The keyword is _smart_ and just by creating a lot of classes it is not a given. DI is a great/terrible example, where, as one wise man wrote, you get a 50c concept for 100$ buzzwords. – TaW Apr 12 '18 at 17:59
  • @JohnWu NuGet fails pretty hard at being modular. Its side libraries (like [NuGet.Frameworks](https://www.nuget.org/packages/NuGet.Frameworks/4.7.0-preview1-4986)) are completely undocumented (I haven't even been able to find the source for their build.), the command line tool is missing a lot of the VS plug-in's functionality, and looking at the code, the need to construct so many objects just to get one piece working means you have to have a very broad understanding of the entire code base to use any of it. It's already effectively monolithic, so I don't buy your argument. – jpmc26 Apr 12 '18 at 19:38
  • 3
    @Taw "find design patterns by all means and at all cost religiously." That sounds like a design decision (output) not a design goal (input). When you are front-loading your desired outputs into an optimization input, the process isn't adding much value (it fails the test of endogeneity), a.k.a. you are doing it wrong. Sounds like your architect just has a "Pet [NFR](https://en.wikipedia.org/wiki/Non-functional_requirement)," which are always bad. – John Wu Apr 12 '18 at 20:07
  • 2
    @JohnWu Except that's the *pervasive* view towards patterns. DI is accepted religiously. No DI proponent I know of says, "Here's what a problem that DI is good as solving looks like," they say, "You should write OO code and that means you should have DI. And oh, btw, you should follow SOLID principles." Virtually no one talks about what problems these ideas are supposed to actually solve. They're just offered as rules that supposedly apply all the time. – jpmc26 Apr 12 '18 at 22:18
  • 1
    @Holger Look, Firefox has been released in 2004, that is 14 years; Android in 2007, that's 11 years. In IT, that's not only old, that's _ancient_. According to your theory, Firefox should have been a "outdated, patched" (at the same time), unusable mess by 2006, or Android around 2010. That's just flat-out denial of the efficiency of maintainable code, because they are now better in almost every aspect - security, usability, feature set, you name it. It seems like you just have a personal agenda against maintainable code. – R. Schmitz Apr 13 '18 at 09:24
  • 3
    @jpmc26 That's because good programmers know that all "rules" have to be applied pragmatically; **all rules automatically get a "except if you have a really good reason to" at the end**. If you work with people who are dogmatic instead of pragmatic, that will turn out bad for _any_ rule. – R. Schmitz Apr 13 '18 at 09:28
  • @R.Schmitz except that Firefox’ main sponsor once decided to write his own browser named Chrome, not based on Firefox at all, you’re right. Firefox is ancient. However, what do you want to prove? My initial statement was that today, no browser is based on Mosaic, because all existing browsers either, have been entirely rewritten since then or are much younger than that. Considering that Mosaic is from 1993, Firexfox *is* much younger than that. So you didn’t prove me wrong. Besides that, I’m not against maintainable code, never said that. Rather, I’m against code that only knows *growing*. – Holger Apr 13 '18 at 10:06
  • 1
    @Holger Wrong again, your initial statement was "_the software is designed in a way that makes creating horribly expensive, hence we have to keep and maintain it until we reach the point that this entirely outdated, patched mess has to die._" The article I linked can give you more insight as to why rewrites are bad if you're interested. Your initial statement has been proven wrong by Firefox and Android. Everything after that was just a discussion, which comments are not for, so let's just stop this here now. – R. Schmitz Apr 13 '18 at 11:57
  • @R.Schmitz you are ripping that phrase out of context. The sentence was “*‘created once but modified many, many times’ **might** be important because the software is designed in a way that makes creating horribly expensive …*”. It’s a speculation about a pattern which *might* apply to *some quantity* of software projects. You already missed the point, by opening a discussion about cherry-picked software, two examples IIRC, that has been maintained for a very long time, ignoring all the billions of software which *did* die. That speculative statement is not “proven wrong” by just two examples. – Holger Apr 13 '18 at 12:11
  • @Holger You wrote _[A] might be important because [B] causes [C]_. That is what your "might" applied to. The theory you had is that [B] causes [C]. Two huge examples where it doesn't apply quickly prove that [B] does not cause [C]. If your point was something else, then I didn't disprove that and only showed that one of your premises was incorrect. – R. Schmitz Apr 13 '18 at 13:09
  • 1
    @R.Schmitz Really good programmers don't think in terms of rules in the first place. They think in terms of solving problems. Even more importantly, good programmers recognize when other programmers aren't already thinking in that mindset and push them towards it, rather than stating rules. – jpmc26 Apr 13 '18 at 16:44
  • @jpmc26 I put "rules" in quotation marks because they are _guidelines_. A rule can not start with "You should". If one doesn't follow even a basic guidelines like "_you should optimize your code for readability_" or "_you should follow you team's code conventions_", (all with the addition "except if you have a really good reason not to"), then they are more of a ["real programmer"](http://catb.org/jargon/html/story-of-mel.html) than a "really good programmer". – R. Schmitz Apr 13 '18 at 17:36
  • 1
    @R.Schmitz I'm saying really good programmers invert the thinking, though. They don't think, "You should optimize your code for readability." They think, "We need to solve the problem of being able to understand code to make changes later in time or by other developers." The first imposes a solution without explaining the problem. The second states the problem and remains open to different solutions, and it has a goal where it's much clearer when you've succeeded or not (even though it is still subjective). – jpmc26 Apr 13 '18 at 18:15
  • @jpmc26 Fair enough, but asking the 5 why-question after you've been told "you should follow you team's code conventions" is not good for your career. Sometimes it's too obvious to always add the explanation. – R. Schmitz Apr 16 '18 at 08:56
70

Well, first of all, readability and maintability are often in the eye of the beholder.

What is readable to you may not be to your neighbour.

Maintainability often boils down to discoverability (how easily is a behaviour or concept discovered in the codebase) and discoverability is another subjective thing.

DDD

One of the ways DDD helps teams of developers is by suggesting a specific (yet still subjective) way of organising your code concepts and behaviours. This convention makes it easier to discover things, and therefore easier to maintain the application.

  • Domain concepts are encoded as Entities and Aggregates
  • Domain behaviour resides in Entities or Domain Services
  • Consistency is ensured by the Aggregate Roots
  • Persistence concerns are handled by Repositories

This arrangement is not objectively easier to maintain. It is, however, measurably easier to maintain when everyone understands they're operating in a DDD context.

Classes

Classes help with maintainability, readability, discoverability, etc... because they are a well known convention.

In Object Oriented settings, Classes are typically used to group closely related behaviour and to encapsulate state that needs to be controlled carefully.

I know that sounds very abstract, but you can think about it this way:

With Classes, you don't necessarily need to know how the code in them works. You just need to know what the class is responsible for.

Classes allow you to reason about your application in terms of interactions between well defined components.

This reduces the cognitive burden when reasoning about how your application works. Instead of having to remember what 600 lines of code accomplishes, you can think about how 30 components interact.

And, considering those 30 components probably span 3 layers of your application, you probably only every have to be reasoning about roughly 10 components at a time.

That seems pretty manageable.

Summary

Essentially, what you're seeing the senior devs do is this:

They are breaking down the application into easy to reason about classes.

They are then organising these into easy to reason about layers.

They are doing this because they know that, as the application grows, it becomes harder and harder to reason about it as a whole. Breaking it down into Layers and Classes means that they never have to reason about the entire application. They only ever need to reason about a small subset of it.

MetaFight
  • 11,549
  • 3
  • 44
  • 75
  • 5
    Besides smaller classes are easier to replace/refactor. – Zalomon Apr 10 '18 at 16:43
  • 15
    Overengineering does *not* give more maintainable or understandable code - quite the opposite, despite what you claim. Who needs an `AddressServiceRepositoryProxyInjectorResolver` when you can solve the problem more elegantly? Design patterns for the sake of design patterns just leads to unecessary complexity and verbosity. – vikingsteve Apr 11 '18 at 12:35
  • 32
    Yeah, overengineering is bad. So is killing puppies. Nobody here is advocating for either. https://www.logicallyfallacious.com/tools/lp/Bo/LogicalFallacies/169/Strawman-Fallacy – MetaFight Apr 11 '18 at 12:40
  • 6
    Also, "elegance" in the software engineering context is often a Weasel Word. https://en.wikipedia.org/wiki/Weasel_word – MetaFight Apr 11 '18 at 12:47
  • and then it takes only one monkey wrench to break the entire pattern – MichaelEvanchik Apr 11 '18 at 14:00
  • 11
    The same could be said of any approach to organising code. Everything hinges on the maintenance team understanding why the code is organised as it is. That's the whole point of using well established and understood conventions. – MetaFight Apr 11 '18 at 14:03
  • 1
    Great answer! I'm surprised at the comments disagreeing with you – reggaeguitar Apr 11 '18 at 18:23
  • If they are *first* breaking it into classes and *then* combining those classes into layers, it's no wonder things get messy. You want to do it the other way around (also, you want to introduce classes to begin with). – Clearer Apr 12 '18 at 08:52
  • "With Classes, you don't necessarily need to know how the code in them works. You just need to know what the class is responsible for." Classes are definitely not the only way to achieve this, though they can be a useful way in some circumstances. More importantly, though, it's not using classes that achieves this, it's *good design choices* by a developer that does. Classes are not a magic sauce that gives you this, by any stretch. – jpmc26 Apr 12 '18 at 22:19
  • 2
    @jpmc26 I agree, classes aren't magic. They do, however, often offer language-level support for things like encapsulation and public contracts. – MetaFight Apr 12 '18 at 22:25
  • 1
    As per the OP, who is "struggling a lot with understanding their thinking, reasoning" it seems that the reasoning behind making code that's easy to reason about is not so easy to reason about. – icc97 Apr 13 '18 at 12:29
  • 3
    @icc97 it sounds like you're saying experience, context, and knowledge of conventions and patterns makes a huge difference. And that a junior dev might lack these things making it hard for them to grok code written with those things in mind. – MetaFight Apr 15 '18 at 00:23
31

Please explain me, why do we need this DDD style, lots of Patterns?

First, a note: the important part of DDD is not the patterns, but the alignment of the development effort with the business. Greg Young remarked that the chapters in the blue book are in the wrong order.

But to your specific question: there tend to be a lot more classes than you would expect, (a) because an effort is being made to distinguish the domain behavior from the plumbing and (b) because extra effort is being made to ensure that concepts in the domain model are expressed explicitly.

Bluntly, if you have two different concepts in the domain, then they should be distinct in the model even if they happen to share the same in memory representation.

In effect, you are building a domain specific language that describes your model in the language of the business, such that a domain expert should be able to look at it and spot errors.

Additionally, you see a bit more attention paid to separation of concerns; and the notion of insulating consumers of some capability from the implementation details. See D. L. Parnas. The clear boundaries empower you to change or extend the implementation without the effects rippling throughout you entire solution.

The motivation here: for an application that is part of the core competency of a business (meaning a place where it derives a competitive advantage), you will want to be able to easily and cheaply replace a domain behavior with a better variation. In effect, you have parts of the program that you want to evolve rapidly (how state evolves over time), and other parts that you want to change slowly (how state is stored); the extra layers of abstraction help avoid inadvertently coupling one to the other.

In fairness: some of it is also Object Oriented Brain Damage. The patterns originally described by Evans are based on Java projects that he participated in 15+ years ago; state and behavior are tightly coupled in that style, which leads to complications you might prefer to avoid; see Perception and Action by Stuart Halloway, or Inlining Code by John Carmack.

No matter what language you work in, programming in a functional style provides benefits. You should do it whenever it is convenient, and you should think hard about the decision when it isn't convenient. Carmack, 2012

VoiceOfUnreason
  • 32,131
  • 2
  • 42
  • 79
  • 3
    I was going to add my own answer until I read this. I would emphasize the first paragraph, that the aim is to model business concepts in software to align the software with the business requirements. In fairness, the analyst driving the project should also express how much of a driver time to delivery is, and code/test quality or completeness should be adjusted accordingly. – Sentinel Apr 11 '18 at 05:41
  • 2
    John Carmack is a great example IMO, since he's well known for writing code that's both clean and easy to understand, while also being well performing. This is especially visible as you track his code with advancing technologies - with better CPUs and memory, you can see a lot of things pushed from "this needs to be really terse" to "this needs to be really clear/isolated/...". One of the most pragmatic programmers I know of :) – Luaan Apr 12 '18 at 09:26
  • 1
    I think this is the best answer here. While I am by no means sold on DDD, this answer certainly at least explains what it really is and an actual motivation for it, rather than appealing to common platitudes that mean nothing. – jpmc26 Apr 14 '18 at 16:16
29

There are many good points in the other answers, but I think they miss or don't emphasize an important conceptual mistake you make:

You are comparing the effort to understand the complete program.

This is not a realistic task with most programs. Even simple programs consist of so much code that it is simply impossible to manage all of it in the head at any given time. Your only chance is to find the part of a program that is relevant to the task at hand (fixing a bug, implementing a new feature) and work with that.

If your program consists of huge functions/methods/classes this is almost impossible. You'll have to understand hundreds of lines of code just to decide if this chunk of code is relevant to your problem. With the estimates you gave it becomes easy to spend a week just to find the piece of code you need to work on.

Compare that to a code base with small function/methods/classes named and organized into packages/namespaces that makes it obvious where to find/put a given piece of logic. When done right in many cases you can jump right to the correct place to solve your problem, or at least to a place from where firing up your debugger will bring you to the right spot in a couple of hops.

I have worked in both kinds of systems. The difference can easily be two orders of magnitude in performance for comparable tasks and comparable system size.

The effect this has on other activities:

  • testing becomes much easier with smaller units
  • less merge conflicts because chances for two developers to work on the same piece of code are smaller.
  • less duplication because it is easier to reuse pieces (and to find the pieces in the first place).
Cubic
  • 301
  • 2
  • 10
Jens Schauder
  • 1,503
  • 8
  • 13
19

Because testing code is harder than writing code

A lot of answers have given good reasoning from a developer's perspective - that maintenance can be reduced, at the cost of making the code more strenuous to write in the first place.

However, there is another aspect to consider - testing can only be fine-grained as your original code.

If you write everything in a monolith, the only effective test you can write is "given these inputs, is the output correct?". This means any bugs found, are scoped to "somewhere in that giant pile of code".

Of course, you can then have a developer sit with a debugger and find exactly where the problem started and work on a fix. This takes a lot of resources, and is a bad use of a developer's time. Imagine that ever minor bug you have, results in a developer needing to debug the entire program again.

The solution: Many smaller tests that pinpoint one specific, potential failure each.

These small tests (for example Unit Tests), have the advantage of checking a specific area of the codebase and helping to find errors within a limited scope. This not only speeds up debugging when a test fails, but also means that if all your small tests fail - you can more easily find the failure in your larger tests (i.e. if it's not in a specific tested function, it must be in the interaction between them).

As should be clear, to make smaller tests means your codebase needs to be split into smaller testable chunks. The way to do that, on a large commercial codebase, often result in code that looks like what you're working with.

Just as a side-note: This isn't to say people won't take things "too far". But there is a legitimate reason for separating codebases into smaller/less connected parts - if done sensibly.

Bilkokuya
  • 337
  • 1
  • 6
  • 5
    While your answer addresses only testing and testability, that is the single most important issue which some of the other answers completely ignored so +1. – skomisa Apr 11 '18 at 19:19
18

Please explain me, why do we need this DDD style, lots of Patterns?

Many (most...) of us really don't need them. Theoreticians and very advanced, experienced programmers write books about theories and methodologies as the result of lots of research and their deep experience - that doesn't mean that everything they write is applicable to every programmer in their everyday practice.

As a junior developer, it's good to read books such as the one you mentioned to broaden your perspectives, and make you aware of certain issues. It will also save you from getting embarrassed and flummoxed when your senior colleagues use terminology you are unfamiliar with. If you find something very difficult and doesn't seem to make sense or seem useful, don't kill yourself over it - just file it away in your head that there is such a concept or approach.

In your day to day development, unless you are an academic, your job is to find workable, maintainable solutions. If the ideas you find in a book don't help you achieve that goal, then don't worry about it right now, as long as your work is deemed satisfactory.

There may come a time when you'll discover that you can use some of what you read about but didn't quite "get" at first, or maybe not.

Vector
  • 3,180
  • 3
  • 22
  • 25
  • 12
    While on a pure level this is correct it sounds like DDD and other Patterns are just theory. They aren't. They are important tools to achieve readable and maintainable code. – Jens Schauder Apr 11 '18 at 05:47
  • 1
    Are you saying that in your 20 years experience, never has the same solution presented itself to part of a problem? You've always created a completely new solution every time you have two classes interacting with each other? Pretty well everyone uses patterns over and over, the books are only there so we name them the same way when we talk about them. – Pete Kirkham Apr 11 '18 at 10:33
  • 10
    @PeteKirkham the OPs dilemma is the *overuse* of design patterns. Do you really need an `AccountServiceFacadeInjectResolver` (real example I just found in a system at work) - answer is most probably no. – vikingsteve Apr 11 '18 at 12:55
  • 4
    @vikingsteve OP is not a programming guru commenting on the general overuse of design patterns. OP is an apprentice and _thinks_ they are overused _at his shop_. I know that beginner-me would have thought the same about the code I write nowadays, but beginner-me had a lot of personal projects fail because they ended up too convoluted. – R. Schmitz Apr 11 '18 at 15:11
  • @Vector I am a bit baffled by how good those edits were. This went from "seems opinionated" to "100% agree" for me, definitely +1! – R. Schmitz Apr 11 '18 at 15:51
  • @JensSchauder - I have edited the answer in light of your comment. I agree that simply calling it "theory" is usually incorrect. "Methodology" is much more appropriate. – Vector Apr 11 '18 at 16:02
  • @R.Schmitz - I read the comments and realized that my language was not really accurate and my position sounded a bit extreme. – Vector Apr 11 '18 at 16:04
  • 4
    @R.Schmitz That said, beginner me had plenty of personal projects fail because they tried too hard to make things well-designed, organized, structured, OOP... All of these are tools. They need to be understood and used properly, and you can hardly blame the hammer for being poor at screwing. Surprisingly, it seems to take a lot of insight and experience to understand this simple thing :) – Luaan Apr 12 '18 at 09:22
  • 3
    @Luaan If you already cared about well-designed, organized, structured, OOP, I'd hardly call that beginner-you, but yeah overuse is bad. However, the question is more about how OP doesn't really understand which problems those things solve. If you don't know the reason, it seems like there is no reason - but actually, you just don't know it yet. – R. Schmitz Apr 12 '18 at 10:38
  • The weird thing in my experience is I find AccountServiceFacadeInjectResolver type things more often in code NOT using DDD. Spring-based applications seem to be almost entirely classes that have more to do with filling in the framework than with the problem domain. – Rob Crawford Apr 12 '18 at 15:41
8

As your question is covering a lot of ground, with a lot of assumptions, I'll single out the subject of your question:

Why do we need so many classes in design patterns

We do not. There is no generally accepted rule that says that there must be many classes in design patterns.

There are two key guides for deciding where to put code, and how to cut your tasks into different units of code:

  • Cohesion: any unit of code (be it a package, a file, a class or a method) should belong together. I.e., any specific method should have one task, and do that one well. Any class should be responsible for one larger topic (whatever that may be). We want high cohesion.
  • Coupling: any two units of code should depend as little on each other as possible - there should especially be no circular dependencies. We want low coupling.

Why should those two be important?

  • Cohesion: a method that does a lot of things (e.g., an old-fashioned CGI script that does GUI, logic, DB access etc. all in one long mess of code) becomes unwieldy. At the time of writing, it is tempting to just put your train of thought into a long method. This works, it is easy to present and such, and you can be done with it. Trouble arises later: after a few months, you may forget what you did. A line of code at the top might be a few screens away from a line on the bottom; it is easy to forget all details. Any change anywhere in the method may break any amount of behaviours of the complex thing. It will be quite cumbersone to refactor or re-use parts of the method. And so on.
  • Coupling: anytime you change a unit of code, you potentially break all other units that depend on it. In strict languages like Java, you might get hints during compile time (i.e., about parameters, declared exceptions and so on). But many changes are not triggering such (i.e. behavioural changes), and other, more dynamic, languages, have no such possibilities. The higher the coupling, the tougher it gets to change anything, and you might grind to a halt, where a complete re-write is necessary to achieve some goal.

These two aspects are the base "drivers" for any choice of "where to put what" in any programming language, and any paradigm (not only OO). Not everybody is explictly aware of them, and it takes time, often years, to get a really ingrained, automatic feeling on how these influence software.

Obviously, those two concepts do not tell you anything about what to actually do. Some people err on the side of too much, others on the side of too little. Some languages (looking at you here, Java) tend to favour many classes because of the extremely static and pedantic nature of the language itself (this is not a value statement, but it is what it is). This becomes especially noticeable when you compare it to dynamic and more expressive languages, for example Ruby.

Another aspect is that some people subscribe to the agile approach of only writing code that is necessary right now, and to refactor heavily later, when necessary. In this style of development, you would not create an interface when you only have one implementing class. You would simply implement the concrete class. If, later, you need a second class, you would refactor.

Some people simply do not work that way. They create interfaces (or, more generally, abstract base classes) for anything that ever could be used more generally; this leads to a class explosion quickly.

Again, there are arguments for and against, and it does not matter which I, or you, prefer. You will, in your life as software developer, encounter all extremes, from long spaghetti methods, through enlightened, just-big-enough class designs, up to incredibly blown-up class schemes that are much overengineered. As you get more experienced, you will grow more into "architectural" roles, and can start to influence this in the direction you wish to. You will find out a golden middle for yourself, and you will still find that many people will disagree with you, whatever you do.

Hence, keeping an open mind is the most important bit, here, and that would be my primary advice to you, seeing that you seem to be much in pain about the issue, judging by the rest of your question...

AnoE
  • 5,614
  • 1
  • 13
  • 17
7

Experienced coders have learned:

  • Because those smallish programs and clasess start to grow, especially successful ones. That simple patterns that worked at a simple level don't scale.
  • Because it may seem burdensome to have to add/change several artifacts for every add/change but you know what to add and it is easy to do so. 3 minutes of typing beats 3 hours of clever coding.
  • Lots of small classes is not "messy" just because you don't understand why the overhead is actually a good idea
  • Without the domain knowledge added, the 'obvious to me' code is often mysterious to my team mates... plus the future me.
  • Tribal knowledge can make projects incredibly hard to add team members to easily and hard for them to be productive quickly.
  • Naming is one of the two hard problems in computing is still true and lots of classes and methods is often an intense exercise in naming which many find to be a great benefit.
Michael Durrant
  • 13,101
  • 5
  • 34
  • 60
  • 6
    But is the overhead necessary? In many cases that I see, design patterns are overused. The result of overcomplexity are increased difficulty in understanding, maintaining, testing and debugging code. When you have 12 classes and 4 maven modules around one simple service class (a real example I just saw), it quickly becomes less manageable than you might think. – vikingsteve Apr 11 '18 at 12:59
  • 4
    @vikingsteve You keep referring to a single example of a flawed implementation hoping that it will prove that structured code, in general, is a bad idea. That just doesn't track. – MetaFight Apr 11 '18 at 14:56
  • 4
    @MetaFight OP isn't talking about structure code. He's talking about, what he sees as, too many abstractions. If you have too many abstractions, I argue, you quickly get very very unstructured code and a lot of nearly identical pieces, simply because people can't cope with the amount of stuff they have to deal with. – Clearer Apr 12 '18 at 08:58
  • 4
    @Clearer I'm pretty sure everyone here is in agreement that the hypothetical misapplication of structured code is a bad thing. The OP says they're Junior. That's why people are assuming he/she is unfamiliar with the benefits of structured code and reiterating them. – MetaFight Apr 12 '18 at 11:03
2

The answers so far, all of them good, having started with the reasonable assumption that the asker is missing something, which the asker also acknowledges. It's also possible that the asker is basically right, and it's worth discussing how this situation can come about.

Experience and practice are powerful, and if the seniors gained their experience in large, complex projects where the only way to keep things under control is with plenty of EntityTransformationServiceImpl's, then they become fast and comfortable with design patterns and close adherence to DDD. They would be much less effective using a lightweight approach, even for small programs. As the odd one out, you should adapt and it will be a great learning experience.

While adapting though, you should take it as a lesson in the balance between learning a single approach deeply, to the point you can make it work anywhere, versus staying versatile and knowing what tools are available without necessarily being an expert with any of them. There are advantages to both and both are needed in the world.

Josh Rumbut
  • 197
  • 1
  • 4
1

Since my initial post of this answer didn't accomplish what I wanted, I purchased the for-Kindle version of this book, and found exactly what I vaguely remembered, in order to directly answer the question

Why do we need so many classes in design patterns?

Short and sweet -- we don't. Exactly why that is true I'm not sure that I can put into words as well as this book, and that was the gist of my initially posted answer.

What follows are excerpts from the book that speak well directly to the question.

This excerpt from the book is from Chapter 3 "Patterns" and sub-chapter 3 "There Are Many Ways to Implement a Pattern":

In this book, you’ll find pattern implementations that look quite different from their Structure diagrams in Design Patterns. For example, here’s the Structure diagram for the Composite pattern:

Structure diagram for the Composite pattern

And here is a particular implementation of the Composite pattern:

A minimalistic implementation of the Composite pattern

As you can see, this implementation of Composite bears little resemblance to the Structure diagram for Composite. It is a minimalistic Composite implementation that resulted from coding only what was necessary.

Being minimalistic in your pattern implementations is part of the practice of evolutionary design. In many cases, a non-patterns-based implementation may need to evolve to include a pattern. In that case, you can refactor the design to a simple pattern implementation. I use this approach throughout this book.

Slightly earlier in the sub-chapter, Joshua says this:

This diagram indicates that the Creator and Product classes are abstract, while the ConcreteCreator and ConcreteProduct classes are concrete. Is this the only way to implement the Factory Method pattern? By no means! In fact, the authors of Design Patterns go to great pains to explain different ways to implement each pattern in a section called Implementation Notes. If you read the implementation notes for the Factory Method pattern, you’ll find that there are plenty of ways to implement a Factory Method.

Here is that whole section, which goes into just a little more detail:

Page screen shot from the Joshua Kerievsky book "Refactoring to Patterns" Kindle Edition, 13%, Location 1134 of 9053


[ORIGINAL POST]

I would like to point you to a book that I think answers your question with more of a heuristic sense of when it's necessary, and when it's overkill, to "use so many classes" in design patterns, as this author often implements a design pattern very frugally, with just a few object-oriented "parts".

enter image description here

This book is one of the Martin Fowler Signature Series, and is an excellent book on Design Patterns by Joshua Kerievsky, entitled "Refactoring To Patterns", but it is really about "Right-Factoring" to and/or away from patterns. It was well-worth the price, to me.

In his book, he sometimes implemented patterns without using object orientation, and instead used a few fields and a few methods, for example. And he sometimes removed a pattern altogether because it was overkill. So I loved his treatment of the subject because the "balance" of when to pattern, and when to go more lightweight, was a gift he imparted to the reader.

Here is a screen shot of the most relevant part of the table of contents. It was one of my best purchases.

Table of Contents Screenshot of Book Refactoring To Patterns by Joshua Kerievsky

And out of this table of contents, I especially emphasize the following:

  • And I emphasize the following:
  • Over-Engineering
  • The Patterns Panacea
  • Under-Engineering
  • Human-Readable Code
  • Keeping it Clean
  • Patterns Happy
  • There Are Many Ways to Implement a Pattern
  • Refactoring to, towards, and away from Patterns
  • Do Patterns Make Code More Complex?
  • Code Smells

So, I think your question can be paraphrased as an internal sense of questioning "Do we really have to use so many classes to implement patterns?" and the answer is "sometimes", and of course, the seemingly ever-present "it-depends". But it takes more of a book to answer you, so I am recommending that you get this one if you can. (I don't actually have it with me at the moment, otherwise I would give you a good example from it -- sorry.) HTH.

  • So basically, your answer is "read this book and you will get it". How reading a book about refactoring (which has nothing to do with DDD) can help OP to understand "Why LoC is a horrible indicator to measure the cost of maintenance? Or when and why DDD is needed and what are the trade-offs" – Laiv Jan 02 '20 at 08:16
  • @Laiv - Sorry that I couldn't put my recollections into words for the initial post. I prepended the information that I really wanted to originally post. And yes, I stick to my guns, and claim that this answer really does answer the question, "Why do we need so many classes in design patterns?" I hope you agree, but at the very least, I DID put some effort into trying to answer. If you still don't agree, would you please add your own answer? Thanks. – MicroservicesOnDDD Jan 10 '20 at 23:58
-4

Making more class and function as per use will be a great approach to resolve problems in a specific manner that help in future to resolve any issues.

Multiple classes help to identify as their basic work and any class can be called at any time.

However if you many class and functions from their getable name they are in easy to call and manage. This is called a clean code.

  • 10
    Sorry, but what are you saying? – Deduplicator Apr 13 '18 at 15:18
  • @Deduplicator let's take an example in java if we design we used jframes threads and classes for their inheritance. From only one class we can't able to use some works of java for design so we need to make more classes – Sanjeev Chauhan Apr 13 '18 at 15:22
  • 3
    This answer needs to present the idea(s) that it's purporting to present in clearer English. It seems like that the core idea in the answer is that smaller classes, each with one well-defined functionality, is a good idea, but the terrible grammar makes it almost impossible to understand. Also, by itself, this assertion may not be enough. – talonx Apr 16 '18 at 08:39