Setiap diagram arsitektur yang pernah saya lihat di wiki salah. Bukan salah secara dramatis. Hanya salah secara diam-diam, bertahap. Layanan yang diberi label “Auth” sudah dipecah menjadi tiga mikroservis enam bulan lalu. Panah yang diberi label “sync call” kini async melalui queue. Database yang diberi label “PostgreSQL” dimigrasi ke sesuatu yang lain saat fire drill dan tidak ada yang memperbarui kotaknya.

Ini bukan kelalaian. Ini fisika. Kode berubah ratusan kali per minggu. Dokumentasi berubah ketika seseorang ingat. Separuh usia diagram arsitektur kurang lebih satu sprint. Setelah itu, diagram tersebut menjadi fiksi.

Tujuannya bukan menulis dokumen yang tidak pernah menyimpang. Tujuannya adalah mendeteksi penyimpangan sebelum dokumen tersebut menyesatkan engineer berikutnya.

Mengapa dokumen membusuk lebih cepat dari kode

Kode memiliki mekanisme koreksi bawaan: kode tersebut berhasil dikompilasi dan lulus pengujian, atau tidak. Dokumentasi tidak memiliki compiler, tidak ada test suite, tidak ada CI gate. Diagram yang salah tetap dirender dengan sempurna. ADR yang basi terbaca sama meyakinkannya dengan ADR yang baru.

Divergensi ini juga bersifat sosial. Engineer memperbarui kode karena build gagal. Mereka memperbarui dokumen karena merasa bersalah. Rasa bersalah adalah scheduler yang tidak andal.

Ketika seorang engineer baru bergabung dan membaca wiki, mereka membangun model mental dari sistem. Jika model tersebut sudah basi enam bulan, mereka akan mengambil keputusan yang memperparah kekacauan yang ada. Dokumentasi yang seharusnya mengurangi gesekan onboarding malah menjadi sumber penyesatan yang halus dan mahal.

Tiga perangkap fiksi

Ada tiga tempat di mana dokumentasi arsitektur paling cepat menjadi fiksi.

Kuburan wiki. Dokumen arsitektur di Confluence, Notion, atau SharePoint berada di luar repo. Dokumen tersebut tidak memiliki riwayat commit yang berkorelasi dengan perubahan kode. Ketika refactor menghapus sebuah layanan, halaman wiki tetap bertahan seperti kota hantu digital. Tidak ada build yang gagal. Tidak ada alert yang berbunyi.

Fiksi diagram. Diagram yang indah diekspor dari Lucidchart atau draw.io dan disematkan ke dalam README terlihat otoritatif. Diagram tersebut juga merupakan gambar statis. Developer berikutnya yang mengubah arsitektur harus membuka tool desain, mencari file sumber, memperbaruinya, mengekspor ulang, dan menyematkannya kembali. Workflow tersebut memiliki tingkat kelangsungan hidup 5%.

README yang serba tahu. README tingkat atas yang mencoba mendokumentasikan setiap layanan, setiap dependency, dan setiap stream data dalam satu file. Dokumen tersebut menjadi mega-dokumen yang ditakuti semua orang untuk disentuh. Pada akhirnya, seseorang yang berani menambahkan catatan: “Bagian ini mungkin sudah usang.” Kemudian yang lain. Lalu seluruh dokumen dibungkus dalam tanda kutip peringatan dan ditinggalkan.

Dokumentasi hidup yang tetap jujur

Solusinya bukan menulis lebih banyak dokumen. Solusinya adalah membuat dokumen tidak dapat dihindari.

Pindahkan dokumen ke dalam repository. Jika dokumentasi tidak berada di pull request yang sama dengan perubahan kode, dokumen tersebut tidak akan diperbarui. ADR, runbook, dan decision log harus berada di docs/architecture/ atau docs/adr/ di samping kode yang mereka deskripsikan. Ketika reviewer melihat refactor tanpa pembaruan dokumen, mereka dapat memblokir merge.

