Pertahanan untuk boilerplate?

14

Bagi saya, kode boilerplate jelas buruk. Namun saya telah bertemu dengan seorang pengembang yang menampilkan resistansi dalam setiap upaya untuk mengurangi boilerplate. Saya menyadari bahwa saya tidak memiliki argumen yang siap dibentuk, dipikirkan dengan baik melewati kebencian yang telah saya kembangkan selama ini.

Agar saya dapat membentuk argumen yang meyakinkan untuk mendukung pelat yang lebih sedikit, apa sajakah yang bertentangan? Dengan kata lain, apa argumen (jika ada) yang mendukung boilerplate?

(Maksud saya apa yang saya pikir pada umumnya dimaksudkan dengan boilerplate, tetapi contoh yang baik adalah getter dan setters di Jawa.)

diabstraksi
sumber
7
Argumen terhadap kode duplikat (dengan asumsi boilerplate disalin / ditempelkan): stackoverflow.com/a/2490897/1583
Oded
1
@ Oded: Itu benar. Tetapi Anda salah membaca pertanyaan. :) Dia mencoba mencari apakah ada sesuatu untuk dikatakan untuk kode boilerplate. Dugaan saya adalah dia sangat tahu tentang kerugiannya.
Steven Jeuris
3
@ SevenJeuris - Saya membaca pertanyaan dengan sempurna. Itu sebabnya saya tidak mengirim jawaban. Saya hanya menambahkan ke sisi lain dari argumen. Persis seperti OP telah "argumen yang siap dibentuk, dipikirkan dengan baik melewati kebencian saya telah dikembangkan untuk itu dari waktu ke waktu" untuk waktu berikutnya;)
Oded
2
Boilerplate bisa menyenangkan secara estetika: en.wikipedia.org/wiki/This_Is_the_House_That_Jack_Built
SK-logic
Beberapa jawaban dan komentar baik yang saling melengkapi ... sulit untuk memilih mana yang akan diterima.
disarikan

Jawaban:

15

Satu hal penting untuk diingat adalah bahwa kode umumnya dibuat lebih kecil dengan menghapus konteks yang tidak perlu. Jika kompilator dapat menemukan sesuatu, argumen itu berbunyi, tidak perlu menuliskannya secara eksplisit.

Dan itu akan bagus jika hanya kompiler yang pernah bermaksud membacanya. Tetapi ingat bahwa "program harus ditulis untuk dibaca orang, dan hanya secara kebetulan untuk dijalankan oleh mesin." (Ironisnya, kutipan ini berasal dari buku teks yang didedikasikan untuk salah satu yang paling sulit dari semua bahasa untuk dibaca oleh manusia biasa, sebagian besar karena kesegarannya yang berlebihan.)

Apa yang terlihat seperti membosankan, berulang-ulang bagi Anda ketika Anda menulisnya dapat menjadi konteks yang berharga bagi orang lain yang datang setahun (atau lima) kemudian dan harus menjaga kode Anda.

WRT contoh Java secara khusus, saya akan setuju bahwa itu adalah contoh yang baik dari platplate yang buruk, karena dapat diganti dengan sesuatu yang lebih pendek dan lebih mudah dibaca, dan juga lebih fleksibel: Properti. Tetapi itu tidak berarti bahwa semua elemen sintaksis boilerplate dari semua bahasa sama borosnya dengan getter dan setter dari Java dan C ++.

Mason Wheeler
sumber
7
Tentu saja, argumen ini bekerja dua arah. Sejumlah besar kode boilerplate ada di sana untuk menenangkan kompiler dan tidak membantu manusia memahami - untuk tetap menggunakan getter / setter, lusinan baris tersebut harus dibaca seluruhnya untuk memastikan "itu hanya getter dan setter yang dilakukan". , daripada membaca satu baris pendek per properti yang hanya menyatakan bahwa itu adalah properti dan jenis apa yang dimilikinya.
6
Saya pikir boilerplate juga berbahaya bagi pembaca manusia. Dengan dipaksa menulis teks berulang yang tidak berarti, kami mengaburkan bagian kode yang relevan dari orang lain. Jika ada sesuatu yang bermanfaat, maka menurut definisi itu bukan boilerplate.
Andres F.
1
@Iorgio: Sebaliknya, ini lebih dari sekadar pendapat saya; itu pendapat sebagian besar orang yang pernah mencoba mempelajarinya. Dan ketika "sulit dibaca" pada dasarnya merupakan masalah pendapat, fakta bahwa pendapat itu dibagikan secara luas cukup banyak menjadikannya fakta.
Mason Wheeler
1
@Mason Wheeler: Bagaimana orang memahami bahasa pemrograman sering dipengaruhi oleh pengalaman masa lalu mereka. Orang yang belajar memprogram dalam Skema menemukan C atau Pascal canggung dan sulit dibaca. Di sisi lain, sebagian besar orang belajar memprogram dalam bahasa umum.
Giorgio
2
Saya berpendapat bahwa ketika lebih banyak konteks disembunyikan dari programmer dengan menghapus boilerplate itu hanya berarti bahwa Manusia harus menjaga peta mental yang lebih besar dari semua hal yang terjadi di balik layar Dan itu adalah kerugian yang lebih besar ketika datang ke debugging daripada menghemat sedikit ruang visual saat menulis.
Patrick Hughes
7

