2.19

View in English

2.19 Refaktoring dan utang teknis

Tinjauan dan motivasi

Refaktoring adalah mengubah struktur internal kode tanpa mengubah apa yang dilakukannya dari luar. Anda mengganti nama variabel, memecah fungsi panjang, mengekstrak kelas, meruntuhkan kekusutan kondisional menjadi sesuatu yang dapat diikuti pembaca, dan program berperilaku persis seperti sebelumnya. Bagian terakhir itu adalah seluruh disiplinnya. Refaktoring bersifat menjaga perilaku menurut definisi, dan begitu Anda juga mengubah perilaku Anda tidak lagi merefaktor, Anda melakukan dua hal berisiko sekaligus dan menyembunyikan masing-masing di balik yang lain. Bab ini memperlakukan keduanya sebagai tindakan terpisah dengan sengaja, karena kebingungan di antara keduanya adalah tempat sebagian besar refaktoring salah arah.

Pada tim besar ini lebih penting daripada bagi pengembang tunggal, karena kode yang Anda bersihkan adalah kode yang dibaca ratusan orang lain, bergantung padanya, dan takut menyentuhnya. Refaktoring adalah cara basis kode bersama tetap layak huni melintasi tahun dan pergantian staf. Ia terhubung langsung dengan konstruksi perangkat lunak (bab 2.9), tempat kualitas pengodean sehari-hari ditetapkan, dan dengan strategi pengujian (bab 2.4), jaring pengaman yang membuat refaktoring aman sama sekali. Ia juga terhubung dengan pertanyaan yang lebih sulit tentang utang teknis: biaya akumulasi jalan pintas, desain yang menua, dan pembersihan yang tertunda yang membuat setiap perubahan mendatang lebih lambat. Refaktoring adalah cara utama Anda melunasi utang itu, sehingga kedua topik termasuk dalam satu bab.

Dalam konteks enterprise dan pemerintah, taruhannya naik. Sistem ini berumur panjang, sering berusia puluhan tahun, dan sering berada di bawah rezim audit dan kendali perubahan yang memperlakukan setiap perubahan kode sebagai peristiwa yang diatur. Anda tidak dapat sekadar menulis ulang sistem tunjangan warga dalam akhir pekan panjang; Anda memodernisasinya dalam langkah kecil, dapat dibalik, dan didukung bukti, yang persis diberikan refaktoring yang disiplin. Mengoordinasikan pekerjaan itu di banyak tim dan sistem berumur panjang (bab 10.4) adalah salah satu tantangan penentu rekayasa skala besar, dan keliru melakukannya adalah cara organisasi berakhir membeku, tidak mampu mengubah perangkat lunak yang tidak lagi mereka pahami.

Prinsip utama

  • Refaktoring menjaga perilaku; jika Anda mengubah apa yang dilakukan kode, itu perubahan terpisah, dikerjakan terpisah.
  • Rangkaian tes yang tepercaya adalah prasyarat refaktoring yang aman, bukan tambahan opsional.
  • Bekerja dalam langkah kecil, bernama, dan dapat dibalik, dan jaga kode tetap berfungsi setelah masing-masing.
  • Jadikan utang teknis terlihat dan terlacak, lalu danai pelunasan sebagai kapasitas stabil alih-alih aksi heroik.
  • Refaktor kode yang sudah Anda ubah, di tempat pembersihan membayar dirinya sendiri.
  • Tidak semua utang layak dilunasi; kode yang stabil, jarang disentuh, atau akan segera dipensiunkan dapat dibiarkan.
  • Ukur kualitas internal untuk menginformasikan penilaian, tidak pernah sebagai target untuk dipermainkan.

Rekomendasi

Jaga refaktoring dan perubahan perilaku tetap terpisah secara ketat

Putuskan sebelum memulai mana yang sedang Anda kerjakan, dan jangan pernah mengaburkan keduanya dalam satu commit. Ketika Anda merefaktor, tes yang lolos sebelumnya harus lolos sesudahnya, tak berubah, karena perilaku yang teramati tidak bergeser. Ketika Anda mengubah perilaku, lakukan sebagai commit sendiri dengan tesnya sendiri. Alasannya praktis: jika perubahan campuran merusak sesuatu, Anda tidak dapat mengatakan apakah restrukturisasi Anda yang memperkenalkan bug atau perubahan perilaku Anda, dan dalam tinjauan kode (bab 2.5) peninjau tidak dapat bernalar tentang kedua bagian dengan bersih. Kebiasaan yang berhasil adalah aturan dua topi dari Martin Fowler: Anda selalu mengenakan topi refaktoring atau topi fitur, Anda tahu yang mana, dan Anda berganti dengan sengaja. Commit terpisah juga membuat riwayat kontrol versi terbaca, sehingga insinyur yang melakukan bisect pada kegagalan dapat melewati commit refaktor murni dengan percaya diri.

