Clean Classes

Clean Code @ Borda: Volume III

Bilal Dinç
Borda Technology
Published in
4 min readAug 31, 2022

--

This article is the third of the clean code series. In this article, we will learn how to code clean classes.

Small Classes

Like functions, classes also should be small. However, in classes, we do not count lines. We measure the size of the class with its responsibilities. This is closely related to one of the SOLID principles Single Responsibility Principle (SRP). SRP states that a class, a module, or any programming unit should have only one responsibility. This can be rephrased as Uncle Bob says.

A class should have one, and only one, reason to change.

Finding Big Classes

A good heuristic for finding classes that have more than one responsibility which is to say more than one reason to change would be examining the names of the classes. If a class name contains conjunctions like AND or OR, it is an indicator that the class is responsible for more than one thing. Moreover, if a class name is too generic, like Manager or Processor, and it is too hard to find a concise name for the class, the responsibilities of the class should be re-examined.

The more ambiguous the class name, the more likely it has too many responsibilities.

Yet another indicator that class is too big is the measure of cohesion. Every class manipulates its instance variables through its methods. Uncle Bob defines cohesiveness as follows.

The more variables a method manipulates the more cohesive that method is to its class. A class in which each variable is used by each method is maximally cohesive.

It is almost impossible to create maximally cohesive classes. However, It is advisable to make classes as cohesive as possible. A highly cohesive class means that the methods and variables of the class are more dependent on each other and compose a logical whole. If one or two variables are only used by a subset of methods, it’s an indicator that the logic of these methods and variables can be removed from the class with ease and reorganized into a new class.

Counter Arguments For Small Classes

Some developers argue that having too many small classes makes it harder to see the bigger picture. Navigation from class to class to understand one simple flow may look more cumbersome at first glance. However, the number of things should be learned in a system with a few but large classes, same as a system with more small classes. Moreover, Navigating through classes is much easy with nowadays’ IDEs, and once you learn the class organization of your system, adding new classes or modifying existing ones becomes relatively easy since you only need to understand and navigate relevant parts of the system.

Organizing for Change

It is almost impossible for a system to stay as it is. Change is inevitable. For this reason, the system must be designed or organized for possible future changes.

In a clean system we organize our classes so as to reduce the risk of change.

The Open-Closed Principle (OCP) is the second rule in SOLID principles that embodies this idea. OCP states that classes should be open for extension and closed for modifications.

In an ideal system, we incorporate new features by extending the system, not by modifying existing code.

A good example of this is having a single class for all error types.

This class is definitely not closed for modifications. Every time we need to add a new error type, we need to modify this class. Also, it is very likely that this class file to be modified in different branches during development, and this will cause merge conflicts.

For the sake of demonstration, the code contains all classes. However new file for each class should be created. Now, if a new error type is needed Error class can be extended, which means we are adding new types of errors by extending the class. Moreover, the remaining classes do not need to be modified, which says classes are closed for modification.

Isolating from Change

Another concept that helps our code to be resistant to change is the Dependency Inversion Principle (DIP) which is one of the SOLID principles.

In essence, the DIP says that our classes should depend upon abstractions, not on concrete details.

DIP decouples implementation detail with a public interface of the class, which makes client code dependent only on the interface. This enables us to plug in any implantation of the interface at will. This is most beneficial when client code goes under test. Dependencies of a class under test can be replaced with mocked implementation if necessary.

Assume we have a class named SummaryCalculator that depends on FileService class that makes file operations. It is needed to be mocked if you want to unit test SummaryCalculator class.

By making the class depends on an interface instead of concrete implementation, we manage to substitute actual FileService with FileServiceMock, which is a dummy implementation of the same interface, and unit testing becomes possible.

This way, dependencies that make API calls to other services or database calls can be mocked with ease since client code that uses these classes only depend on their interface, not implementations.

Conclusion

Writing clean classes mostly depends on applying SOLID principles with proper naming. And continues refactoring as the code base grows. Besides these, the most important idea to be understood is making code work and making code clean are two different activities. Every time code is finished and working properly, instead of going to the next problem, we need to spend considerable effort to make the code clean.

Thanks for reading.

--

--