Konsep independen bahasa yang mendekomposisi alur bisnis di dalam fungsi layanan menjadi blok deklaratif (sequence).
Masalah
SSOT yang ada saat ini hanya mencakup hingga bagian luar fungsi:
| SSOT yang Ada | Cakupan | Bagian dalam fungsi? |
|---|---|---|
| OpenAPI | Route API, parameter, skema respons | X |
| SQL DDL | Struktur tabel, indeks, constraint | X |
Bagian dalam fungsi — alur bisnis seperti “query -> validasi -> buat -> respons” tidak memiliki tempat untuk dideklarasikan. Satu-satunya cara mengetahuinya adalah dengan membaca kode implementasi. Ruang kosong inilah yang diisi oleh sequence.
Hierarki SSOT
SSaC adalah lapisan ketiga yang dibangun di atas SSOT yang sudah ada.
OpenAPI → API 경계 (경로, 파라미터, 응답)
SQL DDL → 데이터 경계 (테이블, 제약, 인덱스)
SSaC → 함수 내부 (비즈니스 흐름, sequence 선언)
─────────────────────────────────────────────────
구현 코드 → 코드젠이 생성 (에러 핸들링, 보일러플레이트)
Ketiga lapisan di atas bertanggung jawab atas deklarasi, dan kode implementasi diturunkan dari deklarasi tersebut. Yang ditulis manusia hanyalah deklarasi.
Konsep Inti
sequence
Unit deklarasi yang mengetipekan blok eksekusi di dalam fungsi.
Hanya deklarasikan what (apa yang dilakukan), dan codegen yang mengisi how (bagaimana melakukannya).
10 Tipe Tetap
| Tipe | Peran | Contoh |
|---|---|---|
| authorize | Verifikasi otorisasi | Query kebijakan berdasarkan action/resource/ID |
| get | Query resource | Model.FindByID(id) -> result |
| guard nil | Keluar jika hasilnya null | Error dan keluar jika tidak ditemukan |
| guard exists | Keluar jika hasilnya ada | Error dan keluar jika sudah ada |
| post | Buat resource | Model.Create(fields…) -> result |
| put | Perbarui resource | Model.Update(id, fields…) |
| delete | Hapus resource | Model.Delete(id) |
| password | Bandingkan password | Bandingkan hash, keluar jika gagal |
| call | Panggilan eksternal | Operasi resource yang tidak bisa dinyatakan sebagai CRUD, keluar jika gagal |
| response | Kembalikan respons | json, view, redirect |
Karena tipe-tipenya tertutup, pembuatan kode melalui template matching per tipe dimungkinkan. Inilah dasar mengapa symbolic codegen dapat bekerja tanpa LLM.
Cakupan model
model tidak terbatas pada tabel DB. Semua resource yang dapat ditangani dengan CRUD adalah model. Query DB, pemeriksaan keberadaan file, panggilan API eksternal — semuanya diekspresikan secara seragam sebagai get/post/put/delete.
Contoh Sintaks (Go PoC)
Meskipun konsepnya independen bahasa, implementasi referensi menggunakan sintaks komentar Go. Karena AI sudah mengenal Go AST, tidak ada biaya pembelajaran tambahan.
Sederhana (Pembuatan)
// @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) {}
Kompleks (Hapus + Otorisasi + Validasi + Panggilan Eksternal)
// @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) {}
Hasil Codegen
Implementasi yang dihasilkan dari deklarasi sequence di atas:
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,
})
}
Perbandingan Biaya Token
| Deklarasi sequence | Kode implementasi | |
|---|---|---|
| Jumlah baris | 10~15 baris | 30~100 baris |
| Isi yang diekspresikan | what (apa yang dilakukan) | how (bagaimana melakukannya) |
| Error handling | Tidak ada (dihasilkan codegen) | Semuanya disertakan |
| Dependensi library | Tidak ada | import, inisialisasi, pemanggilan |
| Waktu perubahan | Saat alur bisnis berubah | Tercermin otomatis dengan menjalankan ulang codegen |
Yang dipelihara manusia hanyalah deklarasi sequence. Ketika deklarasi berubah, cukup jalankan ulang codegen untuk menimpa kode implementasi.
Prinsip Desain
early return — Kontrak Bersama Semua Tipe
Prasyarat agar sequence dapat disusun secara linear. Semua sequence kecuali response langsung keluar saat gagal. call pun bukan pengecualian. Cukup baca dari atas ke bawah tanpa percabangan, dan selesai.
| Tipe | Kondisi Kegagalan |
|---|---|
| authorize | Tidak memiliki otorisasi -> return |
| get | Error query -> return |
| guard nil | null -> return |
| guard exists | Ada -> return |
| post/put/delete | Error DB -> return |
| password | Tidak cocok -> return |
| call | Gagal -> return |
| response | Terakhir (pengembalian) |
Karena call mengikuti kontrak yang sama dengan guard, tidak perlu menambahkan guard terpisah setelah call. Codegen secara otomatis menghasilkan error check + early return untuk setiap call.
@transaction
Metadata level fungsi. Bukan tipe sequence (10 tipe), melainkan deklarasi apakah seluruh fungsi di-wrap dalam transaksi atau tidak.
// @transaction
// @sequence get
// @model Account.FindByID
// @param AccountID request
// @result account Account
// ...
Ketika dikombinasikan dengan struktur early return, batas transaksi menjadi alami:
@transaction dideklarasikan
-> guard gagal -> rollback + return
-> sequence terakhir berhasil -> commit
-> error terjadi -> rollback + return
Karena tidak ada percabangan, batas transaksi juga tunggal yaitu “seluruh fungsi”. Tidak perlu menentukan posisi begin/end, dan codegen menentukan apakah perlu wrapping hanya berdasarkan ada tidaknya @transaction. Jika diperlukan 2 transaksi, itu berarti ada 2 tanggung jawab. Pisahkan fungsinya.
call — Bentuk Khusus dari model
call memiliki esensi yang sama dengan model. Jika model adalah operasi resource yang diekspresikan sebagai CRUD (get/post/put/delete), maka call adalah operasi resource yang tidak bisa diekspresikan sebagai CRUD. Keduanya memanggil pekerjaan yang memiliki dependensi eksternal, dan return saat gagal.
Operasi resource
+-- model (CRUD) -> get/post/put/delete
+-- call (non-CRUD) -> component atau func
@component— Sistem registrasi. Dipromosikan ketika pola berulang muncul 3 kali atau lebih.@func— Logika unik. Diimplementasikan langsung oleh manusia atau AI.
Logika kompleks seperti percabangan lalu penggabungan, pemrosesan kondisional dalam loop, didelegasikan ke call tanpa memperluas sequence. Didelegasikan, tetapi kontraknya tetap sama — keluar saat gagal.
@message
Metadata opsional yang dapat dilampirkan ke semua tipe sequence. Menentukan pesan yang akan disampaikan kepada pengguna saat terjadi kegagalan.
// @sequence guard nil project
// @message "프로젝트가 존재하지 않습니다"
// @sequence post
// @model Session.Create
// @param ProjectID request
// @param Command request
// @result session Session
// @message "세션 생성에 실패했습니다"
Jika @message dihilangkan, codegen secara otomatis menghasilkan pesan default dari tipe + nama model. Deklarasikan hanya ketika pesan kustom diperlukan.
Fungsi Murni Tidak Ada di Lapisan Layanan
Semua blok yang dideklarasikan dalam sequence adalah pekerjaan yang memiliki dependensi eksternal. Fungsi murni seperti konversi format dan perhitungan nilai ditangani di dalam model atau di dalam fungsi yang dipanggil, bukan di lapisan layanan. Fungsi layanan hanya melakukan orchestration, dan komputasi murni menjadi milik target yang dipanggil.
Referensi Tipe
SSaC tidak mendefinisikan tipenya sendiri. SSaC mereferensikan tipe yang dihasilkan dari SSOT yang sudah ada.
| Sumber | Contoh |
|---|---|
| Skema DB (SQL DDL) | Project, Session |
| Spesifikasi API (OpenAPI) | CreateSessionRequest |
| Definisi interface | FileSystem, Cache |
Konvensi Penamaan
| Kategori | Aturan | Contoh |
|---|---|---|
| Tipe | PascalCase, diambil dari SSOT | Project, Session |
| Variabel | camelCase, dideklarasikan via @result | project, sessionCount |
| Field request | PascalCase, diekstrak dari request | ProjectID, Command |
| Variabel reserved | camelCase, disediakan oleh framework | currentUser, config |
Perbedaan huruf besar-kecil antara tipe dan variabel memungkinkan pembedaan hanya dari deklarasi. project adalah variabel, Project adalah tipe.
Ekstensi Bahasa
SSaC adalah konsep independen bahasa. Go adalah implementasi referensi (PoC), dan dari deklarasi sequence yang sama dapat dihasilkan kode dalam bahasa lain.
sequence 선언 (공통)
|
+-- Go 코드젠
+-- Python 코드젠
+-- TypeScript 코드젠
+-- ...
Spesifikasi (definisi tipe, sintaks, aturan validasi) dan codegen dipisahkan.
Implementasi referensi Go tersedia di GitHub.