📜 ⬆️ ⬇️

From STUPID code to SOLID code

Last week, I gave a talk on object-oriented programming in Michelin, in the company where I work. I talked about writing more efficient code, from STUPID code to SOLID code ! STUPID, as well as SOLID are acronyms, and have been considered quite a lot for a long time. However, these mnemonics are not always known, so it makes sense to spread this information.

image

Next, I will introduce you to the principles of STUPID and SOLID. It should be borne in mind that these are principles, not laws. However, considering them as laws would be good for those who want to improve in writing code.

STUPID code, seriously?


This may hurt your feelings, but you probably already wrote a lot of STUPID code. So do I. But what does it mean?
')

Below in the text I will focus on each item in more detail. This can be said, the transcripts of my story in general terms.

Singleton


The loner template is probably the most well-known design pattern, as well as the most underrated. Do you know about loner syndrome? This is when you think that the “singleton” template is the most suitable template for the current use case that you have. In other words, you use it everywhere. This is definitely not cool.

Single elements are contradictory, and they are often considered erroneous patterns. You should avoid them. In fact, using singleton is not a problem, but a sign of a problem. Here are two reasons why:



But should you really avoid them all the time? I would say yes, because it is often possible to replace the use of a singleton with something better. Avoiding everything static is very important to prevent strong cohesion.

Strong connectivity


Strong connectedness is a generalization of the singleton problem. In short, you should reduce the connection between your modules. Connectivity is a measure of how subroutines or modules are related.

If making a change in one module in your application requires that you change another module, then there is a connection. For example, you instantiate objects in your constructor class instead of passing instances as parameters. This is bad because it does not allow further changes, such as replacing an instance with an instance of a subclass, with a mock object or whatever.

Strongly connected modules are difficult to reuse, and also difficult to test.

Impossibility of testing


In my opinion, testing should not be difficult! No, really. Every time you do not write unit tests, because you don’t have time, the real problem is that your code is not that efficient, but this is another story.

In most cases, the impossibility of testing is caused by strong coupling.

Premature optimization


Donald Erwin Knuth said: “Premature optimization is the root of all evil. Only costs alone, no good. ” In fact, optimized systems are much more complicated than simply writing a cycle or using a pre-increment instead of post-increment. Ultimately, you will be left with an unreadable code. That is why Premature Optimization is often considered erroneous.

My friend often says that there are two rules for optimizing an application:



Non-descriptive naming


It should be obvious, but you still have to say it: name your classes, methods, attributes, and variables properly. Oh, and do not cut them! And yes, you write code for people, not machines. They don't understand what you are writing, anyway. Computers understand only 0 and 1. Programming languages ​​are meant for people.

Code duplication


Duplicate code is inefficient, so do not repeat, and also make it shorter and easier. Write the code only once!

Now that I have explained what the STUPID code is, you might think that your code is STUPID. It does not matter (yet). Do not be discouraged, keep calm and write the SOLID code instead!

SOLID to the rescue


SOLID is a term that describes a set of design principles for efficient code, which was invented by Robert C. Martin, also known as Uncle Bob.

SOLID means:



Principle of sole duty


The principle of a single duty (Single-Responsibility Principle, SRP) states that a single duty must be assigned to each class. A class should have only one reason to change.

Just because you can add whatever you want to your class does not mean that you have to do it. Responsibilities will help you develop the application better. Ask yourself if the logic you represent should be in this class or not. Using levels in the app helps a lot. Divide the large classes into smaller ones and avoid the “ divine ” classes. Last but not least, write simple comments. If you start writing comments such as in this case, but if, except when, or, then you do it wrong.

Principle of openness / closeness


The principle of openness / closeness (Open / Closed Principle, OCP): Entities (classes, modules, functions, etc.) must be open for expansion, but closed for modification.

You must make all private instance variables by default. Write get and set methods only when you really need them. I have already answered this question in a previous article, since the ninth rule of Object Gymnastics is associated with this principle.

Barbara Liskov substitution principle


Liskov Substitution Principle (LSP): It should be possible to substitute any subtype instead of the base type.
Let's take an example. A rectangle is a flat figure with four right angles. It has width (width) and height (height).

Now, take a look at the following pseudo-code:
rect = new Rectangle(); rect.width = 10; rect.height = 20; assert 10 == rect.width assert 20 == rect.height 

We simply set the width and height to the height of the Rectangle instance, and then we confirm that both properties are correct. So far, so good.

Now we can improve our definition by saying that a rectangle with four sides of the same length is called a square. The square is a rectangle, so we can create the Square class, which extends the Rectangle class, and replace the first line above with the bottom:
 rect = new Square(); 

According to the definition of a square, its width is equal to its height. Can you identify the problem? The first statement will stop working because we had to change the behavior of the set methods in the Square class to fit the definition. This is a violation of the Barbara Liskov principle of substitution.

Interface separation principle


Interface Segregation Principle or ISP: many specialized interfaces are better than one universal. In other words, you don’t have to implement methods that you don’t use. Implementing the ISP gives weak connectivity and strong connectivity.

When it comes to connectedness, connectivity is also often mentioned. Strong connectivity means keeping similar and related elements together. The union of connectivity and connectedness is an orthogonal structure.

The idea is to keep the components oriented, and try to minimize the dependencies between them.

Please note that this is similar to the principle of the only duty. Interface - a contract that meets the needs. It is normal to have a class that implements different interfaces, but be careful not to break SRP.

Dependency Inversion Principle


Dependency Inversion Principle (DIP) has two main principles:



This principle can be rephrased as using the same level of abstraction at a given level. Interfaces must depend on other interfaces. Do not add specific classes to interface method signatures. However, use interfaces in your class methods.

Note that the principle of dependency inversion does not coincide with dependency injection. Dependency injection is when one object knows about another dependent object. In other words, it’s about how one object gets addicted. On the other hand, the principle of dependency injection is in the level of abstraction. In addition, a dependency injection container is a way to automatically join classes. This does not mean that you are doing dependency injection though. For example, take a look at the Service Locator .

Also, instead of working with classes that are tightly coupled, use interfaces. This is called interface programming . It reduces the dependence on implementation features and allows code reuse. It also ensures that you can replace the implementation without violating the expectations of that interface, according to the Barbara Liskov Substitution Principle.

Conclusion


As you may have noticed, avoiding strong connectivity here is a key element. There is a large amount of code here, and if you start by focusing on fixing it alone, then you will immediately start writing the best code.

Here's a tip for you. There are many principles in software development. Even if you do not understand all these principles, always think before writing code. Take your time, and try to understand what you do not understand.

Honestly, writing a SOLID code is not that difficult.

TL; DR

STUPID is an acronym that describes a bad experience in Oriented Object Programming:



SOLID is an acronym for five basic principles of object-oriented programming and design and engineering to correct STUPID code:



Golden Rule: Turn on your brains!

Source: https://habr.com/ru/post/273843/


All Articles