QuantLib

QuantLib is a cross-platform, quantitative finance C++ library for modeling, pricing, trading, and risk management in real-life.QuantLib offers tools that are useful both for practical implementation and for advanced modeling. It features market conventions, yield curve models, solvers, PDEs, Monte Carlo (low-discrepancy included), exotic options, VAR, and so on.

With QuantLib we can adapt pricing, calendar, market and so on, it’s very flexible but flexibility implies complexity, and its very interesting to discover how QuantLib provide this flexibility and also limit the complexity of using it.

QuantLib has the reputation of being over engineered and it use many design patterns, let’s discover with CppDepend the quality of implementation and design of QuantLib.

Here’s the result of the analysis:

Implementation

Number of line of code

Methods with many number of line of code are not easy to maintain and understand, let’s search for methods with more than 60 lines.

SELECT METHODS WHERE NbLinesOfCode > 60 ORDER BY NbLinesOfCode DESC

Less than 2% of methods has more than 60 lines.

Cyclomatic Complexity

Cyclomatic complexity is a popular procedural software metric equal to the number of decisions that can be taken in a procedure.

Let’s execute the following CQLinq request to detect methods to refactor.

SELECT METHODS WHERE CyclomaticComplexity > 10 ORDER BY CyclomaticComplexity DESC

So only 2% of methods can be considered as complex.

Which methods are complex and not enough commented?

SELECT METHODS WHERE CyclomaticComplexity > 10 AND PercentageComment < 20

only 3 methods considered as complex and not enough commented.

Methods with many variables

Methods where NbVariables is higher than 8 are hard to understand and maintain. Methods where NbVariables is higher than 15 are extremely complex and should be split in smaller methods (except if they are automatically generated by a tool).

SELECT METHODS WHERE NbVariables > 15 ORDER BY NbVariables DESC

less than 1% methods has too many variables.

Types with many methods and fields

Let’s search for types with many methods, for that we can execute the following CQLinq request

SELECT TYPES WHERE NbMethods > 30 AND !IsGlobal ORDER BY NbMethods DESC

Only 23 types has many methods.

And we can do the same search for fields

SELECT TYPES WHERE NbFields > 20 AND !IsGlobal ORDER BY NbFields DESC

Only 12 types has many fields.

DESIGN

inheritance

Multiple inheritance increase complexity ,and we have to use it carefully.

Let’s search for class with many base classes.

SELECT TYPES WHERE NbBaseClass >1

72 classes has multiple base classes , but if you search for bases you can find that a majority of them derived from Observer.

let’s search for classes with multiple base and not derive from Observer, we will see later the interest of inheriting from Observer.

SELECT TYPES WHERE NbBaseClass >1 AND !DeriveFrom “QuantLib.Observer

The blue rectangles represent the result.

Only 14 classes derived from more than one class and not derived from Observer.

Type cohesion

The single responsibility principle states that a class should 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 LCOMHS (HS stands for Henderson-Sellers) takes its values in the range [0-2]. Note that the LCOMHS metric is often considered as more efficient to detect non-cohesive types. LCOMHS value higher than 1 should be considered alarming.

SELECT TYPES WHERE LCOMHS > 0.95 AND NbFields > 10 AND NbMethods >10 AND !IsGlobal ORDER BY LCOMHS DESC

Only 11 types are considered as no cohesive.

Efferent coupling

The Efferent Coupling for a particular type is the number of types it directly depends on.
Types where TypeCe > 50 are types that depends on too many other types. They are complex and have more than one responsibility. They are good candidate for refactoring.

Let’s execute the following CQLinq request.

SELECT TYPES WHERE TypeCe > 50 AND !IsGlobal ORDER BY TypeCe DESC

And the result is empty so no class has many responsibilities.

How about low coupling?

Template provide more flexibility than OOP, but implies more complexity. for example when a template need a Class as template param, there’s no constraints that this class inherit from what the template need but only a constraints that this class T provide methods needed by the template.

This interesting post explain the tension between OOP and template programming.

Let’s discover template classes of QuantLib

SELECT TYPES WHERE IsTemplate AND !IsInTierProject

For no template class , the using of abstract classes can provide more flexibility and low coupling. Take for example CmsMarket and search for abstract classes used.

SELECT TYPES WHERE IsDirectlyUsedBy “QuantLib.CmsMarket” AND IsAbstract

So many abstract classes are used and we can consider that CmsMarket is low coupled.

Layering between namespaces

CppDepend provide DSM graph, and we can triangularize this matrix to focus under red borders highly dependency cycle.

A dependency cycle exist between QuantLib and QuantLib::detail, having this dependency is not problematic but avoiding this kind of dependency enforce loose coupling,this interesting post explain the benefit of layering.

Design Patterns used

PImpl

Managing calendar depends on culture and country, and we need a flexible way to provide a specific calendar.

Many calendars implementation are provided in QuantLib.

SELECT TYPES WHERE DeriveFrom “QuantLib.Calendar+Impl” ORDER BY DepthOfDeriveFrom

Calendar is a concrete class which no virtual methods. Polymorphism is implemented by storing into a Calendar instance a Handle to a CalendarImpl object which implements the polymorphic isBusinessDay() method and to which the Calendar instance delegates the task of determining whether a given day is a business day or a holiday.

