Haruskah solusinya menjadi generik mungkin atau sespesifik mungkin?

124

Katakanlah saya memiliki entitas yang memiliki atribut "tipe". Mungkin ada 20+ tipe yang mungkin.

Sekarang saya diminta untuk mengimplementasikan sesuatu yang memungkinkan perubahan tipe dari A-> B, yang merupakan satu-satunya use case.

Jadi haruskah saya menerapkan sesuatu yang memungkinkan perubahan jenis sewenang-wenang asalkan mereka adalah tipe yang valid? Atau haruskah saya HANYA mengizinkannya untuk berubah dari A-> B sesuai persyaratan dan menolak perubahan jenis lain seperti B-> A atau A-> C?

Saya dapat melihat pro dan kontra dari kedua belah pihak, di mana solusi generik akan berarti lebih sedikit pekerjaan jika persyaratan yang sama muncul di masa depan, tetapi itu juga berarti lebih banyak peluang terjadi kesalahan (meskipun kami 100% mengontrol penelepon pada saat ini). titik).
Solusi spesifik lebih rentan kesalahan, tetapi membutuhkan lebih banyak pekerjaan di masa depan jika persyaratan yang sama muncul.

Saya terus mendengar bahwa pengembang yang baik harus mencoba mengantisipasi perubahan dan merancang sistem sehingga mudah untuk diperluas di masa depan, yang terdengar seperti solusi generik adalah cara untuk pergi?

Sunting:

Menambahkan lebih banyak detail ke contoh saya yang tidak terlalu spesifik: Solusi "generik" dalam kasus ini membutuhkan lebih sedikit pekerjaan daripada solusi "spesifik", karena solusi spesifik memerlukan validasi pada tipe lama dan juga tipe baru, sedangkan solusi generik hanya perlu memvalidasi tipe baru.

Program Cinta
sumber
97
Itu pertanyaan yang menarik. Saya sudah berdiskusi tentang sesuatu seperti itu dengan kakek saya (seorang programmer timer yang sangat, sangat tua) dan jawabannya adalah sesuatu di baris "hal paling umum yang memecahkan masalah spesifik Anda", yang bermuara pada sebuah fantasi " Tergantung". Pernyataan selimut dalam Pengembangan Perangkat Lunak jarang berhasil - hal-hal harus selalu diambil berdasarkan kasus per kasus.
T. Sar
2
@ T.Sar menambahkan ini sebagai jawaban dan saya akan menjawab :-)
Christophe
4
Apa itu "solusi umum" dalam pandangan Anda? Juga, mohon klarifikasi apa yang Anda maksud dengan "satu-satunya kasus penggunaan". Maksud Anda, hanya transisi dari A-> B yang diizinkan atau hanya transisi yang ditentukan, dan itu tidak akan menjadi kondisi kesalahan untuk transisi dari negara lain ke negara lain. Sebagai pengembang, Anda harus meminta penulis kasus penggunaan untuk mengklarifikasi. Jika tidak ada transisi lain yang diizinkan dan kode Anda mengizinkannya terlepas dari siapa yang mengendalikan penelepon, kode Anda gagal memenuhi persyaratan.
RibaldEddie
5
Prinsip bahwa jika X adalah ide yang baik, maka hanya X sepanjang waktu yang harus optimal, tampaknya memiliki daya tarik khusus untuk pengembang (atau setidaknya kelompok vokal di antara mereka), tetapi pertimbangkan ini: aturan pemrograman yang praktis adalah: seperti peribahasa, dalam hal itu Anda sering dapat menemukan pasangan dengan implikasi yang berlawanan. Ini adalah tanda bahwa Anda harus menggunakan penilaian Anda (sebagaimana disarankan oleh jawaban di sini), dan waspadalah terhadap dogma.
sdenham
2
Generalisasi Prematur dapat menyebabkan mulas sebanyak Optimalisasi - Anda akhirnya menulis banyak kode yang mungkin tidak pernah digunakan. Diselesaikan untuk masalah khusus terlebih dahulu, kemudian digeneralisasi ketika kebutuhan muncul.
John Bode

Jawaban:

296

Aturan praktis saya:

  1. pertama kali Anda menemukan masalah, hanya selesaikan masalah spesifik (ini adalah prinsip YAGNI )
  2. kali kedua Anda mengalami masalah yang sama, pertimbangkan menggeneralisasi kasus pertama, jika tidak banyak pekerjaan
  3. setelah Anda memiliki tiga kasus khusus di mana Anda dapat menggunakan versi yang digeneralisasi, maka Anda harus mulai benar-benar merencanakan versi yang digeneralisasi - sekarang, Anda harus memahami masalah dengan cukup baik untuk benar-benar dapat menggeneralisasikannya.

Tentu saja, ini adalah pedoman dan bukan aturan yang keras dan cepat: jawaban sebenarnya adalah menggunakan penilaian terbaik Anda, berdasarkan kasus per kasus.

