Skip to content
loading...
Discussion
markdown guide
 

Readability over being clever and the level of confidence for tests I write for a feature/bug fix over having 100% test coverage.

And if I’m being honest, I’ve never worked on a project that had 100% test coverage aside from a take home test I did for an interview a few years ago. 🙃

 

I've found that you can't really start out trying to make code clean. There are simply too many unknowns, too many variables at the beginning of a project to be able to start out clean. No matter how many "good abstractions" and "clean patterns" you put in place, things will start to get muddled and messy over time.

Thus, what makes code clean is going back after a while, looking at what's messy and deciding then what you actually need to do to make the code maintainable. Code doesn't start out clean. Cleaning it up makes it clean.

 

This ^^^ absolutely.

You start with the best intentions but you're absolutely right, there are too many directions to choose, unknowns, etc. and you end up chopping about to get to where you want to be and to actually get something built.

I wrote an article on this a while back, namely continuous refactoring, which helps as you go.

 

In my early years I had no idea that clean code was even a thing.

Then I started thinking about good variable names and short functions and those things that clean code prescribes without thinking too much about the reasons behind it.

Nowadays, I think more about keeping cognitive complexity low than clean code. Cognitive complexity tries to approximate how many things the reader has to keep in mind to understand a given piece of code. The fewer things to keep track of, the easier to follow the code.

A few things that I've found to reduce cognitive complexity:

  • Few intermediate variables: I have developed a distaste for intermediate variables, as they just clutter the scope and I need to keep track of them. I try to skip intermediate variables by composing functions instead of saving the output of a function to send it into another function. Also, when declaring a variable, I always put it in the smallest scope possible, and avoid mutating it as much as possible.
  • Composability: composable code is code that is made of smaller, independent parts that are composed together. Therefore, to understand a bigger part, I can look at the smaller parts independently and take it bit by bit. Much easier to understand a composition of ten pure functions than a 100-lines long function with a dozen and a half intermediate variables and several blocks of indentation.
  • Purity and referential transparency: there are two big dimensions that we need to keep track of when reading code. First, what is the code doing, and second, how have previous executions changed the internal state. A pure function will always yield the same output with the same input, so I don't need to keep track of what has happened before to see how it will affect the current execution.
  • Avoid/abstract conditional flow: ideally, there should be a single flow to follow. Multiple conditional statements, especially when nested, make it harder to understand what will be the output of a function. A conditional flow can be easily abstracted with Maybe and Either monads.
 

Keeping cognitive complexity low is part of clean code. Clean code isn't just about naming and formatting. It's also about sizes (method arguments, bodies, ...), control flow depth, etc.

Although proper naming also keeps cognitive comexity low. So both terms are highly co-related.

 

I break it down into a couple different layers, but I generally think about it in terms of the audience more than just the code itself.

There are some baselines like: bad/inconsistent names make it difficult to understand intent, dead code makes it difficult to understand what is relevant, flaky tests make it difficult to understand what it working.

The next layer is community. You can tell when someone writes Java in Python or vice versa. This isn't always super clear cut and might have layers to itself. For example, JavaScript is definitely #NotAMonolith.

Next is your team. Every team had slightly different norms.

Lastly, I'm starting to think about codebase size as a significant factor. If you are working on something tiny, I think abstraction probably more weight than it is worth. Just writing code as plainly as possible in as few places as possible is a great thing. I think this is particularly valuable while learning a tool. If haven't developed specific habits and for specific problems with that tool, you are not increasing your productivity by adding a lot of poorly understood layers of indirection. Just write the code as plainly as possible in the place you understand as much as possible and develop those solutions as you feel pain. I belabor the point because I used to value "using the framework well" too highly.

 

In the past, I used to think that you always had to produce clean code, no matter what.

Now, I realized that it's not possible and even bad for the business because it slows you down. You have to make trade-offs and focus both on the technical and business value of your code. Having technical debt is fine.

 

Yes, but I can not define what it was before, or what it is now. It seems I'm currently in transition. It seems that it does not matter how the code is written it is unreasonable. This means it becomes most important to learn to read code in many styles, rather than learning a style.

 