Derived Calendar classes can be defined which initialize the Handle with the desired concrete CalendarImpl. The only task of such derived Calendars is to customize the initialization process, without adding any new functionality to the Calendar interface. As such, they can be upcasted to Calendar without any loss of information occurring.

This dependency graph show the relation between Calendar, Calendar::Impl and a specific Calendar implementation.

Observer

In the finance world there’s many calculations that depends on many parameters, for example an instruments depends on many classes, and it needs to keep track of changes that should cause them to recalculate their values.

Let’s see how many classes inherit from observer.

SELECT TYPES WHERE DeriveFrom “QuantLib.ObserverORDER BY DepthOfDeriveFrom

Many classes derived from observer, it’s an elegant solution to keep track on any modifications.

Visitor

with this kind of library we need to add new operations to existing object structures without modifying those structures, for that the pattern visitor is very interesting.

This technique allows one to specialize calculations on a per-derived-class basis without increasing the number of virtual member functions in the base class interface.

Let’s see how many classes use Visitor pattern.

SELECT TYPES WHERE IsDirectlyUsing “QuantLib.Visitor

We can consider that QuantLib is over engineered but a library for a finance must be generic, because the implementation can be specific to country, bank or maybe hedge fund. For that it must be well designed to be flexible and not too complex.

Learn some basic design principles from GRASP: Spring case study.

A design pattern is a general reusable solution to a commonly occurring problem within a given context in software design. Patterns are formalized best practices that the programmer can use to solve common problems when designing an application or system.

“Gang of Four” patterns are maybe the most popular ones. However, there are some basic design principles not well-known by developers, it’s the General Responsibility Assignment Software Principles, abbreviated GRASP.

GRASP consists of guidelines for assigning responsibility to classes and objects in object-oriented design. In this article we will discover the use of  these principles in the Spring framework.

Spring is one of the most popular application development framework for enterprise Java.
The Spring Framework does not impose any specific programming model, it has become popular in the Java community as an alternative to, replacement for, or even addition to the Enterprise JavaBean (EJB) model.

Spring makes things easy for software designers, it gives them a good basis to have a well-designed projects. But what about Spring itself it’s well designed as well?
To try answering this question let’s X-Ray some Spring jars with JArchitect and discover some of its design facts.

After the analysis here’s the dependency graph between all Spring jars analyzed:

The Matrix view gives us more details about the dependency weight between these jars.

GRASP Principles

Coupling

The loose coupling is desirable because a change in one area of an application will require less 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.

Using interfaces and abstract classes can improve the loose coupling and we can evaluate the abstractness of a defined module by the following metric:

A = Na / Nc
Where:
* A = abstractness of a module
Zero is a completely concrete module. One is a completely abstract module.
* Na = number of abstract classes in the module.
* Nc = number of concrete classes in the module.

Here’s the abstractness of all Spring jars analyzed:

Let’s discover all interfaces of the jars analyzed, for that we can execute the following query:

SELECT TYPES WHERE IsInterface

With a good abstractness ratio, and many interfaces used we can say that Spring enforces low coupling, what makes it very flexible.

High 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 algorithms used 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 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.

SELECT TYPES WHERE LCOMHS > 0.95 AND NbFields > 10 AND NbMethods >10

Only 4 classes are considered as not cohesive.

 Creator

When we use interfaces, one interesting question is: who is responsible of creating concrete implementations? Spring provides a good solution using dependency injection, but it’s not the way used inside Spring itself. Spring use Factories to acheive this job, and as you can see it implements many factory classes:

Information Expert

Information Expert is a principle used to determine where to delegate responsibilities. These responsibilities include methods, computed fields and so on.
Using the principle of Information Expert a general approach to assigning responsibilities is to look at a given responsibility, determine the information needed to fulfill it, and then determine where that information is stored.

The Efferent Coupling metric can be an interesting metric to evaluate if some types has more responsibilities, The Efferent Coupling for a particular type is the number of types it directly depends on.

Types where the efferent coupling  is more than 50 are types that depends on too many other types. They are complex and have more than one responsibility. They are good candidate for refactoring.

SELECT TYPES WHERE TypeCe > 50

Polymorphism

According to Polymorphism, responsibility of defining the variation of behaviors based on type is assigned to the types for which this variation happens. This is achieved using polymorphic operations.

Let’s search for all polymorph methods, for that we can execute the following request:

SELECT METHODS WHERE NbOverloads>1

The Metric view gives us a good idea of using polymorphism inside Spring. In the Metric View, the code base is represented through a Treemap. Treemapping is a method for displaying tree-structured data by using nested rectangles. The tree structure used  is the usual code hierarchy:

  • Java projects contains packages
  • Packages contains types
  • Types contains methods and fields

Protected Variations

The Protected Variations pattern protects elements from the variations on other elements (objects, systems, subsystems) by wrapping the focus of instability with an interface and using polymorphism to create various implementations of this interface.
The “Abstractness vs Instability” graph can be useful to detect projects that will be difficult to change.

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”.

Almost all spring jars are inside the green zone, it’s a good point when changes are needed for maintenance or evolution.

Conclusion

Spring uses all the GRASP principles, what makes it simple to understand and maintain, and developers can learn interesting design choices  when discovering and analyzing the Spring source code.

So give a look inside the source and enjoy with all design best practices implemented.