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.

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?
')
- Singleton
- Strong Coupling
- Impossibility of testing
- Premature optimization
- Non-descriptive naming
- Code duplication
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:
- Programs that use the global state are very difficult to test;
- Programs that depend on the global state hide their dependencies.
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:
- Do not do this;
- (for professionals only!) Don't do it yet.
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
- Principle of openness / closeness
- Barbara Liskov substitution principle
- Interface separation principle
- Dependency Inversion Principle
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:
- Abstractions should not depend on the details.
- Details must depend on abstractions.
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:
- Singleton
- Strong bonding
- Impossibility of testing
- Premature optimization
- Non-descriptive naming
- Code duplication
SOLID is an acronym for five basic principles of object-oriented programming and design and engineering to correct
STUPID code:
- Principle of sole duty
- Principle of openness / closeness
- Barbara Liskov substitution principle
- Interface separation principle
- Dependency Inversion Principle
Golden Rule: Turn on your brains!