GH-6 - More reference documentation.

This commit is contained in:
Oliver Drotbohm
2022-10-18 09:50:35 +02:00
parent 615c72b1ab
commit 6594d7beb0
6 changed files with 270 additions and 24 deletions

View File

@@ -266,6 +266,11 @@ limitations under the License.
<artifactId>asciidoctorj</artifactId>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj-diagram</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>io.spring.asciidoctor.backends</groupId>
<artifactId>spring-asciidoctor-backends</artifactId>
@@ -309,6 +314,9 @@ limitations under the License.
<toclevels>4</toclevels>
<numbered>true</numbered>
</attributes>
<requires>
<require>asciidoctor-diagram</require>
</requires>
</configuration>
</plugin>

View File

@@ -2,10 +2,35 @@
[[preface]]
= Preface
[[preface.subheadline]]
== Subheadline
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
[[preface.project-metadata]]
== Project Metadata
* Version control https://github.com/spring-projects-experimental/spring-modulith
* Bug tracker: https://github.com/spring-projects-experimental/spring-modulith
* Release repository: Maven central
* Milestone repository: https://repo.spring.io/milestone
* Snapshot repository: https://repo.spring.io/snapshot
== Using Spring Modulith
Spring Modulith consists of a set of libraries that can be used individually and depending on which features of it you would like to use.
To ease the declaration of the individual modules, we recommend to declare the following BOM in you Maven POM:
.Using the Spring Modulith BOM
[source, xml, subs="+attributes"]
----
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-modulith-bom</artifactId>
<version>{projectVersion}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
----
The individual sections describing Spring Modulith features will refer to the individual artifacts that are needed to make use of the feature.
For an overview about all modules available, have a look at <<appendix.artifacts>>.

View File

@@ -12,17 +12,17 @@ In a Spring Boot application, an application module is a unit of functionality t
* An API exposed to other modules implemented by Spring bean instances and application events published by the module, usually referred to as _provided interface_.
* Internal implementation components that are not supposed to be accessed by other modules.
* References to API exposed by other modules in the form of Spring bean dependencies, application events listened to and configuration properties exposed.
* References to API exposed by other modules in the form of Spring bean dependencies, application events listened to and configuration properties exposed, usually referred to as _required interface_.
Spring Moduliths provides different ways of expressing modules, primarily differing in the level of complexity involved in the overall arrangement.
Spring Moduliths provides different ways of expressing modules within Spring Boot applications, primarily differing in the level of complexity involved in the overall arrangement.
This allows developers to start simple and naturally move to more sophisticated means as and if needed.
[[fundamentals.modules.simple]]
=== Simple Application Modules
The application's main package is the one that the main application class resides in.
The class, that is annotated with `@SpringBootApplication` and usually contains the `main(…)` method used to run it.
By default, each direct sub-package of the main package is considered an application module package.
The application's _main package_ is the one that the main application class resides in.
That is the class, that is annotated with `@SpringBootApplication` and usually contains the `main(…)` method used to run it.
By default, each direct sub-package of the main package is considered an _application module package_.
If this package does not contain any sub-packages, it is considered a simple one.
It allows to hide code inside it by using Java's package scope to hide types from being referred to by code residing in other packages and thus not subject for dependency injection into those.
@@ -31,13 +31,13 @@ Thus, naturally, the module's API consists of all public types in the package.
Let us have a look at an example arrangement (icon:plus-circle[] denotes a public type, icon:minus-circle[] a package protected one).
.A single inventory application module
[source, subs="macros"]
[source, subs="+specialchars, macros"]
----
icon:cubes[] Example
└─ icon:folder[] src/main/java
├─ icon:cube[] example <1>
├─ icon:cube[] example <1>
| └─ icon:plus-circle[] Application.java
└─ icon:cube[] example.inventory <2>
└─ icon:cube[] example.inventory <2>
├─ icon:plus-circle[] InventoryManagement.java
└─ icon:minus-circle[] SomethingInventoryInternal.java
----
@@ -71,6 +71,7 @@ Code from other application modules is allowed to refer to types within that.
Code within those must not be referred to from other modules.
Note, how `SomethingOrderInternal` is a public type, likely because `OrderManagement` depends on it.
This unfortunately means, that it can also be referred to from other packages such as the `inventory` one.
In this case, the Java compiler is not of much use to prevent these illegal references.
[[fundamentals.modules.explicit-dependencies]]
=== Explicit Application Module Dependencies
@@ -128,7 +129,7 @@ modules.forEach(System.out::println);
Note, how each module is listed and the contained Spring components are identified and the respective visibility is rendered, too.
[[fundamentals.modules.named-interface]]
[[fundamentals.modules.named-interfaces]]
=== Named Interfaces
By default and as described in <<fundamentals.modules.advanced>>, an application module's base package is considered the API package and thus is the only package to allow incoming dependencies from other modules.

