Sometimes the information needed to properly assign a component to an artifact is not part of its architecture filter name. Imagine for example a code generator that generates classes for different functional modules. If all those classes end up in the same package it becomes very hard to assign the generated classes to the right functional modules unless the class name contains some clue. If those generated classes could be properly assigned based on an annotation that would be a far more effective method of assignment.
Tag: software architecture dsl
Logical Architecture Models
With Sonargraph 9.7 our architecture DSL gets a new feature: logical models. Up to 9.7 the concept of a component (the smallest unit assignable to an architectural artifact) was based on the physical layout of your project. So components in a physical model are based on source files and their relative location in the file system. In a logical model components are the top level programming elements in a namespace or package and their name contains the namespace and no relative path.
Adding Transitive Dependencies to the Architecture DSL
This post assumes that you are already familiar with Sonargraph’s architecture DSL. If not, I recommend first reading “how to organize your code”.
Transitive dependencies are a useful addition to formal architecture descriptions. The following example shows a typical use case:
artifact Controller { include "**/controller/**" connect to Foundation } artifact Foundation { include "**/foundation/**" }
Here Controller
depends on Foundation
. We also assume that classes from Foundation
are used in the public interface of the controller classes. That means that each client of Controller
must also be able to access Foundation
.
artifact ControllerClient { include "**/client/**" connect to Controller, Foundation }
This is certainly not ideal because it requires the knowledge that everything that uses the Controller
artifact must also connect to Foundation
. It would be better if that could be automized, i.e. if anything connects to Controller
it will automatically be connected to Foundation
too.
With Sonargraph 9.6 this is now easy to implement:
artifact ControllerClient { include "**/client/**" connect to Controller // No need to connect to Foundation explicitly } artifact Controller { include "**/controller/**" connect to Foundation transitively } // ...
Using the new keyword transitively
in the connect statement will add Foundation
to the default interface of Controller
. That means that anybody connecting to the default interface of Controller
will also have access to Foundation
without needing an explicit dependency.
The new keyword only influences the default interface. For explicitly defined interfaces the transitive export also has to be made explicit:
artifact ControllerClient { include "**/client/**" connect to Controller.Service // Will also have access to Foundation } artifact Controller { include "**/controller/**" interface Service { include "**/service/**" export Foundation // Transitive connection must be explicit } connect to Foundation transitively // only affects default interface } // ...
Before we had transitive connections an interface could only export nested artifacts. Now interfaces can also export connected interfaces. In the example above we add the default interface of Foundation
to the Service
interface of Controller
. Exporting interfaces that are not a connection of he parent artifact will cause an error message.
This feature is available with Sonargraph 9.6 or higher. Let me know what you think about it in the comment section below.
Designing Generic Architectures Using Templates
Many companies already have some established architectural design patterns which are supposed to be used in most of their applications. For example it makes sense to standardize the layering of business components. It also makes sense to establish specific rules how one business component can access another one. In the upcoming 9.4 release of Sonargraph-Architect we implemented a new feature in our architecture DSL which should make it very easy to add generic architectural blueprints to a quality model which would allow automatic verification of those architectural design patterns on any business component without having to create a component specific architecture.
Evolving Sonargraph’s Architecture DSL
Sonargraph’s architecture DSL is now about 18 months old and we received a lot of positive feedback from customers bundled with ideas for improving the language. There are now several projects with more than one million LOC that use this language to define and enforce their architectural blueprint. Of course this feedback is most valuable for us and we did our best to implement a good share of the ideas brought to us. This article requires some basic knowledge of our architecture DSL. An introduction can be found here. To use all the features described below you need Sonargraph-Architect version 9.3 or higher.
Expressing Architectural Patterns as Artifact Stereotypes
There are some basic patterns that are used in almost every architectural model. Those patterns describe the relationships between sibling artifacts, i.e. artifacts that have the same parent.
- Layered architecture – here dependencies are allowed to flow top-down within an ordered list of sibling artifacts. If we use strict layering, an artifact can only access ist next sibling artifact. In the case of relaxed layering, artifacts have access to all artifacts defined beneath them.
- Independent – here sibling artifacts are independent from each other, i.e. there should be no dependencies between them.
- Unrestricted – here siblings artifacts have no restrictions in accessing each other. This is not very desirable because it will allow cyclic dependencies between artifacts, but can be really useful when working on a model for a legacy software system.
How to Organize your Code
In this article I am going to present a realistic example that will show you how to organize your code and how to describe this organization using our architecture DSL (domain specific language) implemented by our static analysis tool Sonargraph-Architect. Let us assume we are building a micro-service that manages customers, products and orders. A high level architecture diagram would look like this:
It is always a good idea to cut your system along functionality, and here we can easily see three subsystems. In Java you would map those subsystems to packages, in other languages you might organize your subsystem into separate folders on your file system and use namespaces if they are available.
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. Read More
Designing a DSL to Describe Software Architecture (Part 2)
Now that we have covered the basic building blocks in the first part of this article we can progress to more advanced aspects. In this post I will focus on how to factor out reusable parts of an architecture into separate files that can best be described as architectural aspects. We will also cover the restriction of dependencies by dependency types. Read More
Designing a DSL to Describe Software Architecture (Part 1)
Software architecture defines the different parts of a software system and how they relate to each other. Keeping a code base matching its architectural blueprint is crucial for keeping a complex piece of software maintainable over its lifetime. Sure, the architecture will evolve over time, but it is always better to have an architecture and enforce it than giving up on keeping your code organized. (See my recent blog post: Love your Architecture)
The problems start when it comes to describing your architecture in a formal and enforceable way. You could write a nice Wiki article to describe the architecture of your system, or describe it on a Powerpoint slide or with a set of UML diagrams; but that would be quite useless because it is not possible to check in an automated way whether or not your architecture is respected by the code. And everybody who ever worked on a non-trivial project with more than 2 developers knows that rules will be broken. That leads to an ever increasing accumulation of architectural debt with all kinds of undesirable side effects for the long term sustainability of a piece of software. You could also use Sonargraph 7 or similar tools to create a graphical representation of your architectural blueprint. That is already a lot better because you can actually enforce the rules in your automated builds or even directly in the IDE. But it also means that everybody who wants to understand the architecture will need the tool to see it. You also will not be able to modify the architecture without having access to the tool.
Wouldn’t it be nice if you could describe your architecture as code, if you had a DSL (domain specific language) that can be used by software architects to describe the architecture of a system and that is expressive and readable enough so that every developer is able to understand it? Well, it took us a while to come up with that idea, but now I believe that this is the missing puzzle piece to significantly boost the adoption of formalized and enforceable software architecture rules. The long term benefits of using them are just to good to be ignored.