Compare commits

...

10 commits

Author SHA1 Message Date
ansgarz
219208f0cd Update layout 2021-11-30 17:51:24 +00:00
ansgarz
7d06d02d6e add adr quasi-idempotence.md 2021-11-30 17:49:07 +00:00
az
92bf1e8934 improve ObjectValidation.md 2021-07-26 21:04:27 +02:00
az
50afdfaa7e add ObjectValidation.md 2021-07-26 20:00:08 +02:00
jem
c706363428 Merge branch 'master' of gitlab.com:domaindrivenarchitecture/overview 2021-07-22 20:01:45 +02:00
jem
7c87b04e23 add validation 2021-07-22 20:00:51 +02:00
bom
211fdec57f finished partial-execution 2021-07-16 13:34:03 +02:00
az
d31ec48711 add ddd-structure.md and one-layer-of-configuration.md 2021-07-16 13:31:37 +02:00
jem
e0f5e8d04f wip 2021-07-16 13:08:56 +02:00
az
9d81226291 clearer text 2021-07-02 15:47:23 +02:00
9 changed files with 229 additions and 1 deletions

View file

@ -0,0 +1,18 @@
# ddd structure
## Status
Accepted
## Context
We wanted to have a consistent structure.
## Decision
* We preliminarily use the ddd structure: application / domain / infrastructure
* Reservation 1: find a better name for domain
* Reservation 2: decide what to put in domain / what to cover with unit tests

View file

@ -0,0 +1,24 @@
# ddd-validation
## Status
to be discussed
## Context
We want express validity on domain objects. Clear described validity helps on
* avoid many redundant and unnecessary (null-)checks spread around in the code
* collects all validity constraints to one defined place
### Principles affected
* Check the domain borders
* Do not tie validation to object creation / serialization
* propagate validation through aggregates
![ddd-validation](ddd-validation.png)
### see also:
* [Fowler] Do not use exceptions for validation: https://martinfowler.com/articles/replaceThrowWithNotification.html
* [Fowler] Contextual Validation: https://martinfowler.com/bliki/ContextualValidation.html
* [Vladimir Khorikov] Some ideas for validation in DDD: https://enterprisecraftsmanship.com/posts/validation-and-ddd/

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

View file

