DRY is to avoid redundancies, right?

Asked

Viewed 4,577 times

90

The DRY means Don’t Repeat Yourself. So every time I see a repeat in the code I’m not doing DRY? Is DRY about not having redundancies? How it should be applied?

  • 2

    I decided to post this pair of question and answer because the question already asked on the subject was broad and had answers that did not fully answer what was asked and done in a very bureaucratic way and that I found wrong on some points. http://answall.com/q/23052/101

2 answers

76


Redundancy X Don’t Repeat Yourself

This is repetition:

valorDoProdutoComprado = valorDoProdutoComprado + 1

In many languages it could be so:

valorDoProdutoComprado++

That’s dry?

This:

meuObjeto.propriedade1 = 0
meuObjeto.propriedade2 = ""
meuObjeto.propriedade3 = true

In some languages it could be written like this:

with meuObjeto
    .propriedade1 = 0
    .propriedade2 = ""
    .propriedade3 = true

Now I did dry?

Well, redundancy is bad? So the below is great?

if valor == 0
    fazALgumaCoisa()
fazOutraCoisa()

Or redundancy can help?

if valor == 0 {
    fazALgumaCoisa();
}
fazOutraCoisa();

This:

UmaClasse obj = new UmaClasse();

It’s the same as this without the redundancy/repetition?

var obj = new UmaClasse()

Note that the former imposes a contract for the variable, it needs to be of that type. The second indicates that the type does not matter and what is assigned to the variable is good. There is semantic difference although the result may be the same.

Repeating or redundancy code is not the problem, of course there are undesirable redundancies:

if ok == true

And there are troublesome redundancies, these are the ones to be observed for DRY.

If you make a simple or complex code that will only be used once, obviously you will not be violating DRY, right?

It’s not that simple. This is strictly true, until one day someone needs it somewhere else and what was unique ceases to be, only who needed it didn’t know it was already ready in one place. You have to think about the extensibility to do DRY.

Take this code (does nothing else with z, but could one day do):

z = x + y
print z

and

print x + y

Which is more DRY?

There are controversies.

Formal definition

To "official information" than is DRY is:

Each piece of knowledge must have a unique, unambiguous and definitive representation within the system.

DRY has to do with canonicality. You cannot have the same information in more than one place of the application or even the solution as a whole.

DRY is about having a rule in one place (canon). Imagine that you put the rule in two places (remembering that codes are rules that the programmer establishes for the computer to run). At some point you need to change the rule, will you remember/know you need to change in both? Change will keep you both doing the same thing?

Canonicality can occur within a function, within a module (class, for example), within an application (an executable, for example) or a solution, including parts that are not code (documentation, for example).

Have a single point of change of a fact is paramount to facilitate maintenance.

The best debate on the subject (Although they cling to silly things like having the C function prototype be anti-DRY or not) is probably on Wiki C2. I particularly highlight the introduction:

Duplication (whether accidental or purposeful) can lead to maintenance nightmares, as well as hinder refactoring and generate logical contradictions.

Duplication and the possibility of contradictions can arise anywhere: in architecture, in requirements, code or documentation. The effects can range from code implementation failures, to developer confusion; to complete system failure.

It can be argued that the greatest difficulty in remedying the Year 2000 problem came from the lack of a simple abstraction of dates within a system; knowledge of the dates and their treatment were spread over many parts.

How to make the code more canonical

Many will think of the canonicality within the function as a way to eliminate repetition, but that’s not it, it’s about the rule. Almost always an excerpt of code can only be canonical creating a new function with this code properly prepared to work in any situation. This code will only respond to the rule in the simplest possible way, keeping, of course, the sole responsibility.

Where this role will be posed is an important issue as well:

  • It may be within the function that will use it (if the language allows);
  • within the same class;
  • same package (no matter how the language works with packages);
  • same executable/script;
  • may even be accessible externally by a webservice, for example.

The rule can be as simple as taking a value from a global variable/constant, or making complex calculations by taking data from a db or a website.

Abstraction

This is also about abstraction. You might wonder that if it’s to take a global variable, why don’t I just take the variable instead of creating an extra layer? Depends on the situation, if the rule is catch this specific variable, no need to do anything else, is already canonical. If this variable is an implementation detail, then the rule is to take information, and where it comes from is detail, then it needs an abstraction to leave canonical.