View File

@@ -29,9 +29,63 @@ class DocumentationTests {
}
----
The first call on `Documenter` will generate a C4 component diagram containin all modules within the system.
The first call on `Documenter` will generate a C4 component diagram containing all modules within the system.
.All modules and their relationships rendered as C4 component diagram
[plantuml, c4-all-modules, svg]
....
top to bottom direction
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4.puml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml
Container_Boundary("Modulith.Application_boundary", "Application") {
Component(Modulith.Application.core, "core", "Module", "", $tags="")
Component(Modulith.Application.catalog, "catalog", "Module", "", $tags="")
Component(Modulith.Application.inventory, "inventory", "Module", "", $tags="")
Component(Modulith.Application.order, "order", "Module", "", $tags="")
Component(Modulith.Application.customer, "customer", "Module", "", $tags="")
}
Rel_D(Modulith.Application.order, Modulith.Application.core, "depends on", $tags="")
Rel_D(Modulith.Application.order, Modulith.Application.customer, "uses", $tags="")
Rel_D(Modulith.Application.catalog, Modulith.Application.core, "depends on", $tags="")
Rel_D(Modulith.Application.inventory, Modulith.Application.order, "listens to", $tags="")
Rel_D(Modulith.Application.inventory, Modulith.Application.catalog, "uses", $tags="")
Rel_D(Modulith.Application.inventory, Modulith.Application.order, "uses", $tags="")
Rel_D(Modulith.Application.inventory, Modulith.Application.core, "uses", $tags="")
Rel_D(Modulith.Application.order, Modulith.Application.catalog, "depends on", $tags="")
SHOW_LEGEND()
....
The second call will create additional diagrams that only include the individual module and the ones they directly depend on on the canvas.
.A subset of application modules and their relationships starting from the order module rendered as C4 component diagram
[plantuml, c4-individual-modules, svg]
....
top to bottom direction
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4.puml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml
Container_Boundary("Modulith.Application_boundary", "Application") {
Component(Modulith.Application.core, "core", "Module", "", $tags="")
Component(Modulith.Application.catalog, "catalog", "Module", "", $tags="")
Component(Modulith.Application.order, "order", "Module", "", $tags="")
Component(Modulith.Application.customer, "customer", "Module", "", $tags="")
}
Rel_D(Modulith.Application.order, Modulith.Application.core, "depends on", $tags="")
Rel_D(Modulith.Application.order, Modulith.Application.customer, "uses", $tags="")
Rel_D(Modulith.Application.catalog, Modulith.Application.core, "depends on", $tags="")
Rel_D(Modulith.Application.order, Modulith.Application.catalog, "depends on", $tags="")
SHOW_LEGEND()
....
[[documentation.component-diagrams.uml]]
=== Using Traditional UML Component Diagrams
@@ -45,7 +99,84 @@ DiagramOptions.defaults()
This will cause the diagrams to look like this:
TODO: Add diagram
.All modules and their relationships rendered as UML component diagram
[plantuml, uml-all-modules, svg]
....
skinparam {
shadowing false
arrowColor #707070
actorBorderColor #707070
componentBorderColor #707070
rectangleBorderColor #707070
noteBackgroundColor #ffffff
noteBorderColor #707070
defaultTextAlignment center
wrapWidth 200
maxMessageSize 100
componentStyle uml1
}
package "Application" <<Container>> {
component 4 <<Component: Module>> #dddddd [
com.acme.commerce.catalog
]
component 3 <<Component: Module>> #dddddd [
com.acme.commerce.core
]
component 7 <<Component: Module>> #dddddd [
com.acme.commerce.customer
]
component 5 <<Component: Module>> #dddddd [
com.acme.commerce.inventory
]
component 6 <<Component: Module>> #dddddd [
com.acme.commerce.order
]
}
4 .[#707070].> 3 : depends on
5 .[#707070].> 4 : uses
5 .[#707070].> 3 : uses
5 .[#707070].> 6 : uses
5 .[#707070].> 6 : listens to
6 .[#707070].> 4 : depends on
6 .[#707070].> 3 : depends on
6 .[#707070].> 7 : uses
....
.A subset of application modules and their relationships starting from the order module rendered as UML component diagram
[plantuml,uml-individiual-module, svg]
....
skinparam {
shadowing false
arrowColor #707070
actorBorderColor #707070
componentBorderColor #707070
rectangleBorderColor #707070
noteBackgroundColor #ffffff
noteBorderColor #707070
defaultTextAlignment center
wrapWidth 200
maxMessageSize 100
componentStyle uml1
}
package "Application" <<Container>> {
component 4 <<Component: Module>> #dddddd [
com.acme.commerce.catalog
]
component 3 <<Component: Module>> #dddddd [
com.acme.commerce.core
]
component 7 <<Component: Module>> #dddddd [
com.acme.commerce.customer
]
component 6 <<Component: Module>> #dddddd [
com.acme.commerce.order
]
}
4 .[#707070].> 3 : depends on
6 .[#707070].> 4 : depends on
6 .[#707070].> 3 : depends on
6 .[#707070].> 7 : uses
....
[[documentation.application-module-canvas]]
== Generating Application Module Canvases
@@ -70,12 +201,53 @@ class DocumentationTests {
A canvas generated looks like this:
TODO: Include generated canvas
.A sample Application Module Canvas
[cols="1h,4a"]
|===
|Base package
|`com.acme.commerce.inventory`
|Spring components
|_Services_
* `c.a.c.i.InventoryManagement`
_Repositories_
* `c.a.c.i.Inventory`
_Event listeners_
* `c.a.c.i.InternalInventoryListeners` listening to `o.s.m.m.DayHasPassed`, `c.a.c.i.QuantityReduced`
* `c.a.c.i.InventoryOrderEventListener` listening to `c.a.c.o.OrderCanceled`, `c.a.c.o.OrderCompleted`
_Configuration properties_
* `c.a.c.i.InventoryProperties`
_Others_
* `c.a.c.i.InventoryItemCreationListener`
|Aggregate roots
|* `c.a.c.i.InventoryItem`
|Published events
|* `c.a.c.i.QuantityReduced` created by:
** `c.a.c.i.InventoryItem.decreaseQuantity(…)`
* `c.a.c.i.StockShort` created by:
** `c.a.c.i.InternalInventoryListeners.on(…)`
|Events listened to
|* `c.a.c.o.OrderCompleted`
* `c.a.c.o.OrderCanceled`
|Properties
|* `acme.commerce.inventory.restock-threshold` -- `c.a.c.c.Quantity`. The threshold at which a `InventoryEvents.StockShort` is supposed to be triggered during inventory updates.
|===
It consists of the following sections:
* __The application module's name and base package.__
* __The Spring beans exposed by the application module, grouped by stereotype.__ -- In other words beans that are located in either the API package or any <<fundamentals.modules.named-interface, named interface package>>.
* __Exposed aggregate roots__
* __The application module's base package.__
* __The Spring beans exposed by the application module, grouped by stereotype.__ -- In other words beans that are located in either the API package or any <<fundamentals.modules.named-interfaces, named interface package>>.
* __Exposed aggregate roots__ -- Any entities that we find repositories for or explicitly declared as aggregate via jMolecules.
* __Application events published by the module__ -- Those event types need to be demarcated using jMolecules `@DomainEvent` or implement its `DomainEvent` interface.
* __Application events listened to by the module__ -- Derived from methods annotated with Spring's `@EventListener`, `@TransactionalEventListener` or beans implementing `ApplicationListener`.
* __Configuration properties__ -- Requires the usage of the `spring-boot-configuration-processor` artifact to extract the metadata attached to the properties.
* __Application events listened to by the module__ -- Derived from methods annotated with Spring's `@EventListener`, `@TransactionalEventListener`, jMolecules' `@DomainEventHandler` or beans implementing `ApplicationListener`.
* __Configuration properties__ -- Spring Boot Configuration properties exposed by the application module.
Requires the usage of the `spring-boot-configuration-processor` artifact to extract the metadata attached to the properties.

View File

@@ -2,6 +2,43 @@
= Appendix
:jdbc-schema-base: ../../../spring-modulith-events/spring-modulith-events-jdbc/src/main/resources
[appendix]
[[appendix.migrating-from-moduliths]]
== Migrating from Moduliths
* `Modules` -> `ApplicationModules`
* `@ModuleTest`-> `ApplicationModuleTest`
[appendix]
[[appendix.artifacts]]
== Spring Modulith modules
.Spring Modulith starter POMs
[cols="3,1,5", options="header, unbreakable"]
|===
|Starter|Typical scope|Description
|`spring-modulith-starter-jdbc`|`compile`|Includes `spring-modulith-api`, `spring-modulith-moments` as well as `spring-modulith-events-jdbc`.
|`spring-modulith-starter-jpa`|`compile`|Includes `spring-modulith-api`, `spring-modulith-moments` as well as `spring-modulith-events-jpa`.
|`spring-modulith-starter-mongodb`|`compile`|Includes `spring-modulith-api`, `spring-modulith-moments` as well as `spring-modulith-events-mongodb`.
|`spring-modulith-starter-test`|`compile`|Includes `spring-modulith-docs` and `spring-modulith-test`.
|===
.Individual Spring Modulith JARs
[cols="3,1,5", options="header, unbreakable"]
|===
|Module|Typical scope|Description
|`spring-modulith-api`|`compile`|The abstractions to be used in your production code to customize Spring Modulith's default behavior.
|`spring-modulith-core`|`runtime`|The core application module model and API.
|`spring-modulith-docs`|`test`|The `Documenter` API to create Asciidoctor and PlantUML documentation from the module model.
|`spring-modulith-events-core`|`runtime`|The core implementation of the event publication registry as well as the integration abstractions `EventPublicationRegistry` and `EventPublicationSerializer`.
|`spring-modulith-events-jackson`|`runtime`|A Jackson-based implementation of the `EventPublicationSerializer`.
|`spring-modulith-events-jdbc`|`runtime`|A JDBC-based implementation of the `EventPublicationRegistry`.
|`spring-modulith-events-jpa`|`runtime`|A JPA-based implementation of the `EventPublicationRegistry`.
|`spring-modulith-events-mongodb`|`runtime`|A MongoDB-based implementation of the `EventPublicationRegistry`.
|`spring-modulith-moments`|`compile`|The Passage of Time events implementation described <<moments, here>>.
|`spring-modulith-observability`|`runtime`|Observability infrastructure described <<observability, here>>.
|===
[appendix]
[[appendix.schemas]]
== Event publication registry schemas

View File

@@ -10,8 +10,11 @@ Oliver Drotbohm
NOTE: Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.
:leveloffset: +1
:!numbered:
// include::00-preface.adoc[]
include::00-preface.adoc[]
:numbered:
include::10-fundamentals.adoc[]