Open Source Framework

goes

Type-safe Aggregates, Commands und Projections - von Prototyping bis Production.

158 ·Apache-2.0· Go ·17 forks
goes Gopher
Scroll
Überblick

Was ist goes?

goes ist ein Event-Sourcing Framework für Go, das die Bausteine für verteilte, event-basierte Anwendungen liefert. Type-safe Aggregates, Commands und Projections - mit austauschbaren Backends für jede Skalierungsstufe.

Im Gegensatz zu vielen Event-Sourcing Libraries, die entweder zu akademisch oder zu opinionated sind, setzt goes auf idiomatic Go. Keine Code-Generierung, keine magischen Annotations - nur Interfaces, Generics und Composition. Du definierst deine Aggregates als normale Go-Structs, registrierst Event-Handler über typisierte Funktionen, und das Framework kümmert sich um Persistence, Replay und Concurrency.

goes richtet sich an Go-Teams, die Event Sourcing und CQRS in bestehende oder neue Systeme integrieren wollen, ohne sich an ein bestimmtes Infrastruktur-Setup zu binden. Ob du mit einem einfachen In-Memory Prototype startest oder ein verteiltes System mit NATS, MongoDB und PostgreSQL betreibst, die Domain-Logik bleibt identisch.

In Aktion
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
}

Keine Code-Generierung, keine Annotations - nur Go Interfaces, Generics und Composition. Die Domain-Logik bleibt sauber und portabel.

Motivation

Warum Event Sourcing?

Das Problem

Traditionelle CRUD-Systeme speichern nur den aktuellen State. Wenn ein Fehler passiert oder ein Audit gebraucht wird, fehlt die History. Daten werden überschrieben, Context geht verloren. Wer hat wann was geändert und warum? Diese Fragen lassen sich mit einem klassischen UPDATE Statement nicht beantworten.

Der Ansatz

Event Sourcing speichert jeden State Change als Event. Der aktuelle State wird aus der Event History rekonstruiert. Nichts geht verloren: vollständige Audit Trails, Time-Travel Debugging und die Möglichkeit, neue Read Models rückwirkend aus bestehenden Events zu bauen. Dein Event Log wird zur Single Source of Truth.

Was goes anders macht

goes nimmt die Komplexität aus Event Sourcing in Go. Kein Boilerplate, keine DSLs - nur Go-Interfaces und Generics. Du startest mit In-Memory Backends und wechselst zu MongoDB, PostgreSQL oder NATS ohne eine Zeile Domain-Code zu ändern. Das Framework übernimmt Event Routing, Aggregate Hydration, Snapshot Management und Projection Scheduling. Du fokussierst dich auf deine Domain.

So funktioniert's

Die Event Pipeline

Jeder State Change fließt durch eine klar definierte Pipeline. Commands lösen Aggregate-Logik aus, die Events produziert. Events werden persistiert und in Read Models projiziert.

1
Command

Ein typisierter Intent wird dispatched und via Middleware Chain validiert.

2
Aggregate

Das Aggregate erzwingt Invarianten und produziert Events aus Commands.

3
Event

Ein immutable Fact, der einen State Change beschreibt. Single Source of Truth.

4
Event Store

Events werden append-only persistiert und an Subscriber verteilt.

5
Projection

Read Models werden aus dem Event Stream gebaut, live oder on-demand.

Architektur

Core Concepts

Event-Sourced Aggregates

Base-Type embedden, typisierte Event-Handler registrieren. Versioning, Persistence und Replay übernimmt das Framework. Aggregates sind normale Go-Structs mit einem eingebetteten aggregate.Base. Event-Handler werden per Generic-Funktion registriert und bei Hydration automatisch aufgerufen. Soft-Deletes, Aggregate-Versioning und optimistische Concurrency Control sind out of the box dabei.

Distributed Events

Events publishen und subscriben über NATS JetStream. MongoDB und PostgreSQL als Event Stores. Backends austauschen ohne Code-Änderungen. Der Event Bus abstrahiert Transport und Delivery. Dein Code arbeitet mit typisierten Events, egal ob lokal, in-process oder über ein Cluster verteilt.

Type-Safe Commands

Commands dispatchen und handlen mit voller Generic-Type-Safety. Synchron oder asynchron, je nach Use Case. Der Command Bus unterstützt Middleware, Context Propagation und Error Handling. Asynchrone Commands werden über den Event Bus dispatched, synchrone direkt im Process.

Projection Toolkit

Read Models bauen mit Continuous oder Periodic Schedules. Automatisches Progress-Tracking, Debouncing und Startup-Catch-up. Projections können von jedem Event Store lesen und in beliebige Read-Datenbanken schreiben. Der Scheduler kümmert sich um Fehler-Retry, Backoff und garantiertes Processing.

Codec Registry

Event-Namen auf Go-Types mappen für automatische Serialisierung. JSON als Default, MessagePack oder Protobuf als One-Line-Swap. Die Codec Registry ist zentral für type-safe Event Handling. Sie stellt sicher, dass Events korrekt serialisiert, deserialisiert und versioniert werden.

Snapshots

Aggregate State zu einem Zeitpunkt capturen. Nur recent Events replayed statt der vollständigen History. Snapshots werden automatisch nach konfigurierbaren Intervallen erstellt. Unterstützt werden MongoDB, PostgreSQL und In-Memory Stores, mit der gleichen Pluggable-Backend-Architektur wie der Event Store.

Testable by Design

Fluent Test-Assertions für Aggregates, In-Memory Backends für Integration-Tests und Conformance Suites für Custom Implementations. Das Testing-Package bietet Expect-Style Assertions: given Events, when Command, then Events. Conformance Suites stellen sicher, dass Custom Event Store Implementations sich korrekt verhalten.

Modular Design

Nur nutzen was gebraucht wird - Event System, Commands, Projections - und weitere Components bei Bedarf dazunehmen. Jedes Package hat klar definierte Interfaces und minimale Dependencies. Du kannst goes schrittweise in ein bestehendes Projekt integrieren, ohne alles auf einmal übernehmen zu müssen.

Backends

Production-Ready Backends

goes folgt dem Prinzip der austauschbaren Backends: Jeder Event Store, Snapshot Store und Event Bus implementiert ein gemeinsames Interface. Du entwickelst gegen Abstractions, nicht gegen Implementations. Das macht es möglich, lokal mit In-Memory Backends zu testen, in Staging MongoDB zu nutzen und in Production auf PostgreSQL mit NATS zu setzen, ohne eine Zeile Domain-Code anzufassen.

MongoDB

Document-basierter Event Store mit nativer Change-Stream-Unterstützung für Real-Time Event Subscriptions. Ideal für Event-Driven Architectures, bei denen Projections in Echtzeit auf neue Events reagieren müssen. Unterstützt auch Snapshots und optimistische Concurrency via Document Versioning.

PostgreSQL

Relationaler Event Store mit ACID-Transaktionen und optimistischer Concurrency Control. Perfekt für Teams, die bereits ein PostgreSQL-Setup haben und keine zusätzliche Infrastruktur einführen wollen. Serializable Isolation garantiert konsistente Event Streams.

NATS JetStream

Distributed Event Bus mit At-Least-Once Delivery, Consumer Groups und horizontaler Skalierung. NATS eignet sich besonders für Microservice-Architekturen, bei denen Events zwischen Services verteilt werden müssen. Persistence über JetStream, Replay über Consumer Offsets.

In-Memory

Zero-Config Backend für Prototyping und Testing. Gleiche API wie Production Backends, damit Tests und Prototypen identischen Code verwenden wie in Production. Kein Setup, keine Dependencies, sofort ready.

Interaktiv 3D

Microservice-Architektur

goes bildet das Rückgrat für event-driven Microservice-Systeme. Jeder Service kommuniziert über den zentralen Event Bus. Scrolle, um jede Komponente zu erkunden.

Aggregates1/8

Domain Entities, die Business Logic kapseln und Invariants enforced. Das Aggregate ist die Consistency Boundary für Events.

Technologie

Tech Stack

Go NATS JetStream MongoDB PostgreSQL Protocol Buffers gRPC Docker
In Production

Battle-Tested in echten Projekten

goes ist nicht akademisch. Das Framework entstand aus der Notwendigkeit, komplexe Domain-Logik sauber abzubilden, und wird seit 2021 in Production eingesetzt.

... und viele weitere Production Systems, die auf goes aufgebaut sind

GitHub
158

GitHub Stars

Lizenz

Apache-2.0

Sprache

Go

Forks

17

Contributors

5+

Auf GitHub ansehen

FAQ

Häufig gestellte Fragen zu goes

Ja. goes wird in mehreren Production Systems eingesetzt und aktiv maintained. Das Framework hat eine stabile API und wird bei modernice intern für Kundenprojekte verwendet. Projekte wie Crovillas, DepositDirect und Prestige Cars laufen seit 2021 auf goes.

goes unterstützt MongoDB, PostgreSQL und NATS JetStream als Production Backends. Für Testing und Prototyping gibt es vollständige In-Memory Implementations. Alle Backends implementieren die gleichen Interfaces, was einen Wechsel ohne Code-Änderungen ermöglicht.

Grundkenntnisse in Go reichen aus. Das Getting-Started Guide und das 12-Kapitel Tutorial führen schrittweise durch alle Konzepte. goes ist so designed, dass du Event Sourcing Patterns inkrementell lernen und anwenden kannst.

Ja. goes ist modular aufgebaut. Du kannst einzelne Components wie das Event System oder Commands unabhängig nutzen und weitere bei Bedarf integrieren. Es gibt keine All-or-Nothing Dependency.

goes ist für High-Throughput Scenarios designed. Snapshots reduzieren die Replay-Zeit drastisch, Projections laufen asynchron und parallelisiert, und der Event Store unterstützt Batching. In Production werden mehrere Millionen Events ohne spürbare Latenz verarbeitet.

EventStoreDB ist eine eigenständige Datenbank, während goes deine bestehende Infrastruktur (MongoDB, PostgreSQL, NATS). Axon ist Java-basiert und deutlich opinionated. goes gibt dir die Bausteine und lässt dich entscheiden, wie du sie zusammensetzt. Keine Runtime-Dependencies außerhalb deines gewählten Backends.

goes benötigt Go 1.23 oder neuer. Das Framework nutzt Go Generics intensiv für Type-Safety bei Commands, Events und Aggregates. Wir empfehlen immer die neueste stable Go-Version.

Contributions sind willkommen. Der beste Einstieg ist das GitHub Repository. Issues labelled mit 'good first issue' eignen sich gut für den Start. PRs werden reviewed und zeitnah gemerged. Für größere Changes empfehlen wir, vorher ein Issue zu erstellen, um den Ansatz abzustimmen.

Nimm Kontakt mit uns auf

Du kennst nun unseren Prozess, jetzt ist der nächste Schritt an der Reihe. Lass uns gemeinsam daran arbeiten, deine Online-Präsenz auf das nächste Level zu bringen. Warte nicht länger, vereinbare noch heute ein Gespräch mit uns und wir schauen, wie wir deinem Business mehr Sichtbarkeit verschaffen können.