Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Designing a DSL to Describe Software Architecture (Part 3)

DZone's Guide to

Designing a DSL to Describe Software Architecture (Part 3)

Here's part 3 of Hello2morrow's series on describing software architecture with a DSL.

Free Resource

SnapLogic is the leading self-service enterprise-grade integration platform. Download the 2018 GartnerMagic Quadrant for Enterprise iPaaS or play around on the platform, risk free, for 30 days.

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 template 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/**"
    connect to Persistence 
 
    interface default
    {
        // Only classes in the "iface" package can be used from outside
        include "**/iface/*"
    }
} 
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 Sonargraph-Explorer.

The new language will also be part of our next major release of Sonargraph-Architect, which is planned for November of 2015. 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.

With SnapLogic’s integration platform you can save millions of dollars, increase integrator productivity by 5X, and reduce integration time to value by 90%. Sign up for our risk-free 30-day trial!

Topics:
integration ,DSL ,software architecture

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}