Apakah monkeypatching dianggap praktik pemrograman yang baik?

15

Saya mendapat kesan, bahwa monkeypatching lebih dalam kategori hack cepat dan kotor, daripada praktik pemrograman standar yang baik. Sementara saya telah menggunakan dari waktu ke waktu untuk memperbaiki masalah kecil dengan lib pihak ke-3, saya menganggap itu perbaikan sementara dan saya akan mengirimkan tambalan yang tepat untuk proyek pihak ke-3.

Namun, saya telah melihat teknik ini digunakan sebagai "cara normal" dalam proyek-proyek utama, misalnya dalam gevent.monkeymodul Gevent .

Apakah monkeypatching menjadi arus utama, normal, praktik pemrograman yang dapat diterima?

Lihat juga: "Monkeypatching For Humans" oleh Jeff Atwood

vartec
sumber
13
Saya akan mengatakan bahwa sesuatu yang disebut patch monyet TIDAK dianggap praktik pemrograman yang baik. Tanpa tahu apa itu, cukup dengan namanya saja.
littleadv
Bagaimana jika pihak ke-3 tidak ingin melakukan perbaikan yang Anda butuhkan?
1
@ Thorbjørn: pertanyaan yang bagus, di satu sisi saya tidak suka monkeypatching, di sisi lain saya tidak terlalu suka ide proyek kloning dan menyimpan patch lokal jika itu hanya masalah kecil.
vartec
1
@ littleadv: ... lalu sebut "hot fix" / "on-the-fly fix" atau "perbaikan runtime" dan kedengarannya bagus bukan? ;) Semuanya sama.
dagnelies
3
javascript cukup banyak dibangun di sekitar konsep
ZJR

Jawaban:

19

Tidak, tapi terkadang monkeypatch adalah kejahatan yang lebih kecil (daripada memiliki kode yang rusak :)). Aturan umum saya untuk monkeipatch di ruby ​​adalah:

  • memiliki alasan yang sangat bagus untuk monkey-patch (perbaikan terbaru sementara yang kritis adalah alasan yang bagus. Pemformatan yang bagus dari metode to_s tidak, kecuali jika Anda sedang mengerjakan ActiveSupport)

  • buatlah setransparan mungkin: letakkan di tempat tertentu dalam basis kode dan pisahkan file, tulis dokumentasi yang menjelaskan alasan monkeypatch (inilah contohnya ).

  • mudah dihapus - dokumentasi harus menyertakan info tentang penghapusan dan apa yang harus diperhatikan. Banyak monkeypatch bersifat sementara, sehingga mudah dihapus.

Lukas Stejskal
sumber
11

Ya, monkeypatching sangat berguna!

Entah bagaimana, nama tampaknya sangat berpengaruh pada persepsi orang. Sebut saja "monkeypatch" dan kedengarannya buruk, sebut saja "hot fix" atau "on-the-fly fix" dan kedengarannya bagus.

Terlepas dari itu, saya pikir kemampuan untuk mengubah metode / atribut / fungsi saat runtime adalah hal yang sangat berguna. Bahkan orang javascript menggunakannya sepanjang hari tanpa mungkin menyadarinya.

Contohnya:

button.onclick = function(e) { ...}

Baris sederhana ini menggambarkan fakta bahwa Anda mengubah perilaku tombol. Itu dirancang seperti itu. Demikian juga, Anda dapat mengubah setiap fungsi lain tetapi itu konyol untuk melakukannya.

Sekarang, untuk pertanyaan tentang pengiriman tambalan seperti itu ... yah ... mengapa tidak. Anda hanya perlu mengunduh tambalan kecil alih-alih rilis besar. Heck, Anda bahkan bisa menambal server tanpa menghentikannya, bagus! Dan kemudian, suatu hari, Anda juga bisa mengambil rilis terbaru untuk pembaruan yang lebih besar. Cukup adil. Jadi ya, saya memilih "runtime patches" sebagai hal yang baik.

Yang cukup menarik, beberapa bahasa seperti Erlang bahkan dibangun di sekitar konsep ini. Kemampuan untuk memperbarui server dengan cepat.

Tentu saja, pada akhirnya, dan suka dengan yang lainnya, itu masalah bagaimana Anda menggunakannya. Anda dapat membuat barang-barang OO yang bagus dan menyebalkan, semuanya sama saja.

EDIT:

Izinkan saya menambahkan beberapa perbedaan huruf besar, baik Anda menambal perpustakaan Anda sendiri atau perpustakaan pihak ketiga .

... pada dasarnya, apa yang Anda lakukan dengan tambalan itu adalah memperbaiki bug Anda sendiri atau pustaka pihak ketiga . Dalam kedua kasus itu berguna. Untuk Anda sendiri, ini memungkinkan Anda mengirimkan perbaikan saat bepergian. Untuk pihak ketiga, Anda menunggu (beberapa bulan?) Sampai mereka memperbaikinya sendiri, atau Anda melakukannya sendiri. (Anda masih bisa mengirimkan mereka tambalan, sehingga mereka akan memperbaikinya di sisi mereka). Ketika mereka merilis versi lib berikutnya dengan masalah diperbaiki, Anda masih bisa, jika Anda ingin memperbarui perpustakaan dan menghapus tambalan di sisi Anda.

Sekarang, tentu saja, jika Anda menggunakan tambalan untuk mengubah perilaku lib dan mengasingkan tujuan / cara kerjanya, maka jelas itu adalah resep untuk bencana. Bahkan seekor monyet akan melihat itu ... well, saya harap. ;)