Salah satu argumen yang mendukung kode boilerplate adalah bahwa jika Anda mengubahnya di satu tempat, itu hanya mempengaruhi satu aliran kode. Ini harus diseimbangkan dengan fakta bahwa lebih-sering-daripada-tidak, Anda benar-benar ingin perubahan mempengaruhi setiap bagian dari kode yang menggunakannya. Tetapi saya telah melihat contoh langka yang mendukung argumen.

Katakanlah Anda memiliki kode yang bertuliskan

public ForTheBar(Foo foo)
{
    Bar bar = foo.bar();
    return bar.BeFooed();
}

Ini digunakan di sekitar 2 tempat dalam kode Anda.

Suatu hari seseorang datang dan berkata "ok, di jalur ini saja, kami ingin Anda Grommit bar sebelum Fooing itu."

Dan Anda berpikir "yah ini sederhana."

public ForTheBar(Foo foo, bool shouldIGrommit)
{
    Bar bar = foo.bar();

    if (shouldIGrommit)
    {
        bar.BeGrommitted();
    }

    return bar.BeFooed();
}

Kemudian pengguna Anda menambahkan beberapa fungsi baru dan Anda merasa cocok dengan FooTheBar. Dan Anda patuh bertanya kepada mereka apakah Anda harus Grommit bar itu sebelum Anda Foo dan mereka berkata "tidak, tidak kali ini".

Jadi Anda tinggal memanggil metode di atas.

Tetapi kemudian pengguna Anda berkata "ok, tunggu, dalam kasus ketiga, kami ingin Anda mencoret-coret Bar sebelum menelepon BeFooed."

Tidak masalah, Anda pikir, saya bisa melakukannya.

public ForTheBar(Foo foo, bool shouldIGrommit, bool shouldIDoodle)
{
    Bar bar = foo.bar();

    if (shouldIGrommit)
    {
        bar.BeGrommitted();
    }

    if (shouldIDoodle)
    {
        bar.BeDoodled();
    }

    return bar.BeFooed();
}

Tiba-tiba kode Anda menjadi kurang matang. Mungkin Anda seharusnya menerima dua baris kode yang berulang. Sekarang Anda akan memiliki tiga potong kode, masing-masing panjangnya 2-3 baris dan tidak terlihat berulang lagi.

Semua ini berkata, saya akan membantah bahwa dengan "ini bukan kasus yang umum, dan ketika itu terjadi, Anda dapat refactor."

Argumen lain yang baru-baru ini saya dengar adalah bahwa kode boilerplate terkadang dapat membantu Anda menavigasi kode. Contoh yang kami diskusikan adalah di mana kami telah menghapus banyak kode pemetaan boilerplate dan menggantinya dengan AutoMapper. Sekarang, itu diperdebatkan, karena semuanya berbasis konvensi, Anda tidak bisa mengatakan "Di mana properti ini diatur," ke IDE dan berharap untuk mengetahuinya.

Saya telah melihat orang-orang memperdebatkan hal-hal serupa tentang wadah IoC.

Bukan untuk mengatakan bahwa saya setuju dengan mereka, tetapi itu adalah argumen yang adil.

pdr
sumber
2
Saya lebih suka bagian kedua dari jawaban Anda. ; p +1
Steven Jeuris
Sadarilah contoh saya sangat mirip dengan milik Anda ... tebak, bahkan jika itu tidak masuk akal tampaknya terjadi sedikit :)
kritzikratzi
6

Evolusi efisiensi

Anda mulai dengan ini:

<p>
    <label for="field">My field</label>
    <input type="text" id="field">
</p>

maka Anda menyingkirkan semua boilerplate yang mengganggu dan memasukkannya ke dalam fungsi:

  1. createFieldHtml( id, label )

    ini bagus, saya menyimpan sendiri begitu banyak baris!

  2. createFieldHtml( id, label, defaultValue )

    ya, saya butuh nilai default juga, itu mudah ditambahkan.

  3. createFieldHtml( id, label, defaultValue, type )

    keren, saya bisa menggunakannya untuk kotak centang sekarang juga

  4. createFieldHtml( id, label, defaultValue, type, labelFirst )

    Perancang UX mengatakan label harus setelah kotak centang.

  5. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate )

    sekarang membuat pemilih tanggal saat dibutuhkan. Hm .. params semakin tidak terkendali

  6. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate, containerCssClasses )

    ada satu kasus ini di mana saya perlu menambahkan kelas CSS

  7. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate, containerCssClasses, fieldCssClasses, disabled, clearAfter, helpText, uploadPath )

    aaaaaaaaaaaaaaaaaaaaa

