Designing a DSL to Describe Software Architecture (Part 3)

Connecting Complex Artifacts

After having covered the basics and some advanced concepts in the previous articles this post will examine the different possibilities to define connections between complex artifacts. Let us assume we use the following aspect to describe the inner structure of a business module:

// File layering.arc
exposed artifact UI 
{ 
    include "**/ui/**"
    connect to Business 
} 
exposed artifact Business 
{ 
    include "**/business/**"
 
    interface default
    {
        // Only classes in the "iface" package can be used from outside
        include "**/iface/*"
    }
 
    connect to Persistence
} 
artifact Persistence 
{ 
    include "**/persistence/**" 
}
exposed public artifact Model
{
    include "**/model/**"
}

This example also shows a special feature of our DSL. You can redefine the default interface if you want to restrict incoming dependencies to a subset of the elements assigned to an artifact. Our layer “Business” is now only accessible over the classes in the “iface” package.

Now lets bring in some business modules:

// File modules.arc
artifact Customer
{
    include "Customer/**" // All in module "Customer"
    apply "layering"
    connect to Core
}
artifact Product
{
    include "Product/**" // All in module "Product"
    apply "layering"
    connect to Core
}
artifact Core
{
    include "Core/**" // All in module "Core"
    apply "layering"
}

Here “Customer” and “Product” are connected to “Core”. We used the most simple way to connect those artifacts which means that all elements in “Customer” or “Product” can use everything in the default interface of “Core”. Since we redefined the default interface of “Business” this is not everything in “Core”. The default interface of “Core” exports all default interfaces of non-hidden nested artifacts which means that the restrictions defined in “Business” are respected by surrounding artifacts.

Nevertheless this way of connecting artifacts does not give us enough control. For example “Product.Model” could now access “Core.UI” – not pretty. That means we need to put a bit more effort into the connection:

// File modules.arc
artifact Customer
{
    include "Customer/**" // All in module "Customer"
    apply "layering"
 
    connect UI to Core.UI, Core.Controller, Core.Model
    connect Controller to Core.Controller, Core.Model
    connect Model to Core.Model
}
artifact Product
{
    include "Product/**" // All in module "Product"
    apply "layering"
 
    connect UI to Core.UI, Core.Controller, Core.Model
    connect Controller to Core.Controller, Core.Model
    connect Model to Core.Model
}
artifact Core
{
    include "Core/**" // All in module "Core"
    apply "layering"
}

Now we are more specific about the details of our connection. Please note that we can only connect to “UI”, “Controller” and “Model” of “Core” because we have marked those artifacts as exposed. Otherwise they would be encapsulated and not directly accessible. The “Persistence” layer is not exposed and can therefore only be used from inside its enclosing artifact.

Introducing Connection Schemes

If you look closely you will find that both connection blocks in “Customer” and “Product” are absolutely identical. Now image you had to connect dozens of artifacts in this way. That would be quite annoying and error prone. To avoid this kind of duplication we added the concept of connections schemes:

// File modules.arc
connection-scheme C2C
{
    connect UI to target.UI, target.Controller, target.Model
    connect Controller to target.Controller, target.Model
    connect Model to target.Model
}
 
artifact Customer
{
    include "Customer/**" // All in module "Customer"
    apply "layering"
 
    connect to Core using C2C
}
artifact Product
{
    include "Product/**" // All in module "Product"
    apply "layering"
 
    connect to Core using C2C
}
artifact Core
{
    include "Core/**" // All in module "Core"
    apply "layering"
}

Now I hope you agree that this is cool. Using connection schemes it becomes possible to describe the wiring between artifacts in an abstract way. That makes it easy to change the wiring if the architect comes up with a new idea or wants to add or remove restrictions.

This concludes this series of articles. If you’d like to try the new language on your own project please request a free evaluation license of the newest version of Sonargraph-Architect.

If you are currently using Sonargraph 7 it is probably a good idea to make yourself familiar with the concepts of this language. On request we will migrate your existing Sonargraph-7 architecture model for you free of charge provided you have an active support contract.

Please let me know what you think about our new idea? Did we miss something? Would you use that on your project? Feedback is always highly appreciated.

4 thoughts to “Designing a DSL to Describe Software Architecture (Part 3)”

  1. Maybe it is a good idea to explain how to apply this DSL on example architectures like use in Domain Driven Design or other concepts?

    1. A good example would definitely help. I am thinking about to create a little video that explains creating an architecture step by step. But please contact me if you’d be interested in an online meeting, where I could work with you to create an architecture for your project.

    1. The DSL supports describing any kind of architectural style including hexagonal architectures. But I agree that it would be nice to see an example. As soon as I have some time I will write another blog article about that.

Leave a Reply

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