Ein sprachunabhaengiges Konzept, das den Geschaeftsfluss innerhalb von Servicefunktionen in deklarative Bloecke (Sequences) zerlegt.
Das Problem
Bestehende SSOT decken nur das ab, was ausserhalb einer Funktion liegt:
| Bestehendes SSOT | Abdeckungsbereich | Funktionsinneres? |
|---|---|---|
| OpenAPI | API-Routen, Parameter, Antwortschema | X |
| SQL DDL | Tabellenstruktur, Indizes, Constraints | X |
Das Innere einer Funktion – der Geschaeftsfluss “Abfrage -> Validierung -> Erstellung -> Antwort” – hat keinen Ort, an dem er deklariert werden kann. Man muss den Implementierungscode lesen, um ihn zu verstehen. Diese Luecke fuellt die Sequence.
SSOT-Hierarchie
SSaC ist die dritte Schicht, die auf bestehenden SSOTs aufbaut.
OpenAPI → API-Grenze (Routen, Parameter, Antworten)
SQL DDL → Datengrenze (Tabellen, Constraints, Indizes)
SSaC → Funktionsinneres (Geschaeftsfluss, Sequence-Deklaration)
─────────────────────────────────────────────────
Implementierungscode → Vom Codegen generiert (Fehlerbehandlung, Boilerplate)
Die obigen drei Schichten uebernehmen die Deklarationen, und der Implementierungscode wird daraus abgeleitet. Der Mensch schreibt nur die Deklarationen.
Kernkonzepte
sequence
Eine deklarative Einheit, die Ausfuehrungsbloecke innerhalb einer Funktion typisiert.
Deklariere nur das What (was zu tun ist), der Codegen uebernimmt das How (wie es getan wird).
10 feste Typen
| Typ | Rolle | Beispiel |
|---|---|---|
| authorize | Berechtigungspruefung | Richtlinienabfrage basierend auf Aktion/Ressource/ID |
| get | Ressourcenabfrage | Model.FindByID(id) -> result |
| guard nil | Beenden wenn Ergebnis null | Fehler und Abbruch wenn nicht vorhanden |
| guard exists | Beenden wenn Ergebnis existiert | Fehler und Abbruch wenn bereits vorhanden |
| post | Ressourcenerstellung | Model.Create(fields…) -> result |
| put | Ressourcenaenderung | Model.Update(id, fields…) |
| delete | Ressourcenloeschung | Model.Delete(id) |
| password | Passwortvergleich | Hash-Vergleich, Abbruch bei Nichtuebereinstimmung |
| call | Externer Aufruf | Ressourcenoperationen, die nicht als CRUD ausdrueckbar sind; Abbruch bei Fehler |
| response | Antwort zurueckgeben | json, view, redirect |
Da die Typen geschlossen sind, ist Codegenerierung durch typweises Template-Matching moeglich. Dies ist die Grundlage fuer symbolischen Codegen ohne LLMs.
Geltungsbereich von model
Ein model ist nicht auf Datenbanktabellen beschraenkt. Jede Ressource, die per CRUD behandelt werden kann, ist ein model. Datenbankabfragen, Dateipruefungen und externe API-Aufrufe werden alle einheitlich mit get/post/put/delete ausgedrueckt.
Syntaxbeispiel (Go PoC)
Obwohl SSaC ein sprachunabhaengiges Konzept ist, verwendet die Referenzimplementierung Go-Kommentarsyntax. Da die KI Go AST bereits versteht, entstehen keine zusaetzlichen Lernkosten.
Einfach (Erstellung)
// @sequence get
// @model Project.FindByID
// @param ProjectID request
// @result project Project
// @sequence guard nil project
// @message "프로젝트가 존재하지 않습니다"
// @sequence post
// @model Session.Create
// @param ProjectID request
// @param Command request
// @result session Session
// @sequence response json
// @var session
func CreateSession(w http.ResponseWriter, r *http.Request) {}
Komplex (Loeschung + Berechtigung + Validierung + externer Aufruf)
// @sequence authorize
// @action delete
// @resource project
// @id ProjectID
// @sequence get
// @model Project.FindByID
// @param ProjectID request
// @result project Project
// @sequence guard nil project
// @message "프로젝트가 존재하지 않습니다"
// @sequence get
// @model Session.CountByProjectID
// @param ProjectID request
// @result sessionCount int
// @sequence guard exists sessionCount
// @message "하위 세션이 존재하여 삭제할 수 없습니다"
// @sequence call
// @component notification
// @param project.OwnerEmail
// @param "프로젝트가 삭제됩니다"
// @sequence call
// @func cleanupProjectResources
// @param project
// @result cleaned bool
// @sequence delete
// @model Project.Delete
// @param ProjectID request
// @sequence response json
func DeleteProject(w http.ResponseWriter, r *http.Request) {}
Codegen-Ergebnis
Die aus den obigen Sequence-Deklarationen abgeleitete Implementierung:
func CreateSession(w http.ResponseWriter, r *http.Request) {
// get
project, err := projectModel.FindByID(projectID)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// guard nil
if project == nil {
http.Error(w, "프로젝트가 존재하지 않습니다", http.StatusNotFound)
return
}
// post
session, err := sessionModel.Create(projectID, command)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// response json
json.NewEncoder(w).Encode(map[string]interface{}{
"session": session,
})
}
Token-Kostenvergleich
| Sequence-Deklaration | Implementierungscode | |
|---|---|---|
| Zeilenanzahl | 10-15 Zeilen | 30-100 Zeilen |
| Ausgedruckter Inhalt | what (was zu tun ist) | how (wie es getan wird) |
| Fehlerbehandlung | Keine (vom Codegen generiert) | Vollstaendig enthalten |
| Bibliotheksabhaengigkeiten | Keine | import, Initialisierung, Aufrufe |
| Aenderungszeitpunkt | Bei Aenderung des Geschaeftsflusses | Automatische Aktualisierung durch erneuten Codegen |
Der Mensch wartet nur die Sequence-Deklarationen. Wenn sich eine Deklaration aendert, wird der Codegen erneut ausgefuehrt und der Implementierungscode ueberschrieben.
Designprinzipien
early return – der gemeinsame Vertrag aller Typen
Dies ist die Voraussetzung, die eine lineare Auflistung von Sequences ermoeglicht. Mit Ausnahme von response beendet jede Sequence bei Fehler sofort die Ausfuehrung. call ist keine Ausnahme. Einfach von oben nach unten lesen, ohne Verzweigung.
| Typ | Fehlerbedingung |
|---|---|
| authorize | Keine Berechtigung -> return |
| get | Abfragefehler -> return |
| guard nil | null -> return |
| guard exists | Existiert -> return |
| post/put/delete | DB-Fehler -> return |
| password | Nichtubereinstimmung -> return |
| call | Fehler -> return |
| response | Letztes (Rueckgabe) |
Da call denselben Vertrag wie guard befolgt, muss nach einem call kein separater guard angehaengt werden. Der Codegen generiert automatisch Fehlerpruefung + early return fuer jeden call.
@transaction
Metadaten auf Funktionsebene. Es ist kein Sequence-Typ (unter den 10), sondern eine Deklaration, ob die gesamte Funktion in eine Transaktion eingehuellt werden soll.
// @transaction
// @sequence get
// @model Account.FindByID
// @param AccountID request
// @result account Account
// ...
In Kombination mit der early-return-Struktur ergeben sich die Transaktionsgrenzen natuerlich:
@transaction deklariert
→ guard-Fehler → rollback + return
→ letzte Sequence erfolgreich → commit
→ Fehler aufgetreten → rollback + return
Da es keine Verzweigung gibt, ist die Transaktionsgrenze einheitlich: “die gesamte Funktion”. Es muessen keine begin/end-Positionen angegeben werden, und der Codegen entscheidet allein anhand des Vorhandenseins oder Fehlens von @transaction ueber das Wrapping. Wenn zwei Transaktionen benoetigt werden, bedeutet das zwei Verantwortlichkeiten. Teile die Funktion auf.
call – eine Sonderform von model
call hat dasselbe Wesen wie model. Wenn model Ressourcenoperationen darstellt, die als CRUD (get/post/put/delete) ausdrueckbar sind, dann stellt call Ressourcenoperationen dar, die nicht als CRUD ausdrueckbar sind. Beide rufen Arbeit mit externen Abhaengigkeiten auf und kehren bei Fehler zurueck.
Ressourcenoperationen
+-- model (CRUD) → get/post/put/delete
+-- call (Nicht-CRUD) → component oder func
@component– Registrierungsbasiert. Wird befoerdert, wenn ein sich wiederholendes Muster dreimal oder oefter auftritt.@func– Einzigartige Logik. Wird direkt von einem Menschen oder einer KI implementiert.
Komplexe Logik wie Verzweigung mit anschliessendem Zusammenfuehren oder bedingte Verarbeitung in Schleifen erweitert nicht die Sequence, sondern wird an call delegiert. Delegiert, aber der Vertrag bleibt derselbe – Abbruch bei Fehler.
@message
Optionale Metadaten, die jedem Sequence-Typ angehaengt werden koennen. Sie geben die Nachricht an, die dem Benutzer bei einem Fehler uebermittelt wird.
// @sequence guard nil project
// @message "프로젝트가 존재하지 않습니다"
// @sequence post
// @model Session.Create
// @param ProjectID request
// @param Command request
// @result session Session
// @message "세션 생성에 실패했습니다"
Wenn @message weggelassen wird, generiert der Codegen automatisch eine Standardnachricht aus Typ + Modellname. Nur bei Bedarf einer benutzerdefinierten Nachricht muss es deklariert werden.
Reine Funktionen existieren nicht in der Serviceschicht
Alle in einer Sequence deklarierten Bloecke sind Operationen mit externen Abhaengigkeiten. Reine Funktionalitaeten wie Formatkonvertierung oder Wertberechnung werden nicht in der Serviceschicht, sondern innerhalb des Models oder der aufgerufenen Funktion verarbeitet. Servicefunktionen uebernehmen nur die Orchestrierung; reine Berechnungen gehoeren dem Aufgerufenen.
Typreferenz
SSaC definiert keine eigenen Typen. Es referenziert Typen, die aus bestehenden SSOT-Quellen abgeleitet werden.
| Quelle | Beispiel |
|---|---|
| DB-Schema (SQL DDL) | Project, Session |
| API-Spezifikation (OpenAPI) | CreateSessionRequest |
| Schnittstellendefinition | FileSystem, Cache |
Namenskonventionen
| Kategorie | Regel | Beispiel |
|---|---|---|
| Typ | PascalCase, aus dem SSOT uebernommen | Project, Session |
| Variable | camelCase, via @result deklariert | project, sessionCount |
| Request-Feld | PascalCase, aus der Anfrage extrahiert | ProjectID, Command |
| Reservierte Variable | camelCase, vom Framework bereitgestellt | currentUser, config |
Die unterschiedliche Gross-/Kleinschreibung von Typen und Variablen ermoeglicht es, sie allein anhand der Deklaration zu unterscheiden. project ist eine Variable, Project ist ein Typ.
Spracherweiterung
SSaC ist ein sprachunabhaengiges Konzept. Go ist die Referenzimplementierung (PoC), und aus denselben Sequence-Deklarationen kann Code in anderen Sprachen generiert werden.
Sequence-Deklaration (gemeinsam)
|
+-- Go Codegen
+-- Python Codegen
+-- TypeScript Codegen
+-- ...
Die Spezifikation (Typdefinitionen, Syntax, Validierungsregeln) und der Codegen sind getrennt.
Die Go-Referenzimplementierung ist auf GitHub verfügbar.