All Projects → fraktalio → fmodel-ts

fraktalio / fmodel-ts

Licence: other
Functional Domain Modeling with Typescript

Programming Languages

typescript
32286 projects

Projects that are alternatives of or similar to fmodel-ts

Netcoremicroservicessample
Sample using micro services in .NET Core 3.1 Focusing on clean code
Stars: ✭ 403 (+882.93%)
Mutual labels:  cqrs, event-sourcing, eventsourcing
Go Cqrs All
All-in-one collection for Go CQRS / ES / DDD examples
Stars: ✭ 39 (-4.88%)
Mutual labels:  cqrs, event-sourcing, eventsourcing
Eventstore
The stream database optimised for event sourcing
Stars: ✭ 4,395 (+10619.51%)
Mutual labels:  cqrs, event-sourcing, eventsourcing
Eventsourcing
A library for event sourcing in Python.
Stars: ✭ 760 (+1753.66%)
Mutual labels:  cqrs, event-sourcing, eventsourcing
Revo
Event Sourcing, CQRS and DDD framework for C#/.NET Core.
Stars: ✭ 162 (+295.12%)
Mutual labels:  cqrs, event-sourcing, eventsourcing
delta
DDD-centric event-sourcing library for the JVM
Stars: ✭ 15 (-63.41%)
Mutual labels:  cqrs, event-sourcing, eventsourcing
Eventhorizon
CQRS/ES toolkit for Go
Stars: ✭ 961 (+2243.9%)
Mutual labels:  cqrs, event-sourcing, eventsourcing
micro
Functional prooph for microservices
Stars: ✭ 53 (+29.27%)
Mutual labels:  cqrs, event-sourcing, eventsourcing
Goes
Go Event Sourcing made easy
Stars: ✭ 144 (+251.22%)
Mutual labels:  cqrs, event-sourcing, eventsourcing
Eventflow.example
DDD+CQRS+Event-sourcing examples using EventFlow following CQRS-ES architecture. It is configured with RabbitMQ, MongoDB(Snapshot store), PostgreSQL(Read store), EventStore(GES). It's targeted to .Net Core 2.2 and include docker compose file.
Stars: ✭ 131 (+219.51%)
Mutual labels:  cqrs, event-sourcing, eventsourcing
Bifrost
This is the stable release of Dolittle till its out of alpha->beta stages
Stars: ✭ 111 (+170.73%)
Mutual labels:  cqrs, event-sourcing, eventsourcing
Totem
Knowledge work at play
Stars: ✭ 56 (+36.59%)
Mutual labels:  cqrs, event-sourcing, eventsourcing
workflow
Functional CQRS Eventsourcing Engine
Stars: ✭ 22 (-46.34%)
Mutual labels:  cqrs, event-sourcing, eventsourcing
eventuous
Minimalistic Event Sourcing library for .NET
Stars: ✭ 236 (+475.61%)
Mutual labels:  cqrs, event-sourcing, eventsourcing
eventsourcing-go
Event Sourcing + CQRS using Golang Tutorial
Stars: ✭ 75 (+82.93%)
Mutual labels:  cqrs, eventsourcing
chronicle
An event sourced CQRS framework for Rust
Stars: ✭ 36 (-12.2%)
Mutual labels:  cqrs, event-sourcing
event-store-mgmt-ui
Event Store Management UI
Stars: ✭ 23 (-43.9%)
Mutual labels:  cqrs, eventsourcing
financial
POC de uma aplicação de domínio financeiro.
Stars: ✭ 62 (+51.22%)
Mutual labels:  cqrs, event-sourcing
cqrs
A lightweight, opinionated CQRS and event sourcing framework targeting serverless architectures.
Stars: ✭ 155 (+278.05%)
Mutual labels:  cqrs, event-sourcing
eda-tutorial
Event-Driven Tutorial for Distributed Data with CQRS and Event Sourcing
Stars: ✭ 49 (+19.51%)
Mutual labels:  cqrs, event-sourcing

f(model) - Functional Domain Modeling with TypeScript

CI with Node/NPM - Test and Build

When you’re developing an information system to automate the activities of the business, you are modeling the business. The abstractions that you design, the behaviors that you implement, and the UI interactions that you build all reflect the business — together, they constitute the model of the domain.

event-modeling

IOR<Library, Inspiration>

This project can be used as a library, or as an inspiration, or both. It provides just enough tactical Domain-Driven Design patterns, optimised for Event Sourcing and CQRS.

The library is fully isolated from the application and infrastructure layers. It represents a pure declaration of the program logic. It is written in TypeScript programming language.

(command: C, state: S) => readonly E[]

On a higher level of abstraction, any information system is responsible for handling the intent (Command) and based on the current State, produce new facts (Events):

  • given the current State/S on the input,
  • when Command/C is handled on the input,
  • expect list of new Events/E to be published/emitted on the output

(state: S, event: E) => S

The new state is always evolved out of the current state S and the current event E:

  • given the current State/S on the input,
  • when Event/E is handled on the input,
  • expect new State/S to be published on the output

Event-sourced or State-stored systems

  • State-stored systems are traditional systems that are only storing the current State by overwriting the previous State in the storage.
  • Event-sourced systems are storing the events in immutable storage by only appending.

Both types of systems can be designed by using only these two functions and three generic parameters

event sourced vs state stored

