Bagaimana cara menghindari metode lem raksasa?

21

Dalam pekerjaan saya saat ini, saya telah ditugaskan untuk membersihkan kode lama beberapa kali. Seringkali kodenya labirin dan data di belakangnya bahkan lebih kusut. Saya menemukan diri saya menyisir hal-hal menjadi metode modular yang bagus, rapi,. Setiap metode melakukan satu hal dan melakukannya dengan baik. Saat itulah segalanya mulai berjalan ke selatan ...

Selalu, saya berakhir dengan API bersih dan tidak ada cara nyata untuk mengikat semuanya. Solusinya adalah dengan menulis metode "lem" jelek besar (umumnya penuh dengan pernyataan kondisional) yang akhirnya memanggil semua metode "bersih" saya.

Metode lem biasanya berakhir dengan versi singkat dari kusut kode / data yang saya coba bersihkan. Secara umum lebih mudah dibaca, tetapi masih mengganggu.

Bagaimana saya bisa menghindari metode seperti itu? Apakah ini gejala dari data kusut atau cerminan dari sesuatu yang saya lakukan salah?

cmhobb
sumber
3
API dimaksudkan untuk digunakan. Dari kekacauan kusut yang Anda dapatkan, Anda membuat API dan kemudian menyusunnya kembali. Mungkin itu hanya persyaratan bisnis. Tetapi Anda menambahkan nilai karena orang lain dapat datang dan membuat fungsi lem lainnya dengan mudah menggunakan API Anda. Tidak perlu meremas-remas tangan ...
Aditya MP
1
Apakah kita bahkan berbicara objek di sini atau hanya berfungsi di semua tempat?
Erik Reppen
3
Saya tidak berpikir ini adalah duplikat dari pertanyaan itu, saya berbicara sedikit lebih umum (dan pada skala yang lebih besar daripada fungsi tunggal).
cmhobbs
1
erik - Saya berbicara tentang objek dan metode di sini. Saya telah mengambil beberapa kekacauan bersyarat dan mengubahnya menjadi API. Masalahnya muncul ketika tiba saatnya untuk memanggil API. Namun, jawaban pertama di sini mungkin persis apa yang saya cari.
cmhobbs
2
Bagaimana bisa itu duplikat?
MattDavey

Jawaban:

12

Saya akan memberi Anda pengalaman kami refactoring LedgerSMB. Kami membuat keputusan untuk melakukan hal-hal yang berbeda sejak awal dan masih melakukan apa yang Anda jelaskan tetapi tanpa banyak metode lem (kami memiliki beberapa metode lem btw, hanya saja tidak banyak).

Hidup dengan Dua Basis Kode

LedgerSMB telah bertahan dengan dua basis kode selama sekitar 5 tahun dan akan ada beberapa lagi sebelum basis kode lama dihilangkan. Basis kode lama adalah horor sejati untuk dilihat. Desain db buruk, Perl membangun seperti IS->some_func(\%$some_object);bersama dengan kode yang menunjukkan dengan tepat mengapa metafora spaghetti kadang-kadang digunakan (jalur eksekusi berkelok-kelok antara modul dan kembali, dan antara bahasa, tanpa sajak atau alasan). Basis kode baru menghindari ini dengan memindahkan kueri db ke dalam prosedur tersimpan, memiliki kerangka kerja yang lebih bersih untuk penanganan permintaan, dan banyak lagi.

Hal pertama yang kami putuskan untuk lakukan adalah mencoba untuk memperbaiki modul demi modul. Ini berarti memindahkan semua fungsi di area tertentu ke modul baru dan kemudian mengaitkan kode lama ke modul baru. Jika API baru bersih, ini bukan masalah besar. Jika API baru bukan sesuatu menjadi berbulu dan itu undangan untuk bekerja sedikit lebih keras di API baru ....

Yang kedua adalah ada banyak waktu ketika kode baru harus mengakses logika dalam kode lama. Hal ini harus dihindari sejauh mungkin karena mengarah pada metode lem yang jelek tapi tidak selalu bisa dihindari. Dalam hal ini metode lem harus diminimalkan dan dihindari sejauh mungkin tetapi digunakan jika perlu.

Untuk membuat ini berfungsi, Anda harus berkomitmen untuk menulis ulang semua fungsi di area tertentu. Jika Anda dapat, misalnya, menulis ulang semua kode pelacakan informasi pelanggan sekaligus, itu berarti bahwa kode yang memanggil ini dari kode lama tidak sulit untuk dikerjakan, dan pengiriman ke kode lama dari kode baru diminimalkan.

Yang kedua adalah bahwa jika Anda memiliki abstraksi yang masuk akal di tempat Anda, Anda harus dapat memilih level API mana yang harus dihubungi dan bagaimana menjaga kebersihannya. Namun, Anda harus memikirkan untuk menulis ulang bagian-bagian yang memanggil API Anda sehingga mereka juga sedikit lebih bersih.

