DEV Community

Cover image for Expressive code > Clean code
Dušan Perković
Dušan Perković

Posted on

Expressive code > Clean code

When people say "clean code", they usually mean "code that's easy to read." I know that the full definition is closer to "code that's easy to read, maintain, understand and change", but people usually get stuck at that first part.

As a result, "easy to read" usually ends up meaning "small files with only a few lines of code", since developers associate big files with a lot of complexity (and rightfully so). Getting away from this complexity is not as easy as it seems, and is not always the right thing to do.

Reducing complexity vs hiding complexity

Image description

Reducing complexity is a good thing. It means you are actually scaling down the complexity of your app. This can include removing some tech debt, or relying on a third-party library to solve your problem, instead of having a bunch of custom code you have to maintain yourself. Reducing complexity basically means you and your co-workers have less of your own code to worry about.

Hiding complexity is what usually happens. Big files do not look aesthetically pleasing to us, so we come up with excuses and abstractions based on personal feelings. We start moving things away from each other, that logically belong together, and as a result make the code less expressive, harder to understand and more difficult to maintain.

Do not be afraid of big files. If the feature you are building is a complex one, the code should reflect that.

Abstraction always increases complexity

Even though it might make the codebase "look" smaller, it is actually more complex. Think about what you are doing when you abstract things: you are moving a piece of code away from where it is needed. So now, to understand the full picture of what's going on inside your component, you need to jump back-and-forth between the abstracted piece of code, and the rest of your component, to understand how they work together.

To be clear: I am not saying that abstraction is always bad, and that you should inline everything. I am saying that you should be very careful with it, when you do it, and for what reason.

Expressive code is easier to maintain

Here's an example using Tailwind, taken from this blog post:

<figure class="md:flex bg-gray-100 rounded-xl p-8 md:p-0">
  <img class="w-32 h-32 md:w-48 md:h-auto md:rounded-none rounded-full mx-auto" src="/sarah-dayan.jpg" alt="" width="384" height="512">
  <div class="pt-6 md:p-8 text-center md:text-left space-y-4">
    <blockquote>
      <p class="text-lg font-semibold">
        “Tailwind CSS is the only framework that I've seen scale
        on large teams. It’s easy to customize, adapts to any design,
        and the build size is tiny.”
      </p>
    </blockquote>
    <figcaption class="font-medium">
      <div class="text-indigo-600">
        Sarah Dayan
      </div>
      <div class="text-gray-500">
        Staff Engineer, Algolia
      </div>
    </figcaption>
  </div>
</figure>
Enter fullscreen mode Exit fullscreen mode

You might say:

Look at all those classes! That's too much, man.

But you only need to understand how tailwind works, to understand what's happening with this component.

If we want to change how this component looks, we just need to add/remove the corresponding class, and everything is done. Even though there's a lot of it, the code is easy to understand, maintain and extend, even for someone new to the codebase.

We can also try to abstract these classes to individual CSS selectors, and make the HTML "look pretty", and move all the classes to a separate scss file that looks like this:

figure {
    @extend .bg-gray-100;
    @extend .rounded-xl;
    @extend .p-8;
    @extend .md\:flex;
    @extend .md\:p-0;
    img {
        @extend .w-32;
        @extend .h-32;
        @extend .rounded-full;
        @extend .mx-auto;
        @extend .md\:w-48;
        @extend .md\:h-auto;
        @extend .md\:rounded-none;
    }
    & > div {
        @extend .pt-6;
        @extend .text-center;
        @extend .space-y-4;
        @extend .md\:p-8;
        @extend .md\:text-left;
        blockquote p {
            @extend .text-lg;
            @extend .font-semibold;
        }
        figcaption {
            @extend .font-medium;
        div.name {
                @extend .text-indigo-600;
            }
        div.work-role {
                @extend .text-gray-500;
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

And change the HTML to this:

<figure>
  <img src="img/175062.png" alt="" width="384" height="512">
  <div>
    <blockquote>
      <p>
        “Tailwind CSS is the only framework that I've seen scale
        on large teams. It’s easy to customize, adapts to any design,
        and the build size is tiny.”
      </p>
    </blockquote>
    <figcaption>
      <div class="name">
        Sarah Dayan
      </div>
      <div class="work-role">
        Staff Engineer, Algolia
      </div>
    </figcaption>
  </div>
</figure>
Enter fullscreen mode Exit fullscreen mode

But this makes it harder to understand the component:

  • The styling of each tag has been moved away from it, so you have to look through the scss selector to understand what affects what.
  • Extending this code is more difficult, because it has to be done in multiple places. And you have to be careful of styles from other selectors impacting each other.
  • Maintaining the code is more difficult as well, because you need to make sure you're not deleting/changing the wrong thing in each of the files.

Maintainable > Aesthetic

At the end of the day, we are building products, not competing for the worlds most visually pleasing component. Coding is not the end goal - it's a means to an end. The code that you write has to be maintained and extended by you and your colleagues. Be expressive with what you write, and don't make things more complicated then they have to be.

Further reading:
The Grug Brained Developer

Top comments (0)