Introduction
Sharpino
Section titled “Sharpino”Sharpino is a lightweight event-sourcing library for F# designed to support scalable, consistent, and domain-driven backend development in .NET.
What is Event Sourcing?
Section titled “What is Event Sourcing?”- State Persistence via History: Event sourcing is a design pattern for persisting the state of an object by storing the sequence of events that have occurred on the object.
- Functional Alignment: It fits the functional paradigm perfectly, as state is computed via a pure
evolvefunction:state = evolve(initialState, events).
Why Sharpino?
Section titled “Why Sharpino?”Sharpino is based on the following core principles:
- PostgresSQL-Based Event Store: Robust persistence to register events and snapshots.
- In-Memory Store: Fast in-memory event store to optimize test suites.
- Event ID Optimistic Locking: Checking the first available event ID position on the basis of the event ID passed by the command handler to prevent concurrency conflicts.
- Multiple Stream Transactions: Executing multiple commands involving different aggregates as single database transactions.
- StateViewers: Query the in-memory cache and fall back to the event store to replay events starting from the latest snapshot if there is a cache miss.
- Soft Deletion & History: Mark aggregates as deleted while keeping the historical record accessible.
- GDPR Compliance: Support for overwriting, clearing, or resetting snapshots and events in case a user requests data deletion.
- Message Broker Integration: Seamlessly fire messages (like InitialState, Events, Deletion) to RabbitMQ or other message buses after events are safely stored.
Library Goals
Section titled “Library Goals”- Idiomatic F#: Domain modeling and event sourcing in backend architectures using the power of F# types (Discriminated Unions, Records).
- Multilanguage Integration: Designed to plug easily into multi-language systems (e.g., Blazor/C# on the frontend and F# on the backend).
- No Impedance Mismatch: Avoid object-relational mapping (ORM) complexity. Domain objects do not need database column-mapping knowledge.