Daniel Pryden
sumber
1
Bisakah Anda jelaskan apa itu YAGNI?
Bernhard
7
@ Bernhard Kau Tidak Akan Membutuhkannya . Prinsip perancangan perangkat lunak yang sangat berguna.
Angew
4
"Di thing1, thing2, pikirkan tentang mungkin menggunakan array. Di thing1, thing2, thing3, hampir pasti menggunakan thing[]array." adalah aturan praktis yang sama untuk memutuskan antara beberapa variabel atau satu array.
Joker_vD
15
Cara lain untuk menyatakan aturan # 1: "Anda tidak dapat menggeneralisasi satu hal."
Wayne Conrad
2
@SantiBailors: Seperti yang dikatakan Doc Brown dalam jawabannya, kita sering sangat melebih-lebihkan jumlah upaya sia-sia yang mungkin kita keluarkan dengan membangun yang pertama untuk dibuang. Dalam The Mythical Man-Month , Fred Brooks mengatakan: "Berencana untuk membuang satu - Anda akan, bagaimanapun." Yang mengatakan: jika Anda segera menemukan lebih dari satu penggunaan untuk sesuatu - misalnya, dengan mengirimkan seperangkat persyaratan di mana Anda jelas perlu menyelesaikan masalah yang sama lebih dari sekali - maka Anda sudah memiliki lebih dari satu kasus untuk digeneralisasi dari, dan itu sama sekali baik dan tidak bertentangan dengan jawaban saya.
Daniel Pryden
95

Solusi spesifik [...] membutuhkan lebih banyak pekerjaan di masa depan jika persyaratan yang sama diperlukan

Saya telah mendengar argumen ini beberapa lusin kali, dan - menurut pengalaman saya - sering berubah menjadi kesalahan. Jika Anda menggeneralisasi sekarang atau nanti, ketika persyaratan serupa kedua muncul, pekerjaan akan hampir sama secara total. Jadi sama sekali tidak ada gunanya menginvestasikan upaya tambahan dalam generalisasi, ketika Anda tidak tahu upaya ini akan membuahkan hasil.

(Jelas ini tidak berlaku ketika solusi yang lebih umum kurang rumit dan membutuhkan lebih sedikit usaha daripada yang spesifik, tetapi menurut pengalaman saya, ini adalah kasus yang jarang terjadi. Skenario seperti itu telah diedit setelahnya ke dalam pertanyaan, dan bukan satu jawaban saya adalah tentang).

Ketika "kasus serupa kedua" muncul, maka sekarang saatnya untuk mulai berpikir tentang generalisasi. Akan lebih mudah untuk menggeneralisasi dengan benar , karena persyaratan kedua ini memberi Anda skenario di mana Anda dapat memvalidasi jika Anda membuat hal-hal yang benar menjadi generik. Saat mencoba menggeneralisasi hanya untuk satu kasing, Anda memotret dalam gelap. Peluangnya tinggi, Anda terlalu generalisasi hal-hal tertentu yang tidak perlu digeneralisasi, dan kehilangan bagian lain yang seharusnya. Dan ketika kemudian kasus kedua muncul dan Anda menyadari bahwa Anda menggeneralisasi hal-hal yang salah, maka Anda memiliki lebih banyak pekerjaan yang harus dilakukan untuk memperbaikinya.

Jadi saya sarankan untuk menunda godaan untuk melakukan hal-hal "berjaga-jaga". Pendekatan ini hanya akan mengarah pada upaya lebih banyak pekerjaan dan pemeliharaan ketika Anda melewatkan kesempatan untuk menggeneralisasi tiga, empat atau lebih kali dan kemudian memiliki tumpukan kode yang mirip (jadi duplikat) untuk dipelihara.

Doc Brown
sumber
2
Bagi saya jawaban ini tidak masuk akal dalam konteks OP. Dia mengatakan dia akan menghabiskan lebih sedikit waktu untuk menggeneralisasi sekarang, dan lebih sedikit waktu di masa depan, kecuali di masa depan ada kebutuhan untuk implementasi menjadi spesifik. Anda menentang "investasi upaya tambahan dalam generalisasi", sedangkan OP akan menginvestasikan upaya tambahan hanya jika mereka tidak menggeneralisasi. (berpikir) .... aneh: $
msb
2
@ msb: konteks itu ditambahkan setelah saya menulis jawaban saya dan bertentangan dengan apa yang OP katakan sebelumnya, terutama di bagian yang saya kutip. Lihat hasil edit saya.
Doc Brown
2
Juga, solusi umum akan lebih rumit, sehingga pada saat Anda harus menyesuaikannya untuk kasus kedua, akan butuh waktu lebih lama untuk memahaminya lagi.
AndreKR
4
Dok, selain itu, tetapi tidak akan pernah menduga Anda adalah penutur asing. Jawaban Anda selalu ditulis dengan baik dan diperdebatkan dengan baik.
user949300
2
Saya akan membayangkan aksen Anda ketika saya membaca jawaban masa depan Anda. :-)
user949300
64

