11.1.  Components and Artifacts

To describe architecture in a formal way we first need to think about the basic building blocks that we could use to describe the architecture of a system. The smallest unit of design is what we call a physical component (or just component in its short form). For most languages like Java or C# that would be just a single source file, for other languages like C or C++ a component is the combination of a header file with the associated source files that implement the elements declared in the header. To define an architecture you would group associated components into architectural artifacts. Then you could group several of those artifacts together into higher level artifacts and so on. For each artifact you would also define which other artifacts can be used by them.

To define which components would belong to a certain artifact you need a way to address components in a way that is independent from the physical location on your file system. We need a naming scheme for components.

// Main.java in package com.hello2morrow:
"Core/com/hello2morrow/Main"
 
// The Method class from java.lang.reflection:
"External [Java]/[Unknown]/java/lang/reflect/Method" 

// SimpleAction.cs in subfolder of NHibernate:
"NHibernate/Action/SimpleAction" 

// An external class from System.dll:
"External [C#]/System/System/Uri"

For internal components (components that actually belong to your project) we use the following naming strategy:

module/rel-path-to-project-root-dir/source-name

For external components (third party components used by your project) we use a slightly different strategy. Here we might not have access to any source files:

External [language]/jar-or-dll-if-present/rel-path-or-namespace/typename

Now we can use patterns to describe groups of components:

// All components from the Core module with "business" in their name:
"Core/**/business/**"

// All components in java.lang.reflect:
"External*/*/java/lang/reflect/*"

As you can see a single '*' matches everything except a slash, '**' matches over slash boundaries. You can also use '?' as a wildcard for a single character.

Now we can build our first artifacts:

artifact Business
{
    include "Core/**/business/**"
}

artifact Reflection
{
    include "External*/*/java/lang/reflect/*"
}
    

We grouped all components from module "Core" with "business" in their name into an artifact named "Business". The reflection classes from the Java runtime are now in their own artifact called "Reflection". Artifacts can also have "exclude" filters. They help you to describe the content of an artifact with an "everything except" strategy. Exclude filters will always be applied after all include filters.

TIP

More than one "include" statement can be used to assign components to an artifact.nIt is also possible to use "exclude" statements to specify exceptions from the elements included above.