Defining & Controlling Codebase Architecture

 

Table of Contents

Defining the Architecture - Components

Software components are parts of a larger system or application by which you can breakdown the complexity of codebases into manageable parts. CMRI allows you to use Components to manually define relationships between different parts of the codebase. This allows CMRI to compare and analyze the similarities and differences of the actual codebase architecture with the theoretical architecture on a more general and comprehensible scale.  

  1. Create & select the desired projects and systems in CMRI.

  2. To create components, use the command:

    system component add -n <component name> -e 'relative/path/to/component/*'
  3. To create a component and a list of expressions, continue using this command:

    # Component A will own all files inside path/to/component/ EXCEPT for files # under the sub1/ tree that are not under the sub2/ tree system component add -n compA -e 'relative/path/to/component/*' system component remove -n compA -e 'relative/path/to/component/sub1/*' system component add -n compA -e 'relative/path/to/component/sub1/sub2/*' # Component B will own all files inside path/to/component/sub1 system component remove -n compB -e 'path/to/component/sub1/*'
  4. To remove a component:

    system component remove -n <component name>

     

a. When specifying the pathname to a component, CMRI is looking for the pathname beginning underneath the top level of the source code directory. Wildcards are allowed (e.g. *).

==================================

1 projects and 1 systems selected.

system component add -n proxies -e Proxies/* 

Added component `proxies` to `vault:ProjectName:ProjectName-47.0`.
Added expression(s) `Proxies/*` to component `proxies` of `vault:ProjectName:ProjectName-47.0`. 

==================================
1 projects and 1 systems selected.

b. This process can be repeated to add multiple files or directories to a single component.

c. For larger projects it can be easier to use the user defined architecture (UDA) file, uda.json, to declare your components and component relationships.  CMRI reads the UDA from that file which should be located at the path assigned to the uda_file system configuration property.  This location defaults to <system root>/uda.json, but can be modified to point to any path within the file system.  Run system architecture --help for more information about user defined architecture files, or download the CLI Reference here.  

  1. Once all the desired components are created, fetch the component data:

job run produce_silverthread_database

  1. Once complete, verify the components were generated properly with the command 

system component list

system component list 

SYSTEM NAME     EXPRESSIONS      FILE COUNT
ProjectName/ProjectName-47.0 tools    Tools/*       XX
ProjectName/ProjectName-47.0 proxies  Proxies/*      10
ProjectName/ProjectName-47.0 server   Server/*       123
ProjectName/ProjectName-47.0 design   Design/*        86 

 

==================================
1 projects and 1 systems selected.

a. If the file count for any directory is listed as “XX,” verify the pathname is spelled correctly, does not include special characters, and that there are source code files in that directory.

  1. To declare expected component relationships, use the command: 

a. This will assign a relationship from component A to B, C, etc.

b. There cannot be a space after the comma. There must be a space between the from component and the to component(s).  The exact syntax for a relationship from component ‘design’ to components ‘server’ and ‘box’ is:

==================================

1 projects and 1 systems selected.

system component-relationship add -f design -t server,box 

 

Added relationship `design`->`server` to `vault:ProjectName:ProjectName_database-1.0`
Added relationship `design`->`box` to `vault:ProjectName:ProjectName_database-1.0`

==================================
1 projects and 1 systems selected.

c. to see all declared component relationships use the command:

  1. Once all components and relationships are declared, produce the reports:

  1. CMRI will create a new 

Component Reports folder in the vault/reports/<project name>/<system name>/ directory.

a. This will include numerous diagrams detailing the hierarchical structure of the actual and theoretical component relationships.

Understanding Component Reports

The Component Reports visually depict the theoretical and actual component architecture. This allows for broad analysis regarding where the least healthy regions of the codebase are. 

The Component Relationship Mosaic will show where the actual architecture differs from the declared architecture.  Circular references are instances where components are linked in a circular fashion:  there is a defined relationship from componentA to componentB and from componentB to componentA.  This is not to be confused with Cores, which are linkages between files.  Undeclared relationships are actual relationships between components but which are not declared in the architecture.  This should be investigated to determine if the architecture definition needs to be updated, or if they are unwanted relationships that should be resolved.

What you see

What it means

What you see

What it means

Valid
  • Dependency declared in UDA

  • Dependency exists in source code

  • Dependency declared in UDA

  • Dependency does NOT exist in source code

  • Dependency exists in source code

  • Dependency NOT declared in UDA

  • Dependency exists in source code

  • Dependency NOT declared in UDA

  • Introduction of dependency in UDA would introduce circular dependencies

  • Dependency exists in source code

  • Code depends on files inside the private internals of a component, not files in the component’s public interface

Monitoring & Controlling Architecture using CMRI in Continuous Integration

One of the most powerful capabilities of CMRI is to use it to monitor and control the codebase architecture.  CMRI can be run in a Continuous Integration (CI) environment and scripted to send warning and error messages.  Some examples:

  • Warning/error if the core size increases – to ensure that things don’t get worse if development and refactoring are being done at the same time.

  • Warning/error if the core size exceeds threshold – once the refactoring has reduced the core to the desired size, ensure that further cores are not created.

  • Warning/error if defined architecture is violated.

  • Fail the build if set criteria are exceeded.

  1. Before setting up CMRI in on your CI system, components and architectural rules must be defined, and all definitions must be checked into the code repository as described above.

  2. On your CI host, set up a vault and a project. This vault and project will contain system metadata for each build. You may want to set up a rotating job to clean systems from this folder in order to ensure you do not run out of disk space.

  3. Create a job for analyzing your code. Add your repository information, and create a build script.  An example of what you might want to write in your build script:

    • Run CodeMRI to generate: a list of error component relationships, a list of file relationships within the error component relationships, and a list of warnings still remaining.

    • If there are component relationship errors, print out the file relationships within those component relationships.

    • If there are no component relationship errors, regenerate the warnings list, and commit to the repository.

 


Customer Support

Phone: 800-674-9366 (9am - 5pm Eastern Time)

Email: support@silverthreadinc.com