Ada banyak bidang alat bisnis yang tidak dapat direduksi menjadi rumit. Anda tidak dapat menghilangkan semua kerumitan. Tetapi Anda dapat mengelolanya dengan berfokus pada API bersih yang secara spesifik melakukan apa yang perlu Anda lakukan, dan modul yang memanfaatkan API itu secara konstruktif. Lem harus menjadi pilihan terakhir hanya setelah mempertimbangkan bahwa menulis ulang sisa kode panggilan mungkin lebih cepat.

Chris Travers
sumber
Saya pikir Anda mungkin telah memukul paku di kepala. Alasan lem ada mungkin karena kode yang memanggil antarmuka yang saya buat. Saya akan menunggu beberapa tanggapan untuk melihat apakah kita kehilangan sesuatu, tapi saya percaya yang satu ini menyimpulkannya dengan cukup baik.
cmhobbs
1
"jalur eksekusi berliku-liku antara modul dan kembali, dan antara bahasa, tanpa sajak atau alasan" - ini mengingatkan saya pada beberapa praktik OO modern juga.
user253751
8

Kedengarannya seperti apa yang telah Anda lakukan diambil berantakan kusut dari basis kode precedural dan menciptakan basis kode modular presedural yang indah .

Selalu, saya berakhir dengan API bersih dan tidak ada cara nyata untuk mengikat semuanya. Solusinya adalah dengan menulis metode "lem" jelek besar (umumnya penuh dengan pernyataan kondisional) yang akhirnya memanggil semua metode "bersih" saya.

Dengan kode prosedural (bahkan jika disamarkan sebagai OO), Anda akan selalu berakhir dengan semacam alur kerja sekuensial yang didefinisikan di suatu tempat, sering kali diisi dengan cabang bersyarat kompleks seperti yang Anda gambarkan. Saya menduga ini adalah sifat prosedural dari kode yang membuat Anda merasa ada sesuatu yang salah. Ini tidak selalu merupakan hal yang buruk, dan ketika bekerja dengan kode lawas mungkin sepenuhnya tidak dapat dihindari

MattDavey
sumber
6

Anda harus membersihkan metode lem besar jelek dengan cara yang sama Anda membersihkan basis kode asli. Membaginya dalam metode modular yang rapi. Anda mungkin memiliki kelompok garis kode yang melakukan beberapa tugas, membagi garis-garis ini dalam metode, jika Anda berbagi beberapa variabel, Anda dapat mempertimbangkan untuk meletakkan variabel bersama dan metode baru dalam satu kelas.

Pagar
sumber
2
Bukankah kamu mendapatkan pohon lem?
Pieter B
3
@PieterB mungkin, tetapi lebih mudah untuk mengekstrak dependensi yang berbeda ketika Anda memiliki tugas yang berbeda dalam metode yang berbeda. Anda bisa melakukan pass refactoring lain setelah mengekstraksi metode baru.
Paling
1

Pada dasarnya, Anda terus menambahkan lapisan abstraksi, hingga terlihat tepat di setiap lapisan yang diambil sendiri . Hal yang paradoksal tentang abstraksi adalah Anda menambahkan kerumitan untuk menguranginya, karena ketika Anda membaca kode yang diabstraksikan, Anda hanya mementingkan diri sendiri dengan satu layer pada satu waktu. Jika setiap lapisan cukup kecil untuk mudah dipahami, tidak peduli berapa banyak lapisan tempat bertumpu.

Itu juga yang membuat abstraksi sulit ditulis. Bahkan sesuatu yang sederhana seperti pensil adalah pikiran yang tertekuk jika Anda mencoba menahan semua lapisan abstraksi di kepala Anda sekaligus. Kuncinya adalah mendapatkan satu lapisan sesuai keinginan Anda, yang telah Anda lakukan, lalu lupakan semua kerumitan yang mendasari lapisan itu dan lakukan hal yang sama di tingkat berikutnya.

Karl Bielefeldt
sumber
0

Sepertinya Anda refactoring API dengan hanya memikirkan implementasi API, tetapi tanpa cukup memikirkan kode yang menggunakan API - yaitu, "kode lem" yang Anda bicarakan.

Jika itu benar, Anda mungkin mencoba memulai dari ujung yang lain. Tulis ulang hal-hal yang mengancam untuk menjadi kode lem jelek Anda terlebih dahulu, dan buat beberapa antarmuka yang belum diimplementasikan yang akan menjadi API Anda dalam proses itu. Jangan terlalu memikirkan implementasi API yang sebenarnya - tidak apa-apa jika Anda punya firasat bahwa Anda dapat melakukannya. Dan baru kemudian menulis ulang labirin kode agar sesuai dengan API itu. Tentu saja akan ada beberapa perubahan dalam API dan kode lem dalam proses ini, tetapi harus cocok bersama lebih baik.

Hans-Peter Störr
sumber