When you use a function pegaEndereçoPeloCep("01234-567) it does not matter if the query is made in a database, on the Post Office website or elsewhere. If you do not have a function for it becomes easy to lose canonicality.

In almost all the legacy codes I’ve worked on and most of the question codes here at Sopt that have more than a very short snippet I see things like:

valorDescontado = valorTotal * (desconto / 100)

Simple, right? This will be spreading all over the code, or for C V or for being so intuitive that it creates in the hand. What if the form of the discount changes? If you have a new condition? If the discount value is picked up from a table? If for some reason it is no longer a simple percentage?

Tools

The most obvious tool for making code more DRY is the function. OOP, services (web, banks with stored procedures, etc.) are others. Data dictionary and techniques of scaffolding also help avoid having redundant code, especially in different technologies.

Use tools to duplicate code automatically nay violates DRY. We are not talking about short code but code with good maintainability.

This is one of the reasons many people prefer to have code in stored Procedure. That’s one way to give canonicality for a multi-application solution. There are other solutions that get the same better, but that’s another matter.

Specific techniques

MVC is today an excessively employed technique that "encourages" to violate DRY. Part of the violation occurs due to lack of understanding of the MVC and not knowing where to place each information. Part is the lack of knowledge of how to solve real problems that cause duplication. Poorly employed MVC causes more problems than solutions, but one thinks that doing the same as everyone else is doing is not wrong. It makes me want to cry seeing the Mvcs around.

If you want to create more than one point of change, don’t do MVC!

There are cases where the problem requires a certain flexibility, allowing the application to have different behaviors. No problem with DRY. Design standards can be applied so that flexibility is achieved without having the same rule in different locations. Having multiple rules is no problem, having the same one in two different places is the problem.

You know that thing about not using magic numbers? That’s dry.

Normalization is a form of DRY.

Redundancies that make the code better do not violate DRY.

That’s why I use data dictionaries extended form (not only in classical definition) for many years. In the dictionary of the application I have all the facts of the application in one place. By changing there, I’m changing everything I need. Depending on the technology used, even the code may be in this dictionary, but in most languages it is not possible to do this. There are specific techniques to link the facts with the code.

As always, of course it is not to use certain techniques in certain types of application.

DRY solves what?

Some may still be thinking that DRY is to reduce typing. Or at least gain maintenance time. It’s even in the latter case, but not because it has less code on its own (though less code always helps something). The reduction in maintenance time is not having to hunt for redundancies, peacefully make a change knowing that everything will remain consistent, without having to fix mistakes that you don’t even imagine will happen when something changes.

DRY requires that any code information be unique. DRY creates an authoritative source of how a behavior should be.

Done correctly increases cohesion and decreases coupling. Done wrong...

DRY helps to have unique responsibility. Trying to stack things together in a function just to avoid repetition only worsens the SRP. That is why it is important to distinguish DRY from repeat elimination.

DRY specifically prevents maintenance nightmares. More abstractly it requires the programmer to think about what he’s doing, because he’s putting that code there and can do otherwise for future use. DRY is planning.

Exaggerations

It is obvious that there may be exaggerations. Today it is very common to make layered applications, including using very heterogeneous technologies.

A typical example is the web application. We often use more than one language in this type of environment. If you have Java on one side and Javascript on the other, probably at least the same validations will have to be in two places, since you need two languages. Some solutions I see around: "we will do everything in JS, so you can enjoy everything", or "all validations will be done on the server".

It’s the same problem when one thinks the solution is to throw everything in the database. Unless she’s thinking of a data dictionary and knows what she’s doing (which needs code in the application for its perfect realization), it doesn’t usually work as well as expected, exaggerating access to the database.

This is a case to use tools that do conversions or generations of code, or accept that some duplication will have to exist in a very well documented way.

You also have to watch out for the wrong abstractions. One of the reasons you wrote this is that many people will want to use DRY to avoid repetition. There is intentional, conscious repetition. This occurs when concepts are different but momentarily use the same code (even if it lasts forever). Do not use DRY in these cases, you will have problems in the future.

DRY can make the code worse

Care must also be taken not to create a repeat to eliminate another. Or to worsen readability on behalf of DRY. It is rare, but it is possible to make the code worse by doing DRY.

DRY can bring complexity to some codes when in exaggeration, but often complexity actually occurs by complex requirements or by the joint use of other techniques that make code overly complex. That’s why I usually prefer DRY if it conflicts with another principle. Repeating yourself to simplify is not usually the solution. If the code would be too complex, automate the repetition and is doing DRY.

Needless to say, one can exaggerate when creating variables where one does not need them, as shown in the last example of the initial section of this answer. Will not, for example, create a variable $p = "<p>" to use in mounting an HTML text instead of the direct literal.

If one code is coincidentally the same, but has no relation to another, do not apply DRY. Projects will have new requirements. Think how this will be affected when doing DRY. In most cases there will be gain, but not always.

Besides this abstractions that produce side effects are very bad. Something to be avoided, not to say forbidden.

And there are cases where trying to do DRY can reduce readability in such a way that it does not compensate for its use. An abstraction hides the real mechanism, it is rare, but it is not always what we want.

And remember the KISS. What is simple depends on context. Simple is not always the shortest, least repeated, but often is. So don’t create an abstraction for free.

Comments and other software points

According to proponents DRY is not only about the code, it is also about the database, tests, documentation, including comments.

What is the point of letting the entire canonical code and other parts allow a break because they are not synchronized.

Some people consider the comments as one of the worst ways to violate DRY. In fact depending on the comment is really bad, I do not know if so bad, because it does not affect the code, but can induce the programmer to error. One of the causes of the jocose use of the term WET (Write Everything Twice).

The database must be handled by the solution as a whole automatically.

The builds and even the deploies should be automated and provide parts of the solution that are purposely missing during development to avoid repetition.

Don’t overdo the documentation, but what you do can’t go out of sync with real code. How to do this automatically?

Completion or TL; late RD

DRY is about having a unique way of treating certain action in a software solution. It is to have in one place all the knowledge you need on a very specific subject of the solution. Even if this site depends on other things.

It is reductionism to say that DRY is to avoid duplication of code.

My opinion is that DRY is the most important principle of computing. If the programmer follows it correctly, no matter the tool, the paradigm, the technology, the methodology he uses, it will already be strongly on the right track. If you make a mistake, you can choose whatever you want, you have garbage on your hands. It’s not OOP, Java, Agile, MVC, Patterns design, layers, etc. that will save you. I see a lot of people avoid DRY in the name of other things that bring much less advantage.

Besides the technique when writing code, it needs automation, automation, automation.

Of course it is not a panacea, it does not cure all ills, it does not dispense with other techniques and doing right is not always easy or possible. If it becomes religious dogma, as often happens with a lot of computing, it can have the opposite effect. Be careful not to turn it into "good practice".

I am a radical proponent of DRY and still do not do at all.

  • 9

    "If one code is coincidentally the same, but has no relation to another, do not apply DRY.". For me this is the hardest point to hit. People end up abstracting classes or creating functions to encapsulate the behavior of two components that at first are similar but evolve separately.

  • 2

    "Note that the former imposes a contract for the variable, it needs to be of that type. The second indicates that the type does not matter and what is assigned to the variable is good. There is semantic difference even if the result is the same." It depends... i) A contract that is met on the same code line seems to me a half useless contract; ii) Modern ides and refactoring tools will alter the two sides of the assignment; iii) var the way it is present in static languages like Scala, Kotlin, C# does not have the semantic difference cited: the variable is, in fact, the same type of expression.

  • 1

    i) you can have whatever opinion you want, but everyone who likes readable codes knows when to spell out a contract. ii) There may be a cascade of modifications including the public API that would break it; iii) var avoids only redrafting, whether it is DRY or not, depends on how it is being used, and again depends on whether the contract needs to be made explicit or not. When to use var is giving a semantics to the code. Reinforcement that DRY is not about redundancy, it’s about semantics. See also: https://answall.com/q/47383/101

  • 2

    Despite the useful references presented, it became strange to start the article with so many examples that have nothing to do with what was asked. I suggest leaving only the most textual part.

  • 1

    @I think you’re wrong even :D I’ll see better before changing

  • Unfortunately when it comes to front-end often use DRY is a shot in the foot, want to reuse css, html, jsp, if not with a good framework (angular, React, etc.), only causes problems, trying to achieve DRY many fall into the sin of excessive use of Templates, too many variables and javascript functions. Finally, it is often better to copy and paste.

