A key principle that must be taken into account when developing this system or making use of it.
Overview
Don't repeat yourself (DRY) is a principle that states that all code should be reduced and abstracted as much as possible to avoid repetition of patterns and redundancy.
Adding additional, unnecessary code to a codebase increases the amount of work required to extend and maintain the software in the future. Duplicate code adds to technical debt. Whether the duplication stems from copy/paste programming or poor understanding of how to apply abstraction, it decreases the quality of the code.
Benefits of DRY
- Maintainability: If we have a chunk of code that executes the same action repeated all over your project, the moment you need to update this action you have to go all over it to check where this logic is applied and update it, while it could be done once had it been correctly implemented following the DRY principle.
- Readability: DRY code tends to be more readable and easily understandable not by the principle itself, but because of the indirect benefit of thinking thouroughly your code when writing it and making it compliant with the principle.
- Reuse: DRY promotes the reuse of code due to its merging nature, increasing the development speed in the long run.
- Cost: Less code written is less code to maintain, easier to maintain code is cheaper.
WET
On the other hand, WET stands for "Write Everything Twice", and it's the definition of DRY violations or badly optimized code that has unelegant solutions. We should try to avoid this.
Nevertheless, we have to be cautious when merging our code, as sometimes a piece of code can look similar, but have subtle differences or a different path for growing in the future. Also, we have to be careful not to "overdry" or code as to make it difficult to read or understand.
Examples
SCSS Examples
We use SCSS in conjunction with BEM in order to dry up our CSS code and make it more maintable and understandable. Following BEM practices along with SCSS we can easily create and maintain our code-shared components.
.box {
padding: 16px;
width: 500px;
background-color: grey;
&__header {
margin: -16px -16px 0;
padding: 8px 16px;
background-color: olive;
}
&__title {
margin: 0;
}
&__footer {
font-size: 12px;
text-align: center;
}
}
.box {
padding: 16px;
width: 500px;
background-color: grey;
}
.box__header {
margin: -16px -16px 0;
padding: 8px 16px;
background-color: olive;
}
.box__title {
margin: 0;
}
.box__footer {
font-size: 12px;
text-align: center;
}
This is a very simple example, but when elements get more complex, keeping this syntax really helps understanding and reusing the code.
When some elements share certain CSS parameters, SCSS brings us a functionality specially created for this purpose: placeholders.
%anim-base {
.icon {
backface-visibility: hidden;
perspective: 1000px;
transform-origin: 50% 50%;
}
}
.u-anim--shake {
@extend %anim-base;
&:hover,
&:focus {
.icon {
animation: shake 300ms ease-in-out 300ms 1;
}
}
}
.u-anim--shake .icon {
backface-visibility: hidden;
perspective: 1000px;
transform-origin: 50% 50%;
}
.u-anim--shake:hover .icon, .u-anim--shake:focus .icon {
animation: shake 300ms ease-in-out 300ms 1;
}
Profiting the
%anim-base
placeholder, we could create any further iterations of the animation as we want, reusing the base parameters that define the class.
There's also the SCSS mixins functionality, they can be used to encapsulate styles that can be dropped into a single style rule.
@mixin btn($color) {
padding: 16px;
background-color: $color;
border-radius: 50%;
}
.button--blue {
@include btn(blue)
}
.button--red {
@include btn(red)
}
.button--blue {
padding: 16px;
background-color: blue;
border-radius: 50%;
}
.button--red {
padding: 16px;
background-color: red;
border-radius: 50%;
}
Another way we can abstract functionality with SCSS is through the use of
functions
.
@function main-or-white($color) {
@if ($color != #fff) {
@return #fff;
} @else {
@return #000;
}
}
.badge--green {
color: main-or-white(green);
}
.badge--white {
color: main-or-white(white);
}
.badge--green {
color: #fff;
}
.badge--white {
color: #000;
}
JS Examples
As we have done with our SCSS code, we can abstract chunks of logic in our JS code, and turn it into functions that we can import and use in different pages or components.
Following the Atomic Design principles in our Design System, it's easy to abstract and dry some of the behaviours in our JS codebase. For example, the
tag-group
component makes use of another component:
autocomplete
, in order to achieve his own functionality. Instead of rewriting the code for that input, we reuse the
autocomplete
atom, to create a
tag-group
molecule.
import AutoComplete from '../v1/01-atoms/autocomplete';