Tetapkan jaring pengaman yang tepercaya sebelum merestrukturisasi

Refaktoring tanpa tes hanyalah menyunting dan berharap. Sebelum merestrukturisasi apa pun yang penting, Anda membutuhkan rangkaian yang Anda percaya untuk menangkap perubahan perilaku jika Anda menyebabkannya, yang merupakan argumen inti strategi pengujian (bab 2.4). Untuk kode yang sudah memiliki cakupan baik, jalankan tes, refaktor dalam langkah kecil, dan jalankan lagi setelah setiap langkah. Untuk kode warisan tanpa tes, langkah jujurnya adalah menulis tes karakterisasi lebih dulu. Tes karakterisasi tidak menegaskan apa yang seharusnya dilakukan kode; ia menangkap apa yang sebenarnya dilakukan kode sekarang, termasuk keanehannya, sehingga setiap perubahan perilaku muncul sebagai tes yang gagal. Michael Feathers mempopulerkan pendekatan ini untuk persis situasi tempat organisasi besar hidup: kode yang berfungsi, penting, dan tidak memiliki tes. Begitu perilaku saat ini terpaku, Anda dapat merefaktor di bawahnya dengan aman, dan baru kemudian mengubah perilaku di atasnya.

Belajar mengenali code smell dan menerapkan refaktoring kecil bernama

Code smell adalah tanda permukaan bahwa sesuatu di bawahnya mungkin perlu perhatian: fungsi yang tumbuh terlalu panjang, kelas yang tahu terlalu banyak, logika terduplikasi, daftar parameter panjang, nama yang berbohong tentang apa yang dilakukannya. Smell adalah petunjuk, bukan vonis, jadi Anda menyelidiki alih-alih menurutinya secara buta. Responsnya adalah refaktoring kecil bernama dari katalog Fowler: Extract Function, Rename Variable, Move Method, Replace Conditional with Polymorphism, dan puluhan lainnya. Nilai memakai gerakan bernama adalah masing-masing kecil, dipahami, aman secara mekanis, dan sering didukung langsung oleh IDE Anda. Anda menyusun perbaikan besar dari banyak langkah kecil yang andal, menjaga kode tetap hijau sepanjang jalan, alih-alih membuat satu lompatan besar yang tidak dapat Anda verifikasi.

Pilih refaktoring oportunistik, dan sisakan kampanye untuk kebutuhan struktural nyata

Sebagian besar refaktoring harus oportunistik, dilipat ke dalam pekerjaan yang sudah Anda lakukan. Aturan pramuka menangkapnya: tinggalkan kode sedikit lebih bersih daripada saat Anda menemukannya. Ketika Anda menyentuh berkas untuk menambah fitur atau memperbaiki bug, Anda sudah memahami sudut itu, dan pembersihan kecil di sana berlipat seiring waktu tanpa membutuhkan izin siapa pun atau anggaran terpisah. Kampanye refaktoring terencana, di mana tim menghentikan kerja fitur untuk merestrukturisasi area besar, kadang perlu, tetapi mahal, sulit dijadwalkan terhadap tekanan produk, dan berisiko jika area itu kurang teruji. Sisakan kampanye untuk masalah struktural yang tidak terjangkau pembersihan oportunistik, dan ajukan kasusnya dengan bukti tentang biaya perubahan yang Anda bayar. Pilih tetesan stabil pembersihan kecil; lebih tahan lama daripada penulisan ulang heroik sesekali.

Gunakan pola strangler fig untuk perubahan struktural besar

Ketika seluruh subsistem perlu diganti, jangan mencoba penulisan ulang big-bang yang berjalan setahun dan digabung di akhir; begitulah proyek modernisasi mati. Gunakan pola strangler fig, dinamai Martin Fowler menurut tanaman merambat yang tumbuh mengelilingi pohon dan perlahan menggantikannya. Anda menempatkan fasad di depan sistem lama, merutekan satu irisan fungsionalitas sekali waktu ke kode baru di balik fasad itu, memverifikasinya di produksi, dan mengulang sampai sistem lama sepenuhnya terkepung dan dapat dihapus. Setiap irisan kecil, dapat dirilis, dan dapat dibalik, sehingga risiko tetap terbatas dan nilai tiba terus-menerus. Sepupu dekatnya, branch by abstraction, melakukan hal yang sama di dalam satu basis kode: Anda memperkenalkan lapisan abstraksi di atas hal yang ingin diganti, membangun implementasi baru di baliknya selagi keduanya berdampingan, memindahkan konsumen secara bertahap, dan menghapus implementasi lama begitu tak ada yang bergantung padanya. Keduanya memungkinkan sistem warisan berkembang sambil tetap hidup, satu-satunya jenis modernisasi yang sanggup dibiayai kebanyakan organisasi besar.