@ -0,0 +1,13 @@
# partial execution of provs
## Status
accepted
## Context
Configuration for our provisioning software provs.
## Decision
We provide a materialized configuration (represented by classes or schema). Configuration is read at application start and injected into services / components (see https://martinfowler.com/articles/injection.html).

View file

@ -0,0 +1,19 @@
# One layer of configuration
## Status
Accepted
## Context
In configuration management often convention code is mixed-up with installation and configuration code.
In order to enable reuse we discussed whether we want to separate convention from installation and configuration code.
## Decision
* To keep it simple, we follow the mixup strategy.
## Consequence
* We use only one layer of configuration
* We are the primary intended user

View file

@ -0,0 +1,19 @@
# partial execution of provs
## Status
to be discussed
## Context
We want to be able to execute single provision steps to apply partial installation / configuration.
### Options
1. By CLI and specify ClassAndFunction
2. Switch on cli per parameter / mapping in code from parameter to function
3. Per KotlinScript file
4. Configurable in the configuration
General points to keep in mind:
- Dependencies
- Transport of credentials

View file

@ -0,0 +1,34 @@
# Quasi idempotence
Idempotence means you can execute a function multiple times and always get the same result.
In real world idempotence typically is difficult because of three aspects:
1. Equality hard to define
2. There are unreflected changes in functions input
3. Function has side effects
For intentionally side effect executing functions we introduce "quasi idempotence". To avoid ambiguousness we have to define on which attribute we recognize former executions.
## Status
Approved.
## Context
Software installation with provs. In case of temporal broken external dependencies we want to be able to do another installation over the previous partially broken one.
We follow the principle "build from scratch", so we leave the question of software version updates unconsidered here.
## Consequence
1. add / change (a line) in existing files
* Solution: Query for changed location respecting the file type / format and skip if it was already performed. We try to avoid this case and use separate files instead of modifying existing ones.
2. installation of an single / directory file
* Solution: If the file/directory exists, we consider installation successful and skip this step in another installation run
3. installation of many files/directories
* Solution: If the last file/directory exists, we consider installation successful and skip this step in another installation run - this is useful in order to skip time consuming steps. For fast / trivial steps we can choose solution 2.
4. install apt/deb package
* Solution: Query whether package (name without version) is installed (either implicitly e.g. in case of apt or explicitly in other cases to avoid unnecessary downloads etc)
5. running docker containers
* Solution: Query whether container with name (we have to provide the name on container start) is already running

View file

@ -0,0 +1,101 @@
# Object validation
Validation of objects is essential for the quality of object-oriented programs.
This page provides a rough overview of different techniques and strategies around object validation.
## Basics
### Object types
The appropriate kind of validation may differ on the kind of object, whether it is
* mutable or
* immutable
### Validation results
Validation results can be divided into:
* **Detailed**: containing a list of violations
* **Simple**: reporting just one violation (or even only success/failure), either with a simple or a generic message
### Technical possibilities
Most languages are offering the following possibilities for failure handling:
* Return values
* Exceptions
### Context
Validations can be
* context-dependent
* context-independent
### Validation time
* Before object creation
* After creation (but before actual usage of the data)
### Validation patterns
* Validation on existing objects/states during business operations (i.e. after object creation) (see https://enterprisecraftsmanship.com/posts/validation-and-ddd/) :
* validate / isValid methods (backdraw: race conditions can lead to invalid state)
* in application services (backdraw: potential business logic leakage)
* TryExecute (backdraw: no CQRS separation: potential state change AND returning data (i.e. error message))
* Execute / CanExecute => call separately „Can“- and „execute“-method, (partial) state is stored locally which means no race conditions can lead to an invalid state
* Validation during object creation (avoids invalid objects), without public validation method
* In constructor
* In factory method (e.g. create method)
* In Factory
* In Builder
* Validation before object creation with public validation method (avoids invalid objects, allows CQRS and detailed results):
* With (static/class level) validation AND factory method - (https://savoiragile.com/2012/06/28/english-object-validation-on-immutable-objects/ & https://reflectoring.io/java-immutables/ )
* Using Essence pattern (https://stackoverflow.com/questions/9776193/good-practice-to-validate-immutable-values-objects )
* Also Factory and Builder pattern could be added with a validate method (https://stackoverflow.com/questions/16221010/should-the-factory-pattern-contain-validation-logic ), but does not seem very common
## Potential strategies
When putting the basics above together, you might consider the strategies below.
### For mutable or context-dependent objects
Use strategies for validations **after** object creation
(from https://enterprisecraftsmanship.com/posts/validation-and-ddd/):
* The Execute / TryExecute pattern works best for task-based scenarios.
* For CRUD scenarios, you need to choose between Execute / TryExecute and validation in application services. The choice comes down to purity versus ease of implementation.
### Immutable and context-independent objects
Use validations **before** object creation
(first, you may want to validate as early as possible,
and secondly, it normally makes no sense to create object that never will be valid.)
* Factory method AND validation method (for less complex cases)
* Note: validation method must be static/at class level
* Essence pattern (for more complex cases)
### Validation results
Consider
* Detailed results (containing a list of violations)
* for crud-y operations e.g. when using multi-field input
* Simple results
* if detailed results would add no benefits, e.g. for task-based operations (if user just wants to execute a task and/or just wants to know if the task was successful or not resp. why not)
### Technical mechanisms
* Return values
* for “expected” failures
* Exceptions
* for “unexpected” failures
https://stackoverflow.com/questions/99683/which-and-why-do-you-prefer-exceptions-or-return-codes
https://stackoverflow.com/questions/5460101/choosing-between-exception-and-return-value
https://enterprisecraftsmanship.com/posts/error-handling-exception-or-result/
---
###Appendix
Object creation (patterns, etc):
* Constructor
* Factory method (e.g. create method)
* Factory
* Builder
* Essence
* Other creational patterns: Prototype, Object Pool, Abstract Factory, Singleton

View file

@ -1,4 +1,4 @@
# Clear execution feedback
# Clear results feedback
While we always hope for success, we all know too well that things can go wrong with software.
To be able to solve potential problems it is important to get clear information e.g. about the steps performed and even more important about where it might gone wrong and especially why.