DEV Community

Cover image for Preaching 'Clean Code' is Lowering the Quality of Developers
Jon Randy πŸŽ–οΈ
Jon Randy πŸŽ–οΈ

Posted on • Edited on

Preaching 'Clean Code' is Lowering the Quality of Developers

Okay - first things first... I am in no way anti clean code, and I'm not saying it is necessarily a bad thing.

However... in recent years it seems to be becoming more like a religion - with overzealous 'experts' preaching it to the young faithful as the 'one true gospel', and condemning those who dare to speak against it as heretics. This is more like a cult, and is profoundly unhealthy for our industry.

But, isn't 'Clean Code' a good thing?

Yes, and no... depending on what you take it as meaning.

The word 'clean', in relation to code quality is obviously subjective and can mean wildly different things to different people - but I think we can all agree that the core of what is intended is:

Code whose purpose is clear to most who read it.

If we leave it there, that is a noble goal and will have many obvious benefits.

'Clean Code' starts to become a problem when its proponents treat it as a series of dogmatic commandments, rather than as a 'pirate code' that is more like 'guidelines'.
The pirate code

Why is this lowering developer quality?

Well... and this is just my personal theory - it seems to have created a mentality where:

The code should be understandable by the most junior dev in the team

I've actually heard this said in some places I've worked, and I've seen similar sentiments echoed online by 'expert' tutors. But, just think it through... if we adhere to this mentality then everything becomes a race to the bottom. We would actively seek to dumb down code to the point where it is more like an introductory reader for a five year old, than an elegant, nuanced work by a master author.

Advanced concepts in languages are deemed 'too difficult' or 'esoteric' without explaining anything about them - they're just swept under the carpet, or filed under 'do not use'. The overall result is a shrinking knowledge of the languages, and of programming techniques and concepts in general. If an indoctrinated new developer comes across any of the 'forbidden' items, they will often dismiss it as bad code and may even seek to replace it with something 'better' that adheres to the clean code commandments - sometimes unwittingly sacrificing objectively faster, more efficient, flexible code with something inferior.

The scary thing here is that the new developers do not know what they lack. They then become senior, and start preaching the same 'correct way' to the next crop of inductees - perpetuating and compounding the problem.

How do we fix this?

I think the best way is to change the way people are learning to code. We need to move away from 'you too can be a developer in 3 days - here's how' type tutorials that jump straight in there and show you how to do specific things in specific ways, and move back toward teaching people about the languages themselves, their features, and how to use them to convert your thought processes into functioning programs. The next step would be encouraging people to build for themselves - based upon what they've discovered and learned. After this they will be well versed in how things work and at a great point to start understanding existing codebases in their own way, and evaluating for themselves (maybe with some guidance) which techniques are better suited to different situations. Learning in this way will bring a much fuller understanding - resulting in much more competent, and - more importantly - creative developers.

To make an analogy, I believe modern teaching of software development has become too much like modern Lego; it used to be that you just had a huge tub of bricks, and you used your own ingenuity and inquisitiveness to firstly work out how all the pieces 'work' and fit together... then use your imagination and creativity to build the things you wanted to build. Nowadays, it's all single Lego sets with specific instructions, movie tie-ins etc. The instructions are followed unquestioningly, everyone builds the same 'cool' things. The joy and benefit of learning and creativity is lost - replaced with the instant gratification so desired in modern convenience culture.

Let's stop the rot, and bring back to software development what is being lost:

  • Joy
  • Curiosity
  • Discovery

Cover illustration courtesy of Danny Sapio

Top comments (31)

Collapse
 
tqbit profile image
tq-bit • Edited

TL:DR

You're right, if you preach about clean code instead of thinking through proper solutions, you're off worse than getting stuff done. But that doesn't mean you should be careless about aesthetics. Code is read by people and interpreted by a machine. Nobody likes to read a badly written article, why would devs like to read badly written code? Even if they have to, don't you think it'd lower their performance more than a clean codebase?


There are a few things I find very enlightening here and some I just can't agree with.

We would actively seek to dumb down code to the point where it is more like an introductory reader for a five year old, than an elegant, nuanced work by a master author

Isn't this a good thing? The best books I've ever read were the ones I could easily digest while learning a lot (e.g. Books by Kahnemann or Carnegie). You're right with one thing - it takes time, patience and practice to write code that just works, it just doesn't stop there. If I was presented two codebases

  1. Works, but looks ugly
  2. Looks beautiful, but has tons of bugs