Perlakukan utang teknis sebagai portofolio, dan buat terlihat

Metafora utang, yang diciptakan Ward Cunningham, memisahkan dua hal: pokok (kode berantakan atau jalan pintas itu sendiri) dan bunga (upaya tambahan yang dibayar setiap perubahan mendatang karenanya). Tidak semua utang sama. Kuadran Fowler memilahnya sepanjang dua sumbu: disengaja versus tidak sengaja, dan bijaksana versus ceroboh. Utang bijaksana-disengaja (“kami rilis sekarang dan membersihkan sprint depan, dan kami tahu biayanya”) adalah keputusan bisnis yang sah. Utang ceroboh-tidak-sengaja (“apa itu pola desain?”) hanyalah kerusakan. Tugas manajemen, yang terhubung dengan pengambilan keputusan dan tata kelola (bab 1.5) dan perlakuannya terhadap utang sebagai portofolio, adalah membuat utang terlihat agar dapat dinalar: lacak butir penting di tempat pekerjaan hidup, beri tag pada kode, dan catat bunga yang Anda bayar agar pelunasan bersaing untuk kapasitas berdasarkan bukti alih-alih siapa yang paling mengeluh. Utang yang tidak dapat Anda lihat, tidak dapat Anda kelola.

Danai pelunasan sebagai kapasitas stabil, bukan aksi heroik

Mode kegagalannya adalah memperlakukan pembersihan sebagai sesuatu yang akan Anda lakukan “ketika segalanya tenang,” yang tidak pernah terjadi. Pola yang tahan lama adalah kapasitas tetap yang dilindungi untuk pelunasan: irisan eksplisit dari setiap siklus, atau kesepakatan tetap bahwa pembersihan menumpang pada kerja fitur di area yang sama. Yang tidak berhasil adalah sprint heroik berkala di mana seseorang membakar akhir pekan untuk memperbaiki segalanya, karena tidak berkelanjutan, tidak ditinjau, dan biasanya membatalkan dirinya sendiri. Kapasitas stabil menjaga pembayaran bunga tetap rendah dan menghindari siklus boom-bust di mana utang menumpuk sampai krisis memaksa penulisan ulang mahal. Ini komitmen manajemen sama banyaknya praktik rekayasa, dan termasuk dalam cara Anda merencanakan pemeliharaan perangkat lunak (bab 3.7) sepanjang umur sistem.

Ukur kualitas internal, tetapi jangan biarkan ukuran menjadi target

Anda dapat mengukur kualitas internal dengan sinyal seperti kompleksitas siklomatik (hitungan jalur independen melalui fungsi), duplikasi, cakupan tes, tingkat kegagalan perubahan, dan berapa lama perubahan berlangsung di area yang Anda curigai. Angka ini berguna untuk melihat di mana utang terkonsentrasi dan untuk mengawasi tren dari waktu ke waktu. Bahayanya adalah hukum Goodhart: ketika ukuran menjadi target, ia berhenti mengukur sesuatu yang nyata. Wajibkan angka cakupan dan Anda mendapat tes yang tidak menegaskan apa-apa; hargai skor kompleksitas rendah dan Anda mendapat logika yang disebar ke lebih banyak fungsi untuk mengelak dari metrik. Gunakan metrik untuk memulai percakapan dan menemukan titik panas, dan jangan pernah mengaitkan metrik kualitas dengan gerbang yang termotivasi dipermainkan orang.

Ketahui kapan tidak merefaktor

Refaktoring adalah investasi, dan sebagian kode tidak akan pernah membayar kembali. Jika modul stabil, jarang disentuh, dan cukup dipahami untuk diubah pada kesempatan langka ketika harus, membersihkannya adalah upaya yang dihabiskan untuk bunga yang tidak Anda bayar. Jika kode dijadwalkan pensiun, merefaktornya adalah memoles sesuatu yang akan Anda buang. Disiplinnya adalah membelanjakan anggaran pembersihan Anda di tempat perubahan sering dan menyakitkan, di mana mengurangi bunga benar-benar berlipat, dan membiarkan sudut-sudut yang tenang.

Trade-off: kelebihan dan kekurangan