TL; DR: itu tergantung pada apa yang Anda coba selesaikan.

Saya sudah melakukan percakapan yang sama dengan kakek saya tentang ini, sementara kami berbicara tentang bagaimana Fungsi dan Aksi di C # mengagumkan. Kakek saya adalah programmer timer yang sangat tua, yang sudah ada di sekitar kode sumber sejak perangkat lunak dijalankan pada komputer yang mengambil seluruh ruangan.

Dia mengubah teknologi beberapa kali dalam hidupnya. Dia menulis kode dalam C, COBOL, Pascal, BASIC, Fortran, Smalltalk, Jawa dan akhirnya memulai C # sebagai hobi. Saya belajar bagaimana memprogram dengan dia, duduk di pangkuannya sementara saya hanyalah seorang pemuja, mengukir baris kode pertama saya pada editor biru dari SideKick IBM. Pada saat saya berusia 20 tahun, saya sudah menghabiskan lebih banyak waktu coding daripada bermain di luar.

Itu sedikit ingatan saya, jadi maafkan saya jika saya tidak benar-benar praktis saat menceritakan kembali. Saya agak suka saat-saat itu.

Itu yang dia katakan kepada saya:


"Haruskah kita pergi untuk generalisasi masalah, atau menyelesaikannya dalam lingkup spesifik, apakah Anda bertanya? Nah, itu ... pertanyaan."

Kakek terdiam sejenak untuk memikirkannya sejenak, sambil memperbaiki posisi kacamatanya di wajahnya. Dia memainkan game match-3 di komputernya, sambil mendengarkan LP Deep Purple di sound system lamanya.

"Yah, itu akan tergantung pada masalah apa yang Anda coba selesaikan", katanya kepada saya. "Sangat menggoda untuk percaya bahwa ada satu solusi suci untuk semua pilihan desain yang ada, tetapi tidak ada. Arsitektur Perangkat Lunak seperti keju, Anda tahu."

"... Keju, Kakek?"

"Tidak masalah apa yang kamu pikirkan tentang favoritmu, akan selalu ada seseorang yang berpikir itu bau".

Aku mengerjap dalam kebingungan sejenak, tetapi sebelum aku bisa mengatakan apa pun, kakek melanjutkan.

"Ketika kamu sedang membangun mobil, bagaimana kamu memilih bahan untuk bagian?"

"Aku ... kurasa itu tergantung pada biaya yang terlibat dan apa yang harus dilakukan bagian itu, kurasa."

"Itu tergantung pada masalah yang coba dipecahkan oleh bagian itu. Anda tidak akan membuat ban yang terbuat dari baja, atau kaca depan yang terbuat dari kulit. Anda memilih bahan yang paling baik memecahkan masalah yang Anda miliki. Sekarang, apa itu solusi generik? Atau yang spesifik? Untuk masalah apa, untuk kasus penggunaan apa? Haruskah Anda menggunakan pendekatan fungsional penuh, untuk memberikan fleksibilitas maksimum untuk kode yang hanya akan digunakan sekali? Haruskah Anda menulis kode yang sangat khusus dan rapuh untuk bagian dari sistem Anda yang akan melihat banyak dan banyak kegunaan, dan mungkin banyak perubahan? Pilihan desain seperti itu seperti bahan yang Anda pilih untuk bagian dalam mobil atau bentuk bata Lego yang Anda pilih untuk membangun rumah kecil . Apa batu bata Lego yang terbaik? "

Programmer tua itu meraih model kereta Lego kecil yang ada di meja sebelum melanjutkan.

"Kamu hanya bisa menjawab itu jika kamu tahu untuk apa kamu membutuhkan batu bata itu. Bagaimana kamu akan tahu jika solusi spesifik lebih baik daripada yang umum, atau sebaliknya, jika kamu bahkan tidak tahu masalah apa yang sedang kamu alami mencoba menyelesaikan? Anda tidak dapat melihat melewati pilihan yang tidak Anda mengerti. "

"..Apakah kamu baru saja mengutip The Matrix? "

"Apa?"

"Tidak apa-apa, teruskan."

