karawaci.kode

2026-07-19 · 6 min

ADR (Architecture Decision Records) Tim 15 Engineer

Dua tahun lalu, tim engineering enterprise yang saya advise (modular monolith bank — lihat Spring Boot modular monolith Bank Indonesia) tumbuh dari 8 ke 15 engineer dalam 6 bulan. Decisions mulai hilang ditangkap. “Kenapa kita pilih Postgres bukan MongoDB?” — tidak ada yang tahu, engineer original sudah pindah perusahaan.

Implementasi ADR. Hari ini, 84 ADR active, 22 superseded, dan saya tahu persis kenapa kita pilih apa. Share format, workflow, dan kapan ADR jadi liability bukan asset.

Konteks tim

  • Ukuran: 15 engineer (8 backend, 4 frontend, 2 SRE, 1 architect).
  • Distribusi: 10 Jakarta (Sudirman/Kuningan), 3 Tangerang, 2 remote (Bandung + Yogyakarta).
  • Domain: bank menengah Indonesia, payment + core banking.
  • Stack: Java + Spring Boot + Postgres + Kafka + Kubernetes.
  • Lifecycle: greenfield 2 tahun lalu, sekarang stable production dengan iteration.

Why ADR

Pain point sebelum ADR:

  • “Kenapa pakai Postgres bukan MongoDB?” — 4 engineer kasih 4 jawaban berbeda.
  • Tech debt: implementation tidak match architectural intent karena intent tidak dicatat.
  • Onboarding: junior engineer butuh 6-8 minggu untuk paham “the way we do things”.
  • Repeated debate: tiap 3-4 bulan ada engineer baru yang re-open keputusan lama.

ADR solve ini dengan: record kenapa, bukan apa (kode sudah show apa).

Format yang dipakai

Setelah trial 3 format (Nygard, MADR, custom), kami stabilize di MADR (Markdown Architecture Decision Records) dengan modifikasi sedikit:

# ADR-042: Pakai Spring Modulith untuk Module Boundary

**Status**: Accepted  
**Date**: 2026-03-14  
**Deciders**: @reza, @lead-arch, @platform-lead  
**Consulted**: @security-officer, @senior-be  
**Informed**: tim engineering, product manager

## Context & Problem Statement

Monolith yang sedang kami bangun butuh enforce module boundary di compile-time, bukan via discipline manual. Tim sudah punya pengalaman buruk di proyek lama dimana service boundary di-violate diam-diam.

Pertanyaan: tooling apa yang enforce module dependency rule + kasih runtime support untuk async inter-module communication?

## Decision Drivers

- Enforce di build time (fail CI), bukan code review-only.
- Async messaging in-process tanpa external broker untuk same-monolith communication.
- Spring Boot 3.x compatible (stack kami sudah committed).
- Active maintenance + community.

## Considered Options

1. **Spring Modulith** (Spring's own modular monolith framework)
2. **JPMS (Java Platform Module System)** standalone
3. **ArchUnit only** (runtime test framework)
4. **Custom Maven plugin** untuk dependency rule

## Decision Outcome

**Chosen**: Spring Modulith.

Reasoning:
- Native Spring integration (event publishing transactional outbox built-in).
- Compile-time module verification via `ApplicationModules.of(...).verify()`.
- Tooling untuk visualize module graph (PlantUML output).
- Production-ready 1.x, dengan roadmap clear.

## Consequences

### Positive
- Module dependency enforced di CI (fail build kalau violate).
- Inter-module async communication semantics jelas (event listener + outbox).
- Documentation auto-generated dari annotations.

### Negative
- Spring Modulith 1.x ada quirk dengan event handler annotation discovery.
- Coupling ke Spring ecosystem (mitigasi: tidak masalah karena kita sudah committed Spring).

### Neutral
- Tim baru butuh 1-2 minggu untuk paham module-info convention.

## Alternatives Considered & Rejected

- **JPMS standalone**: too low-level untuk async messaging, butuh banyak custom code.
- **ArchUnit only**: runtime check, telat detect violation (production deploy).
- **Custom Maven plugin**: maintenance burden, no community support.

## Compliance / Audit Notes

Module boundary enforce satisfies ISO 27001 control A.14.2.5 (system architecture documentation).

## Follow-ups

- [ ] Setup CI step Spring Modulith verification (target: 2026-04-01).
- [ ] Train team Spring Modulith convention (workshop scheduled 2026-04-10).
- [ ] Migrate existing 12 module ke `package-info.java` annotation (target: 2026-05-30).

## References

- Spring Modulith documentation: ...
- ADR-008 (Modular Monolith over Microservices): supersedes context here.
- POC report internal: confluence/...

Workflow

Trigger untuk write ADR

Kami define: ADR mandatory untuk decisions yang:

  1. Cross-team impact: affect > 2 squad.
  2. Reversal cost > 4 minggu engineering: hard to undo later.
  3. Touch core domain: payment flow, account model, security boundary.
  4. External commitment: API contract, partner integration, compliance.
  5. Tool/framework adoption: new dependency yang akan jadi load-bearing.

Tidak butuh ADR untuk: pilih library kecil, rename variable, optimization local.

Author + review process

  1. Engineer who initiate change tulis draft ADR di /docs/adr/NNN-title.md.
  2. PR ke main branch, label adr-proposed.
  3. Review minimum: 2 senior engineer + architect (atau equivalent).
  4. Open meeting kalau ada disagreement (ADR review meeting Selasa siang).
  5. Merge = Status “Accepted”. Atau revise + re-PR. Atau abandon = Status “Rejected”.

Status lifecycle

  • Proposed: PR open, under review.
  • Accepted: merged, in effect.
  • Deprecated: tidak lagi best practice tapi belum di-replace.
  • Superseded by ADR-XXX: explicit reference ke pengganti.

ADR tidak di-delete. Yang sudah superseded tetap di repo dengan link ke pengganti.

Setelah 2 tahun

MetricValue
Total ADR84
Active (Accepted)58
Superseded22
Deprecated4
Rejected (never accepted)12
Avg ADR per quarter10.5
Engineer who authored ADR13/15

13 dari 15 engineer pernah author ADR. Yang 2 belum: 1 junior baru join 3 bulan, 1 yang fokus frontend (jarang ADR).

ADR yang paling impactful

Top 5 menurut team retro:

  1. ADR-008: Modular Monolith over Microservices (foundational, set the whole approach).
  2. ADR-023: Java 21 + Virtual Threads adoption (lihat Java Virtual Threads).
  3. ADR-031: Saga Orchestration via Temporal (lihat Event Sourcing Saga).
  4. ADR-042: Spring Modulith adoption (referenced above).
  5. ADR-067: OAuth 2.1 + PKCE Spring Authorization Server (lihat OAuth 2.1 Spring).

ADR-008 di-reference di 47 ADR lain. Foundational decision punya leverage besar.

Kapan ADR jadi liability

1. ADR diabaikan saat decision

Yang menyedihkan: ada 12 ADR rejected, banyak yang menjadi rejected karena saat review, alternative yang lebih baik muncul. Tapi 4 ADR rejected karena tim “lupa baca dulu” — engineer bikin keputusan baru tanpa lihat ADR existing yang sudah cover topic.

Mitigasi:

  • ADR index searchable (tag, keyword).
  • PR template include checklist “have you searched relevant ADR?”.
  • Architect quarterly review.

2. ADR review fatigue

Bulan ke-8, ADR submission frekuensi naik ke 18/quarter. Review meeting jadi 90 menit. Tim mulai approve formality, tidak deep engage.

Fix:

  • Right-size: tidak semua decision butuh ADR formal. Define threshold tight.
  • Async review default: meeting hanya kalau disagreement.
  • Limit 1 ADR per author per minggu.

ADR frekuensi turun ke 10-12/quarter, review depth meningkat.

3. ADR write tanpa benar-benar evaluate alternatives

Beberapa ADR awal cuma list “kami pilih X” tanpa proper alternatives analysis. Setelah 6 bulan, ada engineer baru yang mempertanyakan: kenapa X tidak Y?

Fix: template enforce minimal 2 alternative + rejection reasoning. Reviewer check “alternatives considered” section quality.

4. ADR sudah accepted tapi tidak di-follow di code

ADR-018: “Pakai jOOQ untuk SQL builder, hindari raw SQL string concatenation”.

6 bulan kemudian, audit show 8 modul masih pakai raw SQL string. ADR tidak enforced di CI.

Fix:

  • Setiap ADR dengan “machine-checkable” rule → add to ArchUnit test atau lint rule.
  • Quarterly ADR compliance audit by architect.

5. ADR jadi changelog history

Beberapa ADR ditulis sebagai “kami akan migrate X ke Y” — itu changelog, bukan architecture decision. Yang ADR-worthy adalah “kami pilih pattern Y over Z karena …”.

Fix: clarify scope. ADR = WHY, bukan WHAT.

ADR untuk team distributed

Setengah tim remote, ADR jadi anchor async communication. Engineer di Yogyakarta bisa read ADR sebelum sync meeting, datang dengan context.

Tools yang kami pakai:

  • ADR di GitHub repo (search-able, version-controlled, PR-reviewable).
  • Mermaid diagrams di ADR (rendered di GitHub).
  • Cross-link antar ADR via shortlink.
  • Dokumentasi index ADR di Confluence (for non-engineer stakeholder).

Kapan tidak rekomendasi ADR

  1. Tim < 5 engineer: communication ad-hoc + code review enough. ADR overhead > benefit.
  2. Startup pre-PMF: decisions changing weekly, ADR jadi out-of-date faster than written.
  3. Tim 1-2 senior dengan banyak junior: junior tidak punya context untuk meaningful contribute ke ADR. Senior nulis ADR untuk dirinya sendiri = waste.

Verdict

Untuk tim engineering 10-30 di organisasi dengan domain kompleks dan tenure mixed: ADR adalah investasi yang membayar dirinya sendiri dalam 12-18 bulan. Tanpa ADR, knowledge bus factor tinggi dan onboarding lama.

Bukan magic. 84 ADR dalam 2 tahun = banyak deliberation, banyak debate, banyak revisi. Tapi setiap engineer baru sekarang produktif dalam 3-4 minggu (sebelumnya 6-8). Customer-facing impact: tidak ada. Internal velocity: signifikan.

Lihat juga legacy modernization 3 tahun untuk konteks bagaimana ADR membantu navigate large project.

Ditulis oleh Reza Pradipta