Blog 6 min read

A Look Inside the Macchina SDK Source Code: Clean Design and Implementation.

Share this article
A Look Inside the Macchina SDK Source Code: Clean Design and Implementation.

In C++, many libraries can help you implement an IoT application, but most of them are low-level. For a high-level SDK, Macchina.io is an excellent choice, especially if you are looking for a robust framework that simplifies IoT application development.

Macchina is not only a powerful solution for IoT applications, but also a well-designed and well-implemented project, making it easy for SDK users to understand and customize its behavior.

Let’s take a look at the Macchina source code using CppDepend and explore some aspects of its design and implementation.

Clean Design

When designing a C++ project with a well-organized folder structure, it's important to consider modularity, maintainability, and scalability. Organizing your code by folders allows you to separate concerns, making it easier to navigate, modify, and extend.

As we can see from the following DSM, the Macchina SDK has a well-organized folder structure:

The technical layer based on the POCO library is isolated in the platform folder. The POCO C++ Libraries are powerful cross-platform open-source C++ libraries for building network- and internet-based applications that run on desktop, server, mobile, IoT, and embedded systems.

Here is the dependency graph for some of the POCO libraries.

Let's take a look inside the Foundation project to explore its structure:

The namespaces in the source code serve three different purposes:

1- Modularize the application

Modern C++ libraries use namespaces extensively to modularize their code base, and they use the “Namespace-by-feature” approach. Namespace-by-feature uses namespaces to reflect the feature set. It places all items related to a single feature (and only that feature) into a single namespace. This results in namespaces with high cohesion and high modularity, and with minimal coupling between namespaces. Items that work closely together are placed next to each other.

2- Anonymous namespace

An unnamed namespace avoids the need for global static variables. The anonymous namespace you create is accessible only within the file in which it is defined.

3- Hiding details by convention

In C++, there is no way to hide public types from library users (in C#, the “internal” keyword serves this purpose). It is therefore useful to indicate that certain types should not be used directly because they are implementation details.

A common idiom in modern C++, pioneered by the developers of the Boost libraries, is to separate symbols that form part of the implementation of your module (that is, don’t form part of the public API) but that have to be publicly available into a separate sub-namespace, by convention named detail.

The Poco.Details and Poco.Dynamic.Impl namespaces are used to hide implementation details by convention.

Loose Coupling for Greater Flexibility

Loose coupling is desirable because changes in one area of an application require fewer changes in other parts of the system. In the long run, this can save significant time, effort, and costs associated with modifying and adding new features to the application.

Loose coupling can be achieved by using abstract classes or generic types and methods.

The Macchina source code contains more than 300 abstract classes:

For example, the client authenticator class is an abstract class that allows for multiple implementations, providing flexibility in the user authentication feature.

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. LCOM values range from 0 to 1. LCOM HS (where HS stands for Henderson-Sellers) values range from 0 to 2. An LCOM HS value greater than 1 should be considered alarming. Here is how 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 the 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 follows: 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.

An LCOM HS value greater than 1 should be considered alarming.

Clean Implementation

Few Large Types in the Codebase

Large types can be extremely complex to develop and maintain. Such a class may control too many other classes in the system and grow beyond reasonable limits, becoming “The Class That Does Everything.”

In the Macchina SDK source code, only a few types are particularly large.

Methods Are Small and Easy to Understand

Many metrics can be used to identify complex functions. NBLinesOfCode, the number of parameters, and the number of local variables are among the basic ones.

There are other interesting metrics to detect complex functions:

  • Cyclomatic complexity is a popular procedural software metric that reflects the number of decision paths in a procedure.
  • Nesting Depth is a method-level metric that represents the maximum depth of nested scopes within a method body.
  • Max Nested Loop represents the maximum level of loop nesting in a function.

The maximum acceptable values for these metrics depend on the team’s choices; there are no universal standard values.

In the Macchina SDK source code, only a few methods can be considered complex.

Code is maintainable

The Maintainability Index is a software metric used to measure how easily a codebase can be maintained over time. It provides a quantifiable score based on factors such as code complexity, size, and readability, helping developers understand how changes might affect the codebase’s long-term maintainability.

Let’s examine the maintainability of the Macchina SDK methods using the CppDepend Treemap:

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 in CppDepend treemap is the usual code hierarchy:

  • C/C++ projects contain namespaces,
  • Namespaces contain types,
  • Types contain methods and fields.

The option Size of the treemap determines the size of the rectangles, which by default is proportional to the number of Lines of Code, and a code metric can be represented by coloring code element rectangles; in our case, the color represents maintainability.

As we can see, only a few methods are shown in red, and most of them are test methods.

Conclusion

Macchina is known for making IoT application development easier. Its implementation is clean, easy to understand, and customizable, making it an excellent choice for IoT applications.

Share this article