Show 1 more comment

9

Look, DRY is a philosophical principle about avoiding duplication of logic here and there. There are many discussions on what is duplication or not and how far it is worthwhile to avoid duplication, including. You can’t take an extremist stance like "now I’m DRY". It’s always good to analyze your context and possibilities.

To apply this principle and philosophy consistently and consciously, it is necessary to be master in other subjects, such as:

  1. Structured Programming
  2. Aspect Oriented Programming
  3. Component Oriented Programming
  4. Domain Driven Design
  5. Design Patterns

These are strategies for you to use and eliminate code redundancy. Well, a simple creation of subroutines also helps a lot.

Then you ask, how to apply?

  1. Develop critical sense. Every time you complete the development of an activity, ask yourself, "How can I improve what I’ve done?" Then you analyze everything you’ve done and eliminate redundancies.

  2. Do conceptual review, continuously. To understand how to avoid redundancies, you need to know how to do the elimination of redundancy itself. For example, how to avoid redundancy by applying Design Patterns? See that Design Patterns has 3 subgroups of patterns. Creation patterns, structural and behavioral patterns. There are 23 patterns in total. Can your code get any simpler if you change its structure? I am sure that at least 3 standards can be applied in a tacit, daily and routine way. In my heart, they are:

    1 Template Method
    2 Strategy
    3 Facade
    4 Decorator
    5 Factory Method
    6 Visitor

Today, I can look at a situation and tell you what pattern I can solve it with. But until I reached that level, I had to criticize my designs and provoke changes by applying standards.

  1. Embark on the world of code refactoring. There is a lot of literature on refactoring. And giving a read on refactoring will throw you into the experience of improvement practices. Martin Fowler may be his first reference. He coauthor of books like Refactoring to Patterns and Refactoring: Improving the Design of Existing Code. Well, there are other authors for you to learn and the more you have access to different people giving different views on the same subject the better.

  2. Use some refactoring tool. Usually they point to duplication of code, mischief and carelessness. For example, Resharper is very powerful.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.