"Yah, misalkan Anda mencoba membangun sesuatu ke Sistem Faktur Nasional. Anda tahu bagaimana API jahat itu dan tiga puluh ribu baris file XML terlihat seperti dari dalam. Bagaimana solusi 'generik' untuk membuat file itu bahkan akan terlihat seperti? File ini penuh dengan parameter opsional, penuh dengan kasus-kasus yang hanya boleh menggunakan cabang bisnis yang sangat spesifik. Untuk sebagian besar kasus, Anda dapat mengabaikannya dengan aman. Anda tidak perlu membuat sistem faktur generik jika satu-satunya hal yang Anda inginkan "Saya akan pernah menjual sepatu. Cukup buat sistem untuk menjual sepatu dan jadikan itu sistem faktur penjualan sepatu terkutuk terbaik di luar sana. Sekarang, jika Anda harus membuat sistem faktur untuk semua jenis klien, pada aplikasi yang lebih luas - dijual kembali sebagai sistem penjualan generik yang independen,misalnya - sekarang menarik untuk menerapkan opsi-opsi yang hanya digunakan untuk Gas, makanan atau alkohol.Sekarang itu adalah kasus penggunaan yang mungkin. Sebelum mereka hanya beberapa hipotetis Jangan gunakan kasus, dan Anda tidak ingin menerapkan Jangan gunakan kasus. Jangan gunakan adalah adik laki-laki dari Tidak perlu . "

Kakek menempatkan kereta lego kembali pada tempatnya dan kembali ke pertandingan-3.

"Jadi, untuk dapat memilih solusi generik atau spesifik untuk masalah tertentu, pertama-tama Anda harus memahami apa masalahnya. Jika tidak, Anda hanya menebak, dan menebak adalah pekerjaan manajer, bukan programmer. semuanya dalam IT, itu tergantung. "


Jadi, begitulah. "Tergantung". Itu mungkin ekspresi dua kata yang paling kuat ketika berpikir tentang desain perangkat lunak.

T. Sar
sumber
14
Saya yakin ada sesuatu yang berguna dalam cerita itu tetapi terlalu menyakitkan untuk dibaca, maaf
GoatInTheMachine
28
Posting pertama Anda adalah anekdot pendek yang menyenangkan - dan tentu saja itu masalah pendapat - tetapi kecuali saya benar - benar menyukai gaya penulisan seseorang, saya menemukan cerita panjang seperti ini benar-benar memanjakan diri dan sedikit tidak pantas di luar blog pribadi
GoatInTheMachine
16
@ T.Sar tidak mendengarkan para pembenci, posting Anda adalah permata saran yang berguna dari seorang guru. +1
LLlAMnYP
7
Bagian "arsitektur perangkat lunak seperti keju" hanya murni luar biasa. Memang, jawaban ini adalah permata!
Mathieu Guindon
3
Mungkin jawaban ini juga seperti keju? ;) Tapi tolong, "Smalltalk" harus "Smalltalk", dan ya, aku menjadi yang pria, maaf.
fede s.
14

Terutama, Anda harus mencoba mengantisipasi apakah kemungkinan perubahan seperti itu akan terjadi - bukan hanya kemungkinan kecil di suatu tempat di telepon.

Jika tidak, biasanya lebih baik menggunakan solusi sederhana sekarang dan memperpanjangnya nanti. Sangat mungkin bahwa Anda akan memiliki gambaran yang lebih jelas tentang apa yang dibutuhkan saat itu.

dua kali kamu
sumber
13

Jika Anda bekerja di domain yang baru bagi Anda, daripada Aturan tiga yang disebutkan Daniel Pryden harus diterapkan. Lagi pula, bagaimana Anda membangun abstraksi yang berguna jika Anda seorang pemula di bidang itu? Orang sering percaya diri dalam kemampuan mereka untuk menangkap abstraksi, meskipun jarang terjadi. Menurut pengalaman saya, abstraksi prematur tidak lebih jahat dari duplikasi kode. Abstraksi yang salah sangat menyakitkan untuk dipahami. Terkadang bahkan lebih menyakitkan untuk refactor.

Ada buku yang membahas poin saya tentang pengembang area yang tidak dikenal bekerja. Terdiri dari domain spesifik dengan abstraksi berguna yang diekstraksi.

Zapadlo
sumber
Pertanyaannya jelas tentang masalah konkret.
RibaldEddie
4
Jawabannya cukup umum untuk mengatasi masalah nyata ini. Dan pertanyaannya tidak cukup spesifik untuk diberikan tanda terima nyata: seperti yang Anda lihat, tidak ada detail domain yang disebutkan dalam pertanyaan. Bahkan nama kelas tidak ditentukan (A dan B tidak masuk hitungan).
Zapadlo
7
"Haruskah jawaban stackoverflow sama generik mungkin atau sejelas mungkin?"
Lyndon White
@ LyndonWhite haruskah pertanyaan stackoverflow menjadi generik mungkin (terlalu luas!) Atau sespesifik mungkin (apa pun kegagalan itu disebut!)? Ha.
4

Mengingat sifat tubuh pertanyaan Anda, dengan asumsi saya memahaminya dengan benar, saya benar-benar melihat ini sebagai pertanyaan desain fitur sistem pusat lebih dari pertanyaan tentang solusi generik vs spesifik.