It feels like I'm becoming more and more radical about this because of the experiences I had in several different projects. It always seems to come down to the same thing: an experienced developer bored by trivial tasks introducing some unnecessary new abstraction layer or unecessarily clever solution. And the result is always the same: the code works, it's utterly complicated and / or unreadable for others, nobody else wants to touch it until they have to.

In my opinion clean code is vital for an application. The simpler the code the cleaner it is.

 

I think it's best to rely on tooling and communication, both proactive, in review, and retroactive, to communicate what's desired as a team. Further, it's best to lean on your code review tools, like pull requests and merge requests, which not only preserve a record of decisions made, but also allows stakeholders to chime in.

As for 'clean code', it all depends on your approach, and your goals. If you're an OOP or FP maximalist, especially when the team is working in a multi-paradigm language like JS, TS, Rust, Ruby, Python, etc., there's absolutely many other factors to consider, than what's "idiomatic". Sure, there's an easy way and a hard way to solve a problem, and sometimes you can contribute your own thoughts and experiences. But this isn't just your codebase. It's your team's, other team's, future teams, and past teams.

Often, I find performance to be underappreciated, but performance is also subjective until it can be measured. Your tools and your review process, your communication process and perhaps even documentation process (but use sparingly, just to communicate objectives and areas of concern, rather than winding up as a maintenance sink, in addition to tests and review), are the major things you'll come to lean on.

I might also say, your approach matters, and using the term 'cleanliness' as a metric to describe code quality is highly subjective, to say the least, and not always that helpful. Linters, code coverage, unit tests and integration tests, end to end tests / smoke tests, regression tests, and most of all, team communication, are your number one guiding factors here.

I will admit, to answer the question originally stated, I regret the approach I once took in my career. I subscribed to FP and/or OOP, "idiomatic" religions, and often was adversarial when challenging the decisions of others. I've had to learn to reign it in, and provide constructive feedback and discussing higher-order goals than can just be addressed through a cursory glance at a PR/MR.

Further, it's always a balance. No single prescriptive approach works everywhere. "It depends" is better than solutioning right out of the gate. Ask more questions, and don't just jump in and do the work. Take a healthy, balanced, measured approach. To some, it might come easy. To others, like me, I've had to learn that software development is more than just writing code, however clean it may be. Much more.

 

In the beginning of my career I was very much focused on consistency; all lines needed to be indented correctly and naming should be consistent. Today, I am working a bit more loosely with the rules of clean code; what matters now most to me is readability. Of course I try to follow the rules of clean code and try to do that in a consistent way, but it is more ok for me now to break the rules if that fosters readability.

After all, code is read more often than written...

 

I used to be a fan of taking things and moving them out to functions, especially if the thing being moved out to a function seemed orthogonal to the stuff around it.

So I would do stuff like this:
setupTableView()
formatLabels()
setupAnalyticsTracking()

etc.

I stopped doing that and now just throw it all together in exactly the order it happens, all in the one function. I only move things out to functions when I know they need to be called from more than one place.

I believe this style does a better job of communicating intent. If something has its own function, it means it is used in more than one place. So just seeing that there is a function off on its own, you can automatically infer something about its place with the rest of the code. You know it gets called more than once.

I do the same with variables.

To me, it is annoying to have to jump all around the file and piece together a mental picture of what really is just one big function. You think you're being clean by moving stuff out into other functions and giving it a name, but you're actually muddying the waters because at that point you can't really tell which of those functions actually do get called from more than one place.

If a thing is in a scope, it should mean it is accessed multiple times by other things from lower scopes.

Although it seems like following this rule makes code more "messy", I have found it far easier to understand my projects that work this way.

 

"Clean code" as a discipline has only become increasingly important, software craftmanship as a movement, and it's raw commerical, politicised focus, can go get in the sea.

One of the most profound changes in my approach to software was understanding it to be literature. Functional literature, but literature regardless. Intent, characterisation, description, text, subtext, flow, rhythm, style, all effect software like they do prose.

It's a constrained form of communication, with grammar, and that's why we work in "programming languages". They are languages. With rules, idioms and quirks. These aren't analogies, it's what software is. It's storytelling. Constrained creative writing with purpose.

Basically, Donald Knuth was right, and called it a bajillion years ago - with the idea of literate programming. Today's languages are that thing. You will never be a great programmer unless you become an excellent communicator, and an excellent writer. The skillset is the same.

