Spesifikasi sebagai Source of Truth di Golang: Cara Berpikir SDD yang Baru
Pahami konsep spesifikasi sebagai single source of truth dalam SDD. Cara membangun sistem governance spec yang efektif untuk proyek Golang dengan Claude Code.
Di proyek software yang sudah berjalan cukup lama, ada satu pertanyaan yang sering tidak bisa dijawab dengan pasti: “Seharusnya bagaimana sistem ini berperilaku dalam kondisi X?”
Kalau kamu tanya developer A, jawabannya berbeda dari developer B. Developer B lihat kodenya, developer C lihat Jira ticket lama, developer D lihat dokumen Confluence yang mungkin sudah outdated. Tidak ada satu tempat yang menjadi sumber kebenaran tunggal.
Inilah masalah yang diselesaikan oleh konsep spesifikasi sebagai source of truth golang dalam SDD. Di artikel ini, kita bahas apa artinya secara operasional, kenapa ini lebih sulit dari kelihatannya, dan bagaimana membangunnya dengan benar untuk proyek Golang.
02.1 Masalah dengan “Kode sebagai Dokumentasi”
Ada kepercayaan populer di kalangan developer: “kode adalah dokumentasi terbaik.” Idenya: kode tidak bisa bohong, kode selalu up-to-date, kode adalah ground truth.
Kepercayaan ini benar sebagian — tapi berbahaya jika dijadikan filosofi tunggal.
Kode adalah ground truth untuk apa yang sistem lakukan sekarang. Bukan ground truth untuk apa yang sistem seharusnya lakukan. Perhatikan potongan usecase cancel order berikut, yang secara teknis benar tapi menyembunyikan sebuah keputusan bisnis.
1// Kode ini ground truth untuk "apa yang terjadi sekarang"
2func (uc *CancelOrderUseCase) Execute(ctx context.Context, input CancelOrderInput) error {
3 order, err := uc.repo.GetByID(ctx, input.OrderID)
4 if err != nil {
5 return err
6 }
7 if order.Status != StatusPending {
8 return ErrCannotCancel // ← kenapa hanya PENDING? Siapa yang memutuskan ini?
9 }
10 // ...
11}Pertanyaan // kenapa hanya PENDING? tidak bisa dijawab hanya dari kode. Bisa jadi ini business requirement, bisa jadi constraint sementara yang lupa diupdate, bisa jadi bug — kode tidak bisa membedakannya. Spesifikasi menjawab pertanyaan “kenapa” itu, sedangkan kode menjawab “bagaimana”. Keduanya dibutuhkan, tapi spec harus hadir lebih dulu.
02.2 Tiga Kandidat Source of Truth yang Sering Bersaing
Di kebanyakan tim, ada tiga kandidat yang bersaing untuk menjadi “sumber kebenaran”:
Kandidat 1: Kode (Code)
Pro: Selalu mencerminkan behavior saat ini. Tidak bisa berbohong — jika kode bilang X, sistem berperilaku X.
Kontra: Tidak menjelaskan mengapa. Tidak bisa dibaca oleh non-developer. Tidak bisa di-review sebelum diimplementasikan. Tidak mencerminkan intended behavior, hanya actual behavior.
Kandidat 2: Tiket (Jira, Linear, dll)
Pro: Tersedia untuk semua stakeholder. Punya konteks bisnis. Ada trail keputusan.
Kontra: Sering tidak di-update setelah implementasi. Tidak structured enough untuk jadi spesifikasi teknikal. Sulit di-cross-reference dengan kode. Bisa contradictory antar ticket.
Kandidat 3: Dokumentasi (Confluence, Notion, dll)
Pro: Bisa punya narrative yang baik. Bisa punya diagram. Mudah dibaca.
Kontra: Mati cepat — tidak ada yang update setelah fitur selesai. Tidak punya single ownership. Sulit verifikasi apakah masih akurat.
SDD Solution: Spec file yang:
- Tersimpan di repository yang sama dengan kode (bersama git)
- Di-update bersamaan dengan kode (enforced via PR process)
- Structured tapi cukup readable untuk non-developer
- Punya ownership yang jelas
02.3 Anatomi Source of Truth yang Efektif
Bukan semua spec bisa jadi source of truth yang efektif. Ada karakteristik yang membedakan spec yang benar-benar berguna dari spec yang cuma dokumen formalitas.
Karakteristik 1: Spesifik tapi Tidak Terlalu Detail
Level detail yang tepat adalah keseimbangan yang sulit. Contoh berikut menyandingkan spec yang terlalu umum, terlalu masuk implementasi, dan yang tepat sasaran.
1❌ Terlalu umum:
2"Sistem harus handle order dengan baik"
3
4❌ Terlalu detail (masuk implementasi):
5"Gunakan BEGIN TRANSACTION dengan isolation level READ COMMITTED,
6 kemudian execute UPDATE orders SET status = 'CANCELLED'..."
7
8✅ Tepat sasaran:
9"Hanya order dengan status PENDING yang bisa dicancel.
10 Order dengan status lain → 409 Conflict dengan error code ORDER_NOT_CANCELLABLE"Versi ketiga menetapkan behavior yang bisa diverifikasi tanpa mengunci developer ke satu cara implementasi tertentu — inilah sweet spot yang kita cari.
Karakteristik 2: Verifiable secara Otomatis
Setiap AC harus bisa ditulis sebagai test. Ambil satu AC sederhana tentang restore stok berikut sebagai contoh.
1AC: Setelah cancel berhasil, stok produk dalam order dikembalikan ke jumlah semulaAC di atas tidak berhenti sebagai kalimat — ia langsung dapat diterjemahkan menjadi kerangka test Go yang eksekutabel seperti berikut.
1func TestCancelOrder_RestoresStock(t *testing.T) {
2 // Given: produk dengan stok 10, order yang berisi 3 unit
3 // When: order dicancel
4 // Then: stok produk menjadi 13
5}Karena setiap AC punya pasangan test yang jelas, “sesuai spec atau tidak” menjadi pertanyaan yang bisa dijawab mesin, bukan opini.
Karakteristik 3: Single Ownership
Setiap spec punya satu orang yang bertanggung jawab untuk akurasinya — bukan “tim”, tapi orang konkret. Header spec berikut mencantumkan owner secara eksplisit.
1# specs/order/cancel-order.md
2# Owner: @ihsan-arif
3# Last reviewed: 2025-07-01
4# Status: ActiveDengan nama owner yang tercantum, tidak ada lagi spec yang “milik semua orang tapi tidak ada yang merawat” — selalu ada satu orang yang bisa dimintai klarifikasi.
Karakteristik 4: Versioned dengan Git
Karena spec ada di repository, setiap perubahan ter-track lewat git. Perintah git log berikut menampilkan riwayat perubahan sebuah spec.
1git log --follow specs/order/cancel-order.md
2# commit abc123 - "Update EC3: tambah rate limiting untuk cancel request"
3# commit def456 - "Initial spec: cancel order feature"Riwayat semacam ini menjadikan spec sebagai audit trail keputusan bisnis, bukan sekadar dokumen statis yang tidak diketahui asal-usulnya.
02.4 Source of Truth dalam Praktik: Konflik yang Umum Terjadi
Mari lihat skenario nyata di mana “source of truth” jadi penting.
Skenario: Bug Report dari Customer
Customer melaporkan: “Saya tidak bisa cancel order saya padahal baru 5 menit dibuat.”
Tanpa Spec:
- Developer A cek kode: “Oh iya, order harus PENDING, tapi order customer sudah CONFIRMED.”
- Developer B cek Jira: “Ada ticket 6 bulan lalu tentang auto-confirm order dalam 3 menit.”
- Developer C bilang: “Tapi di dashboard merchant, harusnya masih bisa cancel sampai 30 menit.”
- QA: “Saya tidak tahu mana yang benar, dokumennya sudah outdated.”
- Result: 2 jam diskusi, belum ada keputusan.
Dengan Spec sebagai Source of Truth: semua orang membuka satu file yang sama, yang isinya seperti kutipan spec berikut.
1# specs/order/cancel-order.md (v1.3, updated 2025-06-15)
2
3## Acceptance Criteria
4AC7: Customer hanya bisa cancel order dalam 15 menit pertama setelah order dibuat,
5 ATAU selama status masih PENDING — mana yang lebih cepat tercapai.
6 Setelah itu → 409 dengan error CANCEL_WINDOW_EXPIRED.
7
8## Changelog
9- v1.3 (2025-06-15): Tambah batas waktu 15 menit berdasarkan keputusan product meeting.
10 Sebelumnya: cancel hanya berdasarkan status PENDING tanpa batas waktu.
11- v1.0 (2025-05-01): Initial spec.Sekarang pertanyaannya jelas: apakah implementasi sesuai dengan AC7 versi 1.3? Jika iya dan customer masih komplain, ada data yang perlu dicek; jika tidak, itu bug yang jelas — diskusi 2 jam tadi berubah jadi pengecekan 5 menit.
02.5 Hirarki Keputusan dalam SDD
Dalam SDD, ada hirarki jelas ketika terjadi konflik. Urutan otoritas berikut menentukan mana yang menang saat dua sumber saling bertentangan.
11. Spesifikasi yang sudah di-approve ← tertinggi
22. Code review yang sudah di-merge
33. Unit test yang sudah ada
44. Kode yang berjalan di production
55. Komentar di kode ← terendahKonsekuensinya tegas: jika kode bertentangan dengan spec yang sudah di-approve, kode yang salah — bukan spec, kecuali ada keputusan eksplisit untuk mengubah spec lewat proses review. Ini bukan aturan yang kaku tanpa pengecualian — ada kasus di mana implementasi menemukan sesuatu yang perlu merevisi spec, tapi proses revisinya harus eksplisit, bukan “diam-diam” lewat perubahan kode.
02.6 Menulis Spec yang Layak Jadi Source of Truth
Sebelum masuk ke governance, kita butuh format spec yang konsisten. Template berikut adalah kerangka yang kita gunakan sepanjang seri ini untuk Santekno Shop.
1# [Nama Fitur]
2# Versi: [X.Y]
3# Owner: @[nama]
4# Status: Draft | Review | Active | Deprecated
5# Dibuat: [tanggal]
6# Terakhir diupdate: [tanggal]
7
8---
9
10## User Story
11Sebagai [siapa], saya ingin [apa] agar [mengapa].
12
13## Scope
14[Apa yang termasuk dalam spec ini. Apa yang TIDAK termasuk.]
15
16## Acceptance Criteria
17
18### Happy Path
19- AC1: [kondisi pertama]
20- AC2: [kondisi kedua]
21- ...
22
23### Error Cases
24- AC[n]: [kondisi error pertama] → [HTTP status] dengan error code [CODE]
25- AC[n+1]: [kondisi error kedua] → [HTTP status] dengan error code [CODE]
26
27## Edge Cases
28- EC1: [kondisi edge pertama] → [behavior yang diharapkan]
29- EC2: [kondisi edge kedua] → [behavior yang diharapkan]
30
31## Non-Functional Requirements (jika relevan)
32- NFR1: Response time < [X]ms untuk p95
33- NFR2: [requirement lain]
34
35## Tidak dalam Scope Spec Ini
36- [hal yang dengan sengaja tidak dibahas]
37
38## Referensi
39- [link ke spec terkait, ticket, atau keputusan arsitektur]
40
41## Changelog
42| Versi | Tanggal | Perubahan | Author |
43|-------|---------|-----------|--------|
44| 1.0 | ... | Initial | @... |Struktur inilah yang membuat spec konsisten antar fitur: siapa pun yang membuka file spec baru langsung tahu di mana mencari AC, EC, atau changelog tanpa harus menebak.
02.7 Source of Truth di Level Tim: Governance
Spec bisa jadi source of truth hanya jika ada proses governance yang memastikan spec selalu akurat. Tanpa governance, spec akan outdated dalam beberapa sprint.
Governance minimal yang efektif:
1. Spec Review sebelum Implementasi
Tidak ada kode yang boleh ditulis untuk fitur baru sebelum spec-nya di-review minimal oleh satu orang lain. Ini enforced via PR: PR berisi kode harus referensikan spec yang sudah di-approve.
2. Spec Update bersamaan dengan Kode
Jika implementasi menghasilkan behavior yang berbeda dari spec (karena alasan teknikal), spec harus diupdate di PR yang sama. Tidak boleh ada “update spec nanti.”
3. Quarterly Spec Audit
Setiap kuartal, lakukan review semua spec yang aktif. Spec yang tidak diupdate lebih dari 6 bulan perlu dicek apakah masih akurat.
4. Spec dalam CLAUDE.md
Instruksikan Claude Code untuk selalu referensikan spec yang ada sebelum generate kode. Lebih lanjut di Artikel 04.
02.8 Spec sebagai Kontrak: Implikasi untuk Testing
Ketika spec menjadi source of truth, implikasinya untuk testing sangat konkret. Test suite yang ideal dalam SDD memetakan setiap fungsi test langsung ke AC dan EC di spec, seperti struktur berikut.
1// cancel_order_test.go — struktur yang mengikuti spec
2
3// === Happy Path Tests (dari AC Happy Path) ===
4func TestCancelOrder_PendingOrder_Success(t *testing.T) {} // AC1
5func TestCancelOrder_StockRestored_AfterCancel(t *testing.T) {} // AC2
6func TestCancelOrder_EventPublished_AfterCancel(t *testing.T) {} // AC3
7func TestCancelOrder_Returns204_OnSuccess(t *testing.T) {} // AC4
8
9// === Error Case Tests (dari AC Error Cases) ===
10func TestCancelOrder_ConfirmedOrder_Returns409(t *testing.T) {} // AC5
11func TestCancelOrder_ShippedOrder_Returns409(t *testing.T) {} // AC6
12func TestCancelOrder_NotFound_Returns404(t *testing.T) {} // AC7
13func TestCancelOrder_Unauthorized_Returns401(t *testing.T) {} // AC8
14func TestCancelOrder_OtherUserOrder_Returns404(t *testing.T) {} // AC9
15
16// === Edge Case Tests (dari EC) ===
17func TestCancelOrder_ConcurrentCancel_OnlyOneSucceeds(t *testing.T) {} // EC1
18func TestCancelOrder_KafkaDown_StillCancels(t *testing.T) {} // EC2
19func TestCancelOrder_AfterWindow_Returns409(t *testing.T) {} // EC3Struktur test ini memastikan coverage berbasis spec, bukan coverage berbasis kode. Perbedaannya signifikan: coverage berbasis kode bisa 100% tapi masih miss business behavior yang penting, sedangkan coverage berbasis spec menjamin setiap AC benar-benar diverifikasi.
02.9 Integrasi dengan Claude Code: Spec sebagai Context
Salah satu kekuatan terbesar SDD adalah bagaimana spec bisa langsung dijadikan context untuk Claude Code. Dibandingkan menjelaskan behavior via prompt panjang, cukup referensikan file spec seperti pada prompt berikut.
1Implementasikan usecase CancelOrderUseCase berdasarkan
2specs/order/cancel-order.md.
3
4Context tambahan:
5- Stack: Go 1.22, Echo v4, pgx/v5
6- Architecture: domain → usecase → repository → handler
7- Referensi pola: internal/usecase/order/create_order.go
8- Jangan tulis test dulu, fokus ke implementasi usecase terlebih dahuluDengan instruksi sesingkat itu, Claude Code bisa membaca spec dan memahami semua AC dan EC, mengidentifikasi error case yang perlu di-handle, membuat interface yang tepat untuk dependency injection, dan menghasilkan kode yang coverage-nya bisa di-trace kembali ke spec.
02.10 Tantangan Psikologis: Kenapa Ini Sulit
Konsep “spec sebagai source of truth” terdengar sederhana, tapi ada beberapa tantangan psikologis yang membuat ini sulit dipraktikkan:
Tantangan 1: “Kode sudah ada, ngapain nulis spec?”
Seringkali spec diminta untuk fitur yang sudah selesai di-implement. Ini terasa membuang waktu. Solusi: spec untuk fitur existing tidak perlu lengkap — cukup dokumentasikan behavior saat ini dan highlight area yang perlu klarifikasi.
Tantangan 2: Fear of Over-Engineering
“Kita startup, tidak ada waktu untuk ini semua.” Tapi spec minimal (user story + 3 AC + 1 EC) bisa ditulis dalam 10 menit. Bukan over-engineering — ini justru mencegah over-engineering karena membatasi scope fitur.
Tantangan 3: “Spec akan outdated anyway”
Ini self-fulfilling prophecy. Spec menjadi outdated karena tidak ada enforcement untuk update-nya. Dengan proper governance (spec dalam git, PR enforcement), ini bisa dicegah.
Tantangan 4: Tidak Tahu Cara Menulis Spec yang Baik
Ini tantangan yang paling valid — dan kenapa Part 2 seri ini (Artikel 05–09) didedikasikan khusus untuk skill ini.
02.11 Spec sebagai Source of Truth untuk AI-Generated Code
Di era AI coding assistant, “spec sebagai source of truth” punya dimensi tambahan yang penting.
Masalah: AI tidak punya “memory” lintas sesi. Setiap sesi baru, AI tidak tahu keputusan arsitektur yang sudah dibuat, business rules yang sudah disepakati, atau pattern yang sudah ditentukan.
Solusi SDD: Spec menjadi “persistent memory” yang bisa dibaca AI setiap saat. Perbandingan dua prompt berikut menunjukkan perbedaan konteks yang diterima AI.
1Prompt yang lemah:
2"Tambahkan validasi untuk endpoint cancel order"
3
4Prompt yang kuat (berbasis spec):
5"Berdasarkan specs/order/cancel-order.md, tambahkan validasi
6untuk semua AC dan EC yang belum diimplementasikan.
7Verifikasi dengan membandingkan implementasi saat ini di
8internal/usecase/order/cancel_order.go dengan spec."Dengan pendekatan kedua, AI punya konteks lengkap tentang apa yang diinginkan, bukan hanya apa yang diminta — dan inilah yang mengubah AI dari penerka menjadi implementer yang akurat.
02.12 Living Spec: Menjaga Spec Tetap Relevan
Spec yang baik adalah “living document” — terus berkembang seiring sistem berkembang, tapi selalu mencerminkan intended behavior saat ini.
Prinsip Living Spec:
1. Spec berubah lebih dulu, kode menyusul
Jika ada requirement baru, update spec dulu (biasanya di PR terpisah), review, baru implementasi. Bukan sebaliknya.
2. Changelog yang akurat
Setiap perubahan spec didokumentasikan di changelog dengan alasan yang jelas. Tabel changelog berikut memperlihatkan bagaimana setiap versi punya alasan konkret.
1## Changelog
2| v | Tanggal | Perubahan | Alasan | Author |
3|---|---------|-----------|--------|--------|
4| 1.3 | 2025-06-15 | Tambah batas 15 menit cancel | UX research: user bingung kalau bisa cancel kapan saja | @budi |
5| 1.2 | 2025-05-20 | Hapus EC4 (guest order) | Out of scope Q2 | @sari |
6| 1.1 | 2025-05-10 | Tambah EC3 concurrent cancel | Bug dari stress test | @andi |
7| 1.0 | 2025-05-01 | Initial spec | - | @budi |Kolom “Alasan” inilah yang membuat changelog berharga: enam bulan kemudian, siapa pun bisa memahami kenapa sebuah keputusan diambil tanpa harus menelusuri chat lama.
3. Deprecated spec tidak dihapus, di-mark
Ketika sebuah spec digantikan, ia tidak dihapus melainkan ditandai deprecated seperti contoh berikut.
1# ~~specs/order/cancel-order-v1.md~~
2# DEPRECATED: 2025-08-01
3# Digantikan oleh: specs/order/cancel-order.md (v2.0)
4# Alasan: Refactor untuk support multi-currency refundDengan menandai (bukan menghapus) spec lama, kamu menjaga jejak sejarah dan mencegah orang tanpa sengaja mengacu ke spec yang sudah tidak berlaku.
02.13 Contoh Lengkap: Spec Order Service Santekno Shop
Agar semua prinsip di atas terasa konkret, berikut contoh spec yang fully fleshed-out untuk fitur cancel order di Santekno Shop.
1# Cancel Order
2# Versi: 1.3
3# Owner: @ihsan-arif
4# Status: Active
5# Dibuat: 2025-05-01
6# Terakhir diupdate: 2025-06-15
7
8---
9
10## User Story
11Sebagai customer Santekno Shop, saya ingin membatalkan order yang belum diproses
12agar saya tidak perlu menunggu jika berubah pikiran, dengan pemulihan stok otomatis.
13
14## Scope
15Mencakup: Cancel order oleh customer via API, restore stok, publish event.
16Tidak mencakup: Proses refund (spec terpisah), cancel oleh admin (spec terpisah).
17
18## Acceptance Criteria
19
20### Happy Path
21- AC1: DELETE /orders/{id} dengan Authorization header valid
22- AC2: Order harus milik user yang melakukan request
23- AC3: Status order harus PENDING pada saat request
24- AC4: Cancel bisa dilakukan dalam 15 menit pertama sejak order dibuat
25- AC5: Setelah cancel: status berubah ke CANCELLED, stok semua item dikembalikan,
26 event ORDER_CANCELLED dipublish ke Kafka
27- AC6: Response: 204 No Content (tidak ada body)
28
29### Error Cases
30- AC7: Order bukan milik user yang request → 404 Not Found (tidak expose existence)
31- AC8: Order tidak ditemukan → 404 Not Found
32- AC9: Status order bukan PENDING → 409 Conflict, error_code: ORDER_NOT_CANCELLABLE,
33 message: "order cannot be cancelled in status {current_status}"
34- AC10: Sudah lebih dari 15 menit sejak order dibuat → 409 Conflict,
35 error_code: CANCEL_WINDOW_EXPIRED,
36 message: "cancellation window has expired"
37
38## Edge Cases
39- EC1: Dua request cancel bersamaan untuk order yang sama →
40 hanya satu berhasil (204 No Content), yang lain mendapat 409
41 Implementasi: SELECT FOR UPDATE di dalam transaction
42- EC2: Kafka publish gagal setelah DB update berhasil →
43 log error level WARNING, tetap return 204 (tidak rollback)
44 Kafka reliability ditangani di level messaging layer
45- EC3: Partial stock restore failure (satu dari N item gagal) →
46 rollback seluruh transaksi, return 500, retry dari client
47- EC4: Order item sudah dihapus (edge case data integrity) →
48 log error, skip item tersebut, restore item lain yang ada
49
50## Non-Functional Requirements
51- NFR1: Response time < 300ms untuk p95 di normal load
52- NFR2: Operasi cancel harus atomic (semua atau tidak ada)
53- NFR3: Audit log untuk setiap cancel action (siapa, kapan, order apa)
54
55## Changelog
56| v | Tanggal | Perubahan | Alasan | Author |
57|---|---------|-----------|--------|--------|
58| 1.3 | 2025-06-15 | Tambah AC4 batas 15 menit | UX feedback | @budi |
59| 1.2 | 2025-05-20 | Tambah EC4 | Data integrity finding | @sari |
60| 1.1 | 2025-05-10 | Tambah EC1 concurrent | Stress test bug | @andi |
61| 1.0 | 2025-05-01 | Initial | - | @budi |Perhatikan bahwa spec selengkap ini tetap bisa dibaca dalam beberapa menit — setiap AC measurable, setiap EC punya behavior yang eksplisit, dan changelog menjelaskan evolusi keputusan. Inilah bentuk source of truth yang siap dipakai tim maupun AI.
02.14 Pertanyaan Review Spec: Checklist untuk Reviewer
Menulis spec yang baik butuh review yang disiplin. Checklist berikut bisa dipakai saat me-review spec orang lain agar tidak ada aspek penting yang terlewat.
1## Spec Review Checklist
2
3### Kelengkapan
4- [ ] User story ada dan jelas (siapa, apa, mengapa)
5- [ ] Minimal 3 AC happy path
6- [ ] Minimal 1 AC error case dengan HTTP status code eksplisit
7- [ ] Minimal 1 EC (edge case)
8- [ ] Scope didefinisikan (apa yang termasuk DAN tidak termasuk)
9
10### Kualitas AC
11- [ ] Setiap AC measurable (bisa ditulis sebagai test)
12- [ ] HTTP status code disebutkan eksplisit untuk setiap error case
13- [ ] Response format didefinisikan (field apa yang dikembalikan)
14- [ ] Error message/code disebutkan jika relevan
15
16### Konsistensi
17- [ ] Tidak konflik dengan spec lain yang sudah ada
18- [ ] Naming konsisten dengan domain glossary
19- [ ] Format enum value konsisten (UPPER_SNAKE_CASE, dll)
20
21### Feasibility
22- [ ] Tidak ada asumsi teknikal yang belum divalidasi
23- [ ] Non-functional requirement realistic dan sudah di-benchmarkChecklist ini mengubah review spec dari “baca sekilas lalu approve” menjadi proses terukur, sehingga kualitas spec tidak bergantung pada mood reviewer di hari itu.
02.15 Template Spec yang Reusable
Agar tim tidak menulis dari nol setiap kali, simpan template berikut di specs/_templates/feature-spec.md untuk dipakai bersama.
1# [Nama Fitur]
2# Versi: 1.0
3# Owner: @[nama-owner]
4# Status: Draft
5# Dibuat: [tanggal]
6# Terakhir diupdate: [tanggal]
7
8---
9
10## User Story
11Sebagai [role], saya ingin [action] agar [benefit/value].
12
13## Scope
14**Termasuk:** [daftar apa yang di-cover]
15**Tidak termasuk:** [daftar apa yang sengaja tidak di-cover]
16
17## Acceptance Criteria
18
19### Happy Path
20- AC1: [kondisi pertama yang harus dipenuhi]
21- AC2: [kondisi kedua]
22- AC3: [minimal 3 AC untuk happy path]
23
24### Error Cases
25- AC[n]: [kondisi error] → [HTTP status] dengan error_code [CODE]
26 message: "[pesan error untuk user]"
27
28## Edge Cases
29- EC1: [kondisi batas/concurrent/unusual] → [behavior yang diharapkan]
30
31## Non-Functional Requirements (hapus jika tidak relevan)
32- NFR1: Response time < [X]ms untuk p[Y]th percentile
33- NFR2: [requirement lain]
34
35## Referensi
36- Terkait spec: [link]
37- ADR: [link ke architecture decision record jika ada]
38
39## Changelog
40| v | Tanggal | Perubahan | Alasan | Author |
41|---|---------|-----------|--------|--------|
42| 1.0 | [tanggal] | Initial spec | - | @[nama] |Dengan template yang di-commit ke repo, memulai spec baru berarti menyalin satu file dan mengisi placeholder — hambatan psikologis “harus mulai dari halaman kosong” pun hilang.
02.16 Anti-Pattern: Yang Tidak Boleh Ada dalam Spec
Spec yang baik juga didefinisikan dari apa yang tidak ada di dalamnya. Empat kontras berikut menunjukkan pola yang harus dihindari beserta versi yang benar.
1Anti-pattern 1: Implementation detail
2❌ "Gunakan pgx.Begin() untuk memulai transaction, kemudian..."
3✅ "Operasi cancel harus atomic — semua berhasil atau semua rollback"
4
5Anti-pattern 2: UI/UX detail
6❌ "Tombol cancel berwarna merah dengan border-radius 8px"
7✅ [UI/UX ada di design spec terpisah, tidak di feature spec]
8
9Anti-pattern 3: Timeline atau estimate
10❌ "Fitur ini harus selesai dalam 3 hari"
11✅ [Timeline ada di project management tool, tidak di spec]
12
13Anti-pattern 4: Naming yang terlalu technical
14❌ "Execute SQL query: UPDATE orders SET status = $1 WHERE id = $2"
15✅ "Status order berubah ke CANCELLED setelah cancel berhasil"Benang merahnya jelas: spec mendefinisikan apa dan kenapa, bukan bagaimana — begitu detail implementasi masuk ke spec, kamu mengunci developer dan membuat spec cepat basi.
02.17 Tooling untuk Mengelola Spec
Spec yang efektif tidak butuh tool khusus, tapi ada beberapa setup yang membantu menegakkan disiplin. Git hook berikut memberi peringatan ketika file Go berubah tapi tidak ada spec yang ikut diupdate.
1# .git/hooks/pre-push (atau via Husky)
2#!/bin/bash
3
4# Cek apakah ada file Go yang berubah tapi spec-nya tidak
5CHANGED_GO=$(git diff --cached --name-only | grep "^internal/")
6CHANGED_SPEC=$(git diff --cached --name-only | grep "^specs/")
7
8if [ -n "$CHANGED_GO" ] && [ -z "$CHANGED_SPEC" ]; then
9 echo "⚠️ WARNING: Go files changed but no spec files updated."
10 echo " Apakah ini perubahan yang tidak mengubah behavior?"
11 echo " Jika ya, tambahkan komentar di commit message: [no-spec-change]"
12 echo " Jika tidak, update spec dulu sebelum push."
13fiHook ini bukan penghalang keras — ia hanya mengingatkan, sehingga developer tetap punya opsi eksplisit untuk perubahan yang memang tidak mengubah behavior. Selain hook, PR template berikut memastikan setiap PR terhubung ke spec.
1## PR: [Nama Fitur]
2
3### Spec Reference
4- [ ] Mengimplementasikan: `specs/[path]/[feature].md` v[X.Y]
5- [ ] Spec tidak berubah (perubahan hanya teknikal, bukan behavior)
6- [ ] Spec diupdate bersamaan dengan PR ini: [link ke perubahan spec]
7
8### AC Coverage
9- [x] AC1: [deskripsi singkat]
10- [x] AC2: [deskripsi singkat]
11- [ ] AC3: [belum diimplementasikan — jelaskan kenapa]
12
13### EC Handling
14- [x] EC1: [handled dengan...]
15- [x] EC2: [handled dengan...]Dengan PR template ini, setiap reviewer langsung melihat AC mana yang sudah tercakup dan mana yang belum — tautan spec-ke-kode menjadi bagian rutin dari proses review, bukan formalitas.
02.18 Tips & Gotchas
💡 Tip 1: Buat spec di branch terpisah sebelum coding — buat branch spec/nama-fitur → tulis spec → buka PR untuk spec review → setelah di-merge, baru buat branch feature/nama-fitur untuk kode. Ini mencegah “coding sambil spec masih draft.”
💡 Tip 2: Spec yang minimal lebih baik dari tidak ada spec — jika tidak punya waktu untuk spec komprehensif, tulis yang minimal: 1 user story + 3 AC + 1 EC. Jangan jadikan “tidak sempurna” sebagai alasan tidak nulis spec.
💡 Tip 3: Gunakan bahasa dari domain, bukan dari implementasi — spec harus bisa dibaca oleh product manager. Jika ada istilah teknikal, tambahkan di glossary.
💡 Tip 4: Link spec dari kode via komentar — praktik kecil ini menjaga traceability dua arah. Contoh komentar di atas function usecase berikut menautkan kode ke AC spesifik.
1// Cancel order sesuai specs/order/cancel-order.md v1.3
2// AC5: stok dikembalikan secara atomic bersama perubahan status
3func (uc *CancelOrderUseCase) Execute(ctx context.Context, input CancelOrderInput) error {
4 // ...
5}Komentar setipis itu membuat siapa pun yang membaca kode langsung tahu ke spec dan AC mana harus merujuk saat menilai apakah implementasi masih benar.
⚠️ Gotcha 1: Spec yang ambigu lebih buruk dari tidak ada spec — “System harus handle error dengan baik” adalah spec yang buruk. Jika kamu tidak bisa menulis test untuk sebuah AC, AC-nya terlalu ambigu.
⚠️ Gotcha 2: Jangan biarkan spec menjadi blocking — spec review tidak boleh jadi bottleneck. Jika review butuh lebih dari 2 hari, ada yang salah dengan proses review-nya — bukan dengan SDD-nya.
⚠️ Gotcha 3: AI bisa generate spec yang terlihat bagus tapi substansinya kosong — jika minta AI generate spec dari deskripsi ambigu, hasilnya formatted dengan baik tapi content-nya tetap ambigu. Kamu yang memutuskan business logic — AI hanya bantu format.
⚠️ Gotcha 4: Spec tidak menggantikan diskusi dengan stakeholder — spec adalah output dari diskusi, bukan pengganti diskusi.
02.19 Spec sebagai Source of Truth di High-Traffic System
Di sistem high-traffic seperti Santekno Shop, ada dimensi tambahan dalam “spec sebagai source of truth”: performansi dan kapasitas harus juga terdokumentasikan. Bagian NFR berikut menunjukkan bagaimana target performa dituangkan secara eksplisit.
1## Non-Functional Requirements untuk Cancel Order
2
3### Performance
4- NFR1: Response time < 300ms untuk p95 di 100 concurrent users
5- NFR2: Response time < 1000ms untuk p99 di 500 concurrent users (load test)
6
7### Availability
8- NFR3: Endpoint ini harus available 99.9% uptime
9- NFR4: Graceful degradation: jika Kafka down, cancel masih berhasil
10 (event dipublish nanti via retry mechanism)
11
12### Load
13- NFR5: Didesain untuk menangani 50 cancel/detik pada peak load
14- NFR6: DB lock (SELECT FOR UPDATE) timeout: 2 detik maksimum
15
16### Monitoring
17- NFR7: Metric yang harus ada: cancel_order_total, cancel_order_errors_total,
18 cancel_order_duration_seconds (histogram)
19- NFR8: Alert jika cancel_order_errors_total/cancel_order_total > 5% dalam 5 menitDengan NFR yang terdokumentasikan di spec, developer tidak perlu “nebak” berapa target performance yang diharapkan — dan ketika ada performance regression, ada baseline yang jelas untuk dibandingkan.
02.20 Ringkasan
“Spesifikasi sebagai source of truth” bukan hanya konsep filosofis — ini praktik engineering yang konkret dengan implementasi yang jelas:
Source of truth yang efektif harus: spesifik tapi tidak terlalu detail, verifiable secara otomatis, punya single ownership, dan versioned dengan git.
Tanpa governance, spec akan outdated. Minimal yang dibutuhkan: spec review sebelum implementasi, spec update bersamaan dengan kode, dan quarterly audit.
Spec dalam konteks AI menjadi “persistent memory” lintas sesi. AI tidak bisa ingat keputusan dari sesi kemarin — tapi bisa membaca file spec yang ada di repository.
Spec tidak bisa menggantikan diskusi, tapi bisa membuat diskusi lebih produktif karena semua pihak bicara dari dokumen yang sama.
Di artikel berikutnya, kita akan melihat ekosistem tools SDD 2025 — Claude Code, Kiro, Cursor, GitHub Spec Kit, dan tools lain yang mendukung workflow ini, serta bagaimana memilih yang tepat untuk kebutuhanmu.