Mempertahankan boilerplate

Saya mengalami kesulitan memasukkan kata-kata ini karena ini benar-benar sesuatu yang saya perhatikan baru-baru ini, jadi saya akan membuat daftar:

  1. Tampaknya bagi saya ada ketakutan tertentu untuk memiliki garis duplikat yang sedikit melebar. Jika hanya beberapa baris mungkin tidak ada masalah sama sekali. beberapa hal secara inheren "hampir berulang" (seperti contoh di atas). Saya melihat sedikit peluang dalam mengoptimalkan sana dalam jangka panjang.
  2. Orang suka merangkum fungsionalitas di suatu tempat; jika Anda melihat secara objektif dan sepertinya itu hanya "menyembunyikan kekacauan" - curiga! mungkin ini waktu untuk beberapa kompor tua yang baik
  3. Ketika Anda memiliki fungsi yang menjadi semakin kuat; yang membutuhkan banyak jalur eksekusi berbeda tergantung pada input dan pada akhirnya tidak terlalu banyak - mungkin ini waktu yang singkat!
  4. Ketika Anda menambahkan lapisan abstraksi di atas lapisan abstraksi lain, tetapi hanya untuk membuat kode Anda lebih pendek (lapisan yang mendasarinya tidak dimaksudkan untuk diubah) - waktu boilerplate!
  5. Ketika Anda memiliki fungsi yang membutuhkan begitu banyak parameter sehingga Anda benar - benar perlu menamai parameter - mungkin ini saatnya boilerplate.

Satu hal yang saya selalu tanyakan pada diri sendiri adalah ini:
Dapatkah saya menyalin & menempel ke proyek lain tanpa mengubah apa pun? jika ya, tidak apa-apa untuk merangkum atau dimasukkan ke dalam perpustakaan, jika tidak: saatnya boilerplate.

Ini sangat bertentangan dengan persepsi umum bahwa boilerplate adalah kode copy & paste. Bagi saya boilerplate adalah tentang copy & paste, tetapi selalu harus sedikit men-tweak.


Pembaruan : Saya baru saja menemukan artikel yang memberikan contoh saya di atas nama sebenarnya: "terlalu anti-pola KERING".

Fungsi ini mendapatkan lebih banyak parameter dan memiliki logika internal yang semakin kompleks untuk mengontrol perilakunya dalam berbagai kasus. Fungsi Terlalu KERING mudah dikenali. Mereka memiliki banyak logika if-then yang rumit yang mencoba menangani beragam penggunaan. [...] Juga, kode berulang tidak selalu buruk jika kode itu kecil dan melakukan fungsi diskrit.

Ini bacaan singkat dan menarik, Anda dapat menemukan artikel di sini: Anti-Pola Terlalu Kering

kritzikratzi
sumber
1
"Ketika Anda menambahkan lapisan abstraksi di atas lapisan abstraksi lain, tetapi hanya untuk membuat kode Anda lebih pendek" Benar, Anda hanya perlu menambahkan lapisan abstraksi ketika ada kemungkinan untuk digunakan kembali.
Steven Jeuris
4
+1. Jangan ulangi diri sendiri, tapi jangan pergi ke panjang canggung untuk menghindari hampir mengulangi diri.
Julia Hayward
4

Saya membenci kode boilerplate, tetapi bisa menghapus kode boilerplate tidak selalu berarti itu adalah cara terbaik untuk pergi.

Kerangka WPF memiliki sifat ketergantungan , yang melibatkan jumlah kode boilerplate yang gila. Selama waktu luang saya, saya menyelidiki solusi yang sangat mengurangi jumlah kode yang perlu ditulis. Lebih dari satu tahun kemudian saya masih meningkatkan solusi ini , dan masih perlu memperluas fungsionalitasnya atau memperbaiki bug.

Apa masalahnya? Ini bagus untuk mempelajari hal baru, dan mencari solusi alternatif, tetapi itu mungkin bukan keputusan komersial terbaik .

Kerangka kerja WPF didokumentasikan dengan baik. Itu benar mendokumentasikan bagaimana menulis kode boilerplate Anda. Mencoba untuk menghapus kode boilerplate ini adalah latihan yang bagus, dan sesuatu yang pasti perlu ditelusuri, tetapi mencapai tingkat 'polesan' yang sama seperti yang ditawarkan msdn membutuhkan waktu lama, yang tidak selalu kita miliki.