PendekatanKelebihanKekurangan
Refaktoring oportunistik (aturan pramuka)Murah, berkelanjutan, tanpa anggaran terpisah, berlipat seiring waktuCakupan tidak merata; berkas panas membaik sementara yang dingin membusuk
Kampanye refaktoring terencanaMemperbaiki masalah struktural yang tidak terjangkau pembersihanMahal; bersaing dengan fitur; berisiko tanpa tes yang baik
Strangler fig / branch by abstractionBertahap, dapat dibalik, menjaga sistem tetap hidup, membatasi risikoLebih lambat daripada penulisan ulang di atas kertas; butuh disiplin untuk menyelesaikan
Penulisan ulang big-bangLembaran bersih; tanpa kendala warisanTingkat kegagalan tinggi; waktu ke nilai panjang; celah perilaku
Utang bijaksana yang disengajaMerilis nilai sekarang; pelunasan eksplisit dan terencanaMenjadi ceroboh bila pelunasan tidak pernah dijadwalkan
Kualitas yang digerbangi metrikObjektif, terlihat, menangkap penyimpangan diniMengundang permainan; menghukum nuansa; dapat merusak kualitas nyata

Ketegangan pusatnya adalah kecepatan sekarang versus kemampuan berubah kelak, dan itu nyata. Merilis jalan pintas bisa menjadi keputusan yang tepat ketika tenggatnya sungguhan dan utangnya bijaksana serta terlacak. Kesalahannya adalah berpura-pura utang itu gratis, atau membiarkannya menumpuk tanpa terlihat sampai sistem terlalu mahal diubah. Selesaikan dengan membuat pertukaran eksplisit setiap kali: namai utangnya, estimasi bunganya, putuskan dengan sengaja, dan catat keputusan agar pelunasan dapat dijadwalkan alih-alih dilupakan. Tim yang meminjam dengan sadar dan melunasi dengan stabil tetap cepat bertahun-tahun; tim yang meminjam secara buta berhenti total.