Hasilkan diagram dari kode. Mermaid, PlantUML, dan Structurizr memungkinkan Anda mendefinisikan diagram dalam file teks yang berada di repo. Sebuah job CI merendernya di setiap commit. Ketika arsitektur berubah, sumber diagram berubah bersamanya. Tidak diperlukan tool desain.

<!-- docs/architecture/data-flow.md -->
## Ingestion Pipeline

```mermaid
graph LR
    A[Client SDK] -->|HTTP POST| B[Ingest API]
    B -->|Pub/Sub| C[Event Consumer]
    C -->|Write| D[(ClickHouse)]

Diagram ini dapat direview dalam diff. Ketika pipeline mendapatkan topic Kafka baru, perubahan tersebut muncul di PR yang sama yang menambahkan consumer.

**Pisahkan "apa" dari "mengapa."** Codebase sudah mendeskripsikan apa yang dilakukan sistem. Komentar, nama fungsi, dan tipe mengkodekan struktur saat ini. Dokumentasi harus fokus pada mengapa sistem terlihat seperti itu. Itulah yang menyimpang secara diam-diam: alasan di balik sebuah keputusan, bukan keputusan itu sendiri.

Architecture Decision Records menangkap hal ini. ADR bukanlah spesifikasi. ADR adalah catatan yang dibubuhi timestamp yang berkata: "Pada tanggal ini, karena alasan-alasan berikut, kami memilih ini. Berikut adalah batasan-batasan yang kami terima." Ketika batasan berubah, ADR tersebut digantikan oleh yang baru. Catatan lama tetap ada sebagai riwayat.

## Otomasikan "apa"-nya, tulis "mengapa"-nya

Dokumen arsitektur yang paling jujur adalah yang tidak Anda tulis dengan tangan.

Spesifikasi OpenAPI yang dihasilkan dari kode controller mendeskripsikan permukaan API Anda secara akurat. TypeDoc, RustDoc, atau Javadoc mendeskripsikan tipe internal Anda. Dependency graph yang dihasilkan oleh `cargo tree`, `go mod graph`, atau `webpack-bundle-analyzer` menunjukkan struktur module yang sebenarnya.

Untuk batasan arsitektur tingkat tinggi, pengujian arsitektur otomatis berfungsi sebagai safety net. Di Java, ArchUnit dapat menegakkan aturan seperti "tidak ada package di `domain` yang boleh bergantung pada `infrastructure`." Di Python, `import-linter` melakukan hal yang sama. Di Go, Anda dapat menulis pengujian kecil yang menelusuri AST dan gagal saat build jika import terlarang muncul.

```java
// This test fails the build if architecture rules break.
@ArchTest
static final ArchRule domain_independence =
    noClasses()
        .that().resideInAPackage("..domain..")
        .should().dependOnClassesThat()
        .resideInAPackage("..infrastructure..");

Ketika seorang developer secara tidak sengaja mengimport package yang salah, build gagal seketika. Dokumen arsitektur tidak perlu memperingatkan mereka. Compiler yang melakukannya.

Trade-off yang tidak diakui siapa pun

Dokumentasi hidup tidak gratis. Dokumentasi hidup membutuhkan waktu review, menit CI, dan perdebatan sesekali tentang apakah sebuah perubahan memerlukan ADR baru.

Tidak setiap sistem membutuhkan diagram. Sebuah monolit tunggal dengan tiga lapisan tidak membutuhkan model C4. Upaya untuk memelihara dokumen yang dihasilkan harus sebanding dengan rasa sakit karena salah memahami sistem. Jika model mental yang salah membuat Anda menghabiskan satu hari untuk debugging, investasikan satu jam untuk diagram. Jika hanya lima menit, tulis komentar.

