
Baca buku ini tahun kedua jadi developer. Telat, tapi better late than never.
Wish dibaca di tahun pertama. Bisa save banyak waktu dan kesalahan.
Buku ini terbit 1999. 25+ tahun lalu. Teknologi berubah drastis - Java masih hot, cloud belum ada, smartphone belum exist, Git belum populer.
Tapi prinsip di buku ini? Masih relevan. Bahkan lebih relevan.
Itu yang bikin buku ini klasik. Bukan tentang teknologi spesifik. Tentang mindset dan pendekatan untuk software development.
Broken Windows Theory
Salah satu konsep paling memorable.
Cerita dari riset kriminologi: kalau ada satu jendela rusak di gedung dan ga diperbaiki, soon semua jendela akan rusak. Karena jendela rusak sinyal: "Ga ada yang peduli. Anything goes."
Begitu ada one sign of neglect, deteriorasi accelerate.
Aplikasi ke codebase:
Satu file dengan kode jelek → "Well, file ini udah messy, jadi ga masalah kalau aku add more messy code."
Satu test yang di-skip → "Kalau satu test di-skip, probably okay untuk skip ini juga."
Satu TODO comment yang never addressed → Soon, codebase penuh dengan TODO yang ignored.
Satu hack "sementara" yang jadi permanen → Technical debt numpuk.
Pengalaman personal
Pernah join project yang codebase-nya udah messy. Ga ada tests. Naming inconsistent. Copy-paste code dimana-mana. Ga ada yang follow standard.
First thought: "Wah, ini jelek."
Second thought: "Well, semua orang nulis kode jelek, jadi probably okay kalau gue juga."
Rasionalisasi. "When in Rome..."
Hasilnya? Codebase jadi worse. Velocity slower. Bug rate tinggi. Semua frustasi.
Ga ada yang mau perbaiki karena "terlalu banyak" dan "bukan tanggung jawab gue."
Broken windows dimana-mana.
Perbaikannya
Buku suggest: perbaiki broken windows saat kamu lihat.
Jangan biarkan membusuk. Jangan rasionalisasi. Jangan bilang "nanti aja."
Nanti never comes.
Kalau lihat kode jelek saat kerja sesuatu, refactor. Leave code better than you found it (Boy Scout Rule).
Small improvements compound. Seperti broken windows compound jadi decay, fixed windows compound jadi quality.
Bagian susah: disiplin. Especially saat deadline pressure, saat tim ga peduli, saat manager cuma peduli feature.
Tapi long-term, ini yang pisahkan good codebase dari maintenance nightmare.
Don't Repeat Yourself (DRY)
Probably prinsip paling terkenal dari buku ini.
Ide simple: setiap piece of knowledge harus punya single, unambiguous representation dalam system.
Bukan cuma "jangan copy-paste code." Lebih dalam dari itu.
Level 1: Duplikasi kode (obvious)
// Jelek
function hitungDiskonPremium(harga) {
return harga * 0.9;
}
function hitungDiskonBiasa(harga) {
return harga * 0.95;
}
Duplikasi: logic perhitungan diulang. Kalau formula diskon berubah, update dua tempat.
// Lebih baik
function hitungDiskon(harga, rateDiskon) {
return harga * (1 - rateDiskon);
}
Ini obvious. Most developers tahu ini.
Level 2: Duplikasi logic (less obvious)
// Validasi di frontend
if (!email.includes('@')) {
tampilkanError('Email tidak valid');
}
// Validasi sama di backend
if (!email.includes('@')) {
return error('Email tidak valid');
}
Duplikasi: logic validasi. Kalau aturan validasi email berubah (misalnya, harus ada domain), update frontend DAN backend.
Lebih baik: shared validation library atau schema (Zod, Yup, dll).
Level 3: Duplikasi knowledge (subtle)
Schema database hardcoded di banyak tempat:
- SQL queries ditulis manual
- Model ORM
- Type response API
- Type frontend
Schema berubah? Update 4 tempat. Mudah miss satu. Bugs terjadi.
Lebih baik: single source of truth. Generate types dari schema. Pakai ORM dengan benar.
Kenapa DRY penting
Bukan cuma tentang mengetik lebih sedikit kode.
Tentang maintainability. Satu perubahan → satu tempat untuk update. Less chance of inconsistency.
Tentang reliability. Ga ada risk update satu tempat dan lupa yang lain.
Tentang clarity. Single source of truth → less confusion.
Pelanggaran DRY adalah silent killer. Ga immediately obvious tapi accumulate over time jadi maintenance nightmare.
Orthogonality (Independensi Komponen)
Konsep ini dipinjam dari matematika/geometri.
Dua komponen orthogonal kalau perubahan di satu tidak affect yang lain.
Contoh: X-axis dan Y-axis orthogonal. Bergerak along X ga mengubah posisi Y.
Di software: modul orthogonal kalau independen. Ubah satu modul → yang lain ga terpengaruh.
Orthogonality jelek
class UserService {
simpanUser(user) {
// Simpan ke database
db.save(user);
// Kirim email notifikasi
emailService.kirim(user.email, 'Selamat datang!');
// Log analytics
analytics.track('user_signup', user.id);
// Update cache
cache.set(user.id, user);
}
}
UserService melakukan terlalu banyak hal. Tightly coupled ke email, analytics, cache.
Kalau email service down, user save gagal. Kalau analytics berubah, modify UserService. Kalau caching strategy berubah, modify UserService.
Ga orthogonal. Perubahan di satu area ripple kemana-mana.
Orthogonality bagus
class UserService {
simpanUser(user) {
db.save(user);
eventBus.publish('user_created', user);
}
}
// Handler terpisah
emailService.subscribe('user_created', (user) => {
kirim(user.email, 'Selamat datang!');
});
analyticsService.subscribe('user_created', (user) => {
track('user_signup', user.id);
});
cacheService.subscribe('user_created', (user) => {
cache.set(user.id, user);
});
UserService cuma bertanggung jawab untuk saving. Concern lain dihandle independently via event bus.
Email service down? User save tetap sukses. Analytics berubah? Ga perlu touch UserService. Caching strategy berubah? Ga perlu touch UserService.
Orthogonal. Independent. Maintainable.
Benefit
- Testing lebih mudah - test tiap komponen secara independen
- Perubahan lebih mudah - modify satu hal tanpa break yang lain
- Pemahaman lebih mudah - tiap komponen punya tanggung jawab jelas
- Reusability - komponen orthogonal lebih likely reusable
Struggle personal
Early di career, gue sering bikin tightly coupled code. "It works" cukup.
Lalu maintenance phase datang. Satu small change break tiga hal lain. Fix satu bug, create dua lagi. Regression dimana-mana.
Learned hard way: upfront effort untuk design komponen orthogonal save massive time later.
Ga selalu mudah. Kadang coupling unavoidable. Tapi default mindset harus: "Gimana caranya bikin ini independent?"
Tracer Bullets vs Prototypes
Buku ini bedakan antara dua pendekatan untuk proyek yang uncertain.
Tracer bullets
Konsep militer: peluru dengan phosphorous yang ninggalin jejak visible. Penembak pakai mereka untuk aim di kegelapan.
Tembak tracer bullet. Lihat kemana perginya. Adjust. Tembak lagi. Eventually kena target.
Di software: build end-to-end skeleton yang thin tapi functional.
Contoh: bikin app e-commerce.
Pendekatan tracer bullet:
- Registrasi user simple (tanpa validasi, storage basic)
- Product listing simple (produk hardcoded, display basic)
- Cart simple (in-memory, basic add/remove)
- Checkout simple (payment dummy, ga ada email)
End-to-end flow works. Skeleton in place. Lalu iterate, add features, improve each part.
Key: kode real, meant to stay. Bukan throwaway. Foundation untuk final system.
Prototypes
Build mockup cepat untuk explore pertanyaan spesifik.
Contoh: "Apakah users paham navigasi ini?"
Build clickable mockup. Test dengan users. Dapat feedback. Buang mockup.
Key: kode disposable. Ga meant untuk production. Cuma untuk answer pertanyaan atau validate assumption.
Perbedaannya penting
Tracer bullets: build foundation real, iterate di atasnya.
Prototypes: explore dan discard.
Mixing these up berbahaya.
Treating prototype sebagai foundation → technical debt nightmare. Kode yang ga pernah meant untuk production jadi production.
Treating tracer bullets sebagai prototype → wasted effort. Buang foundation bagus dan rebuild dari scratch.
Pengalaman personal
Early project, PM mau "quick prototype" untuk demo ke stakeholders.
Gue build it quick and dirty. Hardcoded values. Ga ada error handling. Kode jelek.
PM suka. "Yuk ship ini!"
"Tapi... ini prototype. Ga production-ready."
"Tambahin fixes aja. Kita lagi deadline ketat."
Hasilnya: prototype jadi production. Spent months fixing issues yang bisa dihindari kalau dibangun properly dari awal.
Lesson: be clear upfront. Tracer bullet atau prototype? Kalau potentially going to production, build it right dari awal even if takes longer.
Good Enough Software
Konsep controversial.
"Good enough" kedengarannya kayak excuse untuk mediocrity.
Tapi buku argue: perfection is enemy of done.
Shipping good software hari ini > shipping perfect software never.
Spectrum kualitas
Perfect software: zero bugs, handle semua edge cases, kode beautiful, complete test coverage, full documentation.
Juga: never ships. Infinite development time.
Terrible software: crashes constantly, loses data, security holes everywhere.
Ships cepat. Lalu dies cepat karena unusable.
Good enough software: works reliably untuk intended use cases, handle common scenarios gracefully, punya acceptable bugs di rare edge cases.
Ships. Dapat users. Dapat feedback. Improves iteratively.
Tahu audience kamu
Konteks berbeda butuh kualitas berbeda.
Medical device software, banking systems, aerospace: butuh very high quality. Lives atau billions of dollars at stake.
Internal tool untuk 10 orang: bisa tolerate beberapa bugs. Kalau crash, reload. Bukan end of world.
MVP untuk startup validation: functionality matters more than polish. Ship cepat, learn cepat, iterate.
Struggle personal dengan perfeksionisme
Gue sering stuck dalam perfectionism trap.
"Kode belum clean enough."
"Test coverage baru 85%, butuh 100%."
"Performance bisa dioptimasi lebih."
"Documentation belum complete."
Hasilnya: feature delayed. Opportunity missed. User frustasi.
Sadar: perfect bukan goal. Value delivery is.
Ship good enough. Dapat feedback. Improve based on real usage, bukan imagined requirements.
Hard lesson: users prefer imperfect feature hari ini over perfect feature dalam 3 bulan.
Balance
Bukan excuse untuk ship sampah.
"Good enough" means: meets requirements, works reliably untuk intended use, maintainable, ga ada critical bugs.
Bukan means: "Kinda works, ship aja."
Tahu dimana invest quality effort (core functionality, security, data integrity) dan dimana accept good enough (UI polish, edge case handling, performance optimization beyond needed).
Stone Soup and Boiled Frogs
Dua analogi tentang perubahan dalam organisasi.
Stone Soup
Folk tale: travelers datang ke desa, ga ada yang mau share makanan.
Travelers bilang: "Kita bikin stone soup!" Taruh batu dalam pot air, mulai rebus.
Penduduk desa curious: "Stone soup?"
Travelers: "Iya! Tapi bakal lebih enak dengan bawang..."
Satu penduduk kasih bawang.
"Bakal lebih enak lagi dengan wortel..."
Penduduk lain kasih wortel.
Eventually, pot penuh dengan sayuran, daging, bumbu. Sup enak. Semua share.
Lesson: jadi katalis untuk perubahan.
Mau introduce testing tapi tim resistant?
Jangan bilang "Kita harus nulis tests untuk semuanya!"
Instead: tulis tests untuk kode kamu. Tunjukkan benefit. Orang lain lihat value, gradually adopt.
Mau improve code quality?
Jangan bilang "Kita harus refactor seluruh codebase!"
Instead: refactor area kecil. Tunjukkan improvement. Orang lain follow.
Orang resistant to perubahan besar. Tapi small, incremental improvements lebih mudah diterima.
Boiled Frogs
Katak di pot air. Slowly panaskan air. Katak ga notice perubahan gradual. Eventually direbus sampai mati.
(Secara ilmiah ga benar, tapi analoginya useful.)
Lesson: notice gradual decay.
Codebase ga jadi unmaintainable overnight. It's gradual:
- Satu test di-skip → test coverage drop ke 80% → 60% → none
- Satu hack ditambah → another → technical debt accumulates → refactor impossible
- Satu deadline rushed → code quality suffer → jadi norma → quality never recovers
Kamu katak. Air makin panas. Notice? Atau tunggu sampai terlambat?
Aplikasi personal
Pakai pendekatan stone soup untuk introduce TypeScript di JavaScript codebase.
Tim skeptis: "Migration terlalu banyak kerja. Ga worth it."
Ga force. Mulai nulis file baru dalam TypeScript. Gradually convert utilities yang frequently used.
Tim lihat benefit: better autocomplete, catch bugs early, easier refactoring.
After 6 bulan, majority tim voluntarily nulis TypeScript. Ga perlu mandate.
Juga learned boiled frog lesson hard way.
Join codebase yang "cuma butuh small fixes." Over bulan-bulan, sadar ini massive technical debt. Ga bisa fix incrementally lagi. Butuh complete rewrite.
Seharusnya notice lebih awal. Seharusnya push back lebih keras. Was the boiled frog.
Estimasi untuk Hindari Surprises
Buku emphasize pentingnya estimasi.
Bukan untuk commit ke deadline. Untuk understand scope dan communicate uncertainty.
Kenapa developer benci estimasi
"Berapa lama ini?"
"Ga tahu. Banyak unknowns."
"Kasih angka aja."
"Fine. 2 minggu."
"Great! Gue bilang client 2 minggu."
Lalu 2 minggu jadi hard deadline. Kalau telat, salah developer.
Makanya kita benci.
Pendekatan lebih baik
Estimasi bukan komitmen. Estimasi adalah understanding + communication.
Instead of single number, kasih range dan confidence level.
"Best case: 1 minggu. Likely case: 2 minggu. Worst case: 4 minggu. Confidence: medium, karena third-party API integration ada unknowns."
Sekarang stakeholder punya realistic expectation. Paham uncertainty. Bisa bikin informed decisions.
Break down untuk better estimates
"Berapa lama bikin authentication system?"
Terlalu vague. Ga bisa estimasi.
Break down:
- Registrasi user: 2 hari
- Login/logout: 1 hari
- Password reset: 1 hari
- Email verification: 1 hari
- OAuth integration: 3 hari
- Testing: 2 hari
Total: ~10 hari. Plus buffer untuk unknowns: 12-15 hari.
Tiba-tiba estimasi lebih realistic.
Track estimates vs actuals
Estimasi: 2 minggu.
Actual: 3 minggu.
Jangan cuma move on. Reflect:
- Kenapa underestimate?
- Unknown apa yang muncul?
- Apa yang take longer dari expected?
Learn. Estimasi berikutnya lebih baik.
Over time, estimates improve. Bukan karena crystal ball. Karena understanding velocity kamu dan typical unknowns.
Pengalaman personal
Early career, terrible di estimasi. Selalu underestimate.
Estimasi 1 hari, takes 3 hari. Estimasi 1 minggu, takes 1 bulan.
Frustasi. Feels like failure.
Lalu learned: tambah buffer untuk unknowns. Track actuals. Calibrate.
Sekarang estimates lebih realistic. Not perfect. Tapi stakeholders rarely surprised.
Juga learned: push back pada "kasih angka aja" pressure. Explain uncertainty. Kasih range. Educate stakeholders.
Lebih baik set realistic expectation upfront daripada overpromise dan underdeliver.
Refactor Early, Refactor Often
Kode membusuk. Requirements berubah. Pemahaman meningkat.
Refactoring bukan optional nice-to-have. Ini essential maintenance.
Kapan refactor
Buku suggest: terus-menerus.
Lihat duplikasi? Refactor.
Lihat naming unclear? Refactor.
Lihat logic overcomplicated? Refactor.
Learn better pattern? Refactor.
Jangan tunggu "refactoring sprint." Ga work. Never prioritized.
Refactor sebagai bagian dari normal development. Leave code better than you found it.
Apa yang bikin refactoring safe
Takut refactoring common: "Bagaimana kalau gue break something?"
Valid fear tanpa safety net.
Safety net = tests.
Good test coverage → refactor dengan percaya diri. Tests catch regressions.
Ga ada tests → refactoring risky. Bisa break functionality tanpa sadar.
Makanya buku emphasize testing throughout.
Tipe refactoring
Small refactoring (daily):
- Rename variables untuk clarity
- Extract functions untuk reusability
- Hapus dead code
- Simplify conditionals
Low risk. High value. Lakukan constantly.
Medium refactoring (weekly):
- Restructure modules
- Ubah data structures
- Improve architecture dalam bounded context
Moderate risk. Butuh tests. Plan carefully.
Large refactoring (jarang):
- Rewrite major components
- Ubah fundamental architecture
- Migration ke new framework/language
High risk. Butuh strong justification. Sering lebih baik build new dan migrate incrementally.
Struggle personal
Sering stuck antara "refactor sekarang" vs "ship feature dulu."
Deadline pressure → skip refactoring → accumulate technical debt → slower velocity → more pressure → more shortcuts.
Vicious cycle.
Learned: refactoring bukan terpisah dari feature work. Ini bagian dari itu.
Building feature dalam messy code? Refactor dulu, lalu add feature. Takes longer short-term, faster long-term.
Juga learned: communicate technical debt cost ke stakeholders. "Shipping feature ini takes 2 hari dalam clean codebase, 5 hari dalam current messy codebase. Bisa gue spend 1 hari refactoring dulu, lalu 2 hari feature, total 3 hari instead of 5?"
Biasanya dapat approval kalau framed sebagai efficiency, bukan perfectionism.
Power of Plain Text
Buku ini emphasize: simpan data dalam human-readable formats.
Binary formats proprietary. Tools break. Formats obsolete. Data locked.
Plain text universal. Survive. Readable. Editable. Versionable.
Contoh
Configuration:
- Jelek: binary config files, proprietary formats
- Bagus: JSON, YAML, ENV files
Documentation:
- Jelek: Word docs, proprietary formats
- Bagus: Markdown, plain text
Data exchange:
- Jelek: custom binary protocols
- Bagus: JSON, XML, CSV
Code:
- Sudah plain text (bagus!)
Kenapa ini penting
Future-proof: Plain text readable puluhan tahun kemudian. Binary formats? Good luck.
Tool-agnostic: Any editor bisa open plain text. Binary butuh software spesifik.
Diffable: Git tunjukkan changes dalam plain text easily. Binary files? Cuma "changed."
Debuggable: Bisa inspect, edit, fix plain text manually. Binary? Butuh special tools.
Composable: Unix philosophy: small tools chain together. Works dengan plain text.
Trade-offs
Plain text not always best:
Performance: Binary sering faster to parse, smaller size.
Security: Plain text credentials berbahaya. Encrypt sensitive data.
Complexity: Beberapa data structures awkward dalam plain text.
Balance: default ke plain text kecuali strong reason otherwise.
Pengalaman personal
Kerja di project dengan config dalam SQLite database. "Lebih terstruktur! Lebih mudah di-query!"
Problem: ga bisa diff config changes dalam Git. Ga bisa edit quickly. Butuh special tool.
Setiap config change butuh app restart untuk migrate database. Pain.
Migrate ke YAML files. Instantly better. Bisa lihat history. Bisa edit easily. Bisa review changes.
Lesson learned: plain text default kecuali compelling reason.
Bottom line
"The Pragmatic Programmer" adalah essential reading untuk software developers.
Bukan untuk teknik spesifik (those date quickly).
Untuk mindset dan prinsip yang bikin kamu better developer regardless of stack.
Kalau cuma baca satu buku software engineering, jadikan ini.
Tapi warning: membaca tidak cukup. Harus practice dan internalize prinsip-prinsipnya.
Mudah dibaca dan setuju. Susah actually apply consistently.
Gue udah baca buku ini 3 kali over years. Setiap kali, paham lebih dalam. Setiap kali, sadar berapa banyak gue masih perlu improve.
Itu hallmark dari great book: re-readable, always relevant, always teaching.
Pragmatic programming bukan destination. It's journey. Continuous improvement.
Mulai journey. Baca buku. Apply prinsip. Jadi better craftsperson.
Future self kamu (dan teammates, dan users) akan terima kasih.
