Perubahan apa yang terlalu besar untuk dibuat mudah dengan desain yang tepat?


11

Ini adalah pertanyaan yang agak kabur, tetapi itu adalah sesuatu yang saya tidak pernah merasa telah dijawab dengan cara yang memuaskan ketika membaca tentang desain yang tepat.

Secara umum, ketika belajar tentang pemrograman Berorientasi Objek, abstraksi, anjak piutang, dll, cawan suci desain - dan alasan mereka selalu mengklaim Anda menggunakan teknik pengembangan yang dipermasalahkan - adalah bahwa itu akan membuat program Anda "mudah diubah" , "dipelihara", "fleksibel", atau sinonim apa pun yang digunakan untuk mengekspresikan konsep yang terdengar produktif. Dengan menandai ivars pribadi, memecah kode menjadi banyak metode kecil, mandiri, menjaga antarmuka umum, Anda seharusnya mendapatkan kemampuan untuk memodifikasi program Anda dengan mudah dan anggun.

Untuk perubahan yang relatif kecil, ini berhasil bagi saya. Perubahan pada struktur data internal yang digunakan oleh kelas untuk meningkatkan kinerja tidak pernah menjadi kesulitan besar, dan tidak ada perubahan pada akhir antarmuka pengguna, terlepas dari API, seperti mendesain ulang sistem entri teks atau merombak grafik untuk elemen gameplay .

Semua perubahan ini tampaknya bersifat mandiri. Tidak ada yang melibatkan perubahan pada perilaku atau desain komponen program Anda yang dimodifikasi, sejauh kode luar yang bersangkutan. Apakah Anda sedang menulis secara prosedural atau gaya OO, dengan fungsi besar atau kecil, ini adalah perubahan yang mudah dilakukan walaupun Anda hanya memiliki desain yang cukup bagus.

Namun, setiap kali perubahan menjadi besar dan berbulu - yaitu, perubahan pada API - tidak ada "pola" berharga saya yang pernah datang untuk menyelamatkan. Perubahan besar tetap besar, kode yang terpengaruh tetap terpengaruh, dan banyak jam kerja pemijahan bug ada di depan saya.

Jadi, pertanyaan saya adalah ini. Seberapa besar perubahan yang diklaim dapat difasilitasi oleh desain yang tepat? Apakah ada beberapa teknik desain lebih lanjut, baik yang tidak diketahui oleh saya atau yang gagal saya implementasikan, yang benar-benar membuat modifikasi lengket terdengar sederhana, atau apakah janji itu (yang saya dengar dibuat oleh begitu banyak paradigma yang berbeda) hanyalah ide yang bagus, benar-benar terputus dari kebenaran abadi pengembangan perangkat lunak? Apakah ada "alat perubahan" yang dapat saya tambahkan ke toolbelt saya?

Secara khusus, masalah yang saya hadapi yang mengarahkan saya ke forum adalah ini: Saya telah berupaya menerapkan bahasa pemrograman yang ditafsirkan (diimplementasikan dalam D, tapi itu tidak relevan), dan saya telah memutuskan bahwa argumen penutupan saya haruslah berbasis kata kunci, bukan posisional seperti saat ini. Ini membutuhkan modifikasi semua kode yang ada yang memanggil fungsi anonim, yang, untungnya, agak kecil karena saya sejak awal dalam pengembangan bahasa saya (<2000 baris), tetapi akan sangat besar jika saya membuat keputusan ini pada tahap selanjutnya. Dalam situasi seperti itu, apakah ada cara bahwa dengan pandangan ke depan yang tepat dalam desain saya bisa membuat modifikasi ini lebih mudah, atau apakah perubahan tertentu (sebagian besar) secara intrinsik jauh jangkauannya? Saya ingin tahu apakah ini merupakan kegagalan keterampilan desain saya sendiri - jika ya, saya

