Why FCQRS
One model for every job
Many .NET applications map their tables to one object graph, often with Entity Framework. A customer has addresses, contacts, orders, and a cart. An order has items, an invoice, payments, and shipments. An item points to a product and a discount. Every change and every screen goes through that one graph.
The left side of the picture shows where this leads as the application grows:
- Changes reach too far. Cancelling an order loads part of the graph and saves whatever changed. The rule that a shipped order cannot be cancelled lives in one of those classes, and two requests can change the same order at the same time unless you add concurrency checks.
- Screens pull in different directions. The order list, the order page, and the customer page each need a different shape. They all join through the same graph, so changing it for one screen affects the others.
Two models
CQRS, Command Query Responsibility Segregation, gives each job its own model. The right side of the picture shows the split:
- The command side is a set of small aggregates. Each one owns its data and the rules that protect it, refers to other aggregates only by ID, and changes in a transaction of its own.
- The query side is a set of read models, each shaped for one screen or report. They are flat, duplicate data where that helps, and contain no business rules.
Events connect the two sides
When an aggregate accepts a command, it records what happened as an event, such as OrderShipped.
Read models are updated from those events.
FCQRS also keeps the events as the aggregate's stored data, which is called event sourcing. The database holds every change in order, and an aggregate's current state is rebuilt from its events. A new read model can be built from the history that already exists.
What FCQRS does
You write the rules of each aggregate: which event a command produces, and how an event changes the state. FCQRS runs one instance per aggregate ID and hands it one command at a time. It stores the events, rebuilds the state after a restart, and updates your read models. It also runs workflows that span several aggregates, called sagas. FCQRS runs on Akka.NET and has F# and C# APIs.
Learn it by building a bank
The tutorial applies this split to a small bank. Each account is an aggregate, and a statement is a read model. Every step is a program you run.
- Open an account: commands, events, and the journal.
- Withdraw money: rules, rejections, and one command at a time.
- Restart the bank: loading an account and snapshots.
- Show a statement: read models and projections.
- Transfer money: sagas and commands that are safe to repeat.
- Add a memo: changing events the journal already holds.
When to use FCQRS
FCQRS is useful when several callers can change the same data, decisions depend on history, or workflows must recover after a restart. It adds an event journal, read models that update asynchronously, and an actor runtime to operate. For an application that only edits and reads rows, a conventional database application may need less infrastructure.
