How to write clean code?
What is clean code? Everyone has a different answer. The following are some of my observations from reading blogs, books and a decade of professional experience.
Naming conventions
- Don’t use abbreviations.
- Searchable names are better
- Avoid using coded names
Class names should be nouns.
public class User() {}public class Company() {}
Function names should be verbs, name should clearly state the action they perform.
public User fetchUserByEmail(String email) {}public void deleteUserById(String id) {}
Variables and arguments should be short and descriptive.
String firstName;String billingStatus;public Subscription updateSubscription(UpdateSubscriptionRequest updateRequest) {}
Constants should be all upper-case
String DATE_FORMAT = "YYYY-MM-DD";
String API_KEY = "XXXXXXXX";
Intention revealing names, code is way to communicate with developers reading it.
public boolean isUserHasPermission() {}public List<User> sortUserByAge() {}
Pick one word per concept is abstract and stick with it.
// bad practice
public List<User> getUsers() {}
public List<Message> fetchMessages() {}
public List<Contacts> retrieveContacts() {}// good practice
public List<User> fetchUsers() {}
public List<Message> fetchMessages() {}
public List<Contacts> fetchContacts() {}
Classes
- Classes should be small and contains small functions that strongly promoted idea of abstracting any and every piece of logic that may even are nominally complex into a separate function of something.
- Use access levels properly.
- Keep the utility functions and variables are private except some cases for testing.
- Expose necessary variables through getter and setter.
Functions
- Functions should short and do only one thing. If our functions is doing more than one thing, it is perfect moment to extract to another function.
- Small functions are easy to understand.
- Pass few arguments as possible, ideally none.
- Functions should not be longer than 20 lines and mostly less than 10 lines.
- This means that if statements, for and while loops should be one line long, obviously this line should be calling another function.
Software Engineering Principles
- DRY - Don’t repeat by yourself
- Kiss - Keep it simple stupid
- SOLID Principles
Don’t repeat by yourself
- A piece of code should not be repeated across the software.
- Reduce duplicate and increase reusability.
- Reusability means less code which leads to better maintainability, but remember some reusability can actually increase readability.
- Opposite of DRY is WET - Write everything twice, We enjoy typing, Waster everyone time.
- General rule, when you write something thrice, it is time to refactor the logic to a function and reuse.
Keep it simple stupid
- Keep the code as simple as possible.
- Avoid unnecessary complexity for better understanding and maintainability.
- To keep the code simple, break down the problem into small steps or functions.
SOLID Principles
- Single responsibility principle - One function should do only one thing. If a function does more than one thing, then the function should be split into multiple functions.
- Open or closed principle - The entity should open for extension, but closed for modification.
- Liskov substitution or substitution principle - A variable of a given type may be assigned a value of any sub type, and a method with a parameter of a given type may be invoked with an argument of any subtype of the type.
- Interface segregation - Larger interfaces should be split into smaller ones. By doing so, we can ensure that implementing classes only needs to be concerned about the methods that are interesting to them.
- Dependency inversion principle - High level modules should not depend upon low level modules. Both should depend abstrctions.
Code formatting
Code formatting is about communication.
- Functions should be separated by blank lines
- Concepts that are closely related must be held together vertically.
- Instance variable declarations should be in one location and most preferably on the top of the class
- Dependent functions should be vertically close, the caller should be above the Callee
- Lines should not exceed a maximum 200 characters.
- Don’t break indentation rule, even in the case of short, if statements or functions
Comments
- Comments should be used only as an explanation. If we write functions in a descriptive way, we can avoid writing comments at all.
- Do not write comments for what you are doing, instead write comments why you’re doing.
- Specify about hacks, workaround and temporary fixes.
- Don’t write redundant comments, if the code is self explanatory, no need to add comments.
- TODO & FIXME comments are ok, because the IDE can find them easily before ending the project.
Logging
- Avoid excess or less logging
- Avoid printing object
- Use correct log levels ERROR, WARN, INFO, DEBUG
Exception Handling
Things can go wrong, and when they do, we are responsible for handling and throwing valid responses, user can understand.
- Do not allow functions to take null parameters, use preconditions.
- Consider throwing specific exception rather than throwing null.
- Try not to catch general exceptions, instead catch specific exception and throw an appropriate code and message to the user.
- In the catch block, log exceptions and throw exception with all useful information. Don’t do anything extra.
- Finally block to execute clean up code like close connection, file and freeing up threads, etc.
Tests
- Unit tests should be fast and executed in a short time.
- Tests should not depend on other tests.
- One assert per test.
- Write unit tests to verify function arguments, conditional statements, exceptions and expected results.
Note: In my next posts will explain each topic separately with an example.