Major Changes to our C/C++ System Model

When we added C/C++ to Sonargraph our work was heavily influenced by John Lakos famous book “Large Scale C++ Design”. In this book Mr. Lakos presented a solid system to define the architecture of C++ systems based on components. A component in the most simple case is the combination of a header file and a source file, e.g. User.h and User.cpp. The header declares all elements that can be used from outside of the component, while the source file contains the implementation of the functionality. This unites the header and the source file into a logical component, that is better suited for dependency analysis.

But this approach also has some downsides. For starters, since a component can contain several files that could be coming from different directories, where do you anchor them in the navigation view? We decided to anchor them in the directory of the source file. This works reasonably well, but there are cases when it does not. For example, especially in C++, you can have header only components. E.g. a class that only has inline methods and therefore does not need a source file. This component will be anchored in the directory of the header file, usually an include directory.

Now imagine a typical C++ module with a source directory and an include directory for the public header files. Now it is easy to imagine a case where components from the source directory are using a header only component from the include directory and this component again depends on another component in the source directory. This would create a cyclic dependency between the source directory and the include directory, although in real life there is no cyclic dependency.

This is shown in the screenshot above. This cycle only exists because of the way we create components. If we decide to skip component creation and let each header and source file be their own component we get a cycle free picture:

On the other hand, if we dig a little deeper into the source directory, the model using component construction reveals real component cycles:

Those cycles will be invisible in a physical exploration view when we skip component construction.

Here the cycles disappeared because the source files do not have direct dependencies between them. If a source file calls a function implemented in another source, the dependency points to the declaration in the associated header file. Since most calls happen from source files this picture is not suitable for detecting cyclic dependencies. For that you would have to use the logical exploration view:

In the logical view declarations and implementations are melted together. But the advantage here is that all the cycles shown here are real. With component construction some of the cycles you would see in the physical exploration view are not real, as explained above.

Another advantage of skipping component construction comes when we want to create a physical architectural model. Lets assume we have 3 files:

UserPrivate.h
User.h
User.cpp

The header ending with “Private” contains the private interface of the things implemented in User.Cpp. Now you could create an architecture model that takes this into consideration:

artifact User
{
    include "**/User*"

    interface Public
    {
        include "**/User.h"
    }
    interface Private
    {
        include "**/User.h"
        include "**/UserPrivate.h"
    }
}

This would not have been possible in the old model where all three files would have ended up in the same component. Please notice, that with the new model the component names contain the file extension. In the old model extensions were not needed since headers and sources would be melted together into a singe component.

So since both approaches have pros and cons we let you decide, which model you prefer. By default old systems created before the release of Sonargraph 26.3 would have components enabled, while new systems would have them switched off. You can toggle this system setting via the System/Configure dialog.

If you are unsure about the architecture filter names used in the new model please remember, that you can always see the filter names in the properties view:

For every selected source and header files you can see where there are assigned and which filter name to use.

If you have questions or suggestions about this new feature, please use the comment section below.

Leave a Reply

Your email address will not be published. Required fields are marked *