Dan ketika datang ke fitur dan kemampuan sistem pusat, yang paling dapat diandalkan adalah yang tidak ada. Membayar kesalahan di sisi minimalis, terutama mengingat bahwa itu umumnya lebih mudah untuk menambahkan fungsionalitas terpusat, lama diinginkan, daripada menghapus fungsionalitas yang bermasalah, lama yang tidak diinginkan, dengan banyak dependensi karena telah membuat bekerja dengan sistem jadi jauh lebih sulit. daripada yang dibutuhkan saat mengajukan pertanyaan desain tanpa akhir dengan setiap fitur baru.

Kenyataannya, karena tidak memiliki antisipasi yang kuat tentang apakah ini akan sering dibutuhkan di masa depan, saya akan berusaha untuk menghindari melihat ini sebagai pengganti tipe dari A ke B jika mungkin, dan alih-alih hanya mencarinya sebagai cara untuk mengubah keadaan A. Misalnya, setel beberapa bidang dalam A untuk membuatnya berubah dan tampak seperti B untuk pengguna tanpa benar-benar berubah menjadi 'jenis' benda yang berbeda - Anda berpotensi membuat A toko B secara pribadi menggunakan komposisi dan fungsi panggilan di B saat keadaan A diatur untuk menunjukkan bahwa ia harus meniru B untuk menyederhanakan implementasi jika memungkinkan. Itu harus menjadi solusi yang sangat sederhana dan invasif minimal.

Jadi bagaimanapun, menggemakan banyak orang lain, saya menyarankan untuk berbuat salah di sisi menghindari solusi generik dalam kasus ini, tetapi lebih karena saya menganggap ini dengan pertimbangan menambahkan kemampuan yang sangat berani ke sistem pusat, dan di sana saya akan menyarankan untuk berbuat salah di sisi meninggalkannya, terutama untuk saat ini.


sumber
"Kamu merindukan semua bug yang tidak kamu kode." (dari poster bola basket: Anda melewatkan semua pukulan yang tidak Anda ambil)
3

Sulit untuk memberikan jawaban umum untuk masalah khusus ini ;-)

Semakin generiknya, semakin banyak waktu yang Anda dapatkan untuk perubahan di masa mendatang. Misalnya karena alasan ini banyak program game menggunakan pola komponen entitas alih-alih membangun sistem tipe karakter dan objek yang sangat rumit namun kaku dalam game.

Di sisi lain, membuat sesuatu yang generik membutuhkan investasi waktu dan usaha di muka dalam desain yang jauh lebih tinggi daripada untuk sesuatu yang sangat spesifik. Ini menanggung risiko over-engineering, dan bahkan tersesat dalam persyaratan potensial di masa depan.

Selalu bernilai untuk melihat apakah ada generalisasi alami yang akan membuat Anda terobosan. Namun, pada akhirnya, ini menjadi masalah keseimbangan, antara upaya yang dapat Anda habiskan sekarang dan upaya yang mungkin Anda butuhkan di masa depan.

Christophe
sumber
3
  1. Hibrida. Ini tidak harus berupa pertanyaan salah satu atau dua. Anda dapat merancang API untuk konversi jenis umum sambil hanya menerapkan konversi spesifik yang Anda butuhkan saat ini. (Pastikan bahwa jika seseorang memanggil API umum Anda dengan konversi yang tidak didukung, ia gagal dengan status kesalahan "tidak didukung".)

  2. Pengujian. Untuk konversi A-> B, saya harus menulis satu (atau sejumlah kecil) tes. Untuk konversi x-> y umum, saya mungkin harus menulis seluruh matriks tes. Itu jauh lebih banyak pekerjaan, bahkan jika semua konversi berbagi implementasi generik tunggal.

    Sebaliknya, jika ternyata ada cara umum untuk menguji semua kemungkinan konversi, maka tidak ada lagi pekerjaan dan saya mungkin cenderung untuk mencari solusi generik lebih cepat.

  3. Kopel. Konverter dari A ke B mungkin perlu mengetahui detail implementasi tentang A dan B (kopling ketat). Jika A dan B masih berevolusi, ini berarti saya mungkin harus terus mengunjungi kembali konverter (dan pengujiannya), yang menyebalkan, tetapi setidaknya itu terbatas pada A dan B.

    Jika saya menggunakan solusi generik yang membutuhkan akses ke detail semua jenis, maka bahkan ketika C dan D berevolusi, saya mungkin perlu terus mengubah konverter generik (dan banyak tes), yang dapat memperlambat saya meskipun meskipun tidak ada belum perlu mengkonversi ke C atau D .

    Jika konversi generik dan spesifik dapat diterapkan dengan cara yang hanya digabungkan secara longgar dengan detail jenisnya, maka saya tidak akan khawatir tentang hal ini. Jika salah satu dari itu dapat dilakukan dengan cara yang digabungkan secara longgar tetapi yang lain membutuhkan penggandengan yang ketat, maka itu adalah argumen yang kuat untuk pendekatan yang digabungkan secara longgar keluar dari gerbang.

