Every code base requires maintenance over time. Requirements are altered, bugs are found, features are added, optimizations are required… It never ends.

When a change is needed, it’s much easier to handle when all the required knowledge is in a single place. This is why DRY (Do not repeat yourself) is a fundamental rule we wish to follow.

WETness (write everything twice) should be detected and handled early on, before it leads to project rot.

Some duplications may feel unavoidable, baked into the project requirements or the team behavior. Automation and discipline can reduce this evilness drastically.

At this post, I’ll describe some common duplications sources.


Representing the same information in different forms

An example would be to represent the same model in different parts of the system.

I.e. a User data structure is needed at the client (written with TS/JS) and at the server (written in Java).

We can avoid such duplication by using generators. Writing the data structure once in a general form, and compile it to different languages. Google’s protobuf is an example for such code generator.

Another example would be system documentation, which is by definition a duplication. We represent the system behavior in 2 forms - one is code, and the other is human language.

Even when docs are required be separated from the codebase, it doesn’t mean it must be WET. Just like code, docs can be auto generated too.

Take Angular’s compodoc for example, which generates HTML docs from the codebase JsDoc & README files.


Code inline comments

Some developers feel (or are forced to) they should add comments to the code, explaining its behavior.

I disagree.

Clean code is easy to understand. Bad code needs explaining.

Such WETness can be reduces by properly naming variables and methods.

If a developer can’t easily follow the code and its underling logic, its a strong code smell.


Un-normalized representations

Some duplications comes form data that is dependent on one another. For example

class Circle {
  radius: number;
  diameter: number;
  circumference: number;
}

Obviously diameter and circumference can be derived from the radius, so it can be normalized:

class Circle {
  radius: number;

  diameter() {
    return 2 * this.radius;
  }

  circumference() {
    return Math.Pi * this.diameter();
  }
}

Such normalization does come with a price.

In the above example the diameter circumference are recalculated every time we access it. Later on, and only if needed, we may choose to violate the DRY rule in the name of optimization.


WET design

WET design may be hard to spot sometimes, it’s the bigger brother of the normalization issue we described above.

Consider a system that manages a medical clinics:

class Clinic {
  doctors: Doctor[];
  patients: Patient[];
}

class Doctor {
  patients: Patient[];
}

class Patient {
  doctor: Doctor[];
}

Do we really need to keep track each Doctor patients and each patient doctors?

A DRYer design would represent this relation in a single place. Something like:

class DoctorPatient {
  doctor: Doctor;
  patient: Patient;
}

class Clinic {
  doctors: Doctor[]
}

class Doctor {}

class Patient {}

WET by deadline

We all face this issue at some point. We need a quick and dirty solution ASAP.

So we copy-paste the closest working solution we have, apply some minor changes and ship it away.

Such compromises are fine, but must be tracked.

Leave a TODO, create a tech debt task, anything that would make sure a refactoring would find it’s way to your pipeline.


WET by miscommunication

The worst type of WETness are duplications created without you even knowing it. This happens when two developers create the same logic in two places without even being aware of it.

Finding those issues early (at a code review, or even better, a daily meeting) is the key. Strong project management, collaboration and open communication would help catch such issues early on.


Make no mistake, duplication is an evil. It doubles the effort and reduces the value.

On the long run, a WET project would drown in maintenance tasks, risking team frustration and business failure.

DRY discipline would minimize that risk.