Share
Embed
Architecture as Code in Practice
Roland Weisleder
October 07, 2025
Transcript
43 slides
-
Whoever wishes to build high towers must spend much time
near the foundation. Anton Bruckner -
Did we build the system right? Did we build the
right system? -
The „as Code“ Approach </> Versioning Established change and review
processes Automatable in CI/CD pipelines Reproducibility Machine- readable Artifacts closer to the code Scalability Reduction of manual errors -
Diagrams as Code @startuml package "Some Group" { HTTP -
[First Component] [Another Component] } node "Other Groups" { FTP - [Second Component] [First Component] --> FTP } cloud { [Example 1] } database "MySql" { folder "This is my folder" { [Folder 3] } frame "Foo" { [Frame 4] } } [Another Component] --> [Example 1] [Example 1] --> [Folder 3] [Folder 3] --> [Frame 4] @enduml Source: https://plantuml.com/en/component-diagram -
Docs as Code === Whitebox HtmlSanityChecker [plantuml,whitbox-hsc-level-1,svg] .... include::../../plantuml/whitebox-hsc-level-1.puml[] ....
Rationale:: We used _functional decomposition_ to separate responsibilities: * {xrefConceptCheckerCore} shall encapsulate checking logic and Html parsing/processing. * all kinds of outputs (console, html-file, graphical) shall be handled in a separate component (`Reporter`) * Implementation of Gradle specific stuff shall be encapsulated. Contained Blackboxes:: [cols="1,3" options=""] .HtmlSanityChecker building blocks |=== | <<sec:checker_blackbox, HSC Core>> | hsc core: html parsing and sanity checking, configuration, reporting. | HSC Gradle Plugin | integrates the Gradle build tool with HSC, enabling arbitrary gradle builds to use HSC functionality. | HSC Maven Plugin | integrates the Maven build tool with HSC, enabling arbitrary maven builds to use HSC functionality. | HSC Graphical Interface | (planned, not implemented) |=== Source: https://hsc.aim42.org/arc42/chapters/chap-05-BuildingBlocks.html -
Architecture as Code makes the architecture enforceable through executable source
code Mark Richards Source: https://www.thoughtworks.com/insights/podcasts/technology-podcasts/architecture-as-code -
Our microservices are Java, Kafka in between, and the frontend
service is Angular Random Developer -
Architectural Decision Records https://adr.github.io/ # {short title, representative of solved
problem and found solution} ## Context and Problem Statement {Describe the context and problem statement, e.g., in free form using two to three sentences or in the form of an illustrative story. You may want to articulate the problem in form of a question and add links to collaboration boards or issue management systems.} ## Considered Options * {title of option 1} * {title of option 2} * {title of option 3} * … <!-- numbers of options can vary --> ## Decision Outcome Chosen option: "{title of option 1}", because {justification. e.g., only option, which meets k.o. criterion decision driver | which resolves force {force} | … | comes out best (see below)}. <!-- This is an optional element. Feel free to remove. --> ### Consequences * Good, because {positive consequence, e.g., improvement of one or more desired qualities, …} * Bad, because {negative consequence, e.g., compromising one or more desired qualities, …} * … <!-- numbers of consequences can vary --> -
We’re doing clean architecture … or onion … or maybe
hexagonal who knows … Random Developer -
@PrimaryAdapter class SamplePrimaryAdapter { SamplePrimaryPort primaryPort; } @PrimaryPort interface SamplePrimaryPort
{ } ArchRule hexagonalArchitecture = JMoleculesArchitectureRules.ensureHexagonal(); hexagonalArchitecture.check(javaClasses); Express architectural concepts in code jMolecules -
@startuml [Some Source] <<..some.source..>> [Some Target] <<..some.target..>> as target [Some
Source] --> target @enduml Use Your Diagrams URL myDiagram = getClass().getResource("my-diagram.puml"); classes().should(adhereToPlantUmlDiagram(myDiagram, consideringAllDependencies())); Source: https://www.archunit.org/userguide/html/000_Index.html#_plantuml_component_diagrams_as_rules -
<groupId>org.springframework.modulith</groupId> <artifactId>spring-modulith</artifactId> <version>2.0.0-SNAPSHOT</version> <packaging>pom</packaging> <name>Spring Modulith</name> <description>Modular monoliths with Spring
Boot</descripti <modules> <module>spring-modulith-actuator</module> <module>spring-modulith-api</module> <module>spring-modulith-apt</module> <module>spring-modulith-bom</module> <module>spring-modulith-core</module> <module>spring-modulith-docs</module> <module>spring-modulith-events</module> <module>spring-modulith-junit</module> <module>spring-modulith-moments</module> <module>spring-modulith-observability</module> <module>spring-modulith-runtime</module> <module>spring-modulith-starters</module> <module>spring-modulith-test</module> </modules> <parent> <groupId>org.springframework.modulith</groupId> <artifactId>spring-modulith</artifactId> <version>2.0.0-SNAPSHOT</version> </parent> <name>Spring Modulith - Runtime support</name> <artifactId>spring-modulith-runtime</artifactId> <dependencies> <dependency> <groupId>org.jspecify</groupId> <artifactId>jspecify</artifactId> </dependency> <dependency> <groupId>org.springframework.modulith</groupId> <artifactId>spring-modulith-core</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>com.tngtech.archunit</groupId> <artifactId>archunit</artifactId> <version>${archunit.version}</version> </dependency> Architectural support right in your build tool -
Example: Security • Approach: Role-based access control with Spring Security
• Fitness Function: classes() .that().resideInAPackage("..admin..") .and().areAnnotatedWith(Service.class) .should().beAnnotatedWith(RequiresAdminRole.class) -
Example: Traceability • Scenario: User changes data. It is traceable
when, by whom, and which data was changed. • Approaches: • Logging in services • Hibernate Envers for auditing • Fitness Function: classes() .that().areAnnotatedWith(Service.class) .should(log()) -
Did we build the system right? Did we build the
right system? -
Real Word Example: Document Generator Functional: • Multiple input/output channels
• Programmable document individualization Non-functional: • Preview PDF visible <1s • Paper in printer <3s • Up to 500,000 documents in 24h • … -
Example: Performance • Scenario: Data to be printed are available
→ paper is in the printer within 3 seconds. • Fitness Function: • Collect end-to-end duration from test & production environments • Calculate average • Pass if <3s • Fail if consistently >3s -
Example: Maintainability • Scenario: A user story can be implemented
within a single sprint. • Fitness Functions: • Track lead time from In Progress → Done in Jira • Analyze cycle times across stories • Checks median story lead time ≤ sprint length -
Fitness Functions … 1. check if the implementation fits the
designed architecture Did we build the system right? 2. check if the implementation (and thus the architecture) fits the non-functional requirements Did we build the right system? -
Architecture in a Nutshell • What is the requirement? •
How can we measure whether the requirement is fulfilled? • What is our solution strategy for fulfilling the requirement? -
Architecture as Code • What is the requirement? • How
can we measure whether the requirement is fulfilled? • What is our solution strategy for fulfilling the requirement? • Automatically check whether the solution strategy is implemented consistently. • Automatically check whether the requirement is fulfilled. -
Architecture as Code in Practice Slides speakerdeck.com/rweisleder More https://www.thoughtworks.com/insights/podcasts/technology-podcasts/architecture-as-code https://www.thoughtworks.com/en-de/insights/articles/fitness-function-driven-development
https://www.workingsoftware.dev/the-ultimate-guide-to-write-non-functional-requirements/ [email protected] in/roland-weisleder @rweisleder.de arcNdev Need help with your Legacy System? Let´s connect!