diff --git a/docs/client-libs/dart.md b/docs/client-libs/dart.md new file mode 100644 index 0000000..11dd6e8 --- /dev/null +++ b/docs/client-libs/dart.md @@ -0,0 +1,10 @@ +--- +title: Dart Client Library +headline: Documentation +bodyclass: docs +layout: docs +--- +# Dart Client Library + * [Reference documentation]({{site.dart_api_doc}}/client/index.html) + * [Source code]({{site.dart_repo}}/tree/master/client) + diff --git a/docs/client-libs/index.md b/docs/client-libs/index.md new file mode 100644 index 0000000..9a5aa5c --- /dev/null +++ b/docs/client-libs/index.md @@ -0,0 +1,10 @@ +--- +title: Java Client Library +headline: Documentation +bodyclass: docs +layout: docs +--- +# Java Client Library + + * [Reference documentation]({{site.core_api_doc}}/client/index.html) + * [Source code]({{site.core_java_repo}}/tree/master/client) diff --git a/docs/client-libs/js.md b/docs/client-libs/js.md new file mode 100644 index 0000000..9b42fe8 --- /dev/null +++ b/docs/client-libs/js.md @@ -0,0 +1,11 @@ +--- +title: JavaScript Client Library +headline: Documentation +bodyclass: docs +layout: docs +--- +# JavaScript Client Library + + * [Reference documentation]({{site.js_api_doc}}/index.html) + * [Source code]({{site.web_repo}}/tree/master/client-js) + diff --git a/docs/examples/index.md b/docs/examples/index.md new file mode 100644 index 0000000..c45ea9f --- /dev/null +++ b/docs/examples/index.md @@ -0,0 +1,32 @@ +--- +title: Examples +headline: 'Spine Examples' +bodyclass: 'docs' +layout: docs +--- +
Examples are available through the Spine Examples GitHub organization.
+ +Please see the selected list of the examples with the descriptions below.
+ +## Java ++Note the use of the `protobuf` configuration. This tells our tools that the Protobuf definitions +in the subproject `model` must be converted into Java code in the current subproject. + +Alternatively, if, for instance, the upstream project already contains code generated from Protobuf, +and no additional codegen is required, the `api`/`implementation` configurations should be used. See +[this Gradle doc](https://docs.gradle.org/current/userguide/dependency_management_for_java_projects.html) +for more info. +
+ +### Java web server + +If your project contains a JavaScript frontend, you may declare a `web-server` subproject, which +processes the HTTP requests from JS. In `web-server/build.gradle`: +```groovy +spine.enableJava().webServer() + +dependencies { + implementation(project(':server')) +} +``` +Using `webServer()` has the same effect as just declaring the subproject to be a part of `server()` +and also adds the `io.spine:spine-web` dependency to the subproject. This dependency provides +components for handling requests from a JavaScript frontend See also `firebaseWebServer()` for using +a Firebase database to communicate between the server and the client. + +### JavaScript client + +Finally, a JavaScript client is also one or more Gradle subprojects. In `build.gradle` for those +subprojects, declare: +```groovy +spine.enableJavaScript() + +dependencies { + protobuf(project(':model')) +} +``` +This configuration sets up JavaScript code generation from the `model` definitions. Handle NPM +dependencies separately (e.g. adding the dependency for [`spine-web`](https://www.npmjs.com/package/spine-web)). + +### Working with many Bounded Contexts + +In a system with more than one Bounded Context, we recommend a similar project structure. Instead of +having a single `model` subproject, you should form a subproject per Bounded Context, for example, +`users-model`, `trains-model`, `billing-model`, etc. If one of the Bounded Contexts shares some +domain language with another, add a dependency between them. This way, the downstream context may +use Protobuf definitions of the upstream context. +```groovy +dependencies { + implemetation(project(':model-users')) +} +``` + +For domain logic implementation, also use a single subproject per Bounded Context. The convention +for calling those projects by the context names: `users` , `trains`, `billing`, etc. It is a good +idea to have a server implementation subproject depend only on one model subproject to preserve +language and responsibility boundaries. + +If your server should be deployed as a whole, use a single `web-server` for all the contexts. If you +would like to deploy different contexts separately, declare a specific `web-server` subprojects +for each of those contexts. See the [API reference]({{site.core_api_doc}}/server/io/spine/server/ServerEnvironment.html#use-io.spine.server.transport.TransportFactory-io.spine.base.EnvironmentType-) +for the instructions on integrating Bounded Contexts. Also, see [this guide]({{site.baseurl}}/docs/guides/integration.html) +on the principles of integrating separate Bounded Contexts and third-party systems in Spine. + +## Verbose configuration + +If the Bootstrap configuration is not customizable enough for you, there are other Gradle plugins +which may provide fine-grained API. + +Those plugins are Spine Model Compiler for Java subprojects and Spine ProtoJs plugin for JavaScript +submodules. Under the hood, Bootstrap uses those plugins to do the work. This means that Bootstrap +automatically applies the correct low-level plugin for you. + +### Model Compiler + +Spine Model Compiler is a Gradle plugin which executes all the code generation routines via several +Gradle tasks as well as the `modelCompiler { }` extension, which allows you to configure those +tasks. + +See the API reference for the list of the [declared tasks]({{site.base_api_doc}}/plugin-base/io/spine/tools/gradle/ModelCompilerTaskName.html) +and the [codegen configuration options]({{site.base_api_doc}}/model-compiler/io/spine/tools/gradle/compiler/Extension.html) + +### ProtoJS Plugin + +ProtoJs Gradle plugin manages and enhances JavaScript code generation from Protobuf definitions. +The plugin adds the `generateJsonParsers` task, which appends generated JS files with code parsing +Protobuf messages out of plain JS objects. + +The plugin also provides the `protoJs { }` extension, which allows you to configure JS code +generation. See the [API reference]({{site.base_api_doc}}/proto-js-plugin/io/spine/js/gradle/Extension.html) +for more info. diff --git a/docs/guides/index.md b/docs/guides/index.md new file mode 100644 index 0000000..3865f4a --- /dev/null +++ b/docs/guides/index.md @@ -0,0 +1,6 @@ +--- +title: Guides +headline: Documentation +bodyclass: docs +layout: docs +--- diff --git a/docs/guides/integration.md b/docs/guides/integration.md new file mode 100644 index 0000000..762e670 --- /dev/null +++ b/docs/guides/integration.md @@ -0,0 +1,363 @@ +--- +title: Integrating with a third party +headline: Documentation +bodyclass: docs +layout: docs +--- + +# Integration with a third party + +When developing an [Event-based]({{ site.baseurl }}/docs/introduction/concepts.html#event) system, it +is often tricky to integrate it with other software, be it a third party or a legacy system. + +In this article, we will explore the strategies of integrating third-party systems with your +Spine-based [Bounded Context]({{ site.baseurl }}/docs/introduction/concepts.html#bounded-context). + +Note that we think of a third-party system like of yet another Bounded Context with its own +language. The terms “Bounded Context” and “System” are used interchangeably throughout the article. + +To start the integration, your team should decide what portion of the other system’s domain model +you should adopt and how exactly you want to isolate your system from the third party. In DDD terms, +this means choosing the strategy of Context Mapping. + +## Context Mapping — TL;DR + +For the purpose of this article, let’s consider only the technical (and not the organizational) +aspect of a Context Map. You can read more about the concept as a whole in +the ["Domain-Driven Design" book](https://dddcommunity.org/book/evans_2003/) by Eric Evans. + +A Context Map, from a technical perspective, is the relationship between several Bounded Contexts. +The book lists a few archetypes of a Context Map. Some of them are: + + - *Customer/Supplier Models*, which establish an upstream-downstream relation. The Supplier team +tailors its model specifically for the Customer model. For this strategy to work, the developers of +both models have to collaborate. + - The *Conformist* pattern, which is very similar to the Customer/Supplier, except that the +upstream is not available for change. Thus the downstream has to copy the language into its model +thoughtlessly, hence conformism. + - *Anticorruption Layer* pattern (a.k.a. *ACL*), describing a Bounded Context, which is not willing +to accept the language of the upstream and instead builds an intermediate model in the "no man’s +land". The *ACL* translates the language of the upstream into the native language of the downstream +Context. + ++This list is not exhaustive. The ["Domain-Driven Design" book](https://dddcommunity.org/book/evans_2003/) +offers a few more strategies, all worth considering. However, in this article, we are going to +describe the listed three patterns, because they are the most commonly used. +
+ +## The Domain + + + +For the sake of an example, let’s consider airport management software. An airport is a complex +system which relies on many people and much software working together. Let’s consider the system +which helps the flight dispatchers make decisions on **Takeoffs and Landings**. The system +integrates with the software responsible for **Security Checks**, **Airplane Supplies**, and +**Weather**. All of these systems are independent of **Takeoffs and Landings** as well as of each +other. Thus, each of them can be treated as a third party. + ++**Disclaimer.** The domain of an airport was chosen for being an "easy" example, familiar to many +readers. The system reflects a general impression of an airport and should not be treated as +an accurate representation. +
+ +## Customer/Supplier Contexts + +{: .img-small} + + +The **Takeoffs and Landings** system must know whether an *Aircraft* is ready for the *Flight*. +This decision requires data on the supplies, which are provided for the *Aircraft*. To obtain this +knowledge, the system integrates with the **Airplane Supplies** Context. Note the language +difference between the *Aircraft* and an *Airplane*. Apparently, the two Contexts view the same +entity of the real world from different perspectives. +**Airplane Supplies** Context is an integral part of the airport software. Thus, by communicating +with the developers responsible for **Airplane Supplies**, we are able to build a Customer/Supplier +relationship between the **Airplane Supplies** Context and our system. The **Airplane Supplies** +Context does not implement an Event-based messaging internally. However, it still acts as +a Supplier. Specially for **Takeoffs and Landings**, the Supplier Context generates Events and +publishes them to a shared channel. **Takeoffs and Landings**, the Customer, subscribes to those +Events. + +Note that those Events are specifically tailored to be consumed by our system, and thus we do not +have to set up an elaborate Anticorruption Layer. However, a simple adapter is still required to +parse and validate domain Events, which we then publish to a Bounded Context, implemented in Spine. + + + +The Event Consumer, as depicted above, implements the Event transformation logic. In order to +establish this communication channel, the **Airplane Supplies** system declares a [gRPC](https://grpc.io/) +service. In [`supplies_service.proto`](https://github.com/spine-examples/airport/blob/master/airplane-supplies/src/main/proto/spine/example/airport/supplies/supplies_service.proto): + +Starting off a new project goes smoother when you have an efficient +and straightforward development flow to rely on. In this guide, we describe how we usually start +and develop new projects.
+ +While the key stages of the development process are described in the [Introduction][introduction] +section, this guide provides more hands-on details on the steps that we follow while working +on a project. + +## TL;DR + +In short, please follow the next steps to have a consistent and joyful development flow. + +Each step and sub-step below results in a separate Pull Request +adding its artifacts to the repository.
+ +1. Conduct [EventStorming][EventStorming] to gather domain knowledge. +Digitize the Artifact and store it in the code repository. + +2. Pick up a [Bounded Context][BoundedContext-concept]. + +3. Define [identifiers][identifier-concept] for the entities of the selected context. + +4. Define [signals][signals]: + + 4.1 Define [events][event-concept]. + + 4.2 Define [commands][command-concept]. + + 4.3 Define [rejections][rejection-concept]. + +5. Pick up a [scenario](#picking-up-a-scenario) (a use case, a process, or a flow) +within the Bounded Context: + + 5.1. Define [entity][entity-concept] states for the scenario. + + 5.2 Implement the scenario server-side functionality in Java code. + Cover the business logic with [`BlackBox`][testing] integration tests. + + 5.3 Fulfill the scenario vertically: create UI, public API, or a client whichever is required. + +6. Repeat step 5 until all the scenarios are covered. + +7. Repeat steps 2 through 6 for the other contexts. + +The sections below describe the development process in more detail. + + +## Getting started with a domain: EventStorming + +The first thing to get the project done is to conduct an [EventStorming][EventStorming] session +with the Domain Experts in the chosen field. + +The EventStorming allows both the business people and the engineers to start talking using +the same “language” fast. It is important for engineers to avoid using technical jargon. + +The results of the EventStorming (all the stickies) are captured as the Artifact and stored +as a part of the project documentation. + +We store the EventStorming Artifact electronically as images under the project root +in the `/docs/eventstorming/` folder. If the session is performed offline, the photos +of the EventStorming board are stored in the repository. In case of an online session, +the screenshots of the board are stored.
+ + +An example of the EventStorming board
+ +After the session, a dedicated person creates a Pull Request with the Artifact, and the team reviews +it once again. This first EventStorming is usually addressed as a "Big Picture" and gives +the team and the experts a broad overview of the problem they are trying to solve. + +Going forward, the next EventStorming "Process Modeling" and "Software Design" sessions +produce updates to the Artifact. + +Depending on the size and the scope of the project, you may need to conduct multiple EventStorming +sessions with different experts. + +## Limiting the scope: pick up a Bounded Context + +While the temptation to dive into the development of everything right away may be humongous, +we recommend limiting the development scope down to only one +[Bounded Context][BoundedContext-concept]. + +We follow the rule: "Eat an elephant one bite at a time".
+ +You may need another EventStorming session to go into more detail. + + +An example of a Bounded Context
+ +## Shaping the language + +With the selected Bounded Context in mind, we continue with the creation of the first code +artifacts of the project. During this step we define Protobuf messages that mold the +[Ubiquitous Language][UbiquitousLanguage] of the context. + +The results of these efforts are the `.proto` files [grouped][project-structure] under a specific +package in the `proto` folder. + +If you are new to Protobuf, please see the [Naming Conventions][naming-conventions] +section for how to name things in the proto code.
+ +While writing the protos, make sure to document **all** messages. It's time to unleash +your technical writing skills and lay the project's ground-standing foundation. +Here you may want to introduce some domain-level validation logic. Check out the +[Validation guide][validation-guide] for details. + +### Identifiers + +We put this step aside because in [Reactive DDD][ReactiveDDD] entities reference each other using +the typed [identifiers][identifier-concept]. + +Consider following the [Vaughn Vernon][VaughnVernon]’s rule on Aggregates from +the “Effective Aggregate Design Part II” that is applicable to **any** entity: +“Reference other Aggregates by Identity”
+ +We recommend using message-based identifiers over simple types to make the API strongly pronounced +and type-safe. To make things obvious, consider putting the IDs of the context into the file named +[`identifiers.proto`][identifiers-proto]. This file will be imported when defining events, +commands, entity states, and other types of the selected context. + +Please consult with the Naming Conventions [guide][identifiers-naming] for our +recommendations on naming the identifier types.
+ +When the ID types are defined, please create a Pull Request so that the team can review +and polish the code of this important development step. + +### Events + +When the IDs are defined it’s time to define [event][event-concept] messages. The events are named +as facts formulated as past participles, e.g. `RepositoryRegistered` or `TaskCreated`. +They are defined in files with the [`_events.proto`][events-proto] suffix (e.g. `order_events.proto`, +`customer_events.proto`). If your context is small it can be just `events.proto`. + +Create a Pull Request with the event definitions when they are ready. + +### Commands + +Similar to events, [command][command-concept] messages are defined in files having the names ending +with the [`_commands.proto`][commands-proto] suffix (or just `commands.proto` for a small context). +Commands are defined as imperative in a form of “do something”, e.g. `RegisterRepository` +or `CreateTask`. + +Finalize defining commands with a Pull Request. + +### Rejections + +[Rejections][rejection-concept] are special events that denote a command failed for a reason. +The rejection messages are defined in files with the [`_rejections.proto`][rejections-proto] suffix +(or just `rejections.proto`). For more information on the rejections, please refer to the +[“Working with Rejections”][rejections-guide] guide. + +Create a new Pull Request and review rejection definitions. + +## Picking up a scenario + +A scenario is a defined finite part of the context. It can be either a use case, a business process, +or a complete functional flow. + + + +If you see it getting too big, it may be worth splitting it into two or more smaller parts. +For example, you may want to start with a single [Aggregate][aggregate-concept] or a +[Process Manager][process-manager-concept]. + +### Entity states + +The [entity state][entity-state-naming] is a holder of the entity data. It does not represent +a whole [entity][entity-concept] but depicts the shape of its data. + +The definitions of entity states are [gathered][entity-state-proto] in a file named after +a business model thing. E.g. for a `Task` aggregate, the definitions would be defined in +a `task.proto` file. + +As with the other steps, create a Pull Request to review the entity states with the team. + +### Adding behavior + +We recommend implementing the scenario with the Java implementation of the domain +[entities][entities] and the [`BlackBox`][testing] integration tests. The `BlackBox` tests are +the recommended way to test scenarios in Spine. They are specifically built to allow you to check +the business logic the same way it works in the application. + + + +All the code must conform to your standards of the code and documentation quality +and be tested thoroughly. + +When a backend for the scenario is done a new PR is created and reviewed. + +### Fulfilling the vertical + +We usually do the vertical development, meaning an engineer starts with the domain definition, +continues with its implementation, and finishes with the front-facing tasks. + +Depending on your team workflow and preferences this step can take place in parallel +with the previous one. + +As noted, the scope of this iteration is to prepare the front-facing part for the scenario: +either a UI if one is needed, or the public API, or a dedicated idiomatic client. + +As soon as the implementation is ready, another PR and review come along. + +## Start over again + +When you have finished with the scenario, pick up a new one and start it over again following the PR +and review process. + +As soon as you are done with the Bounded Context, move on to the next one. + +## Summary + +While developing a project, make sure to split the development by Bounded Contexts. Pick up +a context and split it into scenarios. Make sure each of the development steps results +in a separate Pull Request with dedicated artifacts in the source code repository. +Opt for smaller, fine-graded Pull Requests instead of cluttered and complicated ones. + +[introduction]: {{ site.baseurl }}/docs/introduction "Check the Introduction" +[project-structure]: {{ site.baseurl }}/docs/introduction/project-structure.html#example "Check out the Example Project structure" +[naming-conventions]: {{ site.baseurl }}/docs/introduction/naming-conventions.html "Check out the Naming Conventions" +[validation-guide]: {{ site.baseurl }}/docs/guides/validation.html "Learn more about the Validation" +[BoundedContext-concept]: {{ site.baseurl }}/docs/introduction/concepts.html#bounded-context "Check out the Bounded Context definition" +[aggregate-concept]: {{ site.baseurl }}/docs/introduction/concepts.html#aggregate "Check out the Aggregate definition" +[process-manager-concept]: {{ site.baseurl }}/docs/introduction/concepts.html#process-manager "Check out the Process Manager definition" +[signals]: {{ site.baseurl }}/docs/introduction/#getting-domain-knowledge "Learn more about Signals" +[testing]: {{ site.baseurl }}/docs/introduction/#testing "Learn more about Testing" + +[identifier-concept]: {{ site.baseurl }}/docs/introduction/concepts.html#identifier "Learn more about Identifiers" +[identifiers-proto]: {{ site.baseurl }}/docs/introduction/naming-conventions.html#identifiersproto "Learn more about Identifiers proto structure" +[identifiers-naming]: {{ site.baseurl }}/docs/introduction/naming-conventions.html#identifiers "Learn more about Identifiers naming conventions" + +[event-concept]: {{ site.baseurl }}/docs/introduction/concepts.html#event "Learn more about Events" +[events-proto]: {{ site.baseurl }}/docs/introduction/naming-conventions.html#eventsproto "Learn more about Events proto structure" + +[command-concept]: {{ site.baseurl }}/docs/introduction/concepts.html#command "Learn more about Commands" +[commands-proto]: {{ site.baseurl }}/docs/introduction/naming-conventions.html#commandsproto "Learn more about Commands proto structure" + +[rejection-concept]: {{ site.baseurl }}/docs/introduction/concepts.html#rejection "Learn more about Rejections" +[rejections-proto]: {{ site.baseurl }}/docs/introduction/naming-conventions.html#rejectionsproto "Learn more about Rejections proto structure" +[rejections-guide]: {{ site.baseurl }}/docs/guides/rejections.html "Learn more about Rejections" + +[entities]: {{ site.baseurl }}/docs/introduction/#entities "See more examples on entities" +[entity-concept]: {{ site.baseurl }}/docs/introduction/concepts.html#entities "Learn more about Entities" +[entity-state-naming]: {{ site.baseurl }}/docs/introduction/naming-conventions.html#entity-states-1 "Learn more about Entity states" +[entity-state-proto]: {{ site.baseurl }}/docs/introduction/naming-conventions.html#entity-states "Learn more about Entity states proto structure" + +[EventStorming]: https://eventstorming.com "Learn more about EventStorming" +[UbiquitousLanguage]: https://martinfowler.com/bliki/UbiquitousLanguage.html "Learn more about the Ubiquitous Language" +[ReactiveDDD]: https://www.infoq.com/presentations/reactive-ddd/ "Check out the Reactive DDD presentation" +[VaughnVernon]: https://vaughnvernon.co/ diff --git a/docs/guides/validation.md b/docs/guides/validation.md new file mode 100644 index 0000000..4fa5590 --- /dev/null +++ b/docs/guides/validation.md @@ -0,0 +1,647 @@ +--- +title: Validation User Guide +headline: Documentation +bodyclass: docs +layout: docs +--- +# Validation User Guide + +Building a good domain model requires more than just defining data structures. +One of the commodities required for describing domain specifics is making sure that the data +is correct. This guide will walk you through the API the Validation Library which helps achieving +this goal.
+ +All of the validation features described here are currently supported in the Java environment. +Many are supported in Dart as well. For more info, see the description of individual features +given in the sections below. + +## Overview +Spine uses Protobuf for defining data structures of the domain models. The constraints +that define correctness of data are also defined at this level using custom Protobuf options +[offered](#validation-options) by the Validation Library. + +In order to use validation features, you don't need to understand how custom +options work. Those who are interested in the details of this advanced feature of Protobuf, +please see the [Protobuf Guide](https://developers.google.com/protocol-buffers/docs/proto3#custom_options) +for details.
+ +Here are simple steps in adding validation to the data model: + 1. The programmer adds validation constraints to the Protobuf types of the model. + 2. Spine Model Compiler generates the code which provides validation features. + 3. The programmer calls the validation API of these data types as their instances are created. + +## Java validation API + +For Java, we generate additional code to the Protobuf message classes. In particular, the message +builders get one extra method: `vBuild()` — short for "validate and build". It acts just like +`build()` but also throws a `ValidationException` if the message is not valid: + +```java +MyMessage.newBuilder() + .setFoo(invalidValue()) + .vBuild(); // ← Throws ValidationException. +``` + +If the validation is not required, you may call `build()` or `buildPartial()` provided by Protobuf +Java API. + +The message class also gets an extra method — `validate()`. This method does not throw exceptions. +Instead, it returns a list of `ConstraintViolation`s: + +```java +MyMessage msg = MyMessage.newBuilder() + .setFoo(invalidValue()) + .buildPartial(); +List+Protobuf 2 used to have a native support for required fields. +However, from the serialization perspective, that proved to be +a [design mistake](https://stackoverflow.com/a/31814967/3183076). If a required field was missing, +the message could not be serialized and sent over the wire. Also, it is often too easy to add a new +required field, thereby breaking backwards-compatibility of the message type. In Protobuf 3 all +the fields are optional.
+ +In the Validation Library, we've revived the concept of required fields, but on a different level. +The difference to the Protobuf 2 way is that out required fields do not affect the serialization +of the message. +If a required field is missing, it still can be serialized and passed over the wire. By separating +validation from serialization, we allow users to choose to ignore validation errors and still +transfer messages over the wire when needed. + +### How required fields work + +Fields in Protobuf may have either a primitive type or a user-defined type. A user-defined type is +a `message` or an `enum` and primitive types are numbers, `string`, and `bytes`. If a `message` or +an `enum` field is not set, the default value is assigned automatically: + +```java +ZonedDateTime time = getZonedTime(); +ZoneId timeZone = time.getZoneId(); +assert timeZone.equals(ZoneId.getDefaultInstance()); +``` + +However, due to limitations of the binary format, there is no way to tell if a numeric field is set +to `0` or just not set: + +```java +LocalTime time = getTime(); +int hours = time.getHours(); +assert hours == 0; +``` + +This means that a numeric field cannot be required, as there is no way to check if it is set. All +the other fields can be required. For `message` fields this means that the message must not be +empty: + +```java +ZonedDateTime time = getZonedTime(); +LocalDateTime dateTime = time.getDateTime(); +assert !dateTime.equals(LocalDateTime.getDefaultInstance()); +``` + +For `enum` fields, this means that the enum value must have a number other than `0` (since +the enum value with number `0` is the default value of the field): + +```java +LocalDate date = getDate(); +Month month = date.getMonth(); +assert !month.equals(Month.MONTH_UNDEFINED); +``` + +For `string` and `bytes` fields this means that the sequence must not be empty: + +```java +PersonName name = getName(); +String givenName = name.getGivenName(); +assert !givenName.isEmpty(); +``` + +For collection fields (i.e. `repeated` and `map`), a field is considered set if: + 1. The collection is not empty. + 2. At least one of the entries (values for `map`s) matches the rules described above. + +Note that collections of numeric fields can be required. In those cases, only the rule 1. applies +and the rule 2. is ignored. + +### Declaring required fields + +In the basic scenario, a single required field is marked with the `(required)` option: + +```proto +import "spine/options.proto"; + +// A phone number represented by a string of digits. +message PhoneNumber { + string digits = 1 [(required) = true]; +} +``` + +Here, the field `PhoneNumber.digits` is required. If the API user tries to validate an instance of +`PhoneNumber` without this field, a `ConstraintViolation` is produced: + +```java +PhoneNumber.newBuilder() + .setDigits("") + .vBuild(); // ← Throws ValidationException. +``` + +There are more complex cases for required fields than just a single field. Consider a `oneof` field +group, which always has to be set. Applying `(required)` to the fields does not make sense, since +only one field in the group can be set at a time. Instead, Spine provides `(is_required)` option: + +```proto +import "spine/options.proto"; +import "spine/net/email_address.proto"; +import "acme/auth.proto"; + +// The means to identify a user. +message UserIdentity { + oneof auth_type { + option (is_required) = true; + + spine.net.EmailAddress email = 1; + auth.GoogleId google = 2; + auth.TwitterId twitter = 3; + } +} +``` + +In this case one of the fields `UserIdentity.email`, `UserIdentity.google`, +and `UserIdentity.twitter` must be set. + ++`(is_required)` option is not yet supported in Dart. +
+ +In some other cases, a field may be either required or not, depending on the value of another field. +Consider an example of an online store item: + +```proto +import "spine/options.proto"; +import "spine/core/user_id.proto"; +import "google/protobuf/timestamp.proto"; + +// A product which can be purchased at the online store. +message Item { + // ... + + google.protobuf.Timestamp when_opened_for_sale = 42; + spine.core.UserId who_opened_for_sale = 43 [(goes).with = "when_opened_for_sale"]; +} +``` + +The `Item.who_opened_for_sale` field only makes sense for the domain if +the `Item.when_opened_for_sale` field is set. If `who_opened_for_sale` is set and +`when_opened_for_sale` is not, a constraint violation is produced. + +Finally, there are some cases, in which a pair of fields may be set at the same time, but at least +one of them must be set. This and more complex cases are handled by the type-level +`(required_field)` option: + +```proto +import "spine/options.proto"; + +// A name of a person. +message PersonName { + option (required_field) = "given_name|honorific_prefix & family_name"; + + string honorific_prefix = 1; + string given_name = 2; + string middle_name = 3; + string family_name = 4; + string honorific_suffix = 5; +} +``` + +In case of `PersonName`, either `given_name` or both `honorific_prefix` and `family_name` must be +set. All three can be set at the same time. + +### Missing fields + +In case if a required field is missing, the validation error message will explicitly say so. +However, if you need a specific error message for this field, you can provide it via +the `(if_missing)` option: + +```proto +import "spine/options.proto"; + +// A phone number represented by a string of digits. +message PhoneNumber { + string digits = 1 [(required) = true, + (if_missing).msg_format = "Phone number must contain digits."]; +} +``` + +Note that this option only applies to fields marked with `(required)` and not to the fields +referenced via any other options. + +If `(goes)` option is used, the error message can be customized with the `(goes).msg_format` +parameter. Note that the message should contain two "`%s`" insertion points: first for the name of +the field declaring the option and second for the name of the field targeted by the option. + +### When `(required)` is implicit + +When defining the domain [Commands]({{site.baseurl}}/docs/introduction/naming-conventions.html#commandsproto), +[Events]({{site.baseurl}}/docs/introduction/naming-conventions.html#eventsproto), or entity states, we have found +to be convenient that the first field of the respective Message is the identifier. Therefore, by +convention, Spine treats the first fields of such objects as their IDs: + +```proto +import "spine/options.proto"; +import "spine/core/user_id.proto"; +import "spine/people/person_name.proto"; + +// The state of the User Aggregate. +message User { + option (entity).kind = AGGREGATE; + + spine.core.UserId id = 2; + spine.people.PersonName name = 1; + // ... +} +``` + +In this case, the `User.id` field is implicitly `(required) = true`. Note that the field __number__ +has nothing to do with this convention, only the field __order__. Thus, `User.name` is not required. + +For the next example, consider `user_events.proto`: + +```proto +import "spine/options.proto"; +import "spine/net/url.proto"; +import "spine/core/user_id.proto"; + +// An event emitted when a user's profile picture is changed. +message ProfilePictureChanged { + + spine.net.Url new_picture = 1 [(required) = false]; + spine.core.UserId user = 2; +} +``` + +In this case, the `ProfilePictureChanged.id` field is not required, since it's not declared first +in the field. The field `ProfilePictureChanged.new_picture` is not required because the convention +is overridden with an explicit option. + +## Nested message validation + +When a message is validated, only the "shallow" constraints are checked by default. This means that +the message fields can be invalid and the container message is still considered valid. + +In order to enable message field checks, use `(validate)` option: + +```proto +import "spine/options.proto"; +import "spine/people/person_name.proto"; + +// The state of the User Aggregate. +message User { + // ... + + spine.people.PersonName name = 2 [(validate) = true]; +} +``` + +When an instance of `User` is validated, constraints of `User.name` will also be checked. +If any violations are found, they will be packed into a single violation of the `User` message. + +```java +// Honorific prefix not set and `name` is not valid. +PersonName name = PersonName + .newBuilder() + .setFamilyName("Smith") + .build(); // Build without validation. +User user = User + .newBuilder() + .setPersonName(name) + .vBuild(); // ← Throws ValidationException. +``` + +When applied to a `repeated` or a `map` field, each item (value of a `map`) is validated. + ++`(validate)` option is not yet supported in Dart. +
+ +#### Invalid fields + +If a specific error message is required for an invalid field, the `(if_invalid)` option should be +used: + +```proto +import "spine/options.proto"; +import "spine/people/person_name.proto"; + +// The state of the User Aggregate. +message User { + // ... + + spine.people.PersonName name = 2 [(validate) = true, + (if_invalid).msg_format = "User name is invalid."]; +} +``` + +## Number bounds + +For numeric fields, Spine defines a few options to limit the range of expected values. + +### `(min)`/`(max)` + +`(min)` and `(max)` are twin options which define the lower and higher bounds for a numeric fields. +The value is specified as a string. Note that the string must be parsable into the field's number +format (e.g. a `int32` field cannot have a `"2.5"` bound). + +By default, the bounds are __inclusive__. Use the `exclusive` property to make a bound exclusive. + +Example: + +```proto +import "spine/options.proto"; + +// A distance between two points of a map with a millimeter precision. +message Distance { + + uint64 meters = 1; + uint32 millimeters = 2 [(max) = { value: "1000" exclusive: true }]; +} +``` + +### Ranges + +The `(range)` option is a shortcut for a combination of `(min)` and `(max)`. A range specifies both +boundaries for a numeric field. `(range)` is a `string` option. The `(range)` notation allow +declaring inclusive and exclusive boundaries. A round bracket ("`(`" or "`)`") denotes an exclusive +boundary and a square bracket ("`[`" or "`]`") denotes an inclusive one. + +Example: + +```proto +import "spine/options.proto"; + +// A time without a time-zone. +// +// It is a description of a time, not an instant on a time-line. +// +message LocalTime { + + int32 hours = 1 [(range) = "[0..23]"]; + int32 minutes = 2 [(range) = "[0 .. 60)"]; + float seconds = 3 [(range) = "[0 .. 60.0)"]; +} +``` + +In the example above, the `LocalTime.hours` field can span between 0 and 23, the `LocalTime.minutes` +field can span between 0 and 59, and the `LocalTime.seconds` field can span between 0.0 and 60.0, +but can never reach 60. Exclusive boundaries are especially powerful for fractional numbers, since, +mathematically, there is no hard upper limit which a field value can reach. + +Usage of the double dot separator ("`..`") between the bounds is mandatory. + ++In some languages, Protobuf unsigned integers are represented by signed language primitives. +For example, in Java, a `uint64` is represented with a `long`. If a value of a field in Java will +overflow into `long` negatives, it will be considered a negative by the validation library. Keep +that in mind when defining lower bounds. +
+ +## Regular expressions + +For `string` fields, the library provides the `(pattern)` option. Users can define a regular +expression to match the field values. Also, some common pattern modifiers are available: + - `dot_all` (a.k.a. "single line") — enables the dot (`.`) symbol to match all the characters, + including line breaks; + - `case_insensitive` — allows to ignore the case of the matched symbols; + - `multiline` — enables the `^` (caret) and `$` (dollar) signs to match a start and an end of + a line instead of a start and an end of the whole expression; + - `unicode` — enables matching the whole UTF-8 sequences; + - `partial_match` — allows the matched strings to contain a full match to the pattern and some + other characters as well. By default, a string only matches a pattern if it is a full match, + i.e. there are no unaccounted for leading and/or trailing characters. + +Example: + +```proto +import "spine/options.proto"; + +// A link to an HTTP(S) resource. +message HyperReference { + string url = 1 [(pattern) = { + regex: "https?://.+\\..+" + modifier: { + case_insensitive: true + } + }]; +} +``` + +It is recommended to use simple patterns due to performance considerations. For example, fully +fledged URL and email patterns are famously too long to be used in most cases. Treat `(pattern)` +checks as if they were yet another code with regex matching in it. + +## Temporal constraints + +Spine provides an option for validating time-bearing types. Those are: + - `google.protobuf.Timestamp`; + - `spine.time.YearMonth`; + - `spine.time.LocalDate`; + - `spine.time.LocalDateTime`; + - `spine.time.OffsetDateTime`; + - `spine.time.ZonedDateTime`; + - any user-defined type which implements the Temporal interface (`io.spine.time.Temporal` for + Java). + +Using the option `(when)`, you may declare that the timestamp should lie in past or in future. + +```proto +import "spine/time_options.proto"; +import "spine/time/time.proto"; + +// A command to place an order. +message PlaceOrder { + + // ... + + spine.time.ZonedDateTime when_placed = 12 [(when).in = PAST]; + spine.time.ZonedDateTime when_expires = 13 [(when).in = FUTURE]; +} +``` + +Note that the value is checked in relation to the current server time. In most cases, this should +not be an issue. However, be aware that using `FUTURE` in Events and entity states may cause +validation errors when the future comes. Since entity states are validated upon each state change, +and historical events can be replayed, avoid declaring parts of those domain objects to be in +future. Commands, on the other hand, are not replayed or stored automatically. Thus, It is safe +to use `FUTURE` in Commands. + +## Distinct collections + +Often, a `repeated` field logically represents a set rather than a list. Protobuf does not have +a native support for sets. Moreover, it is often an invalid operation to add a duplicate element to +a set. For such cases, Spine provides the `(distinct)` option, which constrains a `repeated` or +a `map` field to only contain non-duplicating elements (values in case of `map`s). + +Example: + +```proto +import "spine/options.proto"; +import "spine/net/email_address.proto"; + +// The state of the User Aggregate. +message User { + // ... + + repeated spine.net.EmailAddress recovery_email = 42 [(distinct) = true]; +} +``` + +## Non-mutable fields + +Some messages persist in your system through a stretch of time. The value represented by such +a message may change. However, some fields must not change ever. For checking that, Spine allows +marking fields as `(set_once)`. The option allows changing a value of a field only if the current +value is the default value. Changing a field from a non-default value to anything else will cause +a violation. + +In Java, you can validate messages against a `set_once` constraint via +the `Validate.checkValidChange()` method. For example: + +```java +MyMessage old = getMessage(); +MyMessage changed = doSomeStuff(old); +Validate.checkValidChange(old, changed); +``` + +`Validate.checkValidChange()` throws a `ValidationException` if the constraint is violated. + ++In Dart, there is no support for this feature. +
+ +Many fields of an entity are immutable. They may be set once in the life of the entity and then +should never be changed. The `(set_once)` constraint is checked automatically for entity states upon +each change. + +Example: + +```proto +import "spine/options.proto"; +import "google/protobuf/timestamp.proto"; + +// The state of the Order Aggregate. +message Order { + option (entity).kind = AGGREGATE; + + // ... + + google.protobuf.Timestamp when_deleted = 314 [(set_once) = true]; +} +``` + +Once the `Order.when_deleted` field is filled, it can never change. + +## External constraints + +Sometimes, you need to impose extra validation rules on types you do not control. Consider +the example of an image URL which should always have the `ftp` protocol. In Spine, a `Url` is a tiny +type for representing URL strings: + +```proto +package spine.net; + +// ... + +// A Universal Resource Locator. +// +message Url { + + // The value of the URL. + string spec = 3 [(required) = true]; + + reserved 1, 2; +} +``` + +Now, we will use this type in our domain definition: + +```proto +import "spine/net/url.proto"; + +// The state of the User Aggregate. +message User { + // ... + + spine.net.Url profile_picture = 42; +} +``` + +How do we add validation to the `Url` so that only the `User.profile_picture` is +affected? Just for this purpose, Spine provides the mechanism of external constraints — validation +constraints defined outside the message. + +To declare an external constraint, use the `(constraint_for)` option: + +```proto +import "spine/options.proto"; + +// The external constraint definition for `User.profile_picture`. +message UserPictureConstraint { + option (constraint_for) = "org.example.user.User.profile_picture"; + + string spec = 3 [ + (required) = true, + (pattern).regex = "ftp://.+", + (pattern).msg_format = "Profile picture should be available via FTP (regex: %s)." + ]; +} +``` + +The definition of `User` itself need not change. + +Note that the fields of an external constraint declaration should replicate the fields of the target +type. In our example, the `Url` type. If the `Url` type had many fields, only those which need any +validation should be declared. However, note that if the `Url` type declares any validation on its +own, all of it is discarded and only the "substitute" rules from the `UserPictureConstraint` are +used. + ++External constraints are not yet supported in Dart. +
+ ++Mind performance considerations when declaring external constraints. It is expected that the number +of such constrains in the whole project is not large, significantly smaller than the number of +normal constraints. This mechanism is not designed to override validation rules of an entire library +of Protobuf definitions, merely a small amount of local patches. +
diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..0b60d4e --- /dev/null +++ b/docs/index.md @@ -0,0 +1,35 @@ +--- +title: Documentation +headline: Documentation +bodyclass: docs +layout: docs +next_btn: false +--- +# Welcome +Welcome to the Spine developer documentation. This page gives the overview of +the documentation sections.
+ +## [Quick Start]({{ site.baseurl }}/docs/quick-start/) +In this section you can learn what it's like to develop with Spine by going through the code of +the [Hello World](https://github.com/spine-examples/hello) example. + +## [Introduction]({{ site.baseurl }}/docs/introduction/) +This section gives an overview of the development process, the architecture of the Spine-based +application, information on DDD concepts implemented by the framework and how framework +users deal with them. + +## [Guides]({{ site.baseurl }}/docs/guides/validation) +This section provides detailed instructions on the framework use. + +## [Client Libraries]({{ site.baseurl }}/docs/client-libs/) +This section provides language-specific guides for building client-side applications. + +## [API Reference]({{ site.baseurl }}/docs/reference/) +This sections provides links to the generated documentation. + +## [Examples]({{ site.baseurl }}/docs/examples/) +This page is the entry point for learning from the code of +the [example applications](https://github.com/spine-examples/). + +## [DDD Resources]({{ site.baseurl }}/docs/resources/) +A brief selection of learning materials we recommend to the colleagues in DDD. diff --git a/docs/introduction/architecture.md b/docs/introduction/architecture.md new file mode 100644 index 0000000..0b39c9a --- /dev/null +++ b/docs/introduction/architecture.md @@ -0,0 +1,32 @@ +--- +title: Architecture +headline: Documentation +bodyclass: docs +layout: docs +customjs: /js/architecture-diagram.js +--- +# Application Architecture + + +A Spine-based application consists of several Bounded Contexts. Client applications interact +with the server-side via `CommandService`, `QueryService`, and `SubscriptionService`. + +The diagram below shows all server-side components +of a cloud application. When developing with Spine, you will be interacting +with only some of them, which +are not shaded on the diagram. The rest is handled by the framework. + +Click on a component to navigate to its definition from +the [Concepts]({{site.baseurl}}/docs/introduction/concepts.html) page.
+ +This document provides terminology used in the framework and its documentation.
+You'll find most of the terms familiar from Domain-Driven Design, CQRS, Event Sourcing or Enterprise
+Integration patterns.
+
+We give brief descriptions for those who are new to these concepts and to tell
+how they are implemented in our framework.
+Terms extending the industry-set terminology are designated as such.
In some cases, Event Reactor may ignore the event, returning `Nothing`.
+ It usually happens when a method returns one of the
+ [`Either`]({{site.core_api_doc}}/server/index.html) types, with `Nothing` as
+ one of the possible options: `EitherOf2
We highly recommend using message-based IDs to make your API strongly pronounced + and type-safe.
+ +### Aggregate + +Aggregate is the main building block of a business model. +From the application point of view it consists of the following: +1. Commands which arrive to it. +2. Events which appear in response to these commands. +3. How these events influence the state of an aggregate. + +[Aggregates](http://martinfowler.com/bliki/DDD_Aggregate.html) guarantee consistency of data +modifications in response to commands they receive. Aggregate is the most common case of +Command Handler. In response to a command, it produces one or more events modifying own state. +These events are used later to restore the state of the aggregate. + +In Spine, aggregates are defined as Java classes, and their states are defined as Protobuf messages. + +### Process Manager + +Process Manager is an independent component that manages the cross-aggregate business flows. +It serves as a mediator by remembering the state of the flow and choosing the next step +based on the intermediate results. + +To do so, a Process Manager can be both [Command Handler](#command-handler) +and [Event Reactor](#event-reactor). Also, it can emit Commands to other Aggregates +and Process Managers. + +In Spine, Process Managers are defined as Java classes, and their states are defined as +Protobuf messages. + +### Projection + +Projection is an [Event Subscriber](#event-subscriber) which transforms multiple events data into +a structural representation. Projections are the main building blocks of the Query side of +the application. + +In Spine, Projections are defined as Java classes, and their states are defined as +Protobuf messages. + +### Repository + +Repository encapsulates storage, retrieval, and search of Entities as if it were +a collection of objects. It isolates domain objects from the details of the database access code. + +The applications you develop using Spine usually have the following types of repositories: +* [`AggregateRepository`]({{site.core_api_doc}}/server/io/spine/server/aggregate/AggregateRepository.html), +* [`ProcessManagerRepository`]({{site.core_api_doc}}/server/io/spine/server/procman/ProcessManagerRepository.html), +* [`ProjectionRepository`]({{site.core_api_doc}}/server/io/spine/server/projection/ProjectionRepository.html). + +### Snapshot + +Snapshot is a state of an Aggregate. A snapshot ”sits” in between events in the history of +the Aggregate to make restoring faster. + +When an Aggregate is loaded, the `AggregateStorage` reads events backwards until encounters +a snapshot. Then the snapshot is applied to the Aggregate, and trailing events are played +to obtain the most recent state. + +## Services + +Services are used by a client application for sending requests to the backend. + +In Spine, services are based on [gRPC](https://grpc.io). + +### Command Service + +The Command Service accepts a command from a client-side application and redirects it to +the [Bounded Context](#bounded-context) to which this command belongs. This means that there +is a context in which there is a [handler](#command-handler) for this command. Otherwise, +the command is not [acknowledged](#acknowledgement). + +### Query Service + +Query Service returns data to the client applications in response to a query. +The query is a request for the following: +* state of one or more aggregates or their fragments; +* one or more projection states or their fragments. +* one or more process manager states or their fragments. + +### Subscription Service + +Subscription Service allows to subscribe to something happening inside a Bounded Context. + +There are two options for subscription: +* receive changes of an Entity state for Projections, Process Managers and Aggregates; +* be notified of domain Events. + +## Architectural + +### Bounded Context + +Bounded Context is an autonomous component with its own domain model and its +own Ubiquitous Language. Systems usually have multiple Bounded Contexts. + +`Orders`, `UserManagement`, `Shipping` as examples of the contexts of an online retail system. + +### Message Buses + +#### Command Bus + +This is a message broker responsible for routing the command to its handler. +Unlike a [Command Handler](#command-handler), it does not modify the application business model, +nor produces domain events. + +There can be only one handler per command type registered in a Command Bus. + +#### Event Bus + +This bus dispatches events to entities that are [subscribed](#event-subscriber) to these +events or [react](#event-reactor) on them. + +### Message Stores + +#### Command Store + +This store keeps the history of all the commands of the application and statuses of +their execution. + +#### Event Store + +This store keeps all the events of the application in the chronological order, which also called +Event Stream. This is the main “database” of the Bounded Context. + +New projections are built by passing the event stream “through” them. + +### Integration Event + +Integration Events are [events](#event) used to communicate between different Bounded Contexts. + +In Spine, every domain Event may become an Integration Event, if it is emitted by the given +Bounded Context and consumed by another Bounded Contexts. + +### Aggregate Mirror + +In Spine, Aggregate Mirror contains the latest state of an Aggregate. +It “reflects” how it “looks” at the time of the last update. + +### Stand + +In Spine, Stand is a read-side API facade of a BoundedContext. + +### System Context + +System Context orchestrates the internal Spine framework entities that serve the goal of monitoring, +auditing, and debugging of domain-specific entities of the enclosing Bounded Context. +Users of the framework do not interact with this component. diff --git a/docs/introduction/diagrams/spine-architecture-diagram-full-screen.html b/docs/introduction/diagrams/spine-architecture-diagram-full-screen.html new file mode 100644 index 0000000..afa429c --- /dev/null +++ b/docs/introduction/diagrams/spine-architecture-diagram-full-screen.html @@ -0,0 +1,27 @@ +--- +layout: full-screen +title: Application Architecture +--- + +This diagram shows all + server-side components of a cloud application. + When developing with Spine, you will be interacting with + some of them.
+Building a solution based on Spine Event Engine framework is an iterative process +which consists of the stages described in this document.
+ +## Getting domain knowledge + +The purpose of this step is to find out what we're going to build and why. +Consider using [EventStorming](https://eventstorming.com) or another domain discovery +approach for grasping the knowledge from the experts. + +Most likely that the solution would have several [Bounded Contexts](concepts.html#bounded-context). +For each context developers need to define: + * Signals + - [Events](concepts.html#event) + - [Commands](concepts.html#command) + - [Rejections](concepts.html#rejection) + * Entities + - [Aggregates](concepts.html#aggregate) + - [Process Managers](concepts.html#process-manager) + - [Projections](concepts.html#projection). + +It is likely that some of the bits of this picture would change during the process. +But the whole team, including domain experts, need to have complete understanding of how the +business works to avoid “surprises” down the road. + +We return to learning the domain when we discover inconsistencies in the model, +or we need more information about how the business works, or the business wants to develop further +and we need to update the model. + +Once we got enough domain knowledge we proceed to the implementation. + +## Implementing a Bounded Context + +At this stage we select one of the Bounded Contexts for the implementation. +Each context is developed separately. In this sense it can be seen as a microservice. +It would be natural to start implementing the context which initiates the business flow. + +### Defining data types + +Implementation starts from defining data types of the selected context as Protobuf messages. + +The first step is to define entity [IDs](concepts.html#identifier). For example: +```proto +// The identifier for a task. +message TaskId { + string uuid = 1; +} +``` + +Then commands, events, rejections are defined: +```proto +// A command to create a new task. +message CreateTask { + TaskId id = 1; + string name = 2 [(required) = true]; + string description = 3; +} +``` + +```proto +// A new task has been created. +message TaskCreated { + TaskId task = 1; + string name = 2 [(required) = true]; + string description = 3; + UserId who_created = 4 [(required) = true]; +} +``` + +Then we define states of entities. + +```proto +message Task { + option (entity).kind = AGGREGATE; + TaskId id = 1; + string name = 2 [(required) = true]; + string description = 3; + UserId owner = 4 [(required) = true]; + DeveloperId assignee = 5; +} +``` + +[Value Objects]({{site.baseurl}}/docs/introduction/concepts.html#value-objects) are added when they +are needed to describe entities or messages like commands or events. + +### Adding business logic + +The business logic of a Bounded Context is based on [Entities](#entities). +They handle messages updating the state in response. Entities like `Aggregate`s and +`ProcessManager`s can generate events. `ProcessManager`s can also generate new commands. +`Projection`s only consume events. + +Updating the state of the domain model in response to messages and generating new messages is +the “life” of the domain model. Messages are delivered to entities by [Repositories](#repositories). + +#### Entities + +During this step we create entity classes and add message handling methods to them. +Code snippets below show `Aggregate` and `Projection` classes with their handler methods. + +```java +final class TaskAggregate + extends AggregateThis document covers naming conventions for the code. Some of these conventions are +used by the framework and code generation, and as such are required. Others are our recommendations +that we find useful for making the code easier to understand.
+ +## Proto files + +Proto files are named using the `snake_case`, as defined by Protobuf. There are several special +kinds of files. + +### `identifiers.proto` + +Commands and events reference model entities using their identifiers. +Having typed identifiers makes a model type safe. +Although the framework also supports `String`, `Integer`, and `Long` as valid ID types, +we strongly recommend defining custom ID types like `CustomerId`, `OrderId`, `ShipmentId`, +and others. You can find similar cases in the framework API which has `EventId`, `CommandId`, +`UserId`, `TenantId`, and others. + +We find it convenient to define ID types in one file called `identifiers.proto`. +A typical project is likely to have more than one Bounded Context. Thus, you will have several +`identifiers.proto` files. +Each of them resides under the directory with proto files defining the data model of the +corresponding Bounded Context. For example: + +
+
+ myproject/
+ users/
+ src/
+ main/
+ java/
+ proto/
+ user.proto
+ group.proto
+ ...
+ identifiers.proto
+ tasks/
+ src/
+ main/
+ java/
+ proto/
+ task.proto
+ project.proto
+ ...
+ identifiers.proto
+ ...
+
+
+This convention is not a requirement. We find `Id` suffix short yet meaningful for + building a rich type-safe API. You can also select another convention that fits your domain + best. Please note that future version of the framework tools will use the `Id` suffix of the + types for code scaffolding and improving intelligence of code generation.
+ +While the identifier type is usually defined with the `Id` suffix, we do not recommend following +the same strategy for the proto field names. Naming fields as `id` or adding the `_id` suffix +is usually excessive because the identifier type already has the `Id` suffix. + +Instead, we name the fields by their respective type reference, so `user_id` becomes +`user` and `project_id` becomes `project`. + +In events:
+{% highlight proto %} +message TaskCreated { + TaskId task = 1; + ProjectId project = 2; +} +{% endhighlight %} +And entity states:
+{% highlight proto %} +message TaskProjection { + TaskId task = 1; + ProjectId project = 2 + string name = 3; +} +{% endhighlight %} +In aggregates:
+{% highlight proto %} +message Task { + TaskId id = 1; + ProjectId project = 2; +} +{% endhighlight %} +And entity creation commands:
+{% highlight proto %} +message CreateTask { + TaskId id = 1; + ProjectId project = 2; +} +{% endhighlight %} +This convention contradicts with the official +[Protobuf Style Guide](https://developers.google.com/protocol-buffers/docs/style#repeated_fields +"Protocol Buffers Style Guide") which suggests naming `map` and `repeated` fields after plural +nouns. Knowing this, we still recommend singular because of the following. + +The code generated for a `repeated` and `map` field named after a singular noun is closer to +real English. For the code related to the Domain-Driven Design this is far more important than +the consistency with the style guide.
+ +So when defining `repeated` and `map` fields use: + +Singulars
+{% highlight proto %} +message Task { + TaskId id = 1; + repeated SubTaskId subtask = 2; + mapOver pluralized names
+{% highlight proto %} +message CreateTask { + TaskId id = 1; + repeated SubTaskId subtasks = 2; + mapFor details on rejections usage, refer to + [Defining Rejections Guide]({{site.baseurl}}/docs/guides/rejections.html).
+ +#### Server-side code + +To avoid unwanted dependencies we find it useful to put server-side code under +a sub-package called `server` with sub-packages for corresponding entity types: + + * `io.acme.todolist.server.task` + * `io.acme.todolist.server.project` + * `io.acme.todolist.server.comment` + +## Handcrafted Java Classes + +### Entities + +When naming entities we find it natural to start with a name of a state class and then +add a suffix which tells the type of the entity: + + * `ProjectAggregate` + * `OrderProcessManager` + * `TaskItemProjection` + +The suffix helps for observing together with other entities in a package. + +For process managers it may be enough to have the `Process` suffix dropping `Manager` +which frequently worked for us too. Other options for suffixes are `Pm` or `Procman`. + +It would be a good idea to decide on such suffix as a team standard before you + start coding.
+ +#### Repositories + +We recommend _not_ using a type infix for naming repository classes. Alphabetical sorting would +make a repository class be next to an entity class, and you would not deal much with repository +classes anyway. Thus, it is just `SomethingRepository` rather than `SomethingAggregateRepository`: + + * `ProjectRepository` + * `OrderRepository` + * `TaskItemRepository` + +### Bounded Contexts + +#### Names + +Bounded Contexts names follow `TitleCapitalization` favoring plurals: + + * `Users` + * `Tasks` + * `DeliveredOrders` + +Although, singular names are perfectly fine too, for example: + + * `Billing` + * `Shipping` + * `DynamiteProduction` + +#### Packages + +If a name of a Bounded Context is used in a package, its name is transformed according to the rules +of a programming language. + +#### Factory classes + +A Java class that creates and configures an instance of a `BoundedContext` is named after the +name of the context with the `Context` prefix: + + * `UsersContext` + * `DeliveredOrdersContext` + * `OnboardingContext` diff --git a/docs/introduction/prior-art.md b/docs/introduction/prior-art.md new file mode 100644 index 0000000..d69f598 --- /dev/null +++ b/docs/introduction/prior-art.md @@ -0,0 +1,87 @@ +--- +title: Prior Art +headline: Prior Art +bodyclass: docs +layout: docs +--- + +# Prior Art + +The demands for software projects increase rapidly as time progresses. +So does the scope of architecture approaches to meet these needs. +This section will give you an overview of the concepts and implementations Spine has inherited, +while bringing some important differences into play. + +Spine is created for applications that follow the [CQRS](http://martinfowler.com/bliki/CQRS.html) +and [Event Sourcing](http://martinfowler.com/eaaDev/EventSourcing.html) architectural patterns. + +Spine didn’t appear out of the blue. While working on our own CQRS/ES based projects we were +alarmed at how much manual effort is spent on creating events and commands, delivering events and data +to the web and mobile clients. It takes time, does not require much creativity from a developer, +whilst this energy could have been spent on productive +[Event Storming](http://ziobrando.blogspot.com/2013/11/introducing-event-storming.html), +detailing the Domain model and so on. Attempts to address this issue led to the Spine vision. + +A major addition Spine brings to the existent variety of tools, libraries, and frameworks is +automatic **code generation** for multiple application clients. +It is reached by using [Protocol Buffers](https://developers.google.com/protocol-buffers/docs/overview). + +When creating an Event Sourcing application, you need to write classes for commands, events, +command handlers, aggregates, aggregate repositories, DTOs etc. +And if your organization wants an application on, let’s say, a couple of mobile platforms, +you would have to add a lot of work to deliver data to each client application. +So you need to make your code work on another platform by writing it in another language *manually*, +or translate it using tools like [J2ObjC](http://j2objc.org/), or resort to using only +Json in the client apps. + +Using [Protobuf](https://developers.google.com/protocol-buffers/docs/overview) for formulating +the business domain allows us to make this language +[ubiquitous](http://martinfowler.com/bliki/UbiquitousLanguage.html) not only in human interaction, +but in communication of computing devices too. + +**Immutability** is another major concept we follow. +Spine uses typed commands and events. Having commands and events as first class citizens in the +applications gives a lot of benefits in terms of business logic. Not having to convert back and +forth with Json gives some performance advantage at the same time. + +We are greatly inspired by [Redux](http://redux.js.org) — one of the most exciting things happening +in JavaScript at the moment. It stands out from the landscape of libraries and frameworks by +getting so many things absolutely right: a simple, predictable state model; an emphasis on functional +programming and immutable data. + +In Spine Event Engine we combined all of our experience and observations of the best-breed market +products and solutions like [Axon](http://www.axonframework.org/), [Spring](https://spring.io/), +[Event Store](https://geteventstore.com/), [InfluxDB](https://influxdata.com/), +[Apache Zest](https://zest.apache.org/) and many others. +Spine has yet to find its own niche. + +Spine probably won’t be the best fit for trading or highly loaded applications, where, for example, +[LMAX](https://www.lmax.com/) does an excellent job. Our motivation is to make development of +modern applications easier and more efficient, and to offer a set of practical solutions to bring +this into life with a corresponding approach and terminology. + +In terminology we heavily lean on [Domain-Driven Design (DDD)](https://en.wikipedia.org/wiki/Domain-driven_design) +and the [“Big Blue Book”](http://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215) +by Eric Evans. + +We learned a lot from the book [“CQRS Journey”](https://msdn.microsoft.com/en-us/library/jj554200.aspx) +by Microsoft, and our choice of the term “Process Manager” over the commonly used “Saga” is +based on the experience of Microsoft engineers. +The “Process Manager” pattern was first defined and brought into common vocabulary by Kyle Brown +and Bobby Woolf under the guidance of Martin Fowler in the book +[“Enterprise Integration Patterns”](http://www.enterpriseintegrationpatterns.com/patterns/messaging/ProcessManager.html). + +Another great resource on object-oriented design worth mentioning here is +[“Patterns of Enterprise Application Architecture”](http://www.martinfowler.com/books/eaa.html) +by Martin Fowler. Many modern frameworks implement these patterns behind the scenes, and so does Spine. +But as [Martin Fowler](http://www.martinfowler.com/books/eaa.html) notes: + + >Frameworks still require you to make decisions about how to use them, + >and knowing the underlying patterns is essential if you are to make wise choices. + +Systems built on top of Spine framework are flexible, loosely-coupled, scalable and open to change. +Here we should thank [Reactive Manifesto](http://www.reactivemanifesto.org/), +which became one the corner stones and drivers of the Spine philosophy. + +We are yet at the beginning of our journey of using Spine in the wild. +Join us and share how it goes! diff --git a/docs/introduction/project-structure.md b/docs/introduction/project-structure.md new file mode 100644 index 0000000..37c4231 --- /dev/null +++ b/docs/introduction/project-structure.md @@ -0,0 +1,92 @@ +--- +title: Project Structure +headline: Documentation +bodyclass: docs +layout: docs +--- +# Project Structure + +This document describes standard structure of a Spine-based project. +It assumes that you are familiar with Gradle.
+ +Spine uses Gradle for project model definition and as the build tool. +It follows the standard structure of the Gradle project with extensions related to +the code generation done by Protobuf Compiler and Spine Model Compiler.
+ +## Handcrafted code + +Following standard Gradle conventions a manually written code is created under the +`src/main/` directory with subdirectories `proto`, `java`, etc. for corresponding languages. + +After a project is defined in Gradle, a work on a module usually starts in the +the `proto` directory. + +## Generated code + +The generated code is placed under the `generated` directory under the module root. +The sub-directories are: + +* `java` — the code generated by Protobuf Compiler +* `resources` — mappings generated by Spine Model Compiler +* `spine` — the code generated by Spine Model Compiler + +### Excluding from version control + +The generated code is created and updated during build time. Directories with the generated +code files should NOT be added to version control system of your project. +This makes a commit to contain only essential changes relevant to the update of the model, +in particular: + + 1) Modifications of `.proto` files of the data model. + + 2) Updated calls from the application code to the generated data model API. + +By not including the generated code into the version control we minimise the “noise” +for developer eyes when a model changes. So, if you are using Git, for example, consider adding + the following line to your `.gitignore` file: + +``` +**/generated/** +``` + +## Example + +Here's how a typical project structure would look like: + +``` +myproject/ + gradle/ + module-one/ + generated/ + main/ + java/ + resources/ + spine/ + ... + test/ + java/ + resources/ + spine/ + ... + src/ + main/ + java/ + proto/ + test/ + java/ + proto/ + ... + build.gradle + module-two/ + generated/ + ... + src/ + ... + build.gradle + ... + build.gradle + gradlew + gradlew.bat + settings.gradle +``` + diff --git a/docs/introduction/rules.md b/docs/introduction/rules.md new file mode 100644 index 0000000..1be93cc --- /dev/null +++ b/docs/introduction/rules.md @@ -0,0 +1,22 @@ +--- +title: Rules +headline: Documentation +bodyclass: docs +layout: docs +type: markdown +--- + +# Rules + +Here are the ground rules the framework is built upon: + +1. An update to a business model is an event. + +2. Entities are changed in response to events. + +3. A command has one and only one handler. + +4. A command must result in an event, a rejection, or other commands. + +5. Events are always appended. Never deleted or edited. + diff --git a/docs/quick-start/index.md b/docs/quick-start/index.md new file mode 100644 index 0000000..c51a733 --- /dev/null +++ b/docs/quick-start/index.md @@ -0,0 +1,996 @@ +--- +title: Getting Started in Java +headline: Documentation +bodyclass: docs +layout: docs +next_btn: + page: Development Process Overview +--- + +# Getting started with Spine in Java + +This guide will walk you through a minimal client-server application in Java +which handles one command to print some text on behalf of the current computer user. The document +goes through already written code which is quite simple. So, it won't take long. +
+ +## What we'll do + +We'll go through the example which shows a Bounded Context called “Hello”. +The context has one `ProcessManager`, which handles the `Print` command +sent from the client-side code to the server-side code hosting the context. +We'll go through the production code of the example suite, and through the code which +tests the Hello context. + +## What you'll need + +1. JDK version 8 or higher. +2. Git. +3. The source code of the [Hello World](https://github.com/spine-examples/hello) example. + + ```bash + git clone git@github.com:spine-examples/hello.git + ``` + +## Run the code + +To check that you've got everything installed, please run the following command: + +```bash +./gradlew :sayHello +``` + +If you're under Windows, it would be: + +```bat +gradlew.bat :sayHello +``` + +This would build and execute the example. +The process should finish with the output which looks like this: + +``` +> Task :sayHello +Dec 18, 2020 5:32:11 PM io.spine.base.Environment setCurrentType +INFO: `Environment` set to `io.spine.base.Production`. +Dec 18, 2020 5:32:12 PM io.spine.server.Server lambda$start$1 +INFO: In-process server started with the name `a7c62b63-2cc6-4679-bb92-072591142275`. +[savik] Hello World! +The client received the event: io.spine.helloworld.hello.event.Printed{"username":"savik","text":"Hello World!"} +Dec 18, 2020 5:32:15 PM io.spine.server.Server shutdown +INFO: Shutting down the server... +Dec 18, 2020 5:32:15 PM io.spine.server.Server shutdown +INFO: Server shut down. +``` + +The first line tells which Gradle task we run. The following couple of lines is the server-side +logging that informs us that the server was started. + +The line with the `Environment` tells that we're running the application in the `Production` +environment. +The line with “Hello World!” text is the “meat” of this example suite. +It is what our `ProcessManager` (called `Console`) does in response to the `Print` command received +from the `Client`. +The text in between brackets is the name of the current computer user. The name was passed as +the argument of the `Print` command. + +We opted to show a `ProcessManager` — instead of an `Aggregate` — because +the console output is similar to an “External System”. Dealing with things like +that is the job of Process Managers. We also want to highlight the importance of using +this architectural pattern.
+ +The output that follows is the logging produced by the `Client` class as it receives the `Printed` +event from the server. + +Then, the server shuts down concluding the example. + +Now, let's dive into the code. + +## Project structure + +For the sake of simplicity, this example is organised as a single-module Gradle project. +Most likely, a project for a real world application would be multi-module. + +### The root directory + +The root of the project contains the following files: + * `LICENSE` — the text of the Apache v2 license under which the framework and + this example are licensed. + * `README.md` — a brief intro for the example. + * `gradlew` and `gradlew.bat` — scripts for running Gradle Wrapper. + * **`build.gradle`** — the project configuration. We'll review this file later + [in details](#adding-spine-to-a-gradle-project). + +The root directory also contains “invisible” files, names of which start with +the dot (e.g. `.gitattributes` and `.travis.yml`). +These files configure Git and CI systems we use. They are not directly related to the subject +of the example and this guide. If you're interested in this level of details, +please look into the code and comments in these files. +
+ +Here are the directories of interest in the project root: + * `gradle` — this directory contains the code of Gradle Wrapper and two Gradle scripts + used in the [project configuration](#other-project-configuration). + * **`generated`** — this directory contains the code generated by Protobuf Compiler and + Spine Model Compiler. This directory and code it contains is created automatically + when a domain model changes. This directory is excluded from version control. + * **`src`** — contains the handcrafted source code. + +Let's see how the source code is structured. + +### The `src` directory + +The source code directory follows standard Gradle conventions and has two sub-directories: + * **`main`** — the production code; + * **`test`** — the tests for the production code. + +The production code consists of two parts allocated by sub-directories: + * **`proto`** — contains the definition of data structures in Google Protobuf. + A domain model definition starts from adding the code to this directory. + Then, the Protobuf code is compiled to the languages of the project. + The output of this process is placed into the `generated` directory, with a sub-directory + for each language. This example uses only Java. + + * **`java`** — this directory contains the model behavior and other server- and client-side code. + A real project would have these parts in separate modules or projects. We put it all + together for the sake of simplicity. + +Now, let's review the code in details, starting with how to add Spine to a Gradle project. + +## Adding Spine to a Gradle project + +Let's open `build.gradle` from the root of the project. The simplest and recommended way for +adding Spine dependencies to a project is the Bootstrap plugin: + +Calling `spine.enableJava().server()` adds both server- and client-side dependencies. +This way a module of a Bounded Context “A” may be a client for a Bounded Context “B”. +Client-side applications or modules should call: `spine.enableJava().client()`. +
+ +### Other project configuration + +The rest of the `build.gradle` file does the following: + 1. Sets the version of Java to 8. + + 2. Adds JUnit dependencies by applying the `tests.gradle` script plugin (which we extracted + for the sake of simplicity). + + 3. Defines the `sayHello` task which runs the `Example` application, which orchestrates + the demo. + +We are not reviewing these parts of the project configuration deeper because they are not +related to the use of the Spine framework. If you're interested in more details, please look into +the mentioned `.gradle` files. + +Now, let's look into the data structure of the Hello context. + +## Hello context data + +The data types of the Hello context are defined under the `src/main/proto/hello` directory with +the following files: + + * **`commands.proto`** — this file defines the `Print` command. + +By convention, commands are defined in a file with the `commands` suffix + in its name. It can be, for example, `order_commands.proto` or just `commands.proto` + like in our example.
+ + * **`events.proto`** — this file defines the `Printed` event. + +Similarly to commands, events are defined in proto files having the `events` + suffix in their names.
+ +These two files define signals used by the Hello context. There's also data of the `Console` +Process Manager, which is defined in the package **`server`** in the file **`console.proto`**. + ++We arrange the sub-package `server` to highlight the fact that this is server-only data. It is not +a convention used by the framework. We find the clarity of this infix useful when creating +cloud applications. So, we share it as a recommendation in this example.
+ +Let's review the context data definition in details. + +### The `commands.proto` file + +After the copyright header the file starts with the syntax declaration. The framework supports only +this version of the Protobuf dialect: +```proto +syntax = "proto3"; +``` + +Then follows the import statement for custom options used when defining data types. This import is +required for all proto files of a Spine-based project. + +Outer classes are used by Protobuf implementation internally. +When the `java_outer_classname` option is omitted, Protobuf Compiler would calculate the Java +class name taking the name of the corresponding `.proto` file. +We recommend setting the name directly to make it straight. This also avoids possible name clashes +with the handcrafted code.
+ +The next standard option instructs the Protobuf Compiler to put each generated Java type into +a separate file. This way it would be easier to analyze dependencies of the code which uses these +generated types. + +In Protobuf a data type is either a **`message`** (we can send it) or an **`enum`**. +If you're new to this language, you may want to look at the [Proto3 Language Guide][proto3-guide]. +
+ +Now, let's see how to define events. + +### The `events.proto` file + +Events are declared similarly to commands. The header of the file has: + + * The `proto3` syntax declaration. + * The `hello` package declaration. + * The import statement for custom Protobuf options used by the framework: + + ```proto + import "spine/options.proto"; + ``` + + * The same `(type_url_prefix)` we use in this project. + * A separate Java package for events of the context: + + ```proto + option java_package="io.spine.helloworld.hello.event"; + ``` + + * The outer Java class for all types in this file: + + ```proto + option java_outer_classname = "EventsProto"; + ``` + + * The instruction to put Java types into separate files. + + ```proto + option java_multiple_files = true; + ``` + +The sole event in this project is declared this way: + ++Unlike for commands, the framework does not assume that the first event field is always +populated. This is so because default routing rules for commands and events are different. +When an event is produced by some entity, it remembers the ID of this producer entity. +By default, the framework uses the producer ID to route events to their target entities — +if they have identifiers of the same type. If the type of producer ID does not match one of the +target entity, then event fields are analyzed. It is also possible to set custom routing rules. +
+ +Now, let's see the server-side data of the Hello context. + +### The `console.proto` file + +The header of the file is similar to those we saw in `commands.proto` and `events.proto`. +The difference is that we use `server` for the proto and Java package names to make sure the +server-only is not used by the client code. + +This file defines a single data type. It is the state of the entity handling the `Print` command: + +After the event is generated, it is posted to the `EventBus` and delivered to +subscribers automatically. You don't need to write any code for this.
+ +Now, let's see how the `Console` Process Manager is exposed to the outer world so that it can +receive commands. + +## Assembling the Hello context + +Let's open the `HelloContext` class. The first thing of interest in this class is the declaration of +the name of the Bounded Context: + +The framework assumes that all entity classes belonging to this and nested packages +belong to the Bounded Context with the name specified in the argument of the annotation. +This arrangement is needed for routing events.
+ +The second thing the `HelloContext` does is creating a Builder for the Bounded Context: + +If an entity uses default routing rules for the incoming events and commands, +its type can be added to `BoundedContextBuilder` directly. If custom routing rules are needed, +they are specified by a custom `Repository` class. In this case, an instance of such `Repository` +is passed to `BoundedContextBuilder` instead of the entity type managed by this `Repository`.
+ +Once we assembled the Bounded Context, let's test it. + +## Testing the Hello context + +Let's open the `HelloContextTest` suite. It is based on JUnit 5 and `spine-testutil-server` library. + +We already added JUnit dependency when defining the Gradle project. +The `testImplementation` dependency for `spine-testutil-server` is automatically added when +you enable Spine in your project using `spine.enableJava().server()`. So, we're good to go testing.
+ +The class of the test suite extends the abstract base called `ContextAwareTest`: + +In-process gRPC communications are normally used for testing. +This example uses in-process client/server arrangement in the production code for +the sake of simplicity. A real-world application would use a `Server` instance exposed +via a TCP/IP port.
+ +Once we have the `Server.Builder` instance returned by the `inProcess()` method, +we add the Hello Context via its builder to the constructed `Server` instance. + +### Start and shutdown + +The remaining code of our `Server` class declares `start()` and `shutdown()` methods that +simply delegate calls to the wrapped `io.spine.server.Server` instance. + +Now we have the server, but how does the client side look like? + +## The client code + +Similarly to `Server`, the `Client` class of our example application wraps around +the `io.spine.client.Client` API provided by the `spine-client` library: + +The `io.spine:spine-client` library is provided +to the example application project as a transitive dependency of +the `io.spine:spine-server` library, which is added to the project when you do +`spine.enableJava().server()` in your Gradle project.
+ +Then, the `Client` class declares a field for keeping subscriptions to the results of a command +execution. We'll see how this field is used in a minute. + +The ideas unfolding in real time
+ +- [Domain Driven Design Weekly](http://dddweekly.com/). +The periodical digest of articles and materials on DDD by Nick Chamberlain. + +- [Martin Fowler on Domain-Driven Design](https://martinfowler.com/tags/domain%20driven%20design.html). + +- [Avanscoperta blog](https://blog.avanscoperta.it/it/). +The blog by Alberto Brandolini and his colleagues. diff --git a/docs/resources/books.html b/docs/resources/books.html new file mode 100644 index 0000000..01e658c --- /dev/null +++ b/docs/resources/books.html @@ -0,0 +1,84 @@ +--- +title: Books +headline: DDD Resources +bodyclass: docs resources +layout: docs +--- + +Key works to get familiar with the approach
+ +Tackling Complexity in the Heart of Software
+ + +The Big Blue Book which lay the basics of Domain-Driven Design methodology. + It provides a broad framework for making design decisions and a vocabulary for + discussing domain design.
+This book provides a brief overview of the DDD methodology. + It also defines the terms, which were coined in this topic since 2004.
+The Big Red Book provides practical guidance on how to apply DDD. Building on Eric + Evans’ seminal book, Domain-Driven Design, the author presents practical DDD techniques + through examples from familiar domains.
+If you are new to Domain-Driven Design, this book and the Domain-Driven Design Reference + by Eric Evans are the best way to get into the topic.
+An act of deliberate collective learning
+ + +The deepest tutorial and explanation about EventStorming, straight from the inventor. + It provides guidance on leveraging the potential of this collaborative brainstorming + technique used to identify domain events.
+Places to discuss DDD with other practitioners
+ +- [Virtual DDD](https://virtualddd.com/) (EN)A brief selection of learning materials we recommend to the colleagues in DDD
+ +Other tools that help with DDD in code
+ +- [Axon](https://axoniq.io/). +Open source framework for event-driven microservices and domain-driven design. + +- [Vlingo](https://vlingo.io/). +The open source toolkit by Vaughn Vernon for fluent reactive, event-driven, +and microservices architectures. + +- [EventStore](https://eventstore.com/). +The stream database by Greg Young built for Event Sourcing. diff --git a/docs/resources/people.html b/docs/resources/people.html new file mode 100644 index 0000000..86d571f --- /dev/null +++ b/docs/resources/people.html @@ -0,0 +1,80 @@ +--- +title: People +headline: DDD Resources +bodyclass: docs resources +layout: docs +--- + +The creators and drivers of the DDD ideas
+ +The author of the DDD methodology. Domain linguist. The author + of “Domain-Driven Design: Tackling Complexity in Software”.
+Domain Model Whisperer. The author of “Implementing Domain-Driven Design” + and “Domain-Driven Design Distilled”. + Founder of Vlingo Platform.
+Creator of CQRS and the driver of Event Sourcing. + Founder of the Event Store.
+The inventor of #EventStorming. Practicing engineer and a coach. The author of + Introducing “EventStorming – An act of deliberate collective learning”.
+And many more advancing the approach every day.
diff --git a/docs/resources/sites.md b/docs/resources/sites.md new file mode 100644 index 0000000..1daf474 --- /dev/null +++ b/docs/resources/sites.md @@ -0,0 +1,22 @@ +--- +title: Sites +headline: DDD Resources +bodyclass: docs resources +layout: docs +--- + +# Sites + +Learning hubs
+ +- [DDD Community](https://dddcommunity.org/). +A collection of resources by Eric Evans and his colleagues. + +- [Domain Driven Design On InfoQ](https://www.infoq.com/domain-driven-design/). +DDD section on one of the leading media on software development. + +- [Awesome Domain-Driven Design](https://github.com/heynickc/awesome-ddd). +An extensive curated list of DDD, CQRS, Event Sourcing, and EventStorming resources. + +- [Learning DDD](https://emacsway.github.io/ru/self-learning-for-software-engineer/#ddd). +A selection of learning materials for gradual immersion into the topic: from the basics to the specific design cases.