Application orchestration and CQRSCQRS: reads and writes split
No narration yet
Module 6 · Lesson 213 min

CQRS: reads and writes split

Fusion splits reading from writing at the port level. This is CQRS (command-query responsibility segregation), and here it's a naming and interface convention more than a grand architecture. Writes and entity-loading go on a Repository; reads go on a QueryStore. The split makes it obvious at a glance which methods have side effects.

The read/write split (anti-pattern #6)
QueryStoreRead-only. Method names Get*. Uses AsNoTracking. Returns DTOs/projections
RepositoryCommand side. Load* (read for operation) + Save*. Returns aggregates
Two ports, one for each side (application/flight-notes/)
// Command side: writes
public interface IFlightNoteRepository
{
    Task SaveMany(IReadOnlyCollection<FlightNoteVo> notes, CancellationToken cancellationToken);
}

// Read side: projections for list views
public interface IFlightNoteQueryStore
{
    Task<IReadOnlyDictionary<string, string>> GetLatestNoteByFlight(
        IEnumerable<string> ejdpUniqueFlightKeys, CancellationToken cancellationToken);
}

Two related conventions ride along. Command-side repositories return aggregates, not DTOs (D4); a read-side projection like a summary DTO belongs on the query store instead. And a warning against your Nest instinct: don't invent a new DTO for a concept that already has a representation (anti-pattern #13). Each representation must earn a unique use case, or it's just another sync point to break.

Practice

Try it yourself

Do

Split a read out of a repository

Refactor a Nest-style all-in-one repo into the CQRS shape.

Tick every step to confirm you did it.

Quiz

Which port gets the method

You need a method that loads a flight aggregate to run an action on it. Which port and which name prefix?