Pertanyaan untuk didiskusikan dengan tim Anda

  1. Bagaimana kita menjaga refaktoring dan perubahan perilaku agar tidak tercampur dalam commit yang sama, dan apakah tinjauan kita benar-benar menegakkannya? Ini disiplin fondasional seluruh bab, dan yang paling sering dilanggar di bawah tekanan tenggat, karena terasa efisien untuk “bersihkan ini sekalian selagi di sini” dan merilis semuanya bersama. Biayanya jatuh kemudian: ketika commit campuran merusak produksi, tak seorang pun dapat mengatakan apakah restrukturisasi atau fitur yang menyebabkannya, dan bisect melalui riwayat Anda berhenti dapat dipercaya. Bawa segelintir pull request terbaru dan periksa dengan jujur berapa banyak yang mencampur dua topi. Pertimbangan yang bersaing adalah gesekan, karena memecah pekerjaan menjadi commit terpisah sedikit lebih banyak upaya di muka. Jawabannya harus membentuk konvensi commit dan daftar periksa tinjauan Anda.

  2. Di mana utang teknis kita, berapa bunga yang kita bayar atasnya, dan siapa yang memutuskan apa yang dilunasi? Kebanyakan tim tidak dapat menjawab ini, yang merupakan masalah sebenarnya, karena utang yang tidak dapat Anda lihat dikelola oleh siapa pun yang paling mengeluh alih-alih oleh di mana biaya sebenarnya. Membuatnya terlihat berarti melacak butir penting, memberi tag pada kode, dan mengumpulkan bukti tentang area mana yang membuat perubahan lambat dan rawan gagal. Tarikan yang bersaing adalah setiap jam yang dihabiskan untuk pelunasan adalah jam yang tidak dihabiskan untuk fitur, jadi keputusannya harus keputusan portofolio yang dibuat bersama pimpinan, terhubung dengan cara Anda mengatur pekerjaan rekayasa (bab 1.5). Bawa data kegagalan perubahan dan daftar berkas yang ditakuti semua orang untuk disentuh. Jawabannya harus menjadi kapasitas pelunasan yang dilindungi dan stabil, bukan niat samar untuk membersihkan ketika segalanya tenang.

  3. Bagian mana dari basis kode kita yang sengaja tidak boleh kita refaktor, dan bagaimana kita tahu? Merefaktor segalanya sama kegagalannya dengan tidak merefaktor apa pun, karena upaya yang dihabiskan membersihkan kode stabil, jarang disentuh, atau akan dipensiunkan adalah bunga yang dibayar atas pinjaman yang tidak Anda utang. Penilaian itu nyata: modul bisa tampak jelek dan tetap menjadi tempat yang salah untuk berinvestasi jika tak seorang pun pernah mengubahnya. Bawa data frekuensi perubahan bersama sinyal kompleksitas Anda, karena irisan antara gejolak tinggi dan kompleksitas tinggi adalah tempat pembersihan berlipat, sementara kode berfrekuensi rendah biasanya paling baik dibiarkan. Risiko yang bersaing adalah bahwa “kita biarkan saja” menjadi alasan untuk tidak pernah menyentuh apa pun yang sulit. Jawabannya harus memberi Anda daftar pendek eksplisit titik panas yang layak diinvestasi dan izin untuk mengabaikan sudut yang tenang.

  4. Apakah kita cukup memercayai rangkaian tes kita untuk merefaktor kode yang paling perlu kita ubah, dan di mana kita harus menulis tes karakterisasi lebih dulu? Jaring pengaman yang tidak dapat Anda percaya mengubah refaktoring menjadi menyunting dan berharap, dan pada tim besar kode yang paling menakutkan biasanya kode yang paling sedikit teruji, persis di tempat pembersihan akan paling membuahkan hasil. Bawa data cakupan dan kegagalan perubahan untuk titik panas Anda, dan jujurlah modul kritis mana yang tidak akan memberi Anda peringatan jika restrukturisasi mengubah perilaku. Pertimbangan yang bersaing adalah menulis tes karakterisasi untuk kode warisan itu lambat dan tidak glamor serta tidak merilis fitur, sehingga mudah ditunda selamanya. Dalam sistem enterprise dan pemerintah di bawah audit dan kendali perubahan, tes yang terpaku itu juga bukti bahwa perubahan menjaga perilaku, jadi mendanainya adalah ukuran keselamatan sekaligus kepatuhan; jawabannya harus menamai area mana yang mendapat harness tes sebelum ada yang menyentuhnya.

  5. Ketika subsistem benar-benar perlu diganti, bagaimana kita memutuskan antara pendekatan strangler fig bertahap dan penulisan ulang, dan siapa yang berwenang berkata tidak pada penulisan ulang? Penulisan ulang big-bang adalah opsi paling memikat dan paling rawan gagal di atas meja, karena lembaran bersih selalu tampak lebih murah di atas kertas daripada hidup dengan kendala lama. Bagi organisasi besar jalur bertahap (fasad, satu irisan sekali waktu, diverifikasi di produksi) menjaga sistem tetap hidup dan membatasi risiko, tetapi lebih lambat, menuntut disiplin untuk menyelesaikan, dan bersaing dengan selera untuk awal yang segar. Bawa peta frekuensi perubahan subsistem, estimasi jujur berapa lama penulisan ulang akan berjalan sebelum menghasilkan nilai, dan celah perilaku yang harus ditutup penulisan ulang paralel. Dalam lingkungan pemerintah dan yang diatur, penulisan ulang multitahun yang digabung di akhir jarang dapat bertahan di bawah audit, jadi jawabannya harus menjadikan strangler fig atau branch by abstraction sebagai bawaan dan memperlakukan penulisan ulang apa pun sebagai pengecualian yang harus dibela dengan bukti.

  6. Bagaimana kita memakai metrik kualitas internal untuk menemukan di mana utang terkonsentrasi tanpa membiarkan angka menjadi target yang dipermainkan orang? Metrik seperti kompleksitas, duplikasi, cakupan, dan tingkat kegagalan perubahan adalah satu-satunya cara organisasi besar dapat melihat lintas kode yang tidak dibaca satu orang pun, namun begitu salah satunya dikaitkan dengan gerbang atau penilaian kinerja, hukum Goodhart mengambil alih dan angka berhenti mengukur sesuatu yang nyata. Bawa contoh di mana metrik sudah menggerakkan perilaku, dan tanyakan apakah ia memulai percakapan atau diam-diam menghargai tes yang tidak menegaskan apa-apa dan logika yang disebar ke fungsi untuk mengelak dari ambang. Tarikan yang bersaing adalah pimpinan menginginkan angka dasbor sederhana, dan “gunakan penilaian” lebih sulit dijual daripada batang hijau. Dalam konteks enterprise dan pemerintah di mana metrik memberi makan pelaporan tata kelola, bersikaplah eksplisit bahwa sinyal kualitas menginformasikan investasi dan menemukan titik panas tetapi tidak pernah menggerbangi individu; jawabannya harus menarik garis tegas antara mengukur untuk belajar dan mengukur untuk menghakimi.

Lensa sektor

