DEV Community

Top 10 Object-Oriented Design Principles for writing Clean Code

javinpaul on July 31, 2019

Disclosure: This post includes affiliate links; I may receive compensation if you purchase products or services from the different links provided i...
Collapse
 
mindplay profile image
Rasmus Schultz

Why are we still teaching new devs that DRY is #1 ?

DRY is an outdated and dogmatic principle - it really should be the #1 principle on the "most harmful" list.

Much has been written on this in the past year or so - most recently this:

kentcdodds.com/blog/aha-programming

This subject is so much more nuanced than simply "don't repeat", which leads every new developer directly into highly coupled code full of accidental dependencies.

We need to start teaching this principle more responsibly - which also means, we need to stop teaching this as the number one rule.

Collapse
 
javinpaul profile image
javinpaul

Hello @Rasmas, you may be right but for the most part "duplicate code" has been evil in coding, at least that's what I have learned. DRY is a reminder to address that duplication, but it's not just code but also the functionality. Having the same functionality at two places makes it hard to maintain.

Collapse
 
mindplay profile image
Rasmus Schultz

Having the same functionality at two places makes it hard to maintain.

That depends.

You can have similar (even identical) code in two different places for different reasons - for example, new devs often conflate input validation with domain validation, because these are often similar in terms of code, but they're done for very different reasons.

Having similar (or identical) code at two places, in this case, makes the codebase easier to maintain, because you can change one without affecting the other.

Real-world example: validation of an address form on the checkout page of an e-commerce page - versus validation of an address form on an admin-only page on the back-end of the same system.

Even if these input validations are 90% similar today, there's a very real risk of one needing to change independently of the other. If there's a complex aspect to these validations, say, validating a street address via an API, that concern can be factored to a common service - but the validation itself (in this case electing to use said service or not) is probably simple and easy enough to maintain, so there's no good reason to mix these validation concerns; eliminating similar (even identical) code in this case creates a liability.

Conflating unrelated responsibilities, even if it eliminates similar/identical code, can make a project harder to maintain.

DRY is harmful dogma that teaches new developers to view complexity as a function of the number of lines of code - that the objective is always to have as few lines of code as possible. Nowhere does it say, "unless that makes the software harder to maintain".

Duplication isn't duplication unless it's duplicating the same responsibility.

DRY is harmful that way, and I really think we need to teach a more nuanced approach.

Collapse
 
engrumair profile image
Umair

I understand that people sometimes overdo or apply things in the wrong places or without context but it does not mean that the said principle is wrong. It is understood wrong.
One can say, don't teache 'Classes' because then they will make too many classes. Or don't teach inheritance they will fall into the trap of class explosions.

Knowledge is different than competency. Knowledge is when one knows about the DRY (more than half of the developers)and competency is when to apply the DRY (Hardly anyone knows).

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
bennyflint profile image
Benjamin Flint • Edited

Good info. However, you are conflating dependency injection and dependency inversion (aka Inversion of Control). They are related, but definitely not the same thing. It would be worth it to clarify, as this is the SOLID principle that, in my experience, is the least followed (perhaps excepting interface segregation).

Collapse
 
melston profile image
Mark Elston

I saw this right away, as well. While other elements of the article are pretty good (or close enough) this one, IMHO, misses the mark entirely. Dependency Injection and Dependency Inversion are only tangentially related. Uncle Bob had a really good explanation of this principle (I think he coined the term).

I agree that this is probably the most overlooked (or misunderstood) principle in the list.

Collapse
 
mindplay profile image
Rasmus Schultz

Dependency injection is not only the last followed principle, it also should be the #1 principle - I've seen the code style and quality of an entire team improve substantially after teaching them DI, IOC and how DI containers work.

So many OO concepts fall into place once you really understand this :-)

Collapse
 
wangvnn profile image
wangvnn • Edited

Alan Kay once said that he did not foresee any things like these with OO. That does not mean DI, IOC are not good. Maybe we just need to call it something else like dependency driven design rather than calling its OO principles. OO is too far from Alan's original idea and land to a place where we deal with classes and their dependencies rather than objects themselves. I am just wondering.

Thread Thread
 
Sloan, the sloth mascot
Comment deleted
 
javinpaul profile image
javinpaul

Sorry, didn't know that Yuma is your dog :-) Well, yes, Head First Design Pattern can be best enjoyed when you are new to the subject matter, I first read it 14 years back when I didn't know anything about design patterns, composition, inheritance etc, except definitions. That book taught me how these concepts can help you write code which is flexible and easier to maintain.

Collapse
 
javinpaul profile image
javinpaul

You are correct, area() is a wrong choice because ultimately it will return the same value. The actual point is that you cannot pass Square object to methods expecting Rectangle and you are also correct in width and height behavior.

One more example of LSP is java.sql.Date which violates the Liskov substitution principle, because even though java.sql.Date extends java.util.Date, you cannot pass around it to the method which expects java.util.Date because all time-related methods e.g. getHour(), getMinute() and getSeconds() method throws java.util.NotSupportedException.

Collapse
 
joesta profile image
Joesta Sebolela

I have almost forgotten to use this principles (at least not completely). I should start being pragmatic and use them in many cases. Thanks a lot.

Collapse
 
javinpaul profile image
javinpaul

It's never too late to write clean code :-)

Collapse
 
w3bist profile image
Webist

You might be interested in M.O.M.

webist.eu/articles/software-develo...

Collapse
 
javinpaul profile image
javinpaul

Hello Yuma, it's definitely a classic, more like a reference book. Though, I enjoyed Head First Design Pattern more.

Collapse
 
klk profile image
Klk • Edited

It's obvious your heart's in the right place but you're examples aren't entirely correct; fix your explanation of dependency inversion & LSP as noted by other commentors.

Collapse
 
javinpaul profile image
javinpaul

Thanks @klk , I am taking notes.

Collapse
 
darkoverlordofdata profile image
Bruce Davidson

This is what, marketing cleverly embedded in stale advice? What kind of kickback are you getting on this courseware?