dagnelies
sumber
1
Tidak ada yang mengatakan itu tidak berguna. Namun, itu bukan praktik yang baik secara umum. Dan "perbaikan terbaru" dan "perbaikan saat ini" tidak terdengar lebih baik bagi saya.
Lukas Stejskal
1
Yah, saya menemukan kemampuan mengubah perilaku aplikasi dengan cepat sangat berguna, bahkan lebih jika itu besar. Heck, Anda bahkan bisa memiliki kode yang menyimpan metode lama sebagai cadangan dan perintah untuk secara otomatis kembalikan pada permintaan! Kemungkinannya luar biasa!
dagnelies
Saya setuju bahwa ini fitur yang kuat dan berguna. Tetapi juga sangat berbahaya (khususnya di Ruby), oleh karena itu harus digunakan dengan sangat hati-hati (khususnya untuk modifikasi perpustakaan standar dan pihak ketiga). Pernahkah Anda mencoba untuk mempertahankan aplikasi tergantung pada beberapa perpustakaan pihak ke-3 yang monkeypatch? Resep bencana setiap kali Anda mencoba memperbarui perpustakaan.
Lukas Stejskal
1
Ya, saya setuju, jika Anda menggunakan patch ini secara sembarangan, dengan cara yang tidak disengaja atau menyalahgunakannya, itu dapat dengan cepat menjadi berantakan. Seperti Anda dapat menyalahgunakan konsep apa pun atau membuat kekacauan dengan apa pun. Namun, jika tidak, jika mereka terorganisir dengan baik dan transparan, dan mereka semua mengalir di rilis besar berikutnya, itu terlihat bersih bagiku. ... Namun, saya tidak punya pengalaman dengan perpustakaan ruby ​​yang sangat ditambal.
dagnelies
... Saya menambahkan beberapa komentar pada kasus terakhir.
dagnelies
8

Saya percaya bahwa semua tambalan secara inheren berisiko karena sifatnya run-time, dan ketidakmampuan untuk ditangkap pada waktu desain.

Mereka menerima pengecualian runtime, dan membutuhkan debugger dan jam tangan yang kompleks hanya untuk mengikuti.

Mereka digunakan ketika orang kelas SEAL, dan jadi warisan tidak mungkin. Namun, ada cara yang lebih baik untuk memperluas objek tanpa merusaknya.

Dua sen saya

Mickey Perlstein
sumber
4

Menambal secara umum harus menjadi pilihan terakhir, bahkan menambal monyet juga. Masalah ini terutama salah satu dari rawatan.

Beberapa waktu yang lalu, kernel linux saya memiliki 3 tambalan terpisah yang diterapkan padanya, yang diperlukan untuk driver kartu video saya dan dua aplikasi berpemilik yang saya miliki. Dua dari mereka memiliki perubahan yang saling bertentangan, yang berarti saya membutuhkan tambalan ke-4 untuk menyelesaikan perbedaan di antara mereka. Sekarang setiap kali masalah keamanan diperbaiki di kernel hulu, saya juga harus menunggu vendor dari 3 patch untuk merilis pembaruan ke versi kernel baru, yang memakan waktu dari satu hingga enam bulan, atau saya harus secara manual mempertahankan upstream patch keamanan sampai vendor patch lain menyusul.

Setelah beberapa tahun, para vendor berhasil dimasukkan ke dalam sumber kernel hulu, dan saya dapat menghentikan tindakan penyeimbangan, tetapi Anda dapat melihat kekacauan apa yang terjadi pada saat itu. Jangan lakukan itu pada programmer Anda kecuali Anda harus melakukannya.

Karl Bielefeldt
sumber
3

Tidak. Ini bukan teknik standar untuk pengembangan perangkat lunak. Ini masih merupakan solusi untuk menyelesaikan masalah akut dan memiliki kelemahan yang jelas. Pelanggaran Prinsip Substitusi Liskov muncul di benak saya. Penambalan monyet membuatnya lebih sulit untuk berpikir tentang program. Untuk program Anda sendiri, Anda harus menempatkan kode di tempatnya. Untuk lib pihak ketiga Anda akan selalu hidup dalam bahaya, bahwa tambalan Anda tidak akan berfungsi dengan versi lib berikutnya.

Tentu saja tambalan monyet berguna jika Anda tahu apa yang Anda lakukan dan tidak punya waktu untuk menerapkan solusi SOLID . Tetapi Anda tidak boleh menganggap ini sebagai teknik standar dan membangun tambalan monyet di atas tambalan monyet.

BTW, apakah Anda pernah menulis unit test untuk patch monyet?

scarfridge
sumber
Saya tidak berpikir Anda dapat menerapkan LSP di sini. Ini memiliki definisi yang sangat spesifik mengenai subtipe.
Konrad Rudolph
@KonradRudolph Monkey menambal objek mengubah tipenya. Dalam bahasa yang diketik secara dinamis, setiap jenis t dengan antarmuka yang sama dengan tipe u adalah subtipe dari u. Jika berjalan seperti bebek ...
scarfridge
"... mengubah tipenya" - cukup adil. Masuk akal.
Konrad Rudolph
RE "Ini bukan teknik standar untuk pengembangan perangkat lunak.", Sepertinya dilakukan * sepanjang waktu dan di perpustakaan utama "dengan Python untuk pengujian.
Tommy