11.6.  Adding Transitive or Deprecated Connections

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.

Using transitive connections this is 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 here
    }

    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 the parent artifact will cause an error message.

Deprecated dependencies are used when to warn about dependencies that are tolerated for now, but should be removed from the code. Instead of producing architecture violation errors they produce deprecation warnings on dependencies. The following example shows a typical use case:

artifact Controller
{
	// ...
	connect to Other deprecated // All dependencies to "Other" will now produce warnings 
}

artifact Other
{
	// ...
}
	

You can add "deprecated" at the end of most "connect to" statements.