Critical thinking, expression of concept, reducing repetiton, form for impact, signposting, intent and subtext. If you want to understand great software, understand great literature.

Communication skills are not optional

If you want to teach a junior programmer to be a better programmer, teach them to write. Language is our tool for organising our thoughts. It's powerful. It has meaning. It has power.

It's a gift, it's for everyone. 🖤

 

Clean code is code I can read.
Clean code is code that any new developer can read.
Clean code is code that any developer can read, though the why may deserve some clarification from a developer experienced with the specific codebase.

 

It evolved in 3 stages for me

Stage 1: Personal projects/university/learning:
Here I wrote code that gets used once and doesn't have to be maintained or changed once it is done. Readability here is get it done, fast. I don't judge my old self, but I can't go back to this lifestyle.

Stage 2: Early Professional Work:
Key here for me was reading Clean Code by 'Uncle Bob'. He gives a good set of rules for what is clean code but the two important ones are good variable names and shorter methods. In this stage I applied the rules without understanding why which in some cases lead to some pretty dirty code.

Also, in this stage I came across some good but a lot of really bad code. For example, I learnt why long classes were bad after having to make a bug fix on a 2000 line class (one of the scariest moments of my career).

Stage 3: Experienced Professional:
I agree with alot of the other answers: Clean code to me is readability. You spend so much more time reading than writing code. As much as possible you want to make code readable. And I would define readable as reducing the amount of thinking anyone reading your code has to do to understand it. You spend the most time reading code your so it's for you too.

Therefore readability for me is:

  • Good names for methods, classes, variables
  • Short methods: Think do one thing and one thing only
  • Prefer pure methods: Would define this as relying as little as possible on what is not passed into the method (but do use composition), and returning back a value rather than mutating the parameters.
  • Prefer immutable objects: With mutable objects always have to think in the back of your mind, has this changed somewhere else without me realising it.
  • Less is more: Write less code. Every line of code you write is a line someone has to understand, and a potential bug. Someone once told me "You are not paid per a line of code you write"
  • Tests: Testing improves readability because you don't have to read code to understand if it works.

Readability trumps everything.

 

I've come to realize that clean code isn't about getting to a perfect final state, but rather an unending process of making code easier to understand and easier to change. That can be done in many different ways, all with their own costs and benefits.

 

It went from "important" to "vital".

If you don't keep your code clean everything will take more and more time until you clean it up.

And with everything I mean everything that has to deal with the code. Maintenance, changes, bugfixing,... But also onboarding new developers.

 

I believe clean code (the book series) does have some great points, however, in real life a lot of these are hard to adhere 100%. The things that I have personally taken from these book series are writing code with meaningful variable names, function names that make semantic sense with the action they're performing, while I don't believe in 100% coverage, I do believe in testing the important parts of your application, the Pareto principle applies here in my case. Avoiding comments has been easy once I have everything making semantic sense. Taking function splitting to an extreme is one thing that I don't find particularly useful, if I can do it comfortably I will, otherwise I'm not gonna force it.

I've found great value in writing code with the mindset of a book author, I can come back to my code months later and pick up where I left without much head-scratching.

In the tech world where we have a constant struggle of egos, I'd be unrealistic to deny the value of clean code, as with many things, if you take it to the extreme its no longer worth the effort, but for developing countries that don't have as big of a tech community its a great resource to learn good principles by yourself

 

I used to think that clean code meant comments everywhere. Now I believe that truly clean code should be self explanatory, with comments only about "why", not "what".

 

I value it more and more, I write it less and less

 

Sometimes, the "cleaner" the code - the more obfuscated and confusing it is. Sometimes

 

Couple years ago, everything is in one line.
Now, every variable is on each own line. :D

 

As simple as possible, not overly abstract, is what I define as clean these days.

 

Overly long, verbose code just to make it more 'clean' or 'readable' annoys the crap out of me

 

Clean code does not necessarily relate to the number of lines of code.

Classic DEV Post from Jul 30 '19

PublishTo.Dev: Scheduling article publishing on dev.to

Ben Halpern profile image
A Canadian software developer who thinks he’s funny. He/Him.