11.7.  Restricting Dependency Types

Sometimes you are in a situation, where you allow one artifact to use another one, but would like to restrict the usage to dependencies of a certain type. For example let us assume you do not want the UI layer to create new instances of classes defined in the "Model" layer. Only "Business" and "Persistence" would be allowed to create "Model" instances. You can solve this by creating a new interface that restricts the usage of certain dependency types:

artifact UI
{
    include "**/ui/**"
    connect to Business, Model.UI
}
artifact Business
{
    include "**/business/**"
    connect to Persistence, Model
}
artifact Persistence
{
    include "**/persistence/**"
    connect to Model
}
artifact Model
{
    include "**/model/**"
    interface UI
    {
        include all // everything in "Model"
        exclude dependency-types NEW
    }
}
    

Now it would be marked as an architecture violation if a class from the UI layer would create a new instance of an object from the model layer. Please note that we had to remove the public modifier from "Model". If we had kept it there would have been an implicit connection from UI to the default interface of Model bypassing our special restriction.

Currently the language supports the following list of language agnostic abstract dependency types:

        // instance creation
        NEW
        
        // inheritance
        EXTENDS 
        
        // interface implementation
        IMPLEMENTS
        
        // function or method calls 
        CALL
                
        // reading a field or variable
        READ 
        
        // writing to a field or variable
        WRITE 
        
        // all other uses
        USES 
    

In the next section we will look at another advanced concept called "connection schemes".