Java Clean Code - How to Write Clean Code in Java?
Clean code is code that is easy to understand and maintain. In short, clean coding is the way of writing code such that the code is easily readable, testable, and less prone to errors.
There are several principles that should be kept in mind while developing a software application. Some of these principles are SOLID principles, DRY and KISS principles.
Apart from principles, there are certain properties such as high cohesion and low coupling, documented code, proper naming, project structure, etc. that leads to quality code.
What Is Clean Code in Java?
Steven C. McConnell, the author of Code Complete, Rapid Development, and Software Estimation who is cited as an expert in software engineering, once said
"Good code is its own best documentation" - Steve McConnell
Steve McConnell wanted the programmers to think before adding any comment in the code. He encouraged improving the code quality to such a level that comments are not required in the code at all. He supported the idea of documentation post coding to make the code functionality even more clearer.
But What is a clean code? The code that is less prone to errors and easily readable, modifiable, scalable(in some cases), maintainable by any developer (not just its programmer) is referred to as "Clean Code". Less prone to errors means that there will be very few chances of getting bugs in that code. Have you ever thought about Why writing clean code is so important? Let's find out in the next section.
Clean Code is easily readable, maintainable, and less prone to errors.
Why do we need to care about Clean Code?
There can be multiple answers to this question, but we will choose the most suitable answer. We need to care about Clean Code because it eventually shows the programmer's capability of writing a well-maintainable piece of code that is easily understood by other developers that are going to work with that code.
See, in real life, when a programmer works on a codebase, there is a high chance that at some point in time, other programmers also work on the same codebase. Hence, the programmer needs to write clean code as it will eventually be easier for other programmers to handle that code. More precisely, it will be easier to troubleshoot errors that can appear in the future.
Writing clean code reflects a programmer's capability to write the code that makes their and other programmers' lives easier.
Characteristics of Clean Code
Let us discuss the characteristics of clean code.
- Simple: The code should be made as simple as possible. Making a piece of code unnecessarily complex not only makes the code hard-to-understand but prone to errors as well.
- Maintainable: It should be maintainable in the long run as many different developers can work on that code. By the term maintainable, it is meant that the code can be easily modified without breaking it.
- Testable: It should be easily testable and less prone to errors. A clean code testing is intuitive and does not require manual intervention. Clean code encourages automated testing as the code organization is itself very standard that supports automation.
These are the characteristics that differentiate Clean Code from Bad Code. But What is a Bad Code? Are there any signs or characteristics of bad code? So yes, you need to be aware of several signs of bad code.
What are the signs of bad code (Unclean code)?
First of all, what is a Bad Code? There can not be any specific answer to this question as the answer depends on the programmer's perspective. To be specific, any code that leads to a specific set of problems, in the long run, can be referred to as Bad Code. These problems can be:
- Hard to read code
- Unnecessarily complex
- Not easily testable
- Hard to modify
How to write Clean Code in Java?
So finally, it's time to learn how to write clean code in Java. Java is one of the most used programming languages, which has evolved immensely in the past few years. Many big tech firms use Java for their prominent operations.
The points mentioned below are extremely important to achieving clean coding in Java and other programming languages as well. So let us dig deeper:
Project Structure refers to the way of organizing different utilities of your projects such as source files, data, configurations, tests, etc.
It is very necessary to maintain a sound project structure to reduce search time among files. In Java, there is no such rule to follow a particular structure for your project, but it does not mean that you should not. In fact, it is a good practice to follow a particular project structure.
Did you know?
A Java build tool is a command-line utility or program that automates the compiling process. In fact, processes like assembling and deploying the software are also automated using Java build tools. Build tools also help in package management(for project structure), dependency handling, etc. Some popular Java build tools are Apache Maven, SBT, Gradle, and Apache Ant with Ivy.
Even though you can follow your pattern, several Java build tools advise a specific structure for your project. One such build tool is Maven. Maven suggests some folders we should create and include in our project structure. So let's have a look at the project structure that Maven suggests.
- src/main/java: It contains the source files of your project. You can identify it as the sub-folder is main in this case.
- src/main/resources: It contains the resource files of your project. You can identify it as the sub-folder is main in this case, also.
- src/test/java: It contains the test source files of your project. You can identify it as the sub-folder is test in this case.
- src/test/resources: It contains the test resource files of your project. You can identify it as the sub-folder is test in this case, also.
As you can see, the files in this type of project structure are properly segregated as application and testing codes and resources. If not Maven, you can choose from other such project structures available for Java according to your requirements. Now we are going to see the second point i.e. Naming.
2. Proper Naming
Any programming language out there has some set of rules that you need to follow for creating and naming identifiers. Java also has a set of such rules that need to be followed. While following the naming rules, one should also name the identifiers that show some meaning (that relates to the variable).
When we name related to the content of a variable, the code becomes much more readable and understandable, which eventually helps in maintaining the code in the long run. In Java, we have to name variables, classes, methods, etc. Hence we should always give them a name that relates to their functionality.
For example, If you want to create a variable for counting, name it 'counter' instead of naming it 'c' or something like that.
You should always avoid naming variables with a single character like 'a', 'b', 'c', etc.
3. Source File Structure
The source file structure can contain many different types of elements inside it. We can follow any source file structure available out there, or we can create our own source file structure if needed and stick to it.
Normally the elements placed in the source file are in the following order:
- Package statement
- Import statements
- All static imports
- All non-static imports
- Exactly one top-level class
- Class variables
- Instance variables
An example of a typical source file structure that is well-formed:
4. Code Formatting: Whitespaces and Indentation
This may look like the most obvious thing in this article, but it is often ignored. Whitespaces can help you make your code very readable. That is why it is advised to add whitespaces and indentation as this makes the code less prone to errors and easy to read and understand.
In this function, whitespaces and indentation are not taken care of.
While in this function, whitespaces and indentation are properly taken care of.
5. Method Parameters
Most of the time, we create methods with parameters, but sometimes we add so many parameters to a single method that it leads to confusion. The idea here is simple: avoid adding more than three parameters if possible, as it can create unnecessary confusion for other developers or programmers who will deal with that code in the future. You can also go for refactoring if possible, as we have done in the example given below:
In Programming, Refactoring is a technique used for restructuring an existing code without modifying the external behavior of the code.
In the example above, we can create a class Employee_Details and data such as awards, ctc, experience can be its instance variables. Hence, instead of passing three variables separately, we can now send an object of Employee_Details class.
6. Avoid Hardcoding
In simple words, hardcoding is the practice of adding the raw data directly into the source code of a program wherever needed instead of using a variable to store the raw data and using that variable. Remember that heavy hard coding can cause serious maintainability problems in your project.
- Let's say you have decided to use 404 as the error code in your project. Whenever, an error occurs in a method 404 is returned. Using this error code 404, the control flow is changed as numerous places.
- Now, what happens when you need to use a new error code say -1. You have replace the raw value 404 with -1 at all the places where it is used.
- This is very difficult and irritating when it comes to large projects. Instead we can simply use a constant ERROR_CODE and assign it the value 404 or -1. Now, this constant identifier can be used anywhere in the code.
- If, in future, any change is required, we have to only change the ERROR_CODE constant identifier and rest everything will work smoothly.
7. Code Comments
Many experienced programmers or developers recommend adding comments to your code so that you or any other developer can understand the functioning of that code in the future. Commenting is also considered one of the best practices to make the code easily understandable. It has been observed that initially, some developers don't follow the commenting practice. Then after some time, when they see that uncommented code, it becomes very difficult for them to understand it.
In Java, two kinds of comments are allowed: Documentation comments and Implementation comments. Let us see them in detail.
- Documentation/JavaDoc Comments
- Here, The target audience is the users of the codebase
- The details added here are generally implementation free and focus mostly on the specification purposes.
- Implementation/Block Comments
- Here, The target audience is the developers that work on the codebase
- The details added here are generally specific to the implementation.
It is a good practice to use JavaDoc comments for most of the classes, interfaces, public and protected methods, etc.
Logging is one of the most important factors in clean coding. A well-logged code is easy to debug and can save a developer's work hours. One should always avoid excessive logging because it can lead to decreased performance.
In the history of object-oriented software development, Robert C. Martin promoted the SOLID design principles. These principles are some of the best design principles in object-oriented software development. So, SOLID is a mnemonic acronym for the five principles given below:
- Single Responsibility Principle
- Open/Closed Principle
- Liskov Substitution Principle
- Interface Segregation Principle
- Dependency Inversion Principle
Each of the above-mentioned principles has one goal: to improve the maintainability, reusability, and robustness of object-oriented applications. Let us see them one by one in brief.
Single Responsibility Principle: This principle states that, In Java, each interface, class, or method we define should be very specific, meaning it should have a single responsibility. Simply put, it should do only one task and do it well. By following this principle consistently, the methods and classes become smaller hence easily testable.
Open-Closed Principle: This principle states that our code should ideally be open to any kind of extension and closed for any modification. In simple words, our code should be easy to extend but good enough that no modification is required in our code.
Liskov Substitution Principle: This principle states that the objects of a superclass should be replaceable with the objects of its subclasses but without causing the application to break.
Interface Segregation Principle: Defined by Robert C., this principle aims to reduce the side effects from the code and frequency of required changes by splitting or dividing the software into many independent parts or interfaces.
Dependency Inversion Principle: According to this principle, classes should only depend on abstractions and not on implementations. In simple words, High-level(complex) modules, which provide complex logic to your software, should be easily reusable. They should not be affected by the low-level modules' changes, which generally provide utility features.
10. DRY & KISS
DRY is an acronym that stands for "Don't Repeat Yourself". DRY emphasizes not repeating the same code again and again. Simply put, the main motive behind this principle is to make the code reusable. It says that every piece of knowledge must have a single authoritative presentation within a system and it must symbolise the idea/functionality it has presented.
KISS is an acronym that stands for "Keep It Simple, Stupid". As the words of this acronym suggest, this principle states that the code should be made as simple as possible. It focuses on the idea that if we can’t understand a product, we can’t use it properly and that the widest possible audience must be able to understand it, if the product is to gain maximum market share.
Example of Clean Code in Java
Now, as we have seen how we can write clean code in Java, let us see an example.
In the above-given example, we have created a public class named Employee (remember that we name the class with the first letter as capital) then we have created a private string variable called employeeName and a public method called getEmployeeName which returns the string employeeName. But why are we calling it "Clean code"? We are calling it "Clean Code" because of the following characteristics that it possesses:
- The variable, class, and method are named according to the naming convention, like the class has the first letter capital, variable and method are named as per camelCase naming convention, and they also reflect a specific meaning according to their name.
- We made sure that our method is doing only one thing i.e., getting employee names.
- Whitespaces and indentation are also properly utilized.
Why Should Your Code Have Low Coupling and High Cohesion?
In Java programming, Cohesion generally means the degree to which the elements of a module are functionally dependent on each other. It refers to the internal glue that keeps the module together.
It can also be said that all the code related to each other should be bundled together in a single module. Like there can be different classes, methods, variables, logic, etc. that are related to each other, then they can be bundled together inside a single module. So Cohesion in particular, deals with the elements of the same module or class.
Coupling generally refers to the degree to which the different modules/classes depend on each other. In simple words, all the modules should be as independent as possible. It also refers that every module should be restricted to any one thing only.
So, Coupling in particular, deals with the elements of different modules or classes. If your code has low coupling and high cohesion, it will be easy to maintain, and debugging can become much more simple.
Low coupling and high cohesion lead to easily maintainable code where debugging becomes very simple.
Tools to Write Clean Code
Till now in this article, we have seen various practices and principles available out there that can be used to write clean code. There are certain tools also that can help you write clean code if utilized effectively. Like there are code formatters to format your code (by whitespaces and standard indentation) and some static analysis tools, etc. Let us discuss them in detail.
- Code Formatters: While writing code, proper formatting is essential, and the popular code editors for Java already have automatic code formatting. Due to automatic code formatting, programmers don't have to think about the code formatting and all. If you don't want the default code formatting that is available in the code editor, you can easily customize it as per your requirements.
- Static Analysis Tools: For Java, there are many static code analysis tools available out there such as Checkstyle, SonarQube, and SpotBugs, etc. which offer a set of rules that can be applied to your projects.
- Clean code can differentiate you from other programmers.
- The characteristics of clean code are: simple, readable, maintainable, and testable.
- The symptoms of bad code are: Hard to read, Unnecessarily complex, and hard to test and maintain.
- Hard coding should be avoided to write quality code. Hardcoding can lead to serious maintainability issues if the project grows in size.
- SOLID is a mnemonic for the five principles to write quality code:
- Single Responsibility Principle
- Open/Closed Principle
- Liskov Substitution Principle
- Interface Segregation Principle
- Dependency Inversion Principle
- DRY stands for "Don't Repeat Yourself". It focuses on code reusability.
- KISS stands for "Keep It Simple, Stupid". It focuses on making to code simple to understand.
- We should write code that has low coupling and high cohesion.
- Various tools like code formatters and Static Analysis Tools are available out there to make our work easier.