Untuk lebih jelasnya, saya sama sekali tidak skeptis terhadap OOP atau pola lainnya yang biasa digunakan. Bagi saya, bagaimanapun, kebajikan mereka ada dalam penulisan asli, bukan pemeliharaan, basis kode. Warisan memungkinkan Anda untuk mengabstraksi pola berulang dengan baik, polimorfisme memungkinkan Anda untuk memisahkan kode berdasarkan fungsi yang dipahami manusia (kelas mana) dan bukan oleh efek yang dipahami mesin (cabang switchpernyataan itu), dan fungsi kecil dan mandiri memungkinkan Anda untuk tulis dengan gaya "bottom-up" yang sangat menyenangkan. Namun, saya skeptis dengan klaim fleksibilitas mereka.


Saya tidak melihat bagaimana perubahan dalam bahasa Anda menyentuh apa pun kecuali parser. Bisakah Anda mengklarifikasi ini?
scarfridge

Dalam bahasa seperti smalltalk, memang benar bahwa Anda hanya perlu memodifikasi parser, karena itu akan menjadi masalah sederhana memperlakukan foo metarg1: bar metarg2: bazsebagai foo.metarg1_metarg2_(bar, baz). Namun, bahasa saya membuat perubahan yang lebih besar, yaitu parameter berbasis daftar ke parameter berbasis kamus, yang memengaruhi runtime tetapi bukan pengurai, sebenarnya, karena properti spesifik dari bahasa saya, saya tidak akan membahasnya sekarang. Karena tidak ada pemetaan yang jelas antara kata kunci yang tidak berurutan dan argumen posisi, runtime adalah masalah utama.
exist-forall

Jawaban:


13

Terkadang perubahan cukup besar sehingga Anda harus merancang jalur migrasi. Bahkan jika titik awal dan akhir dirancang dengan baik, Anda sering kali tidak bisa begitu saja mengganti kalkun dingin. Banyak perancang yang baik gagal untuk merancang jalur migrasi yang baik.

Inilah sebabnya saya pikir setiap programmer harus melakukan perangkat lunak penulisan tugas untuk lingkungan produksi 24/7. Ada sesuatu tentang kerugian yang dikutip berdasarkan urutan gaji tahunan Anda per menit yang memotivasi Anda untuk belajar menulis kode migrasi yang kuat.

Apa yang orang lakukan secara alami untuk perubahan besar adalah merobek cara lama, memasukkan cara baru, lalu menghabiskan beberapa hari memperbaiki kesalahan kompilasi biliuner, sampai kode Anda akhirnya dikompilasi lagi sehingga Anda dapat memulai pengujian. Karena kode tersebut tidak dapat diuji selama dua hari, Anda tiba-tiba memiliki banyak bug yang harus diluruskan.

Untuk perubahan desain besar seperti mengubah dari argumen posisional ke kata kunci, jalur migrasi yang baik adalah menambahkan dukungan untuk argumen kata kunci terlebih dahulu tanpa menghapus dukungan posisional . Kemudian Anda secara sistematis mengubah kode panggilan untuk menggunakan argumen kata kunci. Ini mirip dengan bagaimana Anda melakukannya sebelumnya, kecuali kali ini Anda dapat menguji saat Anda melanjutkan, karena kode panggilan yang tidak berubah masih berfungsi. Karena perubahan Anda lebih kecil di antara pengujian, bug lebih mudah untuk diperbaiki sebelumnya. Kemudian ketika semua kode panggilan telah diubah, itu sepele untuk menghapus dukungan posisi.

Inilah sebabnya mengapa API yang dipublikasikan secara publik tidak lagi menggunakan metode lama alih-alih menghapusnya. Ini memberikan jalur migrasi yang mulus untuk kode panggilan. Mungkin terasa lebih banyak pekerjaan untuk mendukung keduanya untuk sementara waktu, tetapi Anda menebus waktu dalam pengujian.

Jadi untuk menjawab pertanyaan Anda seperti yang diutarakan sebelumnya, hampir tidak ada perubahan yang terlalu besar untuk dipermudah dengan desain yang tepat. Jika perubahan Anda tampak terlalu besar, Anda hanya perlu mendesain beberapa tahap perantara sementara agar kode Anda dapat dimigrasi.