Adrian McCarthy
sumber
2
Pengujian adalah poin yang bagus. Ini adalah keuntungan besar jika Anda merancang solusi generik berdasarkan konsep dari teori kategori , karena Anda sering mendapatkan teorema gratis yang membuktikan bahwa satu-satunya implementasi yang mungkin untuk tanda tangan (yang diterima pemeriksa tipe kompiler) adalah yang benar , atau setidaknya bahwa jika algoritme berfungsi untuk jenis tertentu, ia juga harus bekerja untuk semua jenis lainnya.
leftaroundabout
Saya kira ada alasan khusus domain mengapa hanya satu jenis konversi yang diminta, artinya sebagian besar konversi jenis akan menjadi tindakan yang tidak valid dalam domain masalah, dan untuk alasan itu, tidak boleh didukung oleh aplikasi sampai mereka secara resmi diizinkan. Jawaban ini datang paling dekat dengan argumentasi itu.
Ralf Kleberhoff
3

Haruskah solusinya menjadi generik mungkin atau sespesifik mungkin?

Itu bukan pertanyaan yang bisa dijawab.

Yang terbaik yang bisa Anda dapatkan adalah beberapa heuristik untuk memutuskan seberapa umum atau spesifik untuk membuat solusi yang diberikan. Bekerja melalui sesuatu seperti proses di bawah ini, biasanya perkiraan tingkat pertama benar (atau cukup baik). Ketika tidak, alasannya mungkin terlalu spesifik domain untuk dibahas secara rinci di sini.

  1. Perkiraan tingkat pertama: aturan tiga YAGNI yang biasa seperti dijelaskan oleh Daniel Pryden, Doc Brown, dkk .

    Ini adalah heuristik yang umumnya bermanfaat karena mungkin yang terbaik yang dapat Anda lakukan yang tidak bergantung pada domain dan variabel lainnya.

    Jadi, anggapan awalnya adalah: kita melakukan hal yang paling spesifik.

  2. Perkiraan tingkat kedua: berdasarkan pengetahuan ahli Anda tentang domain solusi , Anda katakan

    Solusi "generik" dalam hal ini membutuhkan lebih sedikit kerja daripada solusi "spesifik"

    jadi kami mungkin menafsirkan kembali YAGNI sebagai merekomendasikan agar kami menghindari pekerjaan yang tidak perlu , daripada menghindari generalisasi yang tidak perlu. Jadi, kita mungkin memodifikasi anggapan awal kita dan melakukan hal yang paling mudah .

    Namun, jika pengetahuan domain solusi Anda menunjukkan bahwa solusi termudah kemungkinan akan membuka banyak bug, atau sulit untuk diuji secara memadai, atau menyebabkan masalah lain, maka menjadi lebih mudah untuk dikodekan belum tentu merupakan alasan yang cukup baik untuk mengubah kami. pilihan asli.

  3. Perkiraan tingkat ketiga: apakah pengetahuan domain masalah Anda menyarankan solusi termudah sebenarnya benar, atau apakah Anda mengizinkan banyak transisi yang Anda tahu tidak ada artinya atau salah?

    Jika solusi yang mudah tetapi generik terlihat bermasalah, atau Anda tidak yakin dengan kemampuan Anda untuk menilai risiko ini, melakukan pekerjaan ekstra dan tetap dengan tebakan awal Anda mungkin lebih baik.

  4. Perkiraan urutan keempat: apakah pengetahuan Anda tentang perilaku pelanggan, atau bagaimana fitur ini berhubungan dengan orang lain, atau prioritas manajemen proyek, atau ... pertimbangan teknis tidak ketat lainnya mengubah keputusan kerja Anda saat ini?

Tak berguna
sumber
2

Ini bukan pertanyaan yang mudah dijawab dengan jawaban sederhana. Banyak jawaban telah memberikan heuristik yang dibangun di sekitar aturan 3, atau yang serupa. Melangkah melampaui aturan praktis seperti itu sulit.

Untuk benar- benar menjawab pertanyaan Anda, Anda harus mempertimbangkan bahwa pekerjaan Anda kemungkinan besar tidak menerapkan sesuatu yang mengubah A-> B. Jika Anda seorang kontraktor, mungkin itu persyaratannya, tetapi jika Anda seorang karyawan, Anda disewa untuk melakukan banyak tugas yang lebih kecil untuk perusahaan. Mengubah A-> B hanyalah salah satu dari tugas itu. Perusahaan Anda akan peduli tentang seberapa baik perubahan di masa depan dapat dilakukan juga, bahkan jika itu tidak disebutkan dalam permintaan. Untuk menemukan "TheBestImplementation (tm)," Anda harus melihat gambar yang lebih besar dari apa yang benar-benar diminta untuk Anda lakukan, dan kemudian menggunakannya untuk menafsirkan permintaan kecil yang telah diberikan kepada Anda untuk mengubah A-> B.