Startup. Dengan segelintir insinyur dan tanpa runway tersisa, refaktor hanya secara oportunistik: kenakan satu topi per commit agar riwayat tetap dapat di-bisect, dan simpan daftar singkat jujur tentang jalan pintas yang Anda ambil dengan sengaja. Jangan luncurkan kampanye pembersihan atau poles modul stabil; belanjakan perhatian langka Anda pada satu berkas yang ditakuti semua orang, dan tulis tes karakterisasi hanya di tempat perubahan benar-benar menakuti Anda. Utang yang disengaja dan terlihat tidak apa-apa pada tahap ini; utang ceroboh yang tak terlihat yang membunuh Anda.

Bisnis kecil. Tanpa spesialis platform atau perkakas khusus dan dengan anggaran ketat, bersandarlah pada yang diberikan IDE dan ekosistem bahasa Anda secara gratis: gerakan rename dan extract otomatis, linter, dan sinyal cakupan dasar. Perlakukan sebagian besar utang sebagai sesuatu yang Anda kelola dalam pekerjaan normal alih-alih sesuatu yang Anda sewa konsultan untuk memperbaikinya, dan pilih membeli pustaka terpelihara baik daripada membangun lalu harus merefaktor milik Anda sendiri. Sisakan upaya berbayar yang langka untuk satu sistem yang kelambatannya langsung memakan pelanggan Anda.

Enterprise. Di banyak tim masalahnya adalah tata kelola portofolio: register utang bersama, pemberian tag titik panas yang konsisten menurut frekuensi perubahan dan kompleksitas, dan irisan kapasitas setiap tim yang dilindungi untuk pelunasan agar pembersihan berhenti kalah dari fitur secara bawaan. Bakukan disiplin dua topi dan praktik tes karakterisasi agar insinyur yang berpindah antartim menemukan aturan yang sama, dan gunakan strangler fig dan branch by abstraction untuk perubahan struktural yang dikoordinasikan antarkelompok. Jaga metrik kualitas informasional agar menemukan utang tanpa dipermainkan dalam penilaian kinerja.

Pemerintah. Sistem berumur panjang di bawah audit dan kendali perubahan yang ketat menjadikan refaktoring yang disiplin aset kepatuhan, bukan hanya rekayasa: menjaga restrukturisasi tetap terpisah ketat dari perubahan perilaku memungkinkan auditor melihat persis commit mana yang mengubah perilaku dan mana yang hanya merapikan. Aturan pengadaan dan transparansi mendukung langkah kecil, dapat dibalik, dan didukung bukti daripada penulisan ulang big-bang, jadi jadikan strangler fig dengan tes karakterisasi yang mendokumentasikan bahwa perilaku terjaga sebagai bawaan. Jadikan register utang dan rencana pelunasannya bagian dari catatan pemeliharaan sistem agar badan pengawas mendapat keterlacakan yang mereka tuntut.

Contoh

Startup. Sebuah startup enam orang merilis cepat dan tahu ia menanggung utang, jadi ia melakukan dua hal murah dengan baik. Setiap pull request mengenakan satu topi: commit refaktor terpisah dari commit fitur, yang menjaga riwayat mereka dapat di-bisect bahkan pada kecepatan tinggi. Dan mereka menyimpan daftar singkat jujur tentang jalan pintas yang mereka ambil dengan sengaja, dengan catatan satu baris tentang bunga yang dimakan masing-masing. Ketika modul pembayaran menjadi berkas yang ditakuti semua orang, daftar itu ditambah riwayat kegagalan perubahan mereka membangun kasus untuk menghabiskan dua hari mengekstrak batas yang lebih bersih. Mereka menulis tes karakterisasi untuk mengunci perilaku saat ini, merefaktor di bawahnya dengan gerakan rename dan extract IDE, dan tidak pernah menyentuh modul stabil yang tidak diubah siapa pun. Utang yang mereka pikul disengaja dan terlihat, sehingga tidak pernah berubah menjadi jenis yang ceroboh.

Enterprise. Sebuah perusahaan logistik global menjalankan sistem pesanan berusia lima belas tahun yang diubah banyak tim setiap minggu. Alih-alih menulis ulang, mereka mengadopsi pola strangler fig: fasad berada di depan monolit, dan satu kemampuan terbatas sekali waktu dirutekan ulang ke layanan baru di baliknya, diverifikasi di produksi sebelum irisan berikutnya dimulai. Mengoordinasikan ini di banyak tim dan sistem berumur panjang (bab 10.4) adalah bagian tersulit, jadi mereka memelihara register utang bersama, memberi tag titik panas menurut frekuensi perubahan dan kompleksitas, dan menyisakan irisan tetap kapasitas setiap tim untuk pelunasan. Metrik kualitas internal menginformasikan di mana melihat tetapi tidak pernah menggerbangi penilaian kinerja siapa pun, yang menjaga angka tetap jujur. Selama dua tahun monolit menyusut dengan stabil dan tak ada satu perubahan pun yang pernah mempertaruhkan seluruh sistem.