+1 untuk mendukung kasing baru dan kasing lama sehingga Anda dapat menghapus fase saat Anda pergi.
Erik Reppen

9

Saya sarankan Anda untuk membaca esai Big Ball of Mud .

Pada dasarnya titik bahwa desain cenderung memburuk saat Anda maju dengan pengembangan dan Anda harus mendedikasikan pekerjaan untuk mengatasi kompleksitas. Kompleksitas itu sendiri tidak dapat dihilangkan, hanya terkandung, karena itu melekat dalam masalah yang Anda coba selesaikan.

Ini mengarah pada prinsip utama pengembangan lincah. Dua yang paling relevan adalah "Anda tidak akan membutuhkannya" memberitahu Anda untuk tidak menyiapkan desain untuk fitur-fitur yang belum Anda implementasikan, karena Anda tidak mungkin mendapatkan desain yang benar dan "refactor tanpa ampun" memberitahu Anda untuk bekerja tentang menjaga kewarasan kode sepanjang proyek.

Tampaknya jawabannya adalah bahwa tidak ada desain yang dapat memfasilitasi setiap perubahan di luar contoh yang dibuat yang dirancang khusus untuk menunjukkan bahwa desain itu lebih kuat daripada yang sebenarnya.

Di samping catatan Anda harus skeptis tentang pemrograman berorientasi objek. Ini adalah alat yang hebat dalam banyak konteks, tetapi Anda harus menyadari batasannya. Terutama penyalahgunaan warisan dapat menyebabkan beberapa kode berbelit-belit yang luar biasa. Tentu saja Anda harus sama skeptisnya dengan teknik desain lainnya. Masing-masing memiliki kegunaan dan masing-masing memiliki titik lemah. Tidak ada peluru perak.


1
+1: desain muka baru jarang berhasil. Desain yang sukses adalah rekapitulasi desain yang telah terbukti, atau secara iteratif disempurnakan.
kevin cline

1
+1 Anda harus skeptis terhadap semua konsep pemrograman, hanya melalui kritik objektif kami menerapkan keterampilan analitis kami untuk menemukan solusi yang tepat dan bukan hanya solusi .
Jimmy Hoffa

4

Secara umum, ada "potongan kode" (fungsi, metode, objek, apa pun) dan "antarmuka antar potongan kode" (API, deklarasi fungsi, apa pun; termasuk perilaku).

Jika sepotong kode dapat diubah tanpa mengubah antarmuka tempat potongan kode lain bergantung, maka perubahan itu akan lebih mudah (dan tidak masalah jika Anda menggunakan OOP atau tidak).

Jika sepotong kode tidak dapat diubah tanpa mengubah antarmuka yang menjadi tempat bergantungnya potongan kode lain, maka perubahan akan lebih sulit (dan tidak masalah jika Anda menggunakan OOP atau tidak).

Manfaat utama OOP adalah "antarmuka" publik ditandai dengan jelas (misalnya metode publik suatu objek) dan kode lain tidak dapat menggunakan antarmuka internal (misalnya metode pribadi objek). Karena antarmuka publik ditandai dengan jelas orang cenderung lebih hati-hati merancang antarmuka publik tersebut (yang membantu menghindari perubahan yang lebih sulit). Karena antarmuka internal tidak dapat digunakan oleh kode lain, Anda dapat mengubahnya tanpa khawatir tentang kode lain tergantung pada mereka.


Keuntungan lain dari OOP adalah merangkum data dengan logika yang beroperasi di atasnya mengarah ke antarmuka publik yang lebih kecil (jika dilakukan dengan baik).
Michael Borgwardt

2

Tidak ada metodologi desain yang dapat menyelamatkan Anda dari kerepotan perubahan persyaratan / ruang lingkup besar. Mustahil untuk membayangkan dan menjelaskan semua kemungkinan perubahan yang bisa dipikirkan di kemudian hari.

