Skip to content

Latest commit

 

History

History
55 lines (34 loc) · 6.24 KB

File metadata and controls

55 lines (34 loc) · 6.24 KB

Extracting components from your codebase

The Structurizr for Java library includes a component finder and a number of prebuilt pluggable strategies that allow you to extract components from a codebase.

Background

The idea behind the C4 software architecture model and Structurizr is that there are a number of levels of abstraction sitting above the code. Although we write Java code using interfaces and classes in packages, it's often useful to think about how that code is organised into "components". In its simplest form, a "component" is just a grouping of classes and interfaces.

If you reverse-engineer some Java code using a UML tool, you'll typically get a UML class diagram showing all of the classes and interfaces. The component diagram in the C4 model is about hiding some of this complexity and implementation detail. You can read more about this at Components vs classes.

Purpose

The purpose of the component finder is to find components in your codebase. Since every codebase is different (i.e. code structure, naming conventions, frameworks used, etc), different pluggable component finder strategies allow you to customize how components are found.

Basic usage

To use a component finder, simply create an instance of the ComponentFinder class and configure it as needed.

Container webApplication = mySoftwareSystem.addContainer("Web Application", "Description", "Apache Tomcat 7.x");

ComponentFinder componentFinder = new ComponentFinder(
    webApplication, "com.mycompany.mysoftwaresystem",
    ... a number of component finder strategies ...);
componentFinder.findComponents();

In this case, we're going to find components and associate them with the webApplication container, and we're only going to find components that reside somewhere underneath the com.mycompany.mysoftwaresystem package to avoid accidentally finding components residing in frameworks that we might be using.

We also need to plug in one or more component finder strategies, which actually implement the logic to find and extract components from a codebase.

Component finder strategies

The are a number of component finder strategies already implemented in this GitHub repository and, since the code is open source, you can build your own too. Some of the component finder strategies work using static analysis and reflection techniques against the compiled version of the code (you will need this on your classpath), others by parsing the source code.

Name Dependency Description Extracted from
TypeBasedComponentFinderStrategy structurizr-core A component finder strategy that uses type information to find components, based upon a number of pluggable TypeMatcher implementations (e.g. NameSuffixTypeMatcher, InterfaceImplementationTypeMatcher, RegexTypeMatcher and AnnotationTypeMatcher). Compiled bytecode
SourceCodeComponentFinderStrategy structurizr-core This component finder strategy doesn't really find components, it instead extracts the top-level Javadoc comment from the code so that this can be added to existing component definitions. It also calculates the size of components, based upon the number of lines of source code. Source code
SpringComponentFinderStrategy structurizr-spring Finds classes annotated @Controller, @RestController, @Component, @Service and @Repository, plus classes that extend JpaRepository. Compiled bytecode

See the Spring PetClinic example for an illustration of how to use the component finder.

Component type and supporting types

In Structurizr, a Component is described by a number of properties, including type and supportingTypes.

  • type: This is designed to refer to a single fully qualified Java type that best describes the type of the component. For example, this could be the fully qualified name of the public interface for the component.
  • supportingTypes: This is the set of fully qualified Java types that support the implementation of the component.

Again, because each codebase is different, the mechanism to find a component's supporting types is pluggable via a number of strategies, which can be used in combination.