Do the developers have less interest in design patterns or they are more pragmatic?

The majority of developers have already heard about the design patterns, GOF(Gang Of Four) patterns are the most popularized, and each developer has his way to learn them , we can enumerate:

  • Reading a book.
  • From web sites.
  • From a collegue.
  • Doing a training.

Regardless of the method chose, we can learn by heart the patterns and spent hours to memorize their UML diagrams, but when we need to use them in a real project, it becomes more problematic. And related to google trends the design patterns are not more popular as before. 

trend

After the analysis of many C++ open source projects using CppDepend. We can confirm this trend. Indeed we discovered that the design patterns are not widely used  even for the known projects. However  some basic concepts like the lose coupling and the high cohesion are widely used in many projects.

 Coupling

Low coupling is desirable because a change in one area of an application will require fewer changes throughout the entire application. In the long run, this could alleviate a lot of time, effort, and cost associated with modifying and adding new features to an application.

Low coupling could be acheived by using abstract classes. Here are three key benefits derived from using them:

  • An abstract class provides a way to define a contract that promotes reuse. If an object implements an abstract class then that object is to conform to a standard. An object that uses another object is called a consumer. An abstract class is a contract between an object and its consumer.
  • An abstract class also provides a level of abstraction that makes programs easier to understand. abstract class allow developers to start talking about the general way that code behaves without having to get in to a lot of detailed specifics.
  • An abstract class enforce low coupling between components, what’s make easy to protect the abstract class consumer from any implementation changes in the classes implementing the abstract classes.

Let’s search for all abstract classes defined by OpenCV :

opencv6

OpenCV defines many abstract classes to enforce loose coupling.

If our primary goal is to enforce loose coupling, there’s a common mistake when using abstract classes, that could kill the utility of using them. It’s the using of the concrete classes instead of abstract ones, to explain better this problem let’s take the following example:

The class A implements the abstract class IA which contains the calculate() method, the consumer class C is implemented like this

public class C
{
   ….
   public:
      void calculate()
      {
        …..
        m_a->calculate();
        ….
       }
       A* m_a;
 };

The class C instead of referencing the abstract class IA, it references the class A, in this case we lose the low coupling benefit, this implementation has two major drawbacks:

  • If we decide to use another implementation of IA, we must change the code of C class.
  • If some methods are added to A not existing in IA, and C use them, we also lose the contract benefit of using interfaces.

C# introduced the explicit interface implementation capability to the language to ensure that a method from the IA will be never called from a reference to concrete classes, but only from a reference to the interface. This technique is very useful to protect developers from losing the benefit of using interfaces.

 Cohesion

The single responsibility principle states that a class should not have more than one reason to change. Such a class is said to be cohesive. A high LCOM value generally pinpoints a poorly cohesive class. There are several LCOM metrics. The LCOM takes its values in the range [0-1]. The LCOM HS (HS stands for Henderson-Sellers) takes its values in the range [0-2]. A LCOM HS value highest than 1 should be considered alarming. Here are  to compute LCOM metrics:

LCOM = 1 – (sum(MF)/M*F)
LCOM HS = (M – sum(MF)/F)(M-1)

Where:

  • M is the number of methods in class (both static and instance methods are counted, it includes also constructors, properties getters/setters, events add/remove methods).
  • F is the number of instance fields in the class.
  • MF is the number of methods of the class accessing a particular instance field.
  • Sum(MF) is the sum of MF over all instance fields of the class.

The underlying idea behind these formulas can be stated as follow: a class is utterly cohesive if all its methods use all its methods use all its instance fields, which means that sum(MF)=M*F and then LCOM = 0 and LCOMHS = 0.

LCOMHS value higher than 1 should be considered alarming.

Here are the less cohesive classes from the Unreal Engine source code:

unreal36

Only few types are not cohesive.

 Abstract vs instability: POCO case study

Robert C.Martin wrote an interesting article about a set of metrics that can be used to measure the quality of an object-oriented design in terms of the interdependence between the subsystems of that design.

Here’s from the article what he said about the interdependence between modules:

What is it that makes a design rigid, fragile and difficult to reuse. It is the interdependence of the subsystems within that design. A design is rigid if it cannot be easily changed. Such rigidity is due to the fact that a single change to heavily interdependent software begins a cascade of changes in dependent modules. When the extent of that cascade of change cannot be predicted by the designers or maintainers the impact of the change cannot be estimated. This makes the cost of the change impossible to estimate. Managers, faced with such unpredictability, become reluctant to authorize changes. Thus the design becomes rigid.

For POCO here’s the “Abstractness vs Instability” graph:

The idea behind this graph is that the more a code element of a program is popular, the more it should be abstract. Or in other words, avoid depending too much directly on implementations, depend on abstractions instead. By popular code element I mean a project (but the idea works also for packages and types) that is massively used by other projects of the program.
It is not a good idea to have concrete types very popular in your code base. This provokes some Zones of Pains in your program, where changing the implementations can potentially affect a large portion of the program. And implementations are known to evolve more often than abstractions.

The main sequence line (dotted) in the above diagram shows the how abstractness and instability should be balanced. A stable component would be positioned on the left. If you check the main sequence you can see that such a component should be very abstract to be near the desirable line – on the other hand, if its degree of abstraction is low, it is positioned in an area that is called the “zone of pain”.

Conclusion:

What’s very important is not to know exactly pattern names and how to implement them as described in the documentation, but what’s more relevant is the motivation behind each pattern, it’s from motivations that we invent the patterns.

Coupling, cohesion, abstractness and instability  are some powerful concepts to enforce the design of your OOP project, Many khown C++ projects use only the singleton from the GOF. But they enforce the design using some basic concepts, they follow more a pragmatic approach.