Jika Anda adalah seorang programmer tingkat rendah yang baru lulus dari perguruan tinggi, sering kali disarankan untuk melakukan persis seperti yang diperintahkan kepada Anda. Jika Anda direkrut sebagai arsitek perangkat lunak dengan pengalaman 15 tahun, biasanya disarankan untuk memikirkan hal-hal besar. Setiap pekerjaan aktual akan jatuh di antara "lakukan persis apa tugas sempitnya" dan "pikirkan gambaran besarnya." Anda akan merasakan di mana pekerjaan Anda cocok dalam spektrum itu jika Anda berbicara dengan cukup banyak orang dan melakukan cukup banyak pekerjaan untuk mereka.

Saya dapat memberikan beberapa contoh konkret di mana pertanyaan Anda memiliki jawaban pasti berdasarkan konteks. Pertimbangkan kasus di mana Anda menulis perangkat lunak yang sangat penting untuk keselamatan. Ini berarti Anda memiliki tim uji yang berdiri untuk memastikan produk berkinerja seperti yang dijanjikan. Beberapa tim uji ini diharuskan menguji setiap jalur yang mungkin melalui kode. Jika Anda berbicara dengan mereka, Anda mungkin menemukan bahwa jika Anda menggeneralisasi perilaku tersebut, Anda akan menambahkan $ 30.000 ke biaya pengujian mereka karena mereka harus menguji semua jalur ekstra tersebut. Dalam hal itu, jangan tambahkan fungsionalitas umum, bahkan jika Anda harus menduplikasi pekerjaan 7 atau 8 kali karenanya. Simpan uang perusahaan dan lakukan persis seperti yang diminta.

Di sisi lain, pertimbangkan bahwa Anda membuat API untuk mengizinkan pelanggan mengakses data dalam program basis data yang dibuat perusahaan Anda. Seorang pelanggan meminta izin perubahan A-> B. API biasanya memiliki aspek borgol emas: ketika Anda menambahkan fungsionalitas ke API, Anda biasanya tidak seharusnya menghapus fungsionalitas itu (hingga nomor versi utama berikutnya). Banyak pelanggan Anda mungkin tidak bersedia membayar biaya peningkatan ke nomor versi utama berikutnya, sehingga Anda mungkin akan terjebak dengan solusi apa pun yang Anda pilih untuk waktu yang lama. Dalam hal ini, saya sangat menyarankan untuk membuat solusi generik sejak awal. Anda benar-benar tidak ingin mengembangkan API buruk yang penuh dengan perilaku satu kali.

Cort Ammon
sumber
1

Hmm ... tidak banyak konteks untuk melanjutkan untuk jawaban ... mengulangi jawaban sebelumnya, "Itu tergantung".

Dalam arti tertentu, Anda harus mengingat kembali pengalaman Anda. Jika bukan milik Anda, maka seseorang yang lebih senior di domain. Anda bisa berdalih tentang apa yang dinyatakan kriteria penerimaan. Jika itu adalah sesuatu di sepanjang baris 'pengguna harus dapat mengubah jenis dari "A" ke "B"' versus 'pengguna harus dapat mengubah jenis dari nilai saat ini ke nilai alternatif yang diizinkan'.

Kriteria penerimaan yang sering tunduk pada interpretasi, tetapi staf QA yang baik dapat menulis kriteria yang sesuai dengan tugas yang ada, meminimalkan interpretasi yang diperlukan.

Apakah ada batasan domain yang tidak memungkinkan perubahan dari "A" ke "C" atau opsi lain, tetapi hanya "A" ke "B"? Atau apakah ini hanya persyaratan khusus yang tidak "berpikir ke depan"?

Jika kasus umum lebih sulit saya akan bertanya sebelum memulai pekerjaan, tetapi dalam kasus Anda jika saya dapat 'memprediksi' bahwa permintaan perubahan 'tipe' lainnya akan datang di masa mendatang, saya akan tergoda untuk: a) tulis sesuatu yang dapat digunakan kembali untuk kasus umum, dan b) bungkus dalam kondisi yang hanya memungkinkan A -> B untuk saat ini.

Cukup mudah untuk memverifikasi kasus saat ini dalam pengujian otomatis, dan cukup mudah untuk membuka ke opsi lain nanti jika / ketika berbagai kasus penggunaan muncul.

railsdog
sumber
1

Bagi saya, pedoman yang saya buat beberapa waktu lalu adalah: "Untuk persyaratan hipotetis hanya menulis kode hipotetis." Yaitu - jika Anda mengantisipasi persyaratan tambahan, Anda harus memikirkan sedikit tentang cara mengimplementasikannya, dan menyusun kode Anda saat ini sehingga tidak memblokir seperti itu.