Steven Jeuris
sumber
Namun, saya masih cukup senang dengan hasil yang saya miliki saat ini, dan dengan senang hati menggunakannya dalam proyek waktu luang saya. :)
Steven Jeuris
3
setiap kali saya menyentuh WPF dan properti dependensi itu, saya selalu berharap C # memiliki sesuatu yang sederhana seperti makro C ++. Memang makro disalahgunakan di tangan yang salah, tetapi mereka bisa menghilangkan begitu banyak pengulangan di sini. Saya harus melihat kerangka kerja AOP Anda lain kali saya mulai berharap untuk makro itu :)
DXM
@DXM Jika Anda melakukannya, dan itu crash dengan menyedihkan, jangan lupa untuk menyalahkan saya dan memposting kesalahan. ; p
Steven Jeuris
Cuplikan kode berfungsi dengan baik untuk properti dependensi.
Codism
@Codism: Ya, mereka adalah solusi, tapi saya juga benci itu . :)
Steven Jeuris
1

Masalah dengan boilerplate adalah melanggar KERING. Intinya, ketika Anda menulis boilerplate, Anda mengulangi kode yang sama (atau kode yang sangat mirip) di sejumlah kelas. Ketika kode itu perlu diubah, sama sekali tidak pasti bahwa pengembang akan mengingat semua tempat kode itu diulang. Ini mengarah ke bug di mana API lama atau metode lama digunakan.

Jika Anda membuat ulang boilerplate ke perpustakaan umum atau kelas induk, maka Anda hanya perlu mengubah kode di satu tempat ketika API Anda berubah. Lebih penting lagi, ketika perubahan tak terduga terjadi, kode terputus di satu tempat, dan membuat Anda tahu persis apa yang harus Anda perbaiki agar semuanya kembali berfungsi. Ini jauh lebih disukai daripada skenario di mana satu perubahan menyebabkan kegagalan dalam lusinan, atau bahkan ratusan kelas.

quanticle
sumber
2
Bagaimana ini argumen yang mendukung boilerplate ?
Chris Wesseling
0

Saya akan mengambil kebijaksanaan yang berbeda. Konsistensi dalam pengembangan adalah salah satu fitur terpenting dari desain perangkat lunak, ini adalah alat penting dalam membuat aplikasi dapat diperluas dan dipelihara tetapi bisa sulit dicapai ketika mengelola tim di berbagai situs, bahasa, dan zona waktu.

Jika tercapai, konsistensi membuat kode jauh lebih mudah diakses "begitu Anda melihatnya, Anda telah melihat semuanya", jauh lebih murah untuk dirawat dan diperbaiki, tetapi di atas semua itu, jauh lebih mudah untuk diperluas. Saat Anda menulis pustaka yang memang membutuhkan beberapa pelat, bersamaan dengan kekuatan pustaka Anda, Anda juga telah memberi pengembang:

  • Titik awal memahami pembukaan (boilerplate) ke dalam fungsionalitas Anda, sebagian besar kelas utama dan titik akses biasanya akan ditampilkan sebagai bagian dari pelat boiler. Ini memberi pengembang titik awal ke dalam dokumentasi
  • Harapan penempatan Anda pada pengembang akan menjadi jelas, misalnya jika Anda menyiapkan objek penelusuran sebagai bagian dari pembukaan, maka pengembang akan tahu di mana harus mencatat pengecualian dan informasi
  • Pemahaman implisit saat Anda memaksa pengembang untuk melalui proses instantiating kelas Anda, mereka dapat menyimpulkan teknik yang mereka butuhkan untuk mengakses perpustakaan Anda yang lain dan memiliki kesempatan untuk memperkenalkan mereka ke konvensi yang telah Anda gunakan di seluruh perpustakaan Anda
  • Validasi mudah ketika kode boilerplate Anda diperlukan, biasanya dapat dengan mudah memvalidasi dirinya sendiri dengan pengecualian dan klausa penjagaan, mencegah konsumen dari terjebak lebih jauh di telepon ketika Anda sudah berkomitmen untuk proses yang salah
  • Konfigurasi pustaka yang membutuhkan kode boilerplate mudah karena sudah ada titik implementasi yang jelas untuk menyesuaikan fungsionalitas untuk satu jalur eksekusi. Ini sangat berguna jika kode boilerplate yang Anda butuhkan ditingkatkan dengan pola Factory atau Command

Ketika konsumen perpustakaan Anda menguasai instantiasi, mereka dapat dengan mudah membuat metode pribadi / ekstensi, kelas induk atau bahkan templat untuk mengimplementasikan kode boilerplate.

Mati
sumber
-3

Satu-satunya masalah nyata dengan kode boilerplate adalah bahwa ketika Anda menemukan bug di dalamnya Anda harus memperbaiki di mana-mana Anda menggunakannya daripada satu-satunya tempat yang Anda gunakan kembali .

Edward Strange
sumber