Pemerintah. Sebuah lembaga pajak nasional harus memodernisasi platform penilaian berusia puluhan tahun di bawah aturan audit dan kendali perubahan yang ketat, di mana setiap perubahan kode adalah peristiwa yang diatur dan didukung bukti. Penulisan ulang big-bang mustahil, jadi mereka memakai branch by abstraction: lapisan abstraksi diperkenalkan di atas mesin perhitungan warisan, implementasi baru dibangun di baliknya, dan konsumen dimigrasikan satu aturan pajak sekali waktu, setiap migrasi didokumentasikan sebagai perubahan kecil dan dapat dibalik dengan tes karakterisasi yang membuktikan perilaku tidak berubah. Karena refaktoring dijaga terpisah ketat dari perubahan perilaku legislatif apa pun, auditor dapat melihat persis commit mana yang mengubah perilaku dan mana yang hanya merestrukturisasi. Register utang dan rencana pelunasannya menjadi bagian dari catatan pemeliharaan sistem (bab 3.7), memberi badan pengawas keterlacakan yang mereka tuntut.

Kasus bisnis: motivasi, ROI, dan TCO

Imbal hasil refaktoring dan pelunasan utang adalah kemampuan berkelanjutan mengubah perangkat lunak dengan murah, dan untuk sebagian besar sistem mayoritas biaya seumur hidup adalah pemeliharaan, sehingga di sinilah total biaya kepemilikan sebagian besar ditentukan. Bunga utang teknis dibayar dalam mata uang yang sudah dilacak pimpinan: pengiriman lebih lambat, tingkat kegagalan perubahan lebih tinggi, waktu pemulihan insiden lebih lama, dan insinyur yang menghindari kode paling menakutkan. Ketika Anda membuat utang terlihat dan mendanai pelunasan secara stabil, Anda menurunkan biaya setiap perubahan mendatang di area yang paling penting, dan menghindari pola boom-bust di mana utang yang diabaikan memaksa penulisan ulang darurat yang mahal.

Biaya mengadopsi sederhana dan sebagian besar budaya: tetapkan disiplin dua topi, bangun jaring pengaman di tempat Anda perlu merefaktor, simpan register utang, dan lindungi irisan kapasitas yang stabil untuk pelunasan. Biaya pengabaian berlipat diam-diam. Bunga menumpuk pada setiap perubahan sampai velocity runtuh dan organisasi mendapati dirinya membeku, tidak mampu mengubah dengan aman sistem yang tidak lagi dipahaminya, hasil termahal dari semuanya. Untuk meyakinkan pimpinan, hubungkan utang langsung dengan metrik pengiriman yang sudah mereka pedulikan, dan bingkai pelunasan sebagai keputusan portofolio dengan imbal balik terukur, bukan insinyur meminta waktu untuk merapikan.

Anti-pola dan jebakan

  • Mencampur refaktoring dengan perubahan perilaku: satu commit melakukan keduanya, sehingga kerusakan tidak dapat diatribusikan dan riwayat menjadi tak tepercaya.
  • Merefaktor tanpa jaring pengaman: merestrukturisasi kode tak teruji dan berharap, yaitu menyunting dengan iman.
  • Penulisan ulang big-bang: mengganti sistem yang berfungsi sekaligus, pola dengan tingkat kegagalan tinggi dan waktu ke nilai panjang.
  • Refaktoring sebagai akhir pekan heroik: pembersihan tak ditinjau dan tak berkelanjutan yang membatalkan dirinya alih-alih kapasitas stabil.
  • Utang tak terlihat: jalan pintas yang tidak dilacak siapa pun, sehingga pelunasan digerakkan volume keluhan alih-alih biaya sebenarnya.
  • Memainkan metrik kualitas: mencapai target cakupan atau kompleksitas sementara kualitas nyata turun, karena ukuran menjadi target.
  • Merefaktor kode yang salah: memoles modul stabil atau yang akan dipensiunkan sementara titik panas sejati terus memakan biaya.
  • Refaktoring tanpa akhir: restrukturisasi tak berujung yang tidak pernah merilis nilai, cermin dari tidak pernah membersihkan.

