JavaRush /Java Blog /Random EN /Coffee break #103. In defense of “Clean Code”: 100 timele...

Coffee break #103. In defense of “Clean Code”: 100 timeless tips

Published in the Random EN group
Source: Hackernoon “Clean Code” by Robert C. Martin is the most recommended programming book of all time. Search for books using the query “best books for software developers” and you are almost guaranteed to find this book in the search results. And while some people feel that Clean Code is not worth paying attention to, I would argue that such sentiments are deeply mistaken. Yes, some of the advice in the book is questionable. Yes, some of the content seems outdated. Yes, some examples are confusing. It's all true. But let's not be so quick to discount the many useful tips this book offers! Completely ignoring Clean Code simply because of a few bad ideas is not the best solution. Coffee break #103.  In defense of “Clean Code”: 100 eternal tips - 1So, without further ado, let's look at the best tips that Clean Code has to offer! We'll go through each chapter, summarizing the ideas that Uncle Bob and his co-authors offer.

Chapter 1: Clean Code

  1. The overall amount of clutter increases over time.

  2. Restoring an outdated system from scratch is very difficult. Refactoring and incremental improvements will be the best option for this.

  3. In a messy codebase, tasks that should only take a few hours can take days or weeks to complete.

  4. Take the time to act quickly.

  5. Clean code does one thing well. Bad code tries to do too much.

  6. Clean code is well tested.

  7. When reading well-written code, each function does roughly what you'd expect.

  8. If you disagree with a principle taught by someone with years of experience, you should at least consider their point of view before ignoring it.

  9. Code is read much more often than it is written.

  10. Code that is easier to read is easier to change.

  11. Leave the codebase better than when you found it (Boy Scout Rule).

Chapter 2: The Meaning of Names

  1. Choose your variable names carefully.

  2. Choosing good names is difficult.

  3. The name of a variable or function should indicate what it is and how it is used.

  4. Avoid using single-character variable names, except for commonly used names, such as i for a counter variable in a loop.

  5. Avoid using abbreviations in variable names.

  6. Variable names should be pronounceable so that you can talk about them and say them out loud.

  7. Use variable names that are easy to find.

  8. Classes and objects must have names in the form of nouns.

  9. Method and function names must be verbs or verb-noun pairs.

