Back, as promised in my previous post — a guide to writing clean code — with a handful of 6 more universal principles. Or best coding practices, if you prefer, leading to simple, clean and overall... beautiful code. That help you write better code.
So far, we've tackled clean code principles such as:
- pure functions
- separation of concerns
- etc.
… and good coding habits such as:
- release early, release often
- learning to collaborate well when sharing a codebase with your peers
Well, in this post we'll be focusing on clean code standards and good habits to develop as a developer, such as:
- test-driven development
- avoiding over-complicated interfaces
- coding each operation only once: never repeat the same code
- never stop learning... new languages
- and so on...
So, here are the 6 other “rules” to consider if you're determined to improve how you write code:
7. Get Used to Writing Tests for Your Own Code
Get into the habit of testing your own code. Of writing custom tests for its specific functions and classes.
This way, if/when “trouble strikes”, you won't be completely clueless about what the source of the problem might be.
And the whole point of testing your own is simple:
Instead of “waiting” for something to go wrong and take you by surprise, totally unprepared, you're... triggering those bad scenarios yourself:
Does your code cope with unusual inputs? Try using classes and functions the “unconventional” way” and see what happens...
This way, when you apply a change to your code, you can re-run your tests just to make sure that it won't lead to “unfamiliar” issues inside your code.
8. Keep Your Skill Set Up to Date: Learn New Programming Languages
Never stop learning! For you can't expect to write better code if you don't strive to keep your skill set... relevant.
Keeping up with the new programming languages is like “future-proofing” your coding skills.
These new languages' constructs stand the chance to become the new baseline for development from now on. Therefore, you can't afford to ignore them and stick to coding in your familiar language only.
Is JavaScript your “mother language”? Then you might want to consider learning a more typed language, such as Typescript, as well.
Or maybe you're more into OO paradigm languages, like Java, rather than dynamic languages? In this case, a good coding habit to develop is to get yourself familiarized with functional paradigm languages like Scala, too, for instance.
In short: try to avoid overspecialization! Be open to learning new programming languages as they start stealing the spotlight...
9. Avoid Deeply Nested Code
For deeply nested code is just... crappy code! There, I've said it...
And since your resolution is to write better code, you definitely want to stay away from getting your code “stuffed” with {curly braces}!
“But what does “too many” mean, actually?"
If you have 7 curly braces, 6 of which are nested, then you can be sure that you've crossed the line! Just imagine:
You'll need to peruse through all the “if” conditions in your code just to find out how precisely you got to line 12. There's no easy way out!
Moreover, if you consider all those developers (even the “future you”), who'll need to dig into your deeply nested code — overly dependent on specific levels of state and on various lines of code throughout the program — you can just guess that:
- they won't understand its impact nor its goal
- they'll be hesitant when it comes to deleting it (when your team doesn't need it anymore)
The clean code standard in this case here is:
Defining a logical path for your code to follow and eventually allowing it to stray off into an “if” block only in exceptional situations!
And here are some of the main benefits stemming from avoiding deep nesting:
- debugging will get way smoother without all those “if” conditions to swift through each and every time you need to track down a bug in a specific line of code
- for adding extra code to handle error conditions, you'll only need to insert a few lines inside those “if” blocks
- your given input will always deliver the same output, irrespective of the changes applied outside of it
- whereas the application state won't get influenced at all by what happens inside of it
10. Write Unit Tests Along the Way
Another good coding practice is pairing each method, each class in your code, with a unit test...
And here are some specific situations when they turn out to be some true “life saviors”:
- when one of your peers wants to know what a particular piece of code does, there's the unit test assigned to it that will “enlighten” him/her
- when properly written, unit tests keep you safe from making the wrong assumptions about what your code does, what its purpose is
11. Want to Write Better Code? Then Don't Code the Same Operation Twice
Do not repeat yourself! Restrain yourself from copying and pasting code over and over again throughout your codebase.
Each operation (presentation element, algorithm, interaction with an external interface) should be coded once and once only.
And whenever:
- a piece of code needs to know about this specific operation, the solution is to refer back to it by name; instead of re-coding it again...
- you need to make a change to that particular operation, just modify a single method or class, and do not repeat the entire code!
Another valid answer to the question “What does it mean to write good code?” is:
“To write code that's not only clean and simple, but easily maintainable and concise, too”
And so, by avoiding to re-write the same code multiple times, it'll be way easier to maintain several copies of that codebase!
12. Aim for Simple, Yet Expressive Interfaces
Stay away from over-complicated interfaces! This is another one of those universal, proven principles to write better code...
Whenever you need to write an interface for one of your code elements — various methods or classes in your code — just remember to keep it:
- simple (couldn't the value that you're providing explicitly be deduced from other values instead?)
- expressive
- small (just a few parameters)
How? By using plain English and not assuming/expecting the caller to already know:
- certain data
- about global state
- the sequence in which operations should take place
Final Word
Here's another answer to your question — “What does it mean to write good code?” — taking the form of another... question, actually:
“Will your code be quick and easy to delete when you/your team will no longer need it?”
That the perfect criterion for telling the difference between good code and... crappy code:
- if it's deeply nested and dependant on a whole infrastructure of lines of code throughout the program, then no one in your team will be comfortable deleting it
- but if your code's clean-simple and readable (anyone would know immediately how many lines of code it interacts with), then your peers will be more confident removing it
So, raise your expectations and make your life and your fellow developers' lives easier:
Write good code, then strive to write better code!