Decider is the most important datatype, but it is not the only one. Let's discuss all of them, and visualize how they fit the Onion architecture. The arrows in the image are showing the direction of the dependency. Notice that all dependencies point inwards, and that Domain is not depending on anything.

onion architecture image

Decider

_Decider is a datatype that represents the main decision-making algorithm. It belongs to the Domain layer. It has five generic parameters C, Si, So, Ei, Eo , representing the type of the values that _Decider may contain or use. _Decider can be specialized for any type C or Si or So or Ei or Eo because these types do not affect its behavior. _Decider behaves the same for C=Int or C=YourCustomType, for example.

_Decider is a pure domain component.

  • C - Command
  • Si - input State
  • So - output State
  • Ei - input Event
  • Eo - output Event

We make a difference between input and output types, and we are more general in this case. We can always specialize down to the 3 generic parameters: export class Decider<C, S, E> extends _Decider<C, S, S, E, E> {}.

The three parameter(s) Decider<C, S, E> is the type you would like to use as an API, rather than using _Decider<C, S, S, E, E>. Nevertheless, you have options.

Notice that Decider implements an interface IDecider to communicate the contract.

export class _Decider<C, Si, So, Ei, Eo> implements I_Decider<C, Si, So, Ei, Eo> {
    constructor(
      readonly decide: (c: C, s: Si) => readonly Eo[],
      readonly evolve: (s: Si, e: Ei) => So,
      readonly initialState: So
    ) {}
}

export type IDecider<C, S, E> = I_Decider<C, S, S, E, E>;
export class Decider<C, S, E> extends _Decider<C, S, S, E, E> implements IDecider<C, S, E> {}

Additionally, initialState of the Decider is introduced to gain more control over the initial state of the Decider.

decider image

We can now construct event-sourcing or/and state-storing aggregate by using the same decider.

Event-sourcing aggregate

Event sourcing aggregate is using/delegating a Decider to handle commands and produce events. It belongs to the Application layer. In order to handle the command, aggregate needs to fetch the current state (represented as a list of events) via EventRepository.fetchEvents function, and then delegate the command to the decider which can produce new events as a result. Produced events are then stored via EventRepository.save function.

event sourced aggregate

State-stored aggregate

State stored aggregate is using/delegating a Decider to handle commands and produce new state. It belongs to the Application layer. In order to handle the command, aggregate needs to fetch the current state via StateRepository.fetchState function first, and then delegate the command to the decider which can produce new state as a result. New state is then stored via StateRepository.save function.

state storedaggregate

View

_View is a datatype that represents the event handling algorithm, responsible for translating the events into denormalized state, which is more adequate for querying. It belongs to the Domain layer. It is usually used to create the view/query side of the CQRS pattern. Obviously, the command side of the CQRS is usually event-sourced aggregate.

It has three generic parameters Si, So, E, representing the type of the values that _View may contain or use. _View can be specialized for any type of Si, So, E because these types do not affect its behavior. _View behaves the same for E=Int or E=YourCustomType, for example.

_View is a pure domain component.

  • Si - input State
  • So - output State
  • E - Event

We make a difference between input and output types, and we are more general in this case. We can always specialize down to the 2 generic parameters: class View<S, E> extends _View<S, S, E> {}.

The two parameter(s) View<S, E> is the type you would like to use as an API, rather than using _View<S, S, E>. Nevertheless, you have options.

Notice that View implements an interface IView to communicate the contract.

export class _View<Si, So, E> implements I_View<Si, So, E> {
    constructor(
        readonly evolve: (s: Si, e: E) => So,
        readonly initialState: So
    ) {}
}

export type IView<S, E> = I_View<S, S, E>;
export class View<S, E> extends _View<S, S, E> implements IView<S, E> {}

view image

Materialized View

A Materialized view is using/delegating a View to handle events of type E and to maintain a state of denormalized projection(s) as a result. Essentially, it represents the query/view side of the CQRS pattern. It belongs to the Application layer.

In order to handle the event, materialized view needs to fetch the current state via ViewStateRepository.fetchState function first, and then delegate the event to the view, which can produce new state as a result. New state is then stored via ViewStateRepository.save function.

Saga

Saga is a datatype that represents the central point of control, deciding what to execute next (A). It is responsible for mapping different events from many aggregates into action results AR that the Saga then can use to calculate the next actions A to be mapped to commands of other aggregates.

Saga is stateless, it does not maintain the state.

It has two generic parameters AR, A, representing the type of the values that Saga may contain or use. Saga can be specialized for any type of AR, A because these types do not affect its behavior. Saga behaves the same for AR=Int or AR=YourCustomType, for example.

Saga is a pure domain component.

  • AR - Action Result
  • A - Action

Notice that Saga implements an interface ISaga to communicate the contract.

export class Saga<AR, A> implements ISaga<AR, A>{
    constructor(readonly react: (ar: AR) => readonly A[]) {}
}

saga image

Saga Manager

Saga manager is a stateless process orchestrator. It belongs to the Application layer. It is reacting on Action Results of type AR and produces new actions A based on them.

Saga manager is using/delegating a Saga to react on Action Results of type AR and produce new actions A which are going to be published via ActionPublisher.publish function.

Install

npm i @fraktalio/fmodel-ts

Available on https://www.npmjs.com/package/@fraktalio/fmodel-ts

Examples

Why don't you start by browsing tests?

Resources

Credits

Special credits to Jérémie Chassaing for sharing his research and Adam Dymitruk for hosting the meetup.


Created with ❤️ by Fraktalio

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].