Dokumen yang dihasilkan juga bisa berbohong. Spesifikasi OpenAPI yang dihasilkan dari kode mendeskripsikan setiap endpoint, termasuk yang internal yang Anda lupa dokumentasikan. Sebuah dependency graph menunjukkan setiap import, termasuk yang melanggar arsitektur Anda. Kebenaran yang dihasilkan akurat tetapi tidak selalu berguna. Anda masih memerlukan kurasi manusia untuk menyoroti apa yang penting.

ADR terakumulasi. Setelah dua tahun, Anda mungkin memiliki tiga puluh ADR di docs/adr/. Sebagian besar tidak relevan. Solusinya bukan menghapusnya. Solusinya adalah menandainya dengan jelas: status: superseded dengan tautan ke penggantinya. Riwayat memiliki nilai. Kebingungan tidak.

Setup minimal yang berfungsi

Anda tidak membutuhkan platform dokumentasi. Anda membutuhkan tiga hal di repo Anda.

  1. docs/adr/YYYY-MM-DD-title.md untuk keputusan. Gunakan template ringan:
# ADR 012: Event Storage Backend

- Status: accepted
- Date: 2026-03-15

## Context
We need durable storage for ingestion events with sub-second query latency.

## Decision
Use ClickHouse for hot storage, S3 for cold archival.

## Consequences
- Fast analytical queries on recent data.
- Complex operational footprint compared to PostgreSQL.
- Migration path defined in ADR 013.
  1. docs/architecture/*.md dengan diagram Mermaid untuk batasan sistem dan stream data. Wajibkan pembaruan dokumen di PR yang sama dengan perubahan kode struktural.

  2. Satu architecture test yang menegakkan invariant termahal Anda. Jika Anda hanya memiliki satu aturan, jadikan aturan tersebut yang mencegah refactor menyakitkan terakhir. Tambahkan lebih banyak seiring pertumbuhan sistem.

FAQ

Apakah saya perlu membuat diagram untuk setiap mikroservis?

Tidak. Buat diagram untuk batasan di mana tim menyerahkan, di mana data melintasi zona kepercayaan, dan di mana kegagalan merambat. Diagram layanan CRUD internal Anda biasanya sia-sia. Diagram layanan mana yang memanggil payment gateway biasanya bernilai.

Bagaimana jika tim saya sudah menggunakan Confluence?

Cerminkan dokumen kritis di repo dan berikan tautan keluar. Sumber kebenaran tetap di git. Wiki menjadi lapisan kenyamanan. Jika wiki menyimpang, engineer tahu di mana menemukan versi yang sebenarnya.

Berapa banyak ADR yang terlalu banyak?

Tidak ada batas atas, tetapi ada batas keterbacaan. Jika seorang engineer baru tidak dapat memindai docs/adr/ dan memahami evolusi sistem dalam sepuluh menit, tambahkan index. Kelompokkan berdasarkan subsistem. Tandai catatan yang digantikan dengan jelas.

Bagaimana dengan wiki untuk stakeholder non-teknis?

Product manager dan eksekutif membutuhkan ringkasan tingkat tinggi. Hasilkan ringkasan tersebut dari index ADR. Jangan memelihara narasi terpisah. Fakta yang sama harus mengalir dari source code, melalui ADR, ke dalam ringkasan manusia. Satu sumber kebenaran, banyak tampilan.

Mulai dengan satu ADR dan satu pengujian

Anda tidak perlu mengubah budaya dokumentasi Anda minggu ini. Pilih keputusan arsitektural terakhir yang menyebabkan kebingungan. Tulis satu ADR yang menjelaskan mengapa Anda memilih apa yang Anda pilih. Pilih satu invariant yang Anda harap bisa ditegakkan secara otomatis. Tulis satu architecture test yang gagal saat build ketika seseorang melanggarnya.

Dua artefak tersebut akan tetap jujur karena mereka berada di repo, mereka direview dalam PR, dan mereka lulus CI atau tidak dikirim. Semua yang lain, halaman wiki, deck slide, poster konferensi, adalah sekunder. Bagus untuk dimiliki. Mungkin berguna. Kemungkinan besar salah.