Write Better Code
Summary
TLDRThis video script humorously addresses the inevitable 'suckiness' of code while advocating for best practices to ease maintenance. It emphasizes the importance of clear comments, meaningful naming, and simplicity in code structure. The video draws from 'Clean Code' by Uncle Bob, offering insights on error handling, avoiding over-engineering, and the significance of testing. It suggests that by adhering to these principles, developers can maintain cleaner, more understandable codebases.
Takeaways
- 😅 Code quality is often measured by the 'WTF per minute' ratio, humorously highlighting the inherent challenges in software development.
- 📚 The book 'Clean Code - A Handbook of Agile Software Craftsmanship' by Uncle Bob is a popular resource for improving code quality.
- 🤔 Comments in code can be a sign of bad code and should be used sparingly; good code should be self-explanatory with clear variable and method names.
- 🔍 Proper naming of variables, functions, and classes is crucial for code clarity and maintainability.
- 🚫 Avoid using misleading or unclear names in code; names should be distinct, meaningful, and easy to pronounce.
- 🔑 Keeping functions small and focused on a single task helps to manage complexity and makes the code easier to maintain.
- 🛠️ Continuously improving code quality by making small refinements, such as renaming variables or simplifying logic, is essential to prevent code decay.
- 🛑 Effective error handling is vital for dealing with unexpected scenarios and should be done in a way that keeps the code clean and maintainable.
- 💡 Simplicity is key in software development; avoid over-engineering and ensure that the functionality implemented is necessary and useful.
- 📝 Writing tests is an essential part of the development process, ensuring that the code is clean, maintainable, and reliable.
- 🔄 The importance of teamwork in testing, especially for considering edge cases and avoiding a narrow focus on 'happy path' scenarios.
Q & A
What is the 'WTF per minute' ratio mentioned in the script, and what does it imply about code quality?
-The 'WTF per minute' ratio is a humorous way to describe the frequency of surprising or confusing elements found in code. It implies that code quality can be subjective and that even with best efforts, code may still be seen as 'terrible' by others, but following good practices can make maintenance easier.
Why should comments not be used to compensate for bad code according to the script?
-Comments should not make up for bad code because they can lead to code smells, indicating poor code design. Good code should be self-explanatory with well-named variables and methods, reducing the need for excessive comments and the associated maintenance burden.
What is the importance of good naming conventions in programming as discussed in the script?
-Good naming conventions are crucial as they make code more understandable and maintainable. Clear names indicate the purpose of variables, functions, and classes, reducing the need for comments and making the codebase easier to navigate and discuss.
How does the script suggest maintaining code quality over time?
-The script suggests following the Boy Scouts' principle of 'Leave the campground cleaner than you found it.' This means making small improvements each time code is checked in, such as renaming variables for clarity, splitting large functions, or removing redundant code, to prevent code decay.
What is the significance of keeping functions small and focused in the script's discussion on code quality?
-Keeping functions small and focused is important for reducing complexity and making code easier to understand and maintain. Small functions are easier to test and modify, which contributes to the overall quality and longevity of the codebase.
How does the script address the topic of error handling in clean code practices?
-The script emphasizes using exceptions instead of return codes to separate error handling from business logic. It also suggests writing try-catch-finally statements first to consider potential problems upfront and avoiding null values to prevent errors related to null checks.
What does the script suggest about the relationship between simplicity and code maintainability?
-The script suggests that simplicity is key to maintainable code. It references Elon Musk's five-step engineering process, which includes simplifying and optimizing, and removing unnecessary parts of the process or code to achieve better maintainability.
How does the script define 'over-engineering' and why should it be avoided in software development?
-Over-engineering is the act of creating overly complex solutions for problems that could be solved with simpler methods. It should be avoided because it can lead to unnecessary complexity, making the code harder to understand, maintain, and modify.
What is the single responsibility principle mentioned in the script, and why is it important?
-The single responsibility principle states that a class or function should have only one reason to change. It is important because it helps prevent unnecessary complexity by ensuring that components of the codebase have a single, well-defined purpose.
What are some best practices for writing tests as discussed in the script?
-The script suggests writing simple, clear tests that are easy to read and understand. It also advises finding a balance for test coverage to avoid over-testing and ensuring that edge cases are thoroughly considered to prevent focusing only on the 'happy path' scenarios.
Outlines
📚 The Essence of Clean Code
This paragraph emphasizes the importance of adhering to basic guidelines in software development to ensure maintainable code, despite the inherent 'suckiness' of code. It introduces 'Clean Code - A Handbook of Agile Software Craftsmanship' by Uncle Bob as a valuable resource. The author humorously acknowledges the 'Agile' red flag but proceeds to discuss key principles such as the futility of comments in bad code, the significance of good naming conventions for variables, functions, and classes, and the necessity of keeping code simple and understandable without over-commenting. The paragraph also touches on the importance of maintaining code quality over time, referencing the Boy Scouts' principle of leaving the codebase cleaner than found.
🛠️ Best Practices in Error Handling and Simplicity
The second paragraph delves into the intricacies of error handling and the principles of simplicity in coding. It advocates for the use of exceptions over return codes to separate error handling from business logic and suggests writing try-catch-finally blocks first to preemptively address potential issues. The paragraph advises against returning or passing null values, recommending the use of special case objects or exceptions instead. It also discusses the importance of defining exceptions based on the needs of the caller and providing meaningful error messages. The 'keep it simple' mantra is further explored with Elon Musk's five-step engineering process, emphasizing the value of removing unnecessary parts of a process. The paragraph concludes with advice on avoiding over-engineering, the importance of testing, and the significance of writing clear and concise tests that cover edge cases.
Mindmap
Keywords
💡WTF per minute ratio
💡Code complexity
💡Comments
💡Good naming
💡Single responsibility principle
💡Error handling
💡Null values
💡Keep it simple
💡Testing
💡Code decay
💡Agile
Highlights
The famous comic's assertion that code quality can be measured by the 'WTF per minute' ratio humorously acknowledges the inherent flaws in software development.
Following basic guidelines can ease code maintenance, even if the code quality remains less than ideal.
The importance of good naming conventions in programming to ensure clarity and reduce the need for excessive comments.
Avoiding misleading or unclear names in code to prevent confusion and maintain distinct, meaningful identifiers.
The significance of comments in code and the potential downsides of over-commenting, including increased maintenance burden and verbosity.
The anecdote about a 'place order' method exceeding 2000 lines, illustrating the impracticality of large functions and the need for smaller, more manageable code blocks.
The principle of keeping functions small and focused to avoid complexity and facilitate easier maintenance.
The Boy Scouts' principle applied to software development, emphasizing the importance of leaving code cleaner than found to prevent decay.
The necessity of error handling in software development and strategies to manage it without cluttering the codebase.
Using exceptions over return codes to separate error handling from business logic for cleaner code.
The recommendation to write try-catch-finally statements first to consider potential problems and maintain code consistency.
Avoiding null values in functions to prevent errors and the clutter of null checks in code.
The importance of simplicity in error handling by defining exceptions based on caller needs and providing meaningful error messages.
Elon Musk's five-step engineering process as a model for simplifying and optimizing code development.
The guidance against over-engineering and the value of removing unnecessary parts of a process or code to achieve simplicity.
The single responsibility principle as a key to preventing unnecessary complexity by ensuring classes and functions have one reason to change.
The importance of writing simple, clear tests and finding a balance in test coverage to ensure code reliability.
The necessity of considering edge cases in testing to avoid focusing solely on the 'happy path' and ensure comprehensive code reliability.
Transcripts
There is this famous comic stating that the only valid measurement of
code quality is the WTF per minute ratio.
Well… in all honesty, this is actually one of the most accurate depictions of software
development. Your code will suck no matter what, but you can at least follow some basic guidelines
to make maintenance easier down the road. Don’t get me wrong… Your code will still be terrible,
but at least you can be proud that you gave it your best shot.
There are various schools of thought and books written on the topic of good software,
and in this video we’ll look at 7 lessons from one of the most popular books on the
subject. Clean Code - A Handbook of Agile Software Craftsmanship by Uncle Bob.
Let me preface this by saying that using the word “Agile” in anything
software related is a big red flag for me, but we’ll let this slide for now.
Let’s start with something we probably agree with:
Comments Do Not Make up for Bad Code. We all jumped into a codebase at some point and were
surprised to find some random method which had more lines of comments than actual code.
While the author might have had good intentions, this is actually a terrible code smell,
and you should mentally prepare for a frustrating reviewing and debugging session whenever a lot of
comments are present. As a rule of thumb, if you feel the need to explain your code with comments,
you probably need to spend more time reducing your code complexity.
Good code needs no explanation. If variables and methods are correctly named, and the logic
is properly implemented, any block of code should be pretty self explanatory.
Keep in mind that comments have to be maintained as well, increasing your workload in the long
run. And, they can even make code more verbose when they are redundant. Java devs deserve a
special medal here, since they made famous the bad habit of commenting even the getters and setters.
I mentioned good naming of methods and variables, which is yet another
important rule in programming. There are a few key concepts you should keep in mind.
First, variables, functions, and classes should clearly indicate their purpose. Poor
names that don't reveal intent lead to code that's hard to understand,
requiring unnecessary comments or extra context. Note however, that naming conventions might be
different depending on your programming language. In practice, naming a member
instance simply “m” might be frowned upon in Java, but it is more than encouraged in Go.
Second, you should avoid using misleading or unclear names,
such as those that might be mistaken for something else or are too similar to other
names. Names should be distinct and accurately reflect the purpose of the item they represent.
Names should not only be unique but also meaningful. Avoid arbitrary
distinctions like misspellings or adding noise words like “info” or
“data” that don't clarify the function or object’s purpose.
On top of that, Names should be easy to pronounce and easy to search for within the codebase. Avoid
single-letter variables or cryptic abbreviations that make the code difficult to discuss or search.
Finally, always add meaningful context. When names by themselves are not sufficient,
provide context by placing them within well-named classes, functions,
or namespaces. This helps to clarify their meaning within the broader scope of the code.
And, as a bonus, while all these rules are important,
you can actually overuse them. So find a balance and don’t over do it.
Another important rule which will help you maintain your
code over time is to keep things small.
To start with a small anecdote, one of the projects I worked on in the past was an online
ordering solution which had a “place order” method which exceeded 2000 lines of code. Yes,
this code is still in production and handles thousands of new orders daily. However,
you can imagine that implementing anything new in the “place order” function is a nightmare.
Keeping functions small and focused on only one thing is a no brainer, but, in practice,
you’ll realize that this is easier said than done. You’ll read about arbitrary rules like the
fact that functions should not exceed 20 lines of code, which can rarely be followed in real world
scenarios. However, the core principle of keeping things small should dictate your implementation,
and is the main mechanism that will allow you to avoid complexity in your code.
Note that it is not enough to write good code. You also have to maintain its quality over time.
Code has this bad habit of deteriorating as projects progress. To combat this,
we need to actively prevent code from degrading. The Boy Scouts of America have a guiding principle
that applies to software development as well: "Leave the campground cleaner than you found it."
If every time we checked-in our code, we made it just a bit cleaner than when we checked it out,
we could prevent code decay. The improvements don't have to be major. You can rename a
variable to make its purpose clearer, split a function that's getting too big,
remove a small piece of redundant code, or simplify a complex conditional statement.
As always, there is a fine line between improving code and breaking functionality,
so such changes should be backed by thorough testing.
Ok, we spent some time looking at the form of the code,
so let’s now take a step further into some more in depth topics.
One really important topic in software development is error handling. Although this is necessary in
order to deal with unexpected scenarios and potential failures, it often leads to
a cluttered codebase due to various checks and logic that might obscure the main functionality.
There are numerous ways programming languages are dealing with this in practice, from Go’s error
values and the somewhat verbose error handling to Rust’s special types and pattern matching.
While the approaches and suggested best practices might vary depending
on the ecosystem you are in, there are a handful of simple rules you
should follow to write clean code that handles errors gracefully.
First, you should use exceptions instead of return codes. This
allows you to separate the concerns of error handling and the business logic.
Then, when possible, you should always write try-catch-finally statements first.
This will force you to think about potential problems and corner case scenarios upfront,
ensuring the code remains in a consistent state regardless of errors.
Null values are a necessary evil in software development, but you should avoid returning
or passing null in your functions. Returning or passing null leads to code that is prone to
NullPointerExceptions and cluttered with null checks. Instead, use special case objects or
throw exceptions to avoid null-related errors. Keeping it simple is a mantra we’ll get back to
in a second, but this applies for errors as well. You should define exceptions based on
caller needs. So always simplify error handling by defining exceptions that align with how they
will be caught, reducing redundancy and making the code more maintainable.
And, of course, it goes without saying that you should provide context with your
exceptions. In other words, exceptions should include meaningful error messages
that clearly describe the failure, helping with debugging and logging.
Now let’s address the keep it simple principle. I recently read about Elon Musk’s five-step
engineering process, which follows this principle closely.
In short, when building something you should follow five clear steps:
Make the requirements less dumb, Delete the part or process step,
Simplify or optimize, Accelerate cycle time, and, finally Automate.
While simplifying and optimizing is an obvious action, I find the second step more
interesting. In practice, you’ll discover that sometimes the best way to simplify
a process is to actually completely remove it from the workflow. And yes,
this applies to coding as well, and Clean Code offers some guidance on this topic.
First, you should always avoid over-engineering,
and, believe it or not, sometimes abstraction can be a pain in the butt.
Second, make sure that you are actually going to need the functionality you are implementing.
Of course you should always avoid duplication and, finally, follow the single responsibility
principle to make sure that your classes and functions have only one reason to change.
This prevents unnecessary complexity by keeping classes and functions focused on a single task.
Finally, let’s address the most hated aspect in software development - testing. As much
as we despise it, testing is a crucial aspect of writing clean, maintainable, reliable code. Again,
there are a few best practices you should keep in mind when forced to write tests.
You should write simple, clear tests that are easy to read and understand.
You should avoid over-testing and find a balance for your test coverage. Finally,
it should be obvious that edge cases should be thoroughly thought out. It’s easy for developers
to only focus on happy path testing, so it is a good idea to team up for proper testing.
If you feel like you learned something,
you should check some of my other videos as well. Until next time, thank you for watching!
5.0 / 5 (0 votes)