Clean Code – Chapter 10: Classes

Tram Ho

Class Organization

By convention, the Class should start with a list of variables. Public static constants, if any, should be left first. Then comes the private static variables. There is rarely a good reason to set a public variable.

Public functions should be implemented according to the list of variables. Place private utilities called by a public funcion immediately after that public function. This follows the Stepdown rule and helps the program to be read as an article. Encapsulation

We want to keep variables and utility functions private, but we shouldn’t be too crazy about it. Sometimes we keep a variable or utility function protected, so it can be accessed by a test. For us, testing is the principle. If a test in the same package needs to call a function or access a variable, we will leave it protected or package scope. However, the first thing we do is look for a way to maintain privacy. Easing packaging is always a last resort.

=> List of variables: public static constants – private static variable – (public variable)

Classes Should Be Small

The first rule is that classes should be made small. The second principle, the class should be made smaller. No, we will not repeat exactly what is in the Functions Chapter. But, like Functions, smaller is the first rule when it comes to designing classes. As Functions, the direct question is always “How small?”

With Functions, we measure them by counting lines. With Classes, we measure it differently, we count responsibilities. An example of a class, SuperDashboard, with about 70 public methods. Most developers claim that it has a super size. Others think of it as a “God class”. The next is also SuperDashboard, but only contains methods:

Five methods is not much right? In this case it may be considered that, but despite the small number of methods, SuperDashboard has many responsibilities.

The class name should describe the responsibility of what it responds to. In fact, naming is probably the first way to determine the size of a class. If we can’t get a concise name for the class, then it’s likely that the class is too large. With a vague name for the class, it was most likely responsible for it.

We can write a brief description for a class with about 25 words, without using words like “if”, “and”, “or” or “but”.

The Single Responsibility Principle

A class or module should have one and only one reason to change. This principle gives us a definition of responsibility and also advocates the size of the class. Class should have a responsibility – a unique reason to change.

For example, the SuperDashboard class has two reasons for changing. First, it tracks the verson information and seems to need to be updated every time the software is shipped. Second, it manages the Java Swing component (a derivative of JFrame, Swing represents a high-level window interface). No doubt we will update the version number if we change anything in the Swing code, but the opposite is not necessarily true: we can change the version information based on the change. Other code is on the system.

Trying to identify responsibilities often helps us to see and create better abstractions in code. We can easily retrieve 3 methods in SuperDashboard to distribute version information to split a class named Version. This class has the potential to reuse in other applications!

SRP is one of the important concepts in object-oriented design. It is also a simple concept to understand and comply with. However, the difficulty is that SRP is the most insulting principle ? ) We often encounter classes that do too many things. Why?

Running software and making it clean are two completely different things. Most of us are confined to prioritizing making our code run over organizing and making it clean. This is a perfect fit. Maintaining relationships is only important when our program is in operation.

The problem here is that so many of us think we’re just doing it so that the program works after one. We fail to reorganize and clean them up. We turn to issues other than going back and breaking classes to cram in the principle that each class should take on a single responsibility.

At the same time, many developers are concerned that a large number of small classes for the sole purpose will make it difficult to understand the big picture. They worry about having to go from class to class to understand how a great piece of work gets done.

However, a system with many small classes does not move much more than a few large classes. It is as much as reading a system with few large classes. So the question here is: Do you want your tool with many small drawers, each with individual components and concepts and labels? Or do you want a drawer and get rid of everything in there

Each large system will contain a large number of logic and complexity. The main goal in managing such complexity is to organize it so that the developer knows where to find everything and simply understands the complexity of the problem to be learned immediately. On the contrary, a system with large classes and many purposes always hinders us by trying to force us to wade through so many things that are not necessarily known right now. => We want our system to be made up of many small classes, not a few but large. Each small class summed up by a single responsibility, there is only one reason to change, interact with a few other objects to achieve the state that the system wants.

Cohesion

Class should have a small number of variables. Each method of a class should manipulate one or more variables. Each variable in the class used by each method should have maximum cohesion.

The maximum cohesion here is that the methods and variables of the class are dependent and cohesive as a logical whole.

Put simply, the class should limit the number of variables, and methods within the class use at least one of these variables to increase cohesion.

Maintaining Cohesion Results in Many Small Classes

If you divide a large function into many smaller functions, this will increase the class size at the same time. Assume that a large function with multiple variables is declared inside it. If you want to extract a smaller function, that function is. However, your code wants to use the 4 variables declared in the function. Do you need to pass all four variables to the new function as a parameter?

Not at all! If we put those 4 variables in the class’s common variable, then we can extract the code without passing any variables there. It is easy to split the function into small pieces.

Unfortunately, that makes the class no longer cohesive, because we are increasingly piling up the class while only a few functions need to share them.

So, if some functions want to share certain variables, why not create a class of their own? Of course, if the class has lost its solidarity, divide it!

Organizing for Change

For every system, the change is continuous. Each change leads to the risk of the rest of the system no longer working as intended. In a clean system, we organize classes to reduce the risk of change.

Example: Class Sql – SRP violation

Fix:

=> We structure our system with as little garbage as possible when we update them with new features or changing features. In an ideal system, we incorporate new features by expanding the system rather than changing the current code.

Isolating from Change (Loose Coupling – Dependency Invertion Principle)

Demand will change, so the code will always change. In a specific class, containing the actual details (code), abstract classes along with that represent concepts. A client class that depends on a particular detail is at risk when the details change. We can use interfaces and abstract classes to help manage collisions with those details.

Depend on a specific detail creates challenges for system testing.

For example: We build a Portfolio class and it depends on the external TokyoStockExchange API to get the value of the portfolio. The test case will be affected by the volatility of such a lookup. It is difficult to write a test when our answer will be different after only 5 minutes.

Instead of designing the portfolio so that it depends directly on TokyoStockExchange, we create an interface, StockExchange, and declare a unique method:

Now our tests can be performed on the StockExchange interface emulated for TokyoStockExchange.

If a system is decoupled, it will be more flexible and promote reuse. Coupling restriction means that elements in the system are isolated from other elements and from changes. Isolation makes each component in the system easier to understand.

Share the news now

Source : Viblo