Tetapi jangan menulis kode aktual untuk ini sekarang - pikirkan sedikit tentang apa yang akan Anda lakukan. Kalau tidak, Anda biasanya akan membuat hal-hal yang tidak perlu rumit, dan mungkin akan terganggu kemudian ketika persyaratan aktual datang yang berbeda dari apa yang Anda perkirakan.

Empat contoh Anda: jika Anda memiliki semua penggunaan metode konversi di bawah kendali Anda, Anda bisa menyebutnya convertAToB untuk saat ini dan berencana untuk menggunakan refactoring "metode rename" dalam IDE untuk mengubah nama jika Anda memerlukan fungsionalitas yang lebih umum nanti. Namun, jika metode konversi adalah bagian dari API publik, ini bisa sangat berbeda: menjadi spesifik yang akan memblokir generalisasi nanti, karena sulit untuk mengubah nama hal-hal dalam kasus itu.

Hans-Peter Störr
sumber
0

Saya terus mendengar bahwa pengembang yang baik harus mencoba mengantisipasi perubahan dan merancang sistem sehingga mudah diperluas di masa depan,

Secara prinsip, ya. Tetapi ini tidak selalu mengarah pada solusi generik.

Ada dua jenis topik dalam pengembangan perangkat lunak, sejauh yang saya ketahui, di mana Anda harus mengantisipasi perubahan di masa depan:

  • Perpustakaan dimaksudkan untuk digunakan oleh pihak ke-3, dan
  • arsitektur perangkat lunak keseluruhan.

Kasus pertama diselesaikan dengan menonton kohesi Anda / kopling, injeksi ketergantungan atau apa pun. Kasus kedua adalah pada tingkat yang lebih abstrak, misalnya memilih arsitektur berorientasi layanan daripada gumpalan kode monolothic besar untuk aplikasi besar.

Dalam kasus Anda, Anda meminta solusi spesifik untuk masalah tertentu, yang tidak memiliki dampak yang dapat diduga di masa depan. Dalam hal ini, YAGNI dan DRY adalah moto yang bagus untuk menembak:

  • YAGNI (Anda tidak akan membutuhkannya) memberi tahu Anda untuk menerapkan hal-hal dasar minimum yang benar-benar Anda butuhkan dan gunakan saat ini . Ini berarti menerapkan minimum yang membuat test suite Anda saat ini berubah dari merah menjadi hijau, jika Anda harus menggunakan pengembangan gaya TDD / BDD / FDD. Tidak satu baris lagi.
  • KERING (jangan ulangi diri Anda sendiri) berarti jika Anda mengalami masalah yang sama lagi, maka Anda perlu melihat apakah Anda memerlukan solusi generik.

Dikombinasikan dengan praktik modern lainnya (seperti cakupan pengujian yang baik untuk dapat melakukan refactor dengan aman) ini berarti Anda berakhir dengan kode yang ditulis dengan cepat, ramping, dan berarti yang tumbuh sesuai kebutuhan.

yang terdengar seperti solusi umum adalah cara untuk pergi?

Tidak, sepertinya Anda harus memiliki lingkungan pemrograman, bahasa, dan perkakas yang membuatnya mudah dan menyenangkan untuk refactor saat Anda membutuhkannya. Solusi umum tidak menyediakan itu; mereka memisahkan aplikasi dari domain yang sebenarnya.

Lihatlah kerangka kerja ORM atau MVC modern, misalnya Ruby on Rails; pada level aplikasi, semua fokusnya adalah melakukan pekerjaan non-generik. Pustaka rel sendiri jelas hampir 100% generik, tetapi kode domain (yang menjadi pertanyaan Anda) harus melakukan shenanigans minimal dalam aspek itu.

AnoE
sumber
0

Cara berbeda untuk memikirkan masalah adalah dengan mempertimbangkan apa yang masuk akal.

Misalnya, ada aplikasi yang saya kembangkan yang memiliki bagian yang melakukan hal yang hampir sama tetapi memiliki aturan izin yang tidak konsisten. Karena tidak ada alasan untuk membuat mereka berbeda, ketika saya refactored bagian itu, saya membuat mereka semua melakukan izin dengan cara yang sama. Kode keseluruhan dibuat lebih kecil, lebih sederhana dan antarmuka lebih konsisten.

Ketika manajemen memutuskan untuk mengizinkan orang lain mengakses fitur, kami dapat melakukannya hanya dengan mengubah bendera.

Jelas masuk akal untuk melakukan konversi jenis tertentu. Apakah masuk akal untuk membuat konversi jenis tambahan?

Ingat, jika solusi umum lebih cepat diterapkan, maka kasus spesifiknya juga mudah, cukup periksa bahwa ini adalah satu-satunya konversi jenis yang Anda izinkan.

Jika aplikasi berada di area yang sangat diatur (aplikasi medis atau finansial) cobalah untuk melibatkan lebih banyak orang dalam desain Anda.

Robert Baron
sumber