Model kematangan

  • Tingkat 1, Memulai: Refaktoring ad hoc dan reaktif, sering bercampur dengan perubahan perilaku dalam commit yang sama. Tidak ada jaring pengaman yang tepercaya, utang teknis tak terlihat dan tak terlacak, dan pembersihan terjadi hanya dalam ledakan heroik sesekali atau tidak sama sekali.
  • Tingkat 2, Mengembangkan: Beberapa tim memisahkan refaktoring dari perubahan perilaku dan bersandar pada tes di tempat ada, dan refaktoring bernama serta tes karakterisasi muncul di kantong-kantong. Praktik tidak konsisten antartim, utang dibahas dan kadang dicatat, dan pelunasan bersaing ad hoc melawan fitur dan biasanya kalah.
  • Tingkat 3, Membakukan: Disiplin dua topi, tes karakterisasi untuk kode warisan, dan refaktoring kecil bernama didokumentasikan dan diharapkan di seluruh organisasi. Utang dilacak dalam register bersama yang memisahkan pokok dari bunga, dan kapasitas terlindungi untuk pelunasan direncanakan setiap siklus dan ditegakkan dalam tinjauan.
  • Tingkat 4, Mengelola: Utang dan pembersihan diukur dan dikendalikan dengan data terhadap garis dasar. Anda melacak frekuensi perubahan dan kompleksitas untuk menemukan titik panas, mengawasi tingkat kegagalan perubahan dan lead time perubahan di area yang direfaktor, dan mencatat bunga yang dimakan setiap butir penting, sehingga keputusan pelunasan bertumpu pada bukti dan keputusan hentikan-atau-investasi dibuat berdasarkan tren alih-alih volume keluhan. Sinyal kualitas menginformasikan investasi tanpa dikaitkan dengan gerbang yang dapat dipermainkan orang.
  • Tingkat 5, Mengorkestrasi: Utang dikelola sebagai portofolio yang terus diseimbangkan ulang dan terintegrasi dengan perencanaan produk dan pemeliharaan di seluruh organisasi. Perubahan struktural rutin memakai strangler fig dan branch by abstraction yang dikoordinasikan antartim, pelunasan berkelanjutan dan dicocokkan dengan tempat perubahan sering dan menyakitkan, dan praktik beradaptasi seiring bergesernya sistem dan gambaran risikonya, sehingga kode berumur panjang tetap dapat diubah selama puluhan tahun.

Gagasan untuk didiskusikan

  1. Apa aturan nyata dan ditegakkan tim Anda untuk menjaga refaktoring terpisah dari perubahan perilaku, dan di mana ia patah di bawah tekanan tenggat?
  2. Bagaimana Anda memutuskan, dengan bukti, kode mana yang layak dibersihkan dan mana yang paling baik dibiarkan?
  3. Di mana tes karakterisasi akan memungkinkan Anda merefaktor area warisan yang saat ini Anda hindari dengan aman?
  4. Untuk modernisasi besar berikutnya, seperti apa pendekatan strangler fig, dan fasad atau abstraksi apa yang akan Anda perkenalkan lebih dulu?
  5. Siapa yang memiliki register utang teknis, dan bagaimana pelunasan benar-benar memenangkan kapasitas melawan kerja fitur?

Poin-poin utama

  • Refaktoring menjaga perilaku; jaga tetap terpisah ketat dari perubahan perilaku, dalam commit terpisah.
  • Rangkaian tes yang tepercaya adalah prasyarat refaktoring yang aman, dan tes karakterisasi memberi kode warisan satu.
  • Bekerja dalam langkah kecil, bernama, dan dapat dibalik, pilih pembersihan oportunistik, dan pakai strangler fig atau branch by abstraction untuk perubahan struktural besar.
  • Jadikan utang teknis terlihat, pisahkan pokok dari bunga, dan danai pelunasan sebagai kapasitas stabil alih-alih aksi heroik.
  • Ukur kualitas internal untuk memandu penilaian, tidak pernah sebagai target untuk dipermainkan, dan jangan merefaktor kode yang stabil atau dijadwalkan pensiun.

Referensi dan bacaan lanjutan

  • Martin Fowler, Refactoring: Improving the Design of Existing Code, edisi kedua
  • Michael Feathers, Working Effectively with Legacy Code
  • Ward Cunningham, The WyCash Portfolio Management System (laporan pengalaman OOPSLA 1992, asal metafora utang)
  • Martin Fowler, “TechnicalDebtQuadrant” dan “StranglerFigApplication” (martinfowler.com)
  • Kent Beck, Tidy First? A Personal Exercise in Empirical Software Design
  • Steve McConnell, Code Complete: A Practical Handbook of Software Construction
  • Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship