Skip to content

Commit

Permalink
docs: Add implementation section to architecture doc (#1961)
Browse files Browse the repository at this point in the history
Fixes #1960 

This PR is adding a section about how to meet architecture requirements in implementation.

![added section](https://github.com/Flank/flank/blob/1960_Add_implementation_section_to_architecture_doc/docs/architecture.md#implementation-)

## Checklist

- [x] Update diagram links before merge
  • Loading branch information
jan-goral authored May 26, 2021
1 parent e933280 commit ec4202d
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 1 deletion.
52 changes: 51 additions & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ This document describes abstract architecture design which should be able to app
1. [Adapter](#adapter)
1. [How to scale](#adapter_scale)
1. [Dependencies](#adapter_dependencies)
1. [Implementation](#implementation)
1. [Public API](#implementation_public_api)
1. [Components composition](#components_composition)
1. [Code composition](#code_composition)
1. [Vertical](#code_composition_vertical)
1. [Horizontal](#code_composition_horizontal)
1. [Horizontal Layered](#code_composition_horizontal_layered)

# Motivation <a name="motivation"/>

Expand Down Expand Up @@ -65,7 +72,7 @@ Typically, `horizontal` scaling is preferred when `vertical` scaling become to b

The example diagram that is exposing relations between layers:

![architecture_template](http://www.plantuml.com/plantuml/proxy?cache=no&fmt=svg&src=https://raw.githubusercontent.com/Flank/flank/1953_Add_abstract_architecture_doc/docs/hld/architecture-template.puml)
![architecture_template](http://www.plantuml.com/plantuml/proxy?cache=no&fmt=svg&src=https://raw.githubusercontent.com/Flank/flank/master/docs/hld/architecture-template.puml)

# Presentation <a name="presentation"/>

Expand Down Expand Up @@ -263,3 +270,46 @@ one of or many:

* internal [`client`](#client) library
* third-party client library

# Implementation <a name="implementation"/>

For convenience and clarity, the code should be written in a functional programming style. It's mandatory to avoid the OOP style which almost always makes things much more complicated than should be.

## Public API <a name="implementation_public_api"/>

Any application or library must always have a public API and an internal/private part. For convenience keep public functions and structures in the root package, so the API will be easy to find. Additionally, if the `component`:

* is providing accessibility to public API's with additional structures. -It is mandatory to keep the public structures and functions distinct from internal implementation which should be kept in nested package(s).
* is just a simple tool with a compact implementation that is not specifying many structures. - Private implementations can be kept in the same file, just behind the public API or even the whole tool can be delivered as one public function if the implementation is simple enough.

DO NOT keep multiple public functions along with internal implementations in the same file or package, because it is messes up the public API, which makes code harder to analyze and navigate.

## Components composition <a name="components_composition"/>

Business logic shouldn't implement complicated tools on its own because it is can mess up crucial high-level implementations making it harder to understand. Instead, it should be decomposed into high-level use-case implementations that operate on tools provided by specialized components.

## Code composition <a name="code_composition"/>

Typically, when huge features are divided into smaller functions and one of those functions is a (public) root, the functions can be composed in two different ways.

### Vertical <a name="code_composition_vertical"/>

The preceding function is calling the following, so the composition of functions is similar to a linked list.

![vertical-composition](http://www.plantuml.com/plantuml/proxy?cache=no&fmt=svg&src=https://raw.githubusercontent.com/Flank/flank/master/docs/hld/vertical-composition.puml)

Try to **AVOID** this pattern where possible, especially in business logic. In some situations it can be even worse than one huge monolithic function with comments, for example when internal functions are not ordered correctly. Understanding the feature composed in vertical style, almost always require analyzing the whole chain of functions which typically is not efficient.

### Horizontal <a name="code_composition_horizontal"/>

Root function is controlling independent internal and specialized functions.

![horizontal-composition](http://www.plantuml.com/plantuml/proxy?cache=no&fmt=svg&src=https://raw.githubusercontent.com/Flank/flank/master/docs/hld/horizontal-composition.puml)

This approach gives a fast overview of high-level implementation but is hiding the details not important from the high-level perspective. Comparing to `vertical` composition where the cost of manual access to internal functions (jumping on references in IDE) in the worst-case scenario is `n`, the horizontal composition almost always gives `1` on the same layer (or `2` taking private functions into account if exist).

### Horizontal-Layered <a name="code_composition_horizontal_layered"/>

An example of horizontal composition in layered architecture can look as following:

![horizontal-composition-layered](http://www.plantuml.com/plantuml/proxy?cache=no&fmt=svg&src=https://raw.githubusercontent.com/Flank/flank/master/docs/hld/horizontal-composition-layered.puml)
62 changes: 62 additions & 0 deletions docs/hld/horizontal-composition-layered.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
@startuml
'https://plantuml.com/object-diagram

left to right direction

package layer1 {
package File1 {
[public function 1]
}
package nested1 {
package File2 {
[internal function 2]
}
package File3 {
[internal function 1]
[private function 1]
[private function 2]
}
package File4 {
[internal function 3]
}
}
}
package layer2 {
package tool1 {
package File5 {
[public function 2]
}
package nested2 {
package File6 {
[internal function 4]
[internal function 5]
[internal function 6]
}
}
}
package api {
package File7 {
() "functional interface 1"
}
package File8 {
() "functional interface 2"
}
}
}

[public function 1] --> [internal function 3]
[public function 1] --> [internal function 1]
[public function 1] --> [internal function 2]

[internal function 1] -right-> [private function 1]
[internal function 1] --> [private function 2]
[internal function 3] ---> [public function 2]

[internal function 2] ---> () "functional interface 2"
[internal function 1] ---> () "functional interface 1"

[public function 2] --> [internal function 4]
[public function 2] --> [internal function 5]
[public function 2] ---> [internal function 6]

@enduml
19 changes: 19 additions & 0 deletions docs/hld/horizontal-composition.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@startuml
'https://plantuml.com/object-diagram

left to right direction

[public function] --> [internal function 1]
[public function] --> [internal function 2]
[public function] --> [internal function 3]
[public function] --> [internal function 4]
[public function] --> [internal function 7]
[internal function 2] --> [private function 5]
[internal function 2] --> [private function 6]
[internal function 7] --> [private function 8]
[internal function 7] --> [private function 9]
[internal function 7] --> [private function 10]
[internal function 7] --> [private function 11]


@enduml
16 changes: 16 additions & 0 deletions docs/hld/vertical-composition.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@startuml
'https://plantuml.com/object-diagram

[public function] -right-> [any function 1]
[any function 1] -right-> [any function 2]
[any function 2] -right-> [any function 3]
[any function 3] -down-> [any function 4]
[any function 4] -left-> [any function 5]
[any function 5] -left-> [any function 6]
[any function 6] -left-> [any function 7]
[any function 7] -down-> [any function 8]
[any function 8] -right-> [any function 9]
[any function 9] -right-> [any function 10]
[any function 10] -right-> [any function 11]

@enduml

0 comments on commit ec4202d

Please sign in to comment.