Chapter 3: Functions

  1. Functions should be small.

  2. The function must perform one action.

  3. Functions must have descriptive names.

  4. Extract the code in the if/else body or switch the statements into clearly named functions.

  5. Limit the number of arguments a function takes.

  6. If a function requires many configuration arguments, consider combining them into a single configuration parameters variable.

  7. Functions must be pure, which means they do not have side effects and do not modify their input arguments.

  8. The function must be a command or a query, but not both at once (Command Query Separation).

  9. It is better to remove errors and exceptions from the code than to leave errors in the code.

  10. Extract duplicate code into clearly named functions (Don't Repeat Yourself).

  11. Unit tests make refactoring easier.

Chapter 4: Comments

  1. Comments may be incorrect. They may be wrong to begin with, or they may be initially accurate and then become outdated over time as the code changes.

  2. Use comments to describe why it is written the way it is, rather than explaining what is happening.

  3. Comments can often be avoided by using clearly named variables and extracting sections of code into clearly named functions.

  4. Prefix TODO comments with consistent prefixes to make them easier to find. Review and clean up your TODO comments periodically.

  5. Don't use Javadocs just for the sake of using them. Comments describing what a method does, what arguments it takes, and what it returns are redundant at best and misleading at worst.

  6. Comments should include all relevant information and context that the reader will need. Don't be lazy when writing a comment.

  7. Log comments and file author comments are not needed due to version control and git blame.

  8. Don't comment out dead code. Just delete it. If you think you'll need the code in the future, that's what version control is for.

Chapter 5: Formatting

  1. As a team, select a set of rules for formatting your code, and then apply those rules consistently. No matter what rules you agree with, you need to come to an agreement.

  2. Use automatic code formatting and a code analyzer. Don't rely on people to manually find and fix every formatting error. This is inefficient, unproductive and a waste of time when reviewing code.

  3. Add vertical spaces between lines of code to visually separate related blocks of code. All you need is to make one new line between the groups.

  4. Small files are easier to read, understand, and move than large files.

  5. Variables should be declared near where they are used. For small functions this is usually at the top of the function.

  6. Even for short functions or if statements, still format them correctly rather than writing them on one line.

Chapter 6: Objects and Data Structures

  1. The implementation details in an object must be hidden behind the object's interface. By providing an interface for use by consumers of an object, you make it easier to later refactor implementation details without causing breaking changes. Abstractions make refactoring easier.

  2. Any given piece of code should have no knowledge of the internals of the object it operates on.

  3. When working with an object, you should require it to perform a command or query, rather than asking it about its internals.

Chapter 7: Correcting Errors

  1. Error handling should not interfere with the rest of the code in the module.

  2. It is better to remove errors and exceptions from the code than to leave errors in the code.

  3. Write tests with errors to make sure your code identifies them and doesn't miss them.

  4. Error messages should be informative, with all the necessary context someone might need to troubleshoot effectively.

  5. Wrapping third-party APIs in a thin layer of abstraction makes it easier to replace one library with another in the future.

  6. Wrapping third-party APIs in a thin layer of abstraction makes it easier to mock the library during testing.

  7. Use the Special Case pattern or Null Object pattern to handle exceptional behavior, such as when certain data does not exist.

Chapter 8: Boundaries

  1. Third-party libraries help speed up product delivery by allowing you to outsource various tasks.

  2. Write tests to ensure you are using the third party library correctly.

  3. Use the adapter pattern to bridge the gap between a third-party library's API and the API you'd like to have.

  4. Wrapping third-party APIs in a thin layer of abstraction makes it easier to replace one library with another in the future. (Repeat from Chapter 7)

  5. Wrapping third-party APIs in a thin layer of abstraction makes it easier to mock the library during testing. (Repeat from Chapter 7)

  6. Try not to tell your application too much information about the details of any third party library.

  7. It's better to depend on what you control than on what you don't control.

Chapter 9: Unit Tests

  1. Test code should be as clean as production code (with some exceptions, usually related to memory or efficiency).

  2. As the production code changes, so does the test code.

  3. Tests help keep your production code flexible and maintainable.

  4. Tests allow you to make changes, allowing you to confidently refactor without the fear of not noticing it yourself.

  5. Structure your tests using the Arrange-Act-Assert (also known as Build-Operate-Check, Setup-Exercise-Verify, or Given-When-Then) pattern.

  6. Use domain-specific functions to make tests easier to write and read.

  7. Score one concept per test.

  8. Tests must be fast.

  9. Tests must be independent.

  10. Tests must be repeatable.

  11. Tests should not require confirmation.

  12. Tests should be written in a timely manner, shortly before or after production code is written, not months later.

  13. If your tests are bad, expect there to be bugs in your code.

Chapter 10: Classes

  1. Classes should be small.

  2. Classes should only be responsible for one thing and should have only one reason for changing (single responsibility principle).

  3. If you can't come up with a clear name for the class, it's probably too big.

  4. Your job doesn't end when you get a piece of code to work. The next step will be to refactor and clean up the code.

  5. Using many small classes instead of several large classes in your application reduces the amount of information a developer must understand when working on any given task.

  6. Having a good test suite allows you to refactor with confidence when you break large classes into smaller ones.

  7. Classes should be open for extension, but closed for modification (open-closed principle).

  8. Interfaces and abstract classes create seams that make testing easier.

Chapter 11: Systems

  1. Use dependency injection to give developers the flexibility to pass any object with the appropriate interface to another class.

  2. Use dependency injection to create interfaces between objects in your application to make testing easier.

  3. Software systems are not like a building that needs to be designed in advance. They are more like cities that grow and expand over time, adapting to current needs.

  4. Postpone making a decision until the last critical moment.

  5. Use domain-specific language so that domain experts and developers use the same terminology.

  6. Don't overcomplicate your system. Use the simplest thing that works.

Chapter 12: Deployment

  1. Systems that cannot be tested cannot be verified, and systems that cannot be verified should never be deployed.

  2. Writing tests leads to better design because code that is easy to test often uses dependency injection, interfaces, and abstraction.

  3. A good set of tests will eliminate the fear of breaking your application while refactoring.

  4. Duplicating code creates more risk because there are more places in the code that can be changed and even more places where errors can be hidden.

  5. The code you write now is easier to understand because you are deeply involved in understanding it. It is not easy for others to quickly reach the same level of understanding.

  6. Most of the cost of a software project is related to long-term maintenance.

  7. Tests serve as living documentation of how your application should (and does) behave.

  8. Don't move any further once your code works. Take the time to make it clearer and more understandable.

  9. The next person to read your code in the near future will most likely be you. Be kind to your future self by writing code that is easy to understand.

  10. Resist dogma. Embrace pragmatism.

  11. It takes decades to become a really good software engineer. You can speed up your learning curve by learning from the experts around you and learning commonly used design patterns.

Chapter 13: Parallelism

  1. Writing parallel code is difficult.

  2. Occasional bugs and problems that are difficult to reproduce are often concurrency problems.

  3. Testing does not guarantee that your application will be bug-free, but it will minimize the risk.

  4. Learn about common concurrency problems and their possible solutions.

Chapter 14: Sequential Refinement

  1. Clean code doesn't usually start with a blank slate. You write a rough solution first and then refactor it to make it cleaner.

  2. It is a mistake to stop working on the code once it has started working. Take the time to make it even better after it's already working.

  3. The unrest is growing gradually.

  4. If you find yourself in a bind where adding features is too difficult or takes too long, stop writing features and start refactoring.

  5. Incremental change is often better than rebuilding from scratch.

  6. Use Test-Driven Development (TDD) to make large numbers of very small changes.

  7. Good software design involves separating the concerns in your code and separating the code into smaller modules, classes, and files.

  8. It's easier to clean up a mess immediately after you've made it than to clean up later.

Chapter 15: JUnit Internals

  1. Negative variable names or conditional expressions are a little more difficult to understand than positive ones.

  2. Refactoring is an iterative process full of trial and error.

  3. Leave the codebase better than when you found it (Boy Scout Rule). (Repeated from Chapter 1)

Chapter 16: Refactoring SerialDate

  1. Code reviews and criticism of our code make us better, and we should welcome that.

  2. First make the code work, then fix it.

  3. Not every line of code needs testing.

Chapter 17: Smells and Heuristics

  1. Clean code is not a set of rules, but rather a system of values ​​that determine the quality of your work.

[In this chapter, Uncle Bob lists 66 more variations of his code and heuristics, many of which were covered in the rest of the book. Reproducing them here would essentially be copying and pasting the name of each item, so I've refrained from doing so. I would suggest you read the book instead!]

Conclusion

Let's end where we started: Clean Code by Robert C. Martin is the most recommended programming book of all time. There's a good reason for this.
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION