a-philosophy-of-software-design

oleh Rob ZappBelum ada pemasanganBelum ada sukaDiperbarui 8 Oktober 2026Kategori: Rekayasa

Apa fungsinya

Gunakan saat menulis, mengubah, atau meninjau kode kapan pun perubahan menambahkan nama yang diekspor atau dapat diimpor, membuat modul, kelas, komponen, helper, hook, layanan, atau pembungkus, memusatkan kode yang berulang, atau mengubah API. Aturan Ousterhout (modul dalam, penyembunyian informasi, menurunkan kompleksitas) plus tes invarian untuk berbagi kode, tes biaya pembaca, dan catatan desain yang wajib di akhir.

Pemasangan membuka entri ini di aplikasi desktop AgentsRoom Anda. Jika aplikasinya belum terpasang, Anda akan diarahkan ke halaman unduhan.

SKILL.md

---
name: a-philosophy-of-software-design
description: Gunakan saat menulis, mengubah, atau meninjau kode kapan pun perubahan menambahkan nama yang diekspor atau dapat diimpor, membuat modul, kelas, komponen, helper, hook, layanan, atau pembungkus, memusatkan kode yang berulang, atau mengubah API. Aturan Ousterhout (modul dalam, penyembunyian informasi, menurunkan kompleksitas) plus tes invarian untuk berbagi kode, tes biaya pembaca, dan catatan desain yang wajib di akhir.
---

# Filosofi Desain Perangkat Lunak (John Ousterhout)

## Kapan menggunakan keterampilan ini

Gunakan keterampilan ini saat Anda merancang, menulis, mengubah, atau meninjau kode. Ini berlaku untuk desain modul, perubahan API, dekomposisi, refaktorisasi, penamaan, komentar, pengujian, dan pekerjaan performa. Gunakan juga saat sebuah perubahan terasa canggung, atau saat satu perubahan menyebar ke banyak file.

## Bias yang harus diperbaiki

Kode yang berjalan bukanlah kode yang sederhana. Potongan kecil, pola yang familiar, flag, pembungkus, dan dokumentasi tambahan dapat membuat desain menjadi lebih kompleks. Hal ini terjadi ketika mereka menambah apa yang harus diketahui pembaca, atau ketika mereka membocorkan pengetahuan ke modul lain.

## Aturan pengambilan keputusan

- Ukur sebuah desain berdasarkan seberapa banyak ia mengurangi kompleksitas. Pilih desain yang mengurangi beban pembaca. Kompleksitas memiliki empat tanda. Satu perubahan membutuhkan edit di banyak tempat. Ketergantungan tersembunyi. Langkah-langkah harus terjadi dalam urutan tetap. Pembaca harus mengingat banyak fakta.
- Perlakukan desain sebagai pekerjaan yang berkelanjutan. Patch pertama yang bekerja belum selesai jika membuat perubahan berikutnya menjadi lebih sulit. Untuk keputusan tentang antarmuka, pemisahan modul, atau abstraksi, bandingkan dua atau lebih desain yang mungkin.
- Pilih modul yang dalam. Modul dalam memiliki antarmuka kecil dan menyembunyikan banyak kompleksitas. Tolak layanan pass-through, pembungkus perpustakaan tipis, dan modul pembantu kecil. Tolak ekstraksi yang menambah nama tapi tidak mengurangi beban pembaca.
- Rancang antarmuka berdasarkan apa yang harus diketahui pemanggil, bukan bagaimana implementasinya bekerja. Hindari urutan setup yang rapuh, flag mode, kenop konfigurasi, dan argumen yang menunjukkan pilihan internal.
- Sembunyikan keputusan yang bisa berubah. Contohnya adalah representasi internal, bentuk penyimpanan, protokol, format file, dan trik performa. Pembukuan, normalisasi, dan kasus tepi adalah contoh lain. Simpan masing-masing di dalam modul yang memiliki pengetahuan tersebut.
- Tarik kompleksitas ke dalam modul yang memiliki detail tersebut. Terima implementasi yang lebih kompleks jika memberikan kontrak yang lebih sederhana kepada pemanggil dan menghilangkan pekerjaan berulang di setiap lokasi panggilan.
- Buat modul menjadi umum pada tingkat yang tepat. Jangan sesuaikan modul untuk satu pemanggil. Jangan tambahkan abstraksi samar untuk kebutuhan masa depan. Jauhkan kasus tepi yang jarang dari jalur utama, dan letakkan perilaku khusus di tempatnya sendiri.
- Gabungkan atau pisahkan modul berdasarkan total kompleksitas. Jangan gabungkan atau pisahkan berdasarkan ukuran, urutan kode berjalan, kebiasaan, atau penampilan. Simpan status, perilaku, aturan, dan keputusan terkait bersama. Pisahkan hanya ketika batas baru lebih dalam dan pembaca dapat memahami masing-masing sisi secara sendiri.
- Perkecil set pengecualian. Jika memungkinkan, ubah antarmuka atau aturan sehingga keadaan tidak valid tidak dapat terjadi. Jangan buat setiap pemanggil mengulang kode defensif yang sama.
- Gunakan komentar untuk mengurangi kompleksitas. Tuliskan kontrak antarmuka, aturan yang harus tetap benar, keputusan desain tersembunyi dan alasannya. Juga tuliskan fakta sulit yang tidak perlu diketahui pemanggil. Jangan ulangi kode dalam komentar. Jangan gunakan komentar untuk menyembunyikan nama yang buruk, pemisahan yang buruk, atau alur kontrol yang membingungkan.
- Perlakukan nama, konsistensi, dan kejelasan sebagai informasi desain. Nama memberi tahu pembaca abstraksi, bukan mekanisme. Operasi terkait menggunakan konvensi yang sama. Kode yang mengejutkan pembaca menambah kompleksitas, bahkan jika singkat.
- Tulis pengujian terhadap kontrak publik dan API yang stabil. Uji kompleksitas tersembunyi dan kasus khusus melalui kontrak tersebut. Jangan biarkan kemudahan pengujian memaksa antarmuka yang dangkal atau bocor.
- Tambahkan perubahan performa, pola, paradigma, atau kerangka kerja hanya untuk satu dari dua alasan. Itu mengurangi kompleksitas di basis kode ini, atau bukti menunjukkan bahwa trade-off diperlukan. Sembunyikan setiap optimasi di balik antarmuka yang stabil.

## Sinyal dan respons terhadap masing-masing

- Fitur terasa canggung, atau satu perubahan menyebar ke banyak file, atau peninjau harus menemukan ketergantungan tersembunyi. Respons: cari penyembunyian informasi yang hilang dan modul dangkal. Juga cari langkah dalam urutan tetap, dan kompleksitas yang dibawa pemanggil.
- Anda menambahkan modul, lapisan, layanan, pembantu, pembungkus, atau fasad. Atau Anda menambahkan pola, opsi, callback, atau argumen. Respons: tunjukkan bahwa itu menyembunyikan lebih banyak kompleksitas daripada yang ditambahkan.
- Anda mengubah API. Respons: periksa apa yang harus diketahui pemanggil normal. Pemanggil tidak perlu tahu urutan panggilan, representasi, atau penyimpanan. Pemanggil tidak perlu tahu transport, cache, protokol, atau format file. Pemanggil tidak perlu tahu alur kerja internal atau banyak langkah setup.
- Anda menambahkan kasus khusus, flag, jalur pengecualian, kondisi, atau kontainer yang dapat dilihat pemanggil. Respons: tanyakan dulu apa yang bisa dilakukan modul pemilik sebagai gantinya. Modul tersebut bisa menghilangkan keadaan tidak valid, mengisolasi perilaku tidak biasa, atau memberikan operasi yang lebih kuat.
- Anda memisahkan kode, mengekstrak fungsi, atau menambahkan variabel. Respons: periksa bahwa batas atau nama baru membawa makna. Tidak boleh hanya menambah loncatan, status yang diteruskan, atau langkah perantara yang dapat dilihat pemanggil.
- Kode memiliki fase seperti `prepare`, `process`, dan `finalize`, atau pemanggil harus membangun objek secara bertahap. Respons: periksa bahwa urutan waktu adalah konsep sebenarnya. Jika tidak, atur kode berdasarkan tanggung jawab yang stabil.
- Nama samar, menamai mekanisme, tidak konsisten, atau mengejutkan pembaca. Respons: pikirkan lagi tentang batas abstraksi. Jangan terima nama yang hampir benar.
- Komentar panjang, mengulang kode, menjelaskan antarmuka yang membingungkan, atau menunjukkan bagian internal untuk menjelaskan penggunaan. Respons: ubah abstraksi, atau pindahkan kontrak yang hilang ke dalam antarmuka.
- Anda mengoptimalkan performa. Respons: ukur dulu, lalu sembunyikan optimasi. Jangan korbankan kedalaman modul atau penyembunyian informasi tanpa bukti bahwa trade-off diperlukan.
- Anda menguji atau meninjau. Respons: lihat perilaku publik dan kontrak antarmuka. Juga lihat kompleksitas tersembunyi di balik API yang stabil, dan kasus khusus yang disimpan di balik abstraksi.

## Daftar periksa akhir

- Apakah perubahan tersebut mengurangi upaya untuk memahami, mengubah, memverifikasi, dan memperluas sistem?
- Apakah setiap elemen antarmuka, pembungkus, lapisan, pembantu, opsi, dan nama menyembunyikan cukup kompleksitas untuk membenarkannya?
- Apakah keputusan penting berada di satu tempat? Apakah ketergantungan terlihat? Apakah batasan yang perlu diketahui pemanggil tertulis? Apakah bagian internal yang bisa berubah terlindungi?
- Apakah kasus umum bekerja tanpa langkah tambahan? Apakah kontrol langka, kasus khusus, trik performa, dan detail pengecualian tetap di luar jalur umum?
- Apakah nama tepat dan konsisten? Apakah komentar terkini, tanpa pengulangan kode? Apakah kode mengikuti konvensi yang ada, kecuali ada informasi baru yang memberi alasan untuk mengubahnya?

## Gerbang

Gunakan daftar periksa lengkap saat perubahan menambahkan nama yang dapat diekspor atau diimpor oleh kode lain. Gunakan juga saat perubahan membuat modul, kelas, komponen, pembantu, hook, layanan, atau pembungkus, atau menempatkan kode yang diulang di satu tempat. Penggantian nama, codemod, perubahan konfigurasi, perubahan data, dan perbaikan satu baris tidak memerlukannya.

## Tes invarian: bagikan hanya kode yang berubah bersama

- Ekstrak kode bersama hanya ketika melindungi aturan yang bisa Anda beri nama. Buktinya adalah perubahan bersama: sejarah menunjukkan bahwa salinan diperbaiki atau diubah bersama. Kode yang hanya terlihat mirip dan berubah secara independen adalah sajak. Biarkan sajak sebagai duplikat. Tiga blok serupa tidak membuktikan aturan.
- Perbaikan harus menghilangkan masalah, bukan memindahkannya. Enam cast yang dipindahkan ke satu pembantu cast generik tetap enam cast. Tulis pemetaan bertipe yang disembunyikan oleh cast tersebut.
- Ketika sebuah abstraksi salah, kembalikan kode secara inline dan biarkan duplikasi kembali. Jangan memaksakan abstraksi dengan flag.
- Jangan membagi kode hanya karena ukurannya. Satu modul 400 baris yang menyembunyikan satu keputusan lebih baik daripada empat modul 100 baris yang bocor gabungan yang sama.
- Membaca mekanis Clean Code atau SOLID (fungsi sangat kecil, satu kelas untuk setiap tanggung jawab) menghasilkan modul dangkal. Keterampilan ini lebih diutamakan daripada tekanan tersebut.

## Biaya pembaca: tes ketiga

Tes kedalaman dan tes invarian memutuskan apakah batas harus ada. Tes biaya pembaca memutuskan apakah kode di sekitar batas mudah diubah. Pembaca berikutnya, orang atau agen, membayar untuk setiap baris yang harus mereka baca. Agen membayar dalam token. Agen menemukan kode dengan pencarian teks, pembacaan parsial, pemeriksaan tipe, dan tes.

- **Dapat ditemukan.** Gunakan satu nama untuk setiap konsep. Eja sama di mana-mana, sehingga pencarian teks biasa menemukannya. Cacat: nama dibangun dari string, pengkabelan melalui efek samping impor, dua nama untuk satu konsep. Rantai ekspor ulang yang menyembunyikan definisi juga cacat.
- **Berhenti awal.** Letakkan kontrak di atas file atau di atas ekspor. Katakan apa yang dijanjikan, apa yang disembunyikan, dan apa yang tidak pernah dilakukan. Maka pembaca bisa berhenti lebih awal.
- **Dapat diperiksa mesin.** Gunakan tipe tepat masuk dan keluar dari setiap batas, sehingga pemeriksaan tipe menggantikan pembacaan pemanggil. Cacat: `any`, kamus biasa, flag boolean yang maknanya hanya di dalam badan.
- **Kopling terlihat.** Dua tempat harus berubah bersama. Tegakkan itu dengan tipe bersama, tes, atau sumber tunggal. Jika tidak bisa, tandai di kedua tempat.
- **Tanpa kebisingan.** Hapus komentar yang mengulang kode, dan kode yang dikomentari. Hapus cabang mati dan komentar yang merekam riwayat perubahan. Hapus jalur lama yang tetap di samping penggantinya.
- **Dapat diprediksi.** Ikuti tata letak repositori yang ada. Letakkan tes di tempat pembaca mencarinya, dan buat tes berjalan sendiri.

Ukuran file sengaja tidak ada dalam daftar ini. File yang sangat besar adalah alasan untuk mencari keputusan tersembunyi kedua. Tidak pernah menjadi alasan untuk memotong file.

## Keamanan

Untuk kode yang ada, pertama tulis tes yang mempertahankan perilaku saat ini. Kemudian buat modul lebih dalam. Untuk kode baru, tulis tes yang mendefinisikan perilaku yang dimaksud.

## Catatan desain (wajib saat gerbang berlaku)

Saat gerbang berlaku, letakkan bagian dengan judul `## Design note` dalam deskripsi permintaan tarik. Tulis dua sampai empat baris:

- Setiap batas yang Anda tambahkan, dan keputusan yang disembunyikannya.
- Setiap duplikasi yang Anda pertahankan dengan sengaja, dan alasannya.
- Setiap bagian dangkal yang Anda terima, dan alasannya.

Jika gerbang tidak berlaku, tulis `## Design note` diikuti dengan `Gate not applicable: <reason>`. Juga letakkan catatan desain di ringkasan langkah akhir Anda.

## Mode tinjau

Gunakan bagian ini saat Anda meninjau atau menguji kode yang ditulis agen atau orang lain.

1. Periksa catatan desain. Saat gerbang berlaku dan permintaan tarik tidak memiliki bagian `## Design note`, laporkan temuan yang memblokir. Saat catatan tidak sesuai dengan diff, laporkan temuan yang memblokir.
2. Temuan desain hanya memblokir jika memenuhi kedua kondisi:
   - Menyebutkan aturan dari keterampilan ini. Aturan tersebut adalah aturan keputusan, gerbang, tes invarian, atau item biaya pembaca.
   - Menyatakan biaya konkret untuk pembaca atau perubahan berikutnya. Contoh: "Pemanggil harus tahu bentuk penyimpanan." "Satu konsep memiliki dua nama." "Perubahan cap membutuhkan edit di tiga file."
3. Tandai setiap pengamatan desain lain sebagai tidak memblokir. Letakkan dalam daftar terpisah dengan judul "Non-blocking design notes". Catatan tidak memblokir tidak pernah mengirimkan pekerjaan kembali ke pembuat.
4. Jangan laporkan preferensi sebagai temuan. Nama, tata letak file, atau gaya berbeda adalah preferensi. Menjadi temuan hanya jika melanggar aturan bernama dan memiliki biaya konkret.
5. Saat temuan desain yang sama muncul kembali di siklus tinjau kedua, tingkatkan. Jangan minta perubahan yang sama untuk ketiga kalinya.

## Keterampilan terkait (saat terpasang)

- `find-shared-code`: pencarian hanya laporan sejarah terbaru untuk kode yang layak dibagikan. Menggunakan tes invarian dan tes kedalaman dari keterampilan ini.
- `refactoring` dan `working-effectively-with-legacy-code`: langkah aman menuju desain yang lebih dalam. Keterampilan ini memutuskan apakah batas baru tetap ada.

## Sumber dan lisensi

Keahlian ini dibangun berdasarkan aturan "mini" dari A Philosophy of Software Design dalam repositori ciembor/agent-rules-books di GitHub (lisensi MIT, commit 893a88a). Gerbang, tes invarian, tes biaya pembaca, catatan desain, dan mode tinjauan adalah tambahan dari aturan-aturan tersebut. Repositori tersebut juga memuat aturan lengkap dari buku tersebut.

Tag

designarchitectureousterhoutreview