Di mana desain yang baik tidak membantu Anda dalam membantu Anda memahami bagaimana semua bagian saling cocok dan apa yang akan dipengaruhi oleh perubahan yang diusulkan.
Selain itu, desain yang baik dapat membatasi bagian-bagian yang dipengaruhi oleh sebagian besar perubahan yang diusulkan.

Singkatnya, semua perubahan dibuat lebih mudah dengan desain yang bagus, tetapi desain yang baik tidak bisa mengubah perubahan besar menjadi kecil. (Di sisi lain, desain yang buruk / tidak ada dapat mengubah perubahan kecil menjadi perubahan besar.)


1

Karena desain dimaksudkan untuk mengambil proyek pengembangan dari nol kosong menjadi produk akhir yang dapat diandalkan (setidaknya desain untuk satu), dan itu adalah perubahan terbesar untuk proyek yang mungkin ada, saya ragu ada yang namanya perubahan terlalu besar untuk ditangani.

Jika ada yang sebaliknya. Beberapa perubahan terlalu kecil untuk mengganggu "desain" atau pemikiran mewah. Perbaikan bug sederhana, misalnya.

Ingatlah bahwa pola desain adalah untuk membantu berpikir jernih dan menemukan solusi desain yang baik untuk situasi umum, seperti menciptakan sejumlah besar objek tipe identik kecil. Tidak ada daftar pola yang lengkap. Anda, dan semua dari kita, akan memiliki masalah desain yang tidak umum, yang tidak akan cocok dengan lubang merpati. Upaya untuk membuat setiap langkah kecil dalam proses pengembangan perangkat lunak menurut satu pola resmi atau lainnya, adalah cara yang terlalu religius untuk melakukan berbagai hal, dan mengarah pada kekacauan yang tidak dapat dipertahankan.

Semua pekerjaan dalam perangkat lunak secara alami bug-spawning Pemain sepakbola mengalami cedera. Musisi mendapatkan kapalan atau kejang bibir tergantung pada instrumen mereka. (Jika Anda mendapatkan kejang bibir saat bermain gitar, Anda salah melakukannya.) Pengembang perangkat lunak mendapatkan bug. Kami senang menemukan cara untuk mengurangi tingkat pemijahan mereka, tetapi itu tidak akan pernah menjadi nol.


3
Posisi awal juga bisa negatif. Jangan meremehkan kekuatan Legacy :)
Maglob

Merancang proyek dari nol adalah bagian yang mudah. Tetapi bahkan jika Anda bisa memulai proyek baru dari awal, yang jarang terjadi dengan sendirinya, Anda hanya akan menikmati membangun dari nol selama beberapa hari pertama. Daripada keputusan desain awal pertama ternyata salah dan semuanya hanya akan mulai menurun dari sana. Desain dari nol sama sekali tidak relevan dalam praktiknya.
Jan Hudec

1

Biaya perubahan sweeping seringkali sebanding dengan ukuran basis kode. Oleh karena itu, pengurangan ukuran basis kode harus selalu menjadi salah satu tujuan dari setiap desain yang tepat.

Dalam contoh Anda, desain yang tepat telah membuat pekerjaan Anda lebih mudah: harus membuat perubahan di sepanjang 2000 baris basis kode, alih-alih 20.000 atau 200000 baris basis kode.

Desain yang tepat mengurangi perubahan besar, tetapi tidak menghilangkannya.

Perubahan menyeluruh cukup mudah dilakukan jika ada dukungan yang tepat dari alat analisis bahasa. Perubahan blanket refactoring dapat diterapkan ke seluruh basis kode dengan gaya pencarian-dan-ganti (sambil tetap menghormati aturan bahasa). Programmer hanya perlu membuat penilaian ya / tidak untuk setiap klik pencarian.


+1 untuk saran otomatisasi. Saya pikir saya akan benar-benar menggunakannya untuk banyak fungsi pustaka saya yang memanggil penutupan - ini masalah sederhana untuk mendeteksi fungsi mana yang mengambil blok dan memodifikasinya untuk memiliki parameter simbol tambahan untuk nama argumen untuk meneruskan nilainya.
exist-forall
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.