Framework Open Source

goes

Aggregates, Commands e Projections type-safe - dalla prototipazione alla produzione.

158 ·Apache-2.0· Go ·17 forks
goes Gopher
Scroll
Panoramica

Cos'è goes?

goes è un framework Event Sourcing per Go che fornisce i componenti di base per applicazioni distribuite e basate sugli eventi. Aggregates, Commands e Projections type-safe - con backend intercambiabili per ogni livello di scalabilità.

A differenza di molte librerie Event Sourcing, che sono troppo accademiche o troppo opinionated, goes punta su Go idiomatico. Nessuna generazione di codice, nessuna annotation magica - solo Interfaces, Generics e Composition. Definisci i tuoi Aggregates come normali Go Structs, registri Event Handler tramite funzioni tipizzate e il framework gestisce persistence, replay e concurrency.

goes è rivolto ai team Go che vogliono integrare Event Sourcing e CQRS in sistemi nuovi o esistenti, senza vincolarsi a uno specifico setup infrastrutturale. Che tu inizi con un semplice prototipo In-Memory o gestisca un sistema distribuito con NATS, MongoDB e PostgreSQL, la logica di dominio rimane identica.

In azione
order.go
// Define your aggregate
type Order struct {
    *aggregate.Base

    Items  []LineItem
    Status OrderStatus
}

// Register typed event handlers
func NewOrder(id uuid.UUID) *Order {
    o := &Order{Base: aggregate.New("order", id)}

    event.ApplyWith(o, o.placed, "order.placed")
    event.ApplyWith(o, o.paid, "order.paid")

    return o
}

// Produce events from commands
func (o *Order) Place(items []LineItem) error {
    aggregate.Next(o, "order.placed",
        OrderPlaced{Items: items},
    )
    return nil
}

// Rebuild state from events
func (o *Order) placed(e event.Of[OrderPlaced]) {
    o.Items = e.Data().Items
    o.Status = Placed
}

Nessuna generazione di codice, nessuna annotation - solo Go Interfaces, Generics e Composition. La logica di dominio rimane pulita e portabile.

Motivazione

Perché Event Sourcing?

Il problema

I sistemi CRUD tradizionali salvano solo lo stato attuale. Quando si verifica un errore o serve un audit, manca la cronologia. I dati vengono sovrascritti e il contesto va perso. Chi ha modificato cosa, quando e perché? Queste domande non possono trovare risposta con un classico statement UPDATE.

L'approccio

Event Sourcing salva ogni State Change come evento. Lo stato attuale viene ricostruito dalla Event History. Nulla va perso: Audit Trails completi, Time-Travel Debugging e la possibilità di costruire retroattivamente nuovi Read Models da eventi esistenti. Il tuo Event Log diventa la Single Source of Truth.

Cosa fa goes diversamente

goes elimina la complessità dell'Event Sourcing in Go. Nessun boilerplate, nessuna DSL - solo Go Interfaces e Generics. Inizi con backend In-Memory e passi a MongoDB, PostgreSQL o NATS senza modificare una riga di codice di dominio. Il framework gestisce Event Routing, Aggregate Hydration, Snapshot Management e Projection Scheduling. Tu ti concentri sul tuo dominio.

Come funziona

La Event Pipeline

Ogni State Change attraversa una pipeline chiaramente definita. I Commands attivano la logica degli Aggregates, che produce eventi. Gli eventi vengono persistiti e proiettati in Read Models.

1
Command

Un intento tipizzato viene inviato e validato tramite una Middleware Chain.

2
Aggregate

L'Aggregate applica gli invariants e produce eventi dai Commands.

3
Event

Un fatto immutabile che descrive uno State Change. Single Source of Truth.

4
Event Store

Gli eventi vengono persistiti in append-only e distribuiti ai subscriber.

5
Projection

I Read Models vengono costruiti dall'Event Stream, live oppure on-demand.

Architettura

Concetti chiave

Event-Sourced Aggregates

Incorpora il Base-Type, registra Event Handler tipizzati. Il framework gestisce versioning, persistence e replay. Gli Aggregates sono normali Go Structs con un aggregate.Base incorporato. Gli Event Handler vengono registrati tramite funzione Generic e richiamati automaticamente durante la hydration. Soft Deletes, Aggregate Versioning e Optimistic Concurrency Control sono inclusi out of the box.

Distributed Events

Pubblica e sottoscrivi eventi tramite NATS JetStream. MongoDB e PostgreSQL come Event Stores. Sostituisci i backend senza modifiche al codice. L'Event Bus astrae transport e delivery. Il tuo codice lavora con eventi tipizzati, sia in locale, in-process o distribuiti su un cluster.

Type-Safe Commands

Invia e gestisci Commands con piena Generic-Type-Safety. Sincroni o asincroni, a seconda del caso d'uso. Il Command Bus supporta Middleware, Context Propagation ed Error Handling. I Commands asincroni vengono inviati tramite l'Event Bus, quelli sincroni direttamente nel Process.

Projection Toolkit

Costruisci Read Models con schedule Continuous o Periodic. Progress-Tracking automatico, debouncing e startup catch-up. Le Projections possono leggere da qualsiasi Event Store e scrivere in qualsiasi database di lettura. Lo Scheduler gestisce error retry, backoff e processing garantito.

Codec Registry

Mappa i nomi degli eventi ai Go Types per la serializzazione automatica. JSON come default, MessagePack o Protobuf con un cambio di una riga. La Codec Registry è centrale per un Event Handling type-safe. Garantisce che gli eventi vengano serializzati, deserializzati e versionati correttamente.

Snapshots

Cattura lo stato di un Aggregate in un momento preciso. Vengono riprodotti solo gli eventi recenti anziché l'intera history. Gli snapshots vengono creati automaticamente secondo intervalli configurabili. Sono supportati MongoDB, PostgreSQL e In-Memory Stores, con la stessa architettura di backend pluggable dell'Event Store.

Testable by Design

Fluent Test Assertions per Aggregates, backend In-Memory per Integration Tests e Conformance Suites per Custom Implementations. Il package testing offre Assertions in stile Expect: given Events, when Command, then Events. Le Conformance Suites garantiscono che le Custom Event Store Implementations si comportino correttamente.

Modular Design

Usa solo ciò di cui hai bisogno - Event System, Commands, Projections - e aggiungi ulteriori Components quando necessario. Ogni package ha interfacce chiaramente definite e dipendenze minime. Puoi integrare goes gradualmente in un progetto esistente, senza dover adottare tutto in una volta.

Backend

Backend pronti per la produzione

goes segue il principio dei backend intercambiabili: ogni Event Store, Snapshot Store ed Event Bus implementa un'interfaccia comune. Sviluppi contro astrazioni, non contro implementazioni. Questo consente di testare localmente con backend In-Memory, usare MongoDB in staging e passare a PostgreSQL con NATS in produzione, senza toccare una riga di codice di dominio.

MongoDB

Event Store basato su documenti con supporto nativo ai Change Stream per Event Subscriptions in tempo reale. Ideale per Event-Driven Architectures in cui le Projections devono reagire in tempo reale ai nuovi eventi. Supporta anche snapshot e optimistic concurrency tramite document versioning.

PostgreSQL

Event Store relazionale con transazioni ACID e Optimistic Concurrency Control. Perfetto per team che dispongono già di un setup PostgreSQL e non vogliono introdurre infrastrutture aggiuntive. Serializable Isolation garantisce Event Streams coerenti.

NATS JetStream

Event Bus distribuito con delivery At-Least-Once, Consumer Groups e scalabilità orizzontale. NATS è particolarmente adatto alle architetture a microservizi, in cui gli eventi devono essere distribuiti tra i servizi. Persistenza tramite JetStream, replay tramite Consumer Offsets.

In-Memory

Backend zero-config per prototipazione e testing. Stessa API dei backend di produzione, così test e prototipi usano lo stesso codice della produzione. Nessun setup, nessuna dipendenza, pronto subito.

3D interattivo

Architettura a microservizi

goes costituisce la spina dorsale dei sistemi di microservizi event-driven. Ogni servizio comunica attraverso l'Event Bus centrale. Scorri per esplorare ogni componente.

Aggregates1/8

Entità di dominio che incapsulano la business logic e applicano gli invariants. L'Aggregate è il confine di consistenza per gli eventi.

Tecnologia

Tech Stack

Go NATS JetStream MongoDB PostgreSQL Protocol Buffers gRPC Docker
GitHub
158

GitHub Stars

Licenza

Apache-2.0

Lingua

Go

Forks

17

Contributors

5+

Visualizza su GitHub

FAQ

Domande frequenti su goes

Sì. goes viene utilizzato in diversi sistemi in produzione ed è mantenuto attivamente. Il framework ha un'API stabile e viene usato internamente da modernice per progetti clienti. Progetti come Crovillas, DepositDirect e Prestige Cars funzionano con goes dal 2021.

goes supporta MongoDB, PostgreSQL e NATS JetStream come backend di produzione. Per testing e prototipazione sono disponibili implementazioni In-Memory complete. Tutti i backend implementano le stesse interfacce, consentendo il passaggio senza modifiche al codice.

Sono sufficienti conoscenze di base di Go. La guida Getting Started e il tutorial di 12 capitoli accompagnano passo dopo passo attraverso tutti i concetti. goes è progettato in modo da permetterti di apprendere e applicare i pattern Event Sourcing in modo incrementale.

Sì. goes ha un'architettura modulare. Puoi utilizzare singolarmente Components come l'Event System o Commands e integrare gli altri quando necessario. Non esiste alcuna dipendenza all-or-nothing.

goes è progettato per scenari ad alto throughput. Gli snapshots riducono drasticamente il tempo di replay, le Projections vengono eseguite in modo asincrono e parallelizzato, e l'Event Store supporta il batching. In produzione vengono elaborati diversi milioni di eventi senza latenza percepibile.

EventStoreDB è un database indipendente, mentre goes utilizza la tua infrastruttura esistente (MongoDB, PostgreSQL, NATS). Axon è basato su Java e molto più opinionated. goes ti fornisce i componenti di base e ti lascia decidere come combinarli. Nessuna runtime dependency oltre al backend scelto.

goes richiede Go 1.23 o una versione successiva. Il framework utilizza intensamente Go Generics per la Type-Safety di Commands, Events e Aggregates. Consigliamo sempre la versione stabile più recente di Go.

I contributi sono benvenuti. Il miglior punto di partenza è il repository GitHub. Le issues etichettate con 'good first issue' sono ideali per iniziare. Le PR vengono revisionate e unite rapidamente. Per modifiche più grandi, consigliamo di creare prima una issue per concordare l'approccio.

Contattaci

Usi goes o stai valutando se l'event sourcing fa per il tuo progetto? Contattaci, parliamo volentieri di architettura ed esperienze in produzione.