Blog

Die Verwendung von "Annotationen" hat unsere Produktivität in Golang gesteigert

Marcus Martina

Aktualisiert Oktober 17, 2025
3 Minuten

Das Schreiben von REST-Diensten in Go ist ziemlich langweilig und repetitiv. Sowohl mit der Standard http-Bibliothek als auch mit Frameworks müssen Sie ziemlich viel Code schreiben, um einen einfachen Dienst zu implementieren. Da uns Javas "JAX-RS"-Ansatz (mit Annotationen) gefällt, haben wir uns gefragt, ob wir diesen deklarativen Ansatz auch in Go verwenden können. Dieser Blog beschreibt dieses erfolgreiche Experiment.

Dieser Ansatz ist inzwischen ausgereift und hat sich in einem großen Gesundheitsprojekt bewährt. Den Quellcode unseres selbst entwickelten Tools finden Sie auf Github: Github MarcGrol / golangAnnotations.

Überblick über unsere Lösung

Unsere Anmerkungen sind in normale Kommentare verpackt. Folglich wird die AST-Bibliothek (aus der Go-Standardbibliothek) verwendet, um den Go-Quellcode zu analysieren (einschließlich unserer speziellen Anmerkungen). Anschließend werden Code-Generatoren ausgelöst, um langweiligen und vorhersehbaren Quellcode zu erzeugen. Dieser generierte Code wird einfach mit dem Rest Ihres Codes committed. Ein Vorteil dieses Ansatzes ist, dass der generierte Code kein magischer Bytecode ist (wie in Java), sondern leicht lesbarer und debuggbarer Quellcode.

Schritt für Schritt

JAX-RS-ähnliche Annotationen

Alles beginnt mit dem Hinzufügen von Anmerkungen zu unserem eigenen Go-Quellcode. Wir haben keine neue Syntax für Go-Annotationen erfunden. Damit die Anmerkungen leicht zu erkennen sind, werden die Anmerkungen wie in Java modelliert. Eine oder mehrere Annotationen können an Strukturen, Enums, Funktionen, Methoden und Schnittstellen angehängt werden.

Beispiel für ein Fragment unseres Golang-Codes:

package tourdefrance
// @RestService( path="/api/tour" )
type TourDeFranceService struct{}
type EtappeResult struct{ ... }
// @RestOperation( method="PUT", path="/{year}/etappe/{etappeUid}" )
func (ts *TourService) addEtappeResults(c context.Context, year int,
                etappeUid string, results EtappeResult) error {
    // ...
    return nil
}

Parsen von Go-Code in ein Zwischenmodell

Wenn wir diesen Code parsen, spuckt die AST-Bibliothek von Golang etwas wie dieses aus: Beispiel

Dieser haarige AST (=Abstrakter Syntaxbaum) wird dann in eine vereinfachte Zwischendarstellung umgewandelt. Die Kodierung dieser Umwandlung war ziemlich mühsam und wird durch einen soliden Satz von Unit-Tests abgedeckt. Derzeit werden die folgenden Konstrukte aus dem AST extrahiert:

  • Strukturen mit ihren Feldern
  • Aufzählungen mit ihren Literalen
  • Funktionen und Methoden mit ihren Eingabe- und Ausgabeparametern
  • Schnittstellen mit Operationen mit ihren Eingabe- und Ausgabeparametern

Dies ist die resultierende Zwischendarstellung des kommentierten go-Beispiels oben:

{
    packageName: "tourdefrance",
    structs: [
        {
            docLines: ["// @RestService( path=/api/tour)"],
            name: "TourService",
            operations: [
                {
                    docLines: ["// @RestOperation( method=PUT, path=/{year}/etappe/{etappeUid}"],
                    name: "addEtappeResults",
                    inputArgs: [
                        {name: "c", typeName: "context.Context"},
                        {name: "year", typeName: "int"},
                        {name: "etappeUid", typeName: "string"},
                        {name: "results", typeName: "EtappeResult"}
                    ],
                    outputArgs: [
                        {typeName: "error"},
                    ],
                }
            ]
        }
    ]
}

Generierung von Quellcode aus dem ausgefüllten Zwischenmodell

Sobald wir eine vollständig ausgefüllte Zwischendarstellung haben, können wir sie in unsere Code-Generatoren einspeisen. Diese Generatoren basieren normalerweise auf der "text/template"-Bibliothek von go. Auf der Grundlage unserer rest-Annotationen wird der folgende vorhersehbare und sich wiederholende Code generiert, um den gesamten HTTP-Kram zu erledigen. Annotationen in go

Fazit

Die Go-Standardbibliothek ermöglicht es Ihnen, Go-Code in Ihr eigenes Metamodell zu parsen. Auf der Grundlage dieses Zwischenmodells und kommentarähnlicher Anmerkungen verwenden wir die Codegenerierung, um langweilige und wiederholbare Teile unserer Anwendung zu erstellen. Dieser Ansatz wird derzeit in der Gesundheitsplattform Duxxie intensiv genutzt.

Neben den Rest-Annotationen haben wir noch weitere Anmerkungen hinzugefügt, um Folgendes zu unterstützen:

  • type-strong http-clients (um automatisierte Tests zu erleichtern)
  • serialisierbare Enums
  • Event-Sourcing
  • Ereignisbehandlung
  • Datenspeicher CRUD
  • Dokumentation.

Jetzt ist die harte Arbeit getan und neue Anmerkungen und Generatoren können relativ einfach hinzugefügt werden. Hat jemand Vorschläge für andere Situationen, in denen dieser Ansatz ebenfalls sinnvoll sein könnte? Sie können uns gerne Pull Requests vorschlagen.

 

Verfasst von

Marcus Martina

Contact

Let’s discuss how we can support your journey.