I'd always scrap 2 and move on with 1. Refactoring imo is more fun (and often less time consuming) than debugging.

Learning in this way will bring a much fuller understanding - resulting in much more competent, and - more importantly - creative developers.

Again, not saying being creative is a bad thing per se. But try to imagine

  • You're lead dev of a 5-person team
  • 2 fe, 2be, 1qa guys.
  • 1be dev, 1qa dev quit because they received a better job offer. Vacancies are opened to be filled within the next 3 months
  • Your customer wants a new feature by yesterday
  • Your manager wants to deploy more features faster (= optimise pipe)
  • Nothing is documented, half of the codebase knowledge is gone with be dev #2

Taking over responsibility, you'll jump into the codebase trying to grasp what's going on. You see one module by dev#2 looking like that (pseudocode to extract mandatory build steps for a database schema, based on a true story):

export function build(cmd, cd) {
  const array = [];
  let ct = 0;

  for (let k in cmd) {
    cd.forEach(item => {
      if(cmd[k].step === item.step) {
        ct = count(count)
        array.push(cmd[k].step);
      }
    })
  }
  console.log(`Built ${ct} times`)
  return array
}

function count(abc) {
  return abc +1
}
Enter fullscreen mode Exit fullscreen mode

In another universe, your other, but slightly luckier you, is confronted with the same problem. With a difference in the codebase:

type DatabaseBuildStep = {
    step: string;
    handler?: () => void;
};

type DatabaseBuildStepMap = {
    [key: string]: DatabaseBuildStep;
};

interface DatabaseBuildTraits {
  appliedSteps: number;
    build(
        availableSteps: DatabaseBuildStepMap,
        mandatorySteps: DatabaseBuildStep[]
    ): DatabaseBuildStep[];
}

export default class Database implements DatabaseBuildTraits {
    public appliedSteps: number;

    public build(availableSteps: DatabaseBuildStepMap, mandatorySteps: DatabaseBuildStep[]) {
        let buildSteps: DatabaseBuildStep[] = [];
        for (let key in availableSteps) {
            const buildStep = this.extractMandatoryStep(availableSteps[key], mandatorySteps);
      if(!!buildStep) {
        buildSteps.push(buildStep);
      }
        }
    console.log(`Applied ${this.appliedSteps} building steps`)
        return buildSteps;
    }

    private extractMandatoryStep(
        availableStep: DatabaseBuildStep,
        mandatorySteps: DatabaseBuildStep[]
    ): DatabaseBuildStep | null {
    if(mandatorySteps.includes(availableStep)) {
      this.incrementSteps();
      return availableStep;
    }
    return null
  }

  private incrementSteps() {
    this.appliedSteps ++
  }
}
Enter fullscreen mode Exit fullscreen mode

There's a few obvious differences:

  • The 2nd codepart is more than 2x as long as the first
  • The TS code is verbose and (probably) bloated
  • Both snippets are far from perfect. I mean, we have deadlines to keep after all.

What makes the second, class based approach superior to the module implementation is:

  • It follows a logical top-down order of responsibilities (one function doesn't do it all)
  • It conveys meaning by its Types and Interface traits
  • It's readable by a human
  • The TS compiler complains if returned variables looks fishy
  • It's less prone to bugs and can easily be interpreted by other devs

Both times, the code probably works. And some people might say: "What's wrong with code 1? It does the job, doesn't it?".

Sure. But be honest. Put yourself into the world of the poor lead developer who has to jump into the breach whenever shit hits the fan. Once you're confronted with the code: Which approach would you prefer - Quick & Dirty OR well thought & aesthetic?

Collapse
 
darkwiiplayer profile image
π’ŽWii πŸ³οΈβ€βš§οΈ

I'd disagree with your assertion that the second snippet is (slightly) better; it is, in my opinion, more complex in its structure, whereas the first snippet only seems more complex because of the poorly named variables and some sub-optimal choices of syntax.

This sort of problem is usually easy to clean up by just renaming the variables to what they represent (cmd β†’ commands, ct β†’ counter, etc.) and tweaking the code to use more readable syntax (for ... in β†’ for ... of, not mixing for loops with forEach for a nested loop, etc.)

Meanwhile the second snippet of code obfuscates its intention much more deeply with its program structure. A function is hidden behind a stateless class (instant red flag), trivial actions (increasing a counter) are extracted into separate subroutine, but it hides these flaws by having more descriptive variable names, so it seems "friendlier" to the reader.

Collapse
 
jonrandy profile image
Jon Randy πŸŽ–οΈ • Edited

I think you may have misunderstood me somehow. In no way did I suggest being careless about aesthetics

Collapse
 
tqbit profile image
tq-bit

I wasn't so sure here, might as well be a misinterpretation from my side.

On the one hand, you mention 'elegant, nuanced work', on the other hand, to quote:

it used to be that you just had a huge tub of bricks, and you used your own ingenuity and imagination to firstly work out how all the pieces 'work' and fit together

I'd interpret this statement as a call to action for a trial and error approach. It works fine. Just in my experience, just as often it leads to the 1st scenario I described above (working, but 'ugly' code). Which still isn't a problem until the first change request hits.

Since I have an econ/business'ish background, I've got two hearts beating in my chest. Be diligent AND done in time/budget. Which is extremely hard to achieve. Uncle Bob got me with one statement though.

If you try to code fast, on the long run you'll always be slow

Thread Thread
 
jonrandy profile image
Jon Randy πŸŽ–οΈ

Yup, really seems like we're not on the same wavelength

Collapse
 
toxicsmurf profile image
toxicsmurf

what did I just read?

Collapse
 
maddy profile image
Maddy

Interesting topic, I enjoy reading controversial articles, they help me expand how I see coding.

To me, clean code has more to do with the question "Will I be able to understand this piece of code in 6 months time?". Often, it's okay to break the rules.

The code should be understandable by the most junior dev in the team

I mostly agree with this statement. Do we write code for clarity, or to show off how much we know about a language? My philosophy is that simple is always best. I think the meaning behind that is to say that there's no need to write overly-engineered code when you can just keep it simple.

I agree with you that learning how to code takes a lifetime. There is not set period to learn "coding", it's just never-ending.

The instant gratification you mentioned (meaning, "Learn How To Code Within X Days/Week) is a business thing, in the same way people buy programs promising them to get abs within 6 weeks (it's the same logic).

Collapse
 
fjones profile image
FJones • Edited

Do we write code for clarity, or to show off how much we know about a language?

Oh, this always bugs me. No, advanced or more complex code isn't "showing off". It's brevity. It's using the language's features. There's wide gaps between "write so simple everyone understands it", "write concise code that leverages the language's tools to the fullest" and "lolcodegolf", and we should certainly aiming for a solid balance of these.

(In fact, sometimes code golf is actually the right answer, but that's a bit beside the point...)

Collapse
 
jonrandy profile image
Jon Randy πŸŽ–οΈ

It often performs better too

Collapse
 
maddy profile image
Maddy • Edited

I agree with you, a 100%. I do believe we should use the language features whenever appropriate. My concern is more with those who write over engineered code.

Collapse
 
jonrandy profile image
Jon Randy πŸŽ–οΈ

Another problem is that too often 'simple' is confused with 'simplistic'

Collapse
 
justtanwa profile image
Tanwa Sripan

Good post!

...move back toward teaching people about the languages themselves, their features, and how to use them to convert your thought processes into functioning programs.

This is definitely something I also agree with. Since I started learning to code all I see is "how to become a developer in X days/weeks" and they all tell you to learn a whole language in like 1-2 weeks... I have been learning the same language for months... am I doing something wrong? πŸ˜… But my approach has always been, try to learn how things work to understand as much as possible.

Collapse
 
jonrandy profile image
Jon Randy πŸŽ–οΈ

Carry on like that. It really is the best way

Collapse
 
thomasjunkos profile image
Thomas Junkツ

I have some issues with this. Say 5 years ago I would have fully agreed with you on this topic. Clean code for me was defined:

1) does what it says without surprises (mostly surprising side-effects)
2) is easy to read for everyone fluent in the language
3) is careful with used ressources ~ "efficient"

I think so far we are on the same page.

But I changed my attitude towards (2).

The code should be understandable by the most junior dev in the team

I agree upon that is not the goal to have. But today I would say

2) is easy to read for everyone in the audience

Which is a small change, but with an interesting impact:

Say you are working with a high skilled team there is no reason to hold back some knowledge. You are fluent in x so use it up to its full potential.

If you are publishing your code for your own behalf there is no reason anyway to hold back knowledge.

But if you are working on a team where others have to read your code the mentality of "when you do not understand quality code you are a low quality developer" does help nobody it only feeds your ego. The problem is not having a low quality team but you being a blocker in the team, because you cause extra work. I changed my perspective due to an experience where I supported another senior developer getting his project out of the door. The project was overdue. I knew newer language features the other did not at the time. So it was natural for me to put my knowledge to work. But what happened? I wasn't there when my code broke and he had to fix it. Instead of fixing the code right away he was forced to learn the new language features.

Of course you could argue with educational debt on the companies side - and you would be quite right with that - but this is of no help, when you are in a hurry to to fix just a simple bug.

So: Yes, it would be easy to blame "low quality developers", but it doesn't help the team. Sometimes there is even no time or money to educate your team.

Write for your audience - and if you are the only senior then it would be better for the team you write junior level code than to foce every other developer to adapt to your level. If that feels wrong, maybe you are in the wrong team?

Collapse
 
jonrandy profile image
Jon Randy πŸŽ–οΈ

Yup, it's a fine balance... but in recent years I do feel the balance is being lost - at least in places where I've worked

Collapse
 
michaelmangial1 profile image
Michael Mangialardi

There are some good points in this article. Specifically, I agree that many new developers know how to do some things (by doing tutorials) but lack the understanding of the why.

Moreover, we need to let developers think through things for themselves.

It is a complicated problem with that no black-and-white solution will fix.

My suggestion would be that we have clear standards for junior developers to follow. Letting them go off an do their own thing won't really invoke creativity but a mess. There is a period of time where they just need to trust and absorb from others more experienced. As they mature, you can allow them to be more influential on coding standards, let them think on their own. You may even want to have a supplementary codebase, or a portion of the codebase, that it more lack to see what those developers come up with apart from the current standards.

Order and consistency in a codebase is more important than anything. However, the focus of clean code should be to the end of reducing complexity, which may or may not improve readability--often it does.

In a word, clean code almost always will provide higher code quality than no coding standards. However, that does not mean that there aren't some gaps that we have to be intentional to fill in to get the most from it.

Collapse
 
peerreynders profile image
peerreynders

41:00: "so most teams actually like the idea of normalizing in fact some of them like it too much where if you have a creative idea of doing things differently, β€œoh I don't want to rock the boat, I don't want to do my own thing here or go off the reservation”, so instead we tend to just gravitate towards the lowest common denominator on a lot of teams and that's not good…"

Collapse
 
jonrandy profile image
Jon Randy πŸŽ–οΈ

I saw an interesting, very accurate post on a similar topic today:

positech.co.uk - Code bloat has become astronomical

Collapse
 
git_revert profile image
.git • Edited

I have to be honest, by seeing this title I first thought you were talking about the clean code architecture by Uncle Bob lol.

Regardless, you are quite on point through this whole post. For example, I have recently been working on a project which tries its best to do abstraction. But through trying to make sure the project has "Clean Code" it has been over abstracted through and through such that you cannot have people comfortably settle into the project or even comfortably make changes.

Collapse
 
pierrewahlberg profile image
Pierre Vahlberg

Clean code is not about abstraction and he who promoted that in your poor codebase should indeed read uncle bobs book(s). Its about maintainability and leveling your codes intent with the amount of abstraction you possibly introduce. People are so black and whlte its scary.

The red green refactor is a good tool in clean code. Make it work, then make it read better. Then when someone else makes changes, they do the same. Code should be possible to be used in discussion, hencr hiding an ugly for loop in a function makes sense (get filtered posts function speaks better than the for loop on line 13 where we filter posts, for an example)

Other abstractions like factories, visitors and observer, these are terms that lets people talk about code like you and me can talk about cars, drivers and mechanics. We all know the meaning without having to describe how each one works in the world esch time it is mentioned.

These are, imo, the main intents of clean code. Using these methods any senior dev can use any language features as much as he wants to leverage it for performance. If he actually is good, that is ;)

Collapse
 
xinnks profile image
James Sinkala

A great read πŸ‘.

Collapse
 
leob profile image
leob • Edited

You should provide some examples, this is all a bit vague and fuzzy ...

Where I agree is that we shouldn't dumb things down to the extreme, by leaving half the features of our programming languages unused ...

Where I don't agree is that we we should strive to inject as many obscure features into our code as we can, just to make it more "terse", or to prevent our senior devs/rock stars/ninjas/code magicians from "getting bored" ...

Readability and maintainability should be number 1 - ALWAYS.

Whether you call that "clean code" or not doesn't really interest me.

So, do I agree with the jest of what you're saying here? I don't know ... I'm not sure ... and that's the "problem" I have with this article ;)