Apa yang harus diutamakan: YAGNI atau Good Design?

76

Pada titik mana YAGNI harus diutamakan terhadap praktik pengkodean yang baik dan sebaliknya? Saya sedang mengerjakan proyek di tempat kerja dan ingin secara perlahan memperkenalkan standar kode yang baik kepada rekan kerja saya (saat ini tidak ada dan semuanya hanya diretas bersama tanpa sajak atau alasan), tetapi setelah membuat serangkaian kelas (kami jangan melakukan TDD, atau dengan sedih segala jenis pengujian unit sama sekali) Saya mengambil langkah mundur dan berpikir itu melanggar YAGNI karena saya cukup banyak tahu dengan pasti bahwa kami tidak memerlukan kebutuhan untuk memperpanjang beberapa kelas ini.

Berikut ini adalah contoh nyata dari apa yang saya maksud: Saya memiliki lapisan akses data yang membungkus satu set prosedur yang tersimpan, yang menggunakan pola gaya Repositori yang belum sempurna dengan fungsi CRUD dasar. Karena ada beberapa metode yang semua kelas repositori saya butuhkan, saya membuat antarmuka umum untuk repositori saya, yang disebut IRepository. Namun, saya kemudian membuat antarmuka "marker" (yaitu antarmuka yang tidak menambahkan fungsionalitas baru) untuk setiap jenis repositori (misalnya ICustomerRepository) dan kelas konkret mengimplementasikannya. Saya telah melakukan hal yang sama dengan implementasi Pabrik untuk membangun objek bisnis dari DataReaders / DataSet yang dikembalikan oleh Prosedur Tersimpan; tanda tangan dari kelas repositori saya cenderung terlihat seperti ini:

public class CustomerRepository : ICustomerRepository
{
    ICustomerFactory factory = null;

    public CustomerRepository() : this(new CustomerFactory() { }

    public CustomerRepository(ICustomerFactory factory) {
        this.factory = factory;
    }      

    public Customer Find(int customerID)
    {
        // data access stuff here
        return factory.Build(ds.Tables[0].Rows[0]);
    }
}

Kekhawatiran saya di sini adalah bahwa saya melanggar YAGNI karena saya tahu dengan kepastian 99% bahwa tidak akan pernah ada alasan untuk memberikan apa pun selain beton CustomerFactoryuntuk repositori ini; karena kami tidak memiliki unit test, saya tidak memerlukan MockCustomerFactoryatau hal-hal serupa, dan memiliki begitu banyak antarmuka dapat membingungkan rekan kerja saya. Di sisi lain, menggunakan implementasi beton dari pabrik sepertinya seperti bau desain.

Apakah ada cara yang baik untuk mencapai kompromi antara desain perangkat lunak yang tepat dan tidak overarchitecting solusinya? Saya mempertanyakan apakah saya perlu memiliki semua "antarmuka implemenasi tunggal" atau jika saya bisa mengorbankan sedikit desain yang bagus dan hanya memiliki, misalnya, antarmuka dasar dan kemudian beton tunggal, dan tidak khawatir tentang pemrograman ke antarmuka jika implementasinya akan pernah digunakan.

Wayne Molina
sumber
17
Anda berkata "karena kita tidak memiliki tes unit saya tidak perlu MockX" yang secara alami mengarah ke "Saya tidak perlu IX, saya hanya perlu X". Saya membalikkan itu, fakta bahwa Anda tidak memiliki tes unit menyoroti fakta bahwa Anda memerlukan IX dan MockX, karena hal-hal ini akan membantu Anda memiliki tes unit. Jangan menerima kenyataan tidak memiliki tes, anggap itu sebagai masalah sementara yang akan diperbaiki dalam waktu (mungkin baik, lama).
Anthony Pegram
10
Meskipun itu sepele untuk google itu, seseorang harus menyebutkan bahwa YAGNI singkatan dari "Kamu tidak akan membutuhkannya"
thedaian
1
Saya pikir jika Anda menulis kelas baru seperti ini, Anda ingin menambahkan beberapa tes unit. Bahkan jika rekan kerja Anda tidak akan menjalankannya. Paling tidak nanti Anda bisa mengatakan, "Lihat! Tes unit saya menangkapnya ketika Anda memecahkan kode saya! Lihat betapa hebatnya tes unit!" Kalau begitu, membuatnya bisa dipermainkan mungkin bermanfaat di sini. (Meskipun, saya lebih suka jika objek bisa diejek tanpa mendefinisikan antarmuka)
Winston Ewert
Bukankah tes unit memaksa saya untuk membuat (atau menggunakan) kerangka tiruan jadi saya tidak menekan prosedur tersimpan langsung? Itulah alasan utama saya cenderung tidak menambahkan tes - kami masing-masing memiliki salinan lokal dari basis data produksi yang kami uji dan tuliskan kodenya.
Wayne Molina
3
@Anthony Dan apakah mengejek selalu membenarkan kompleksitas ekstra yang terjadi? Mengejek adalah alat yang bagus, tetapi kegunaannya juga harus dipertimbangkan terhadap biaya dan kadang-kadang skalanya dibalik dengan cara yang berlebihan. Tentu, ada alat untuk membantu dengan kompleksitas ekstra tetapi mereka tidak akan membuat kompleksitas hilang. Tampaknya ada tren yang berkembang memperlakukan "pengujian di semua biaya" sebagai pemberian. Saya percaya ini salah.
Konrad Rudolph

Jawaban:

75

Apakah ada cara yang baik untuk mencapai kompromi antara desain perangkat lunak yang tepat dan tidak overarchitecting solusinya?

YAGNI.

Saya bisa mengorbankan sedikit desain yang bagus

Anggapan yang salah.

dan antarmuka dasar dan kemudian beton tunggal,

Itu bukan "pengorbanan". Itu adalah desain yang baik.

S.Lott
sumber
72
Kesempurnaan tercapai, bukan ketika tidak ada lagi yang ditambahkan, tetapi ketika tidak ada lagi yang tersisa untuk diambil. Antoine De St-Exupery
Newtopian
5
@Newtopian: orang memiliki perasaan campur aduk tentang hal itu mengenai produk terbaru Apple. :)
Roy Tinker
14
Saya punya masalah besar dengan jawaban semacam ini. Apakah "X benar karena Y mengatakannya, dan Y didukung oleh komunitas" dengan alasan yang masuk akal? Jika seseorang dalam kehidupan nyata mengomel terhadap YAGNI, apakah Anda akan menunjukkan kepadanya jawaban ini sebagai argumen?
vemv
2
@ vemv. Tidak seorang pun di sini mengomel melawan YAGNI. Semua S.Lott katakan adalah bahwa kontradiksi yang dirasakan OP antara 2 tujuan yang layak adalah kesalahan. BTW, apakah Anda tahu ada pengembang aktif di dunia perangkat lunak saat ini yang akan menentang YAGNI? Jika Anda mengerjakan proyek nyata, Anda tahu bahwa persyaratan terus berubah dan bahwa pengguna dan manajer umumnya tidak tahu apa yang mereka lakukan atau tidak inginkan sampai Anda meletakkannya di depan mereka. Menerapkan yang diperlukan adalah BANYAK pekerjaan - mengapa perlu waktu, energi, dan buang-buang uang (atau risiko pekerjaan Anda) dengan menulis kode yang mencoba memprediksi masa depan?
Vektor
6
Maksud saya bukan tentang YAGNI - ini tentang kualitas jawaban. Saya tidak mengatakan seseorang secara khusus mengomel, itu bagian dari alasan saya. Silakan baca lagi.
vemv
74

Dalam kebanyakan kasus, menghindari kode yang tidak Anda perlukan mengarah ke desain yang lebih baik . Desain yang paling mudah dirawat dan tahan di masa depan adalah yang menggunakan jumlah terkecil dari kode sederhana yang telah memenuhi persyaratan.

Desain yang paling sederhana adalah yang paling mudah berkembang. Tidak ada yang membunuh perawatan seperti lapisan abstraksi yang tidak berguna dan direkayasa ulang.

Michael Borgwardt
sumber
8
Saya menemukan 'menghindari kode YAGNI' sangat membingungkan. Itu bisa berarti kode yang tidak Anda perlukan atau kode yang menganut prinsip YAGNI . (Lih 'Kode Kiss')
lihat
2
@ Sehe: Ini sama sekali tidak ambigu (sementara "penganut prinsip YAGNI" langsung bertentangan dengan dirinya sendiri) jika Anda mengejanya: apa yang bisa berarti "Anda-tidak-akan-membutuhkan-itu" mungkin berarti tetapi kode yang kamu tidak akan membutuhkan?
Michael Borgwardt
1
Saya akan mencetak jawaban ini dalam font besar dan menggantungnya di mana semua astronot arsitektur dapat membacanya. +1!
kirk.burleson
1
+1. Saya masih dapat mengingat proyek perusahaan pertama saya yang saya berikan untuk mendukung dan menambahkan beberapa fitur baru. Hal pertama yang saya lakukan adalah menghapus 32.000 baris kode tidak berguna dari program 40.000 baris tanpa kehilangan fungsionalitas apa pun . Programmer asli dipecat tak lama kemudian.
EJ Brennan
4
@ vemv: baca "tidak berguna" sebagai "tidak sedang digunakan, kecuali sepele", yaitu kasus YAGNI. Dan "overengineered" sedikit lebih spesifik daripada "buruk". Secara khusus itu berarti "kompleksitas yang disebabkan oleh konsep-konsep teoretis atau persyaratan yang dibayangkan yang mungkin, daripada persyaratan konkret, saat ini".
Michael Borgwardt
62

YAGNI dan SOLID (atau metodologi desain lainnya) tidak saling eksklusif. Namun, mereka saling bertentangan. Anda tidak harus mematuhi 100%, tetapi akan ada beberapa memberi dan menerima; semakin Anda melihat pola yang sangat abstrak yang digunakan oleh satu kelas di satu tempat, dan katakan YAGNI dan sederhanakan, semakin kurang PADAT desainnya. Kebalikannya bisa benar juga; berkali-kali dalam pengembangan, desain diimplementasikan SOLIDly "on faith"; Anda tidak melihat bagaimana Anda akan membutuhkannya, tetapi Anda hanya punya firasat. Ini bisa benar (dan semakin mungkin benar semakin banyak pengalaman yang Anda peroleh), tetapi itu juga bisa menempatkan Anda dalam utang teknis sebanyak pendekatan "do it light"; alih-alih basis kode "kode spaghetti" DIL, Anda mungkin berakhir dengan "kode lasagna", memiliki begitu banyak lapisan yang hanya menambahkan metode atau bidang data baru menjadi proses mengarungi melalui proksi layanan dan ketergantungan yang longgar dengan satu hari saja hanya dengan satu implementasi. Atau Anda bisa berakhir dengan "kode ravioli", yang datang dalam potongan ukuran gigitan kecil sehingga bergerak naik, turun, kiri atau kanan dalam arsitektur akan membawa Anda melalui 50 metode dengan masing-masing 3 baris.

Saya sudah mengatakannya dalam jawaban lain, tetapi ini dia: Pada pass pertama, buat itu berfungsi. Pada pass kedua, buat itu elegan. Pada umpan ketiga, buatlah SOLID.

Hancurkan itu:

Ketika Anda pertama kali menulis satu baris kode, itu hanya harus bekerja. Pada titik ini, untuk semua yang Anda tahu, ini hanya sekali saja. Jadi, Anda tidak mendapatkan poin gaya untuk membangun arsitektur "menara gading" untuk menambahkan 2 dan 2. Lakukan apa yang harus Anda lakukan, dan anggap Anda tidak akan pernah melihatnya lagi.

Lain kali kursor Anda masuk dalam baris kode itu, Anda sekarang telah menyangkal hipotesis Anda sejak pertama kali Anda menulisnya. Anda meninjau kembali kode itu, kemungkinan untuk memperpanjang atau menggunakannya di tempat lain, jadi itu tidak hanya satu kali. Sekarang, beberapa prinsip dasar seperti KERING (jangan ulangi diri Anda sendiri) dan aturan sederhana lainnya untuk desain kode harus diterapkan; ekstrak metode dan / atau bentuk loop untuk kode berulang, ekstrak variabel untuk literal atau ekspresi umum, mungkin menambahkan beberapa komentar, tetapi secara keseluruhan kode Anda harus didokumentasikan sendiri. Sekarang, kode Anda terorganisasi dengan baik, jika masih mungkin digabungkan dengan erat, dan siapa pun yang melihatnya dapat dengan mudah mempelajari apa yang Anda lakukan dengan membaca kode, alih-alih melacaknya baris demi baris.

Ketiga kalinya kursor Anda memasukkan kode itu, itu mungkin masalah besar; Anda bisa memperpanjangnya lagi atau menjadi berguna di setidaknya tiga tempat lain di basis kode. Pada titik ini, ini adalah kunci, jika bukan inti, elemen sistem Anda, dan harus dirancang seperti itu. Pada titik ini, Anda biasanya juga memiliki pengetahuan tentang bagaimana itu digunakan sejauh ini, yang akan memungkinkan Anda untuk membuat keputusan desain yang baik tentang bagaimana merancang desain untuk merampingkan penggunaan tersebut dan yang baru. Sekarang aturan SOLID harus memasukkan persamaan; ekstrak kelas yang berisi kode dengan tujuan tertentu, tentukan antarmuka umum untuk setiap kelas yang memiliki tujuan atau fungsi serupa, mengatur dependensi yang digabungkan secara longgar di antara kelas, dan desain dependensi sedemikian rupa sehingga Anda dapat dengan mudah menambah, menghapus, atau menukar mereka.

Dari titik ini, jika Anda perlu memperluas, menerapkan kembali atau menggunakan kembali kode ini, semuanya dikemas dengan baik dan diabstraksi dalam format "kotak hitam" yang kita semua tahu dan sukai; pasang di mana pun Anda membutuhkannya, atau tambahkan variasi baru pada tema sebagai implementasi baru antarmuka tanpa harus mengubah penggunaan antarmuka tersebut.

KeithS
sumber
Aku yang kedua kehebatannya.
Filip Dupanović
2
Iya. Ketika saya biasa mendesain untuk digunakan kembali / ekstensi dimuka, saya akan menemukan bahwa ketika saya ingin menggunakan kembali atau memperluasnya, itu akan dengan cara yang berbeda dari yang saya perkirakan. Prediksi itu sulit, terutama menyangkut masa depan. Jadi saya mendukung aturan 3-serangan Anda - pada saat itu, Anda memiliki ide yang masuk akal tentang bagaimana itu akan digunakan kembali / diperpanjang. NB: pengecualian adalah jika Anda sudah tahu bagaimana jadinya (misalnya dari proyek sebelumnya, pengetahuan domain, atau sudah ditentukan).
13ren
Pada kartu keempat, buat AWESOME.
Richard Neil Ilagan
@KeithS: Tampaknya John Carmack melakukan sesuatu yang serupa: "kode sumber Quake II ... satukan Quake 1, Quake World dan QuakeGL menjadi satu arsitektur kode yang indah." fabiensanglard.net/quake2/index.php
13ren
+1 Saya pikir saya akan menyebutkan aturan Anda: "Praktis refactoring" :)
Songo
31

Alih-alih salah satu dari itu, saya lebih suka WTSTWCDTUAWCROT?

(Apa hal paling sederhana yang bisa kita lakukan yang berguna dan kita bisa lepaskan pada hari Kamis?)

Akronim yang lebih sederhana ada dalam daftar hal-hal yang harus saya lakukan, tetapi itu bukan prioritas.

Mike Sherrill 'Cat Recall'
sumber
8
Akronim itu melanggar prinsip YAGNI :)
riwalk
2
Saya menggunakan persis huruf yang saya butuhkan - tidak lebih dan tidak kurang. Dengan cara itu, saya seperti Mozart. Ya. Saya Mozart dari akronim.
Mike Sherrill 'Cat Recall'
4
Saya tidak pernah tahu Mozart buruk dalam membuat akronim. Saya belajar sesuatu yang baru setiap hari di situs SE. : P
Cameron MacFarland
3
@Mike Sherrill 'CatRecall': Mungkin orang harus memperluas itu ke WTSTWCDTUWCROTAWBOF = "Apa hal paling sederhana yang bisa kita lakukan yang berguna, kita bisa rilis pada hari Kamis dan tidak akan istirahat pada hari Jumat?" ;-)
Giorgio
1
@ Stargazer712 no :) itu melanggar POLA.
v.oddou
25

YAGNI dan desain yang bagus tidak saling bertentangan. YAGNI adalah tentang (tidak) mendukung kebutuhan masa depan. Desain yang bagus adalah tentang membuat transparan apa yang dilakukan perangkat lunak Anda saat ini dan bagaimana melakukannya.

Akankah memperkenalkan pabrik membuat kode Anda yang sudah ada menjadi lebih sederhana? Jika tidak, jangan tambahkan. Jika ya, misalnya saat Anda menambahkan tes (yang harus Anda lakukan!), Tambahkan itu.

YAGNI adalah tentang tidak menambah kompleksitas untuk mendukung fungsi di masa depan.
Good Design adalah tentang menghilangkan kompleksitas sambil tetap mendukung semua fungsi saat ini.

Jaap
sumber
15

Mereka tidak dalam konflik, tujuan Anda salah.

Apa yang ingin Anda capai?

Anda ingin menulis perangkat lunak berkualitas, dan untuk itu Anda ingin menjaga basis kode Anda kecil dan tidak memiliki masalah.

Sekarang kita mencapai konflik, bagaimana kita menutup semua kasus jika kita tidak menulis kasus yang tidak akan kita gunakan?

Seperti inilah masalah Anda.

masukkan deskripsi gambar di sini (siapa pun yang tertarik, ini disebut awan penguapan )

Jadi, apa yang mendorong ini?

  1. Anda tidak tahu apa yang tidak akan Anda butuhkan
  2. Anda tidak ingin membuang waktu dan mengasapi kode Anda

Yang mana yang bisa kita pecahkan? Yah, sepertinya tidak ingin membuang waktu dan kode mengasapi adalah tujuan yang bagus, dan masuk akal. Bagaimana dengan yang pertama? Bisakah kita mencari tahu apa yang perlu kita kode?

Saya sedang mengerjakan proyek di tempat kerja dan ingin secara perlahan memperkenalkan standar kode yang baik kepada rekan kerja saya (saat ini tidak ada dan semuanya hanya diretas bersama tanpa sajak atau alasan) [...] Saya mengambil langkah mundur dan saya pikir itu melanggar YAGNI karena saya cukup tahu dengan pasti bahwa kita tidak perlu perlu memperpanjang beberapa kelas ini.

Mari kita ulangi semua itu

  • Tidak ada standar kode
  • Tidak ada perencanaan proyek yang sedang berjalan
  • Koboi di mana-mana melakukan hal sialan mereka sendiri (dan Anda mencoba untuk bermain sheriff di alam liar barat), ya ampun.

Apakah ada cara yang baik untuk mencapai kompromi antara desain perangkat lunak yang tepat dan tidak overarchitecting solusinya?

Anda tidak perlu kompromi, Anda membutuhkan seseorang untuk mengelola tim yang kompeten dan memiliki visi keseluruhan proyek. Anda membutuhkan seseorang yang dapat merencanakan apa yang akan Anda butuhkan, alih-alih setiap orang melemparkan hal-hal yang TIDAK Anda perlukan karena Anda begitu tidak yakin tentang masa depan karena ... mengapa? Aku akan memberitahumu mengapa, itu karena tidak ada yang punya rencana sialan di antara kalian semua. Anda mencoba memasukkan standar kode untuk memperbaiki masalah yang sepenuhnya terpisah. Masalah PRIMER Anda yang perlu Anda selesaikan adalah peta jalan dan proyek yang jelas. Setelah Anda memilikinya, Anda dapat mengatakan "standar kode membantu kami mencapai tujuan ini secara lebih efektif sebagai sebuah tim," yang merupakan kebenaran absolut tetapi di luar ruang lingkup pertanyaan ini.

Dapatkan manajer proyek / tim yang dapat melakukan hal-hal ini. Jika Anda memilikinya, Anda perlu meminta mereka untuk peta dan menjelaskan masalah YAGNI yang tidak dipresentasikan oleh peta. Jika mereka sangat tidak kompeten, tulis sendiri rencana itu dan katakan "ini laporan saya untuk Anda tentang hal-hal yang kami butuhkan, silakan tinjau dan beri tahu kami keputusan Anda."

Penyamaran
sumber
Sayangnya, kita tidak memilikinya. Manajer Pengembangan lebih peduli tentang menyelesaikan sesuatu dengan cepat daripada tentang standar / kualitas, atau akan membuat praktik standar seperti menggunakan DataSets mentah di mana-mana dikembalikan langsung dari kelas, pengkodean gaya VB6 dan semua yang ada dalam kode di belakang dengan logika duplikat disalin dan ditempelkan semua lebih.
Wayne Molina
Tidak apa-apa, ini akan sedikit lebih lambat, tetapi Anda perlu berbicara dengan kekhawatiran mereka saat itu. Jelaskan bahwa masalah kode YAGNI / Useless ini membuang-buang waktu, menyarankan peta jalan, memberinya peta jalan, menjelaskannya akan membuat pekerjaan lebih cepat. Ketika dia membeli, datang dengan masalah bahwa standar yang buruk harus dengan kecepatan pengembangan, menyarankan yang lebih baik. Mereka ingin proyeknya selesai, mereka hanya tidak tahu cara mengaturnya, Anda harus menggantinya atau merawatnya ... atau berhenti.
Incognito
Erm ..... Saya pikir tujuan mengemudi adalah 'Anda ingin memiliki produk yang bagus dan berharga'?
sehe
@sehe itu bukan keputusannya: p.
Incognito
3
Jawaban yang bagus Dia menghadapi pertempuran yang berat. Menyelesaikannya akan sulit jika tidak ada manajemen yang mau. Dan Anda benar bahwa pertanyaan itu prematur dan tidak membahas masalah sebenarnya.
Seth Spearman
10

Mengizinkan kode Anda diperpanjang dengan unit test tidak akan pernah tercakup dalam YAGNI, karena Anda akan membutuhkannya. Namun, saya tidak yakin bahwa perubahan desain Anda ke antarmuka implementasi tunggal sebenarnya meningkatkan testabilitas kode karena CustomerFactory sudah mewarisi dari antarmuka dan dapat diganti untuk MockCustomerFactory kapan saja.

DeadMG
sumber
1
Beri +1 untuk komentar bermanfaat tentang masalah aktual dan bukan hanya tentang pertempuran kosmik dan / atau cinta-antara antara Good Design dan YAGNI.
psr
10

Pertanyaan itu menghadirkan dilema yang salah. Penerapan prinsip YAGNI yang benar bukanlah hal yang tidak terkait. Ini salah satu aspek dari desain yang bagus. Setiap prinsip SOLID adalah aspek desain yang baik juga. Anda tidak dapat selalu sepenuhnya menerapkan setiap prinsip dalam disiplin apa pun. Masalah dunia nyata menempatkan banyak kekuatan pada kode Anda, dan beberapa dari mereka mendorong ke arah yang berlawanan. Prinsip-prinsip desain harus menjelaskan semua itu, tetapi tidak ada prinsip yang dapat memenuhi semua situasi.

Sekarang, mari kita lihat setiap prinsip dengan pemahaman bahwa meskipun mereka kadang-kadang menarik ke arah yang berbeda, mereka sama sekali tidak inheren dalam konflik.

YAGNI dirancang untuk membantu pengembang menghindari jenis pengerjaan ulang: yang berasal dari membangun hal yang salah. Hal ini dilakukan dengan membimbing kita untuk menghindari membuat keputusan yang salah terlalu dini berdasarkan asumsi atau prediksi tentang apa yang kita pikir akan berubah atau dibutuhkan di masa depan. Pengalaman kolektif memberi tahu kita bahwa ketika kita melakukan ini, kita biasanya salah. Sebagai contoh, YAGNI akan memberitahu Anda untuk tidak membuat antarmuka untuk tujuan usabilitas , kecuali Anda tahu sekarang bahwa Anda memerlukan beberapa pelaksana. Demikian pula YAGNI akan mengatakan jangan membuat "ScreenManager" untuk mengelola formulir tunggal dalam aplikasi kecuali Anda tahu sekarang bahwa Anda akan memiliki lebih dari satu layar.

Berlawanan dengan apa yang dipikirkan banyak orang, SOLID bukan tentang usabilitas, kedermawanan, atau bahkan abstraksi. SOLID dimaksudkan untuk membantu Anda menulis kode yang disiapkan untuk perubahan , tanpa mengatakan apa pun tentang perubahan spesifik apa yang mungkin terjadi. Lima prinsip SOLID menciptakan strategi untuk membangun kode yang fleksibel tanpa terlalu generik, dan sederhana tanpa naif. Penerapan kode SOLID yang tepat menghasilkan kelas kecil, fokus dengan peran dan batasan yang jelas. Hasil praktisnya adalah bahwa untuk setiap perubahan kebutuhan yang diperlukan, sejumlah kelas minimum perlu disentuh. Dan demikian pula, untuk perubahan kode apa pun, ada jumlah minimal "riak" hingga ke kelas lain.

Melihat contoh situasi yang Anda miliki, mari kita lihat apa yang mungkin dikatakan YAGNI dan SOLID. Anda mempertimbangkan antarmuka repositori yang umum karena semua repositori terlihat sama dari luar. Tetapi nilai antarmuka umum yang umum adalah kemampuan untuk menggunakan implementer mana pun tanpa perlu tahu yang mana itu pada khususnya. Kecuali jika ada suatu tempat di aplikasi Anda di mana ini akan diperlukan atau berguna, YAGNI mengatakan jangan lakukan itu.

Ada 5 prinsip SOLID untuk dilihat. S adalah Tanggung Jawab Tunggal. Ini tidak mengatakan apa-apa tentang antarmuka, tetapi mungkin mengatakan sesuatu tentang kelas konkret Anda. Dapat dikatakan bahwa penanganan akses data itu sendiri mungkin paling baik dijadikan tanggung jawab satu atau lebih kelas lain, sedangkan tanggung jawab repositori adalah menerjemahkan dari konteks implisit (CustomerRepository adalah repositori secara implisit untuk entitas Pelanggan) ke dalam panggilan eksplisit ke API akses data umum yang menetapkan jenis entitas Pelanggan.

O Terbuka-Tertutup. Ini sebagian besar tentang warisan. Itu akan berlaku jika Anda mencoba untuk mendapatkan repositori Anda dari basis umum yang mengimplementasikan fungsi umum, atau jika Anda diharapkan untuk mendapatkan lebih jauh dari repositori yang berbeda. Tapi kamu tidak, jadi tidak.

L adalah Pengganti Liskov. Ini berlaku jika Anda bermaksud menggunakan repositori melalui antarmuka repositori umum. Itu menempatkan pembatasan pada antarmuka dan implementasi untuk memastikan konsistensi dan menghindari penanganan khusus untuk pelaksana yang berbeda. Alasan untuk ini adalah bahwa penanganan khusus seperti itu merusak tujuan antarmuka. Mungkin bermanfaat untuk mempertimbangkan prinsip ini, karena mungkin memperingatkan Anda untuk tidak menggunakan antarmuka repositori umum. Ini bertepatan dengan bimbingan YAGNI.

Saya adalah Segregasi Antarmuka. Ini mungkin berlaku jika Anda mulai menambahkan operasi kueri yang berbeda ke repositori Anda. Segregasi antarmuka berlaku di mana Anda dapat membagi anggota kelas menjadi dua himpunan bagian di mana satu akan digunakan oleh konsumen tertentu dan yang lain oleh orang lain, tetapi tidak ada konsumen yang kemungkinan akan menggunakan kedua himpunan bagian. Panduannya adalah membuat dua antarmuka terpisah, bukan satu antarmuka yang umum. Dalam kasus Anda, tidak mungkin mengambil dan menyimpan instance individual akan dikonsumsi oleh kode yang sama yang akan melakukan kueri umum, jadi mungkin berguna untuk memisahkannya menjadi dua antarmuka.

D adalah Injeksi Ketergantungan. Di sini kita kembali ke titik yang sama dengan S. Jika Anda memisahkan konsumsi API akses data ke objek yang terpisah, prinsip ini mengatakan bahwa alih-alih hanya membuat instance objek itu, Anda harus meneruskannya ketika Anda membuat repositori. Ini membuatnya lebih mudah untuk mengontrol masa pakai komponen akses data, membuka kemungkinan berbagi referensi untuk itu di antara repositori Anda, tanpa harus menempuh jalur membuatnya singleton.

Penting untuk dicatat bahwa sebagian besar prinsip SOLID tidak selalu berlaku pada tahap pengembangan aplikasi Anda. Sebagai contoh, apakah Anda harus membagi akses data tergantung pada seberapa rumitnya itu, dan apakah Anda ingin menguji logika repositori Anda tanpa mengenai database. Sepertinya ini tidak mungkin (sayangnya, menurut saya), jadi mungkin tidak perlu.

Jadi setelah semua pertimbangan itu, kami menemukan bahwa YAGNI dan SOLID benar-benar memberikan satu saran umum yang solid, relevan segera: Mungkin tidak perlu membuat antarmuka repositori umum yang umum.

Semua pemikiran yang cermat ini sangat berguna sebagai latihan pembelajaran. Ini memakan waktu ketika Anda belajar, tetapi seiring waktu Anda mengembangkan intuisi dan menjadi sangat cepat. Anda akan tahu hal yang benar untuk dilakukan, tetapi tidak perlu memikirkan semua kata-kata ini kecuali seseorang meminta Anda untuk menjelaskan alasannya.

Chris Ammerman
sumber
Saya pikir sebagian besar diskusi di halaman ini menyisakan 2 pesaing besar "kopling rendah" dan "kohesi tinggi" dari GRASPrinciples. Keputusan desain yang lebih mahal berasal dari prinsip "kopling rendah". Seperti kapan harus "mengaktifkan" SRP + ISP + DIP demi kopling rendah. Contoh: satu kelas -> 3 kelas dalam pola MVC. Atau bahkan lebih mahal: pisahkan dalam .dll / .so modul / rakitan. Itu sangat mahal karena implikasi pembangunan, proyek, pembuat daftar, bangun server, penambahan file berversi sumber ...
v.oddou
6

Anda tampaknya percaya bahwa 'desain yang baik' berarti mengikuti semacam idealogi dan seperangkat aturan formal yang harus selalu diterapkan, bahkan ketika tidak berguna.

IMO itu desain yang buruk. YAGNI adalah komponen desain yang baik, tidak pernah menjadi kontradiksi.

Vektor
sumber
2

Dalam contoh Anda, saya akan mengatakan bahwa YAGNI harus menang. Anda tidak akan dikenakan biaya banyak jika Anda perlu menambahkan antarmuka nanti. Ngomong-ngomong, apakah benar-benar desain yang bagus untuk memiliki satu antarmuka berdasarkan kelas jika tidak ada tujuan sama sekali?

Satu pemikiran lagi, mungkin terkadang yang Anda butuhkan bukanlah Desain yang Baik tetapi Desain yang Memadai. Berikut adalah urutan posting yang sangat menarik tentang topik tersebut:

David
sumber
Tautan pertama dan ketiga Anda pergi ke tempat yang sama.
David Thornley
2

Beberapa orang berpendapat, bahwa nama antarmuka tidak boleh dimulai dengan I. Khususnya satu alasan adalah, bahwa Anda benar-benar membocorkan ketergantungan pada apakah jenis yang diberikan adalah kelas atau antarmuka.

Apa yang melarang Anda CustomerFactorymenjadi kelas pada awalnya dan kemudian mengubahnya menjadi sebuah antarmuka, yang akan diimplementasikan oleh DefaultCustormerFactoryatau UberMegaHappyCustomerPowerFactory3000? Satu-satunya hal yang harus Anda ubah adalah tempat, di mana implementasi mendapatkan instantiate. Dan jika Anda memiliki desain yang kurang bagus, maka ini adalah beberapa tempat paling banyak.

Refactoring adalah bagian dari pengembangan. Lebih baik memiliki sedikit kode, yang mudah untuk refactor, daripada memiliki antarmuka dan kelas yang dideklarasikan untuk setiap kelas, memaksa Anda untuk mengubah setiap nama metode di setidaknya dua tempat pada waktu yang sama.

Poin sebenarnya dalam menggunakan antarmuka adalah mencapai modularitas, yang mungkin merupakan pilar terpenting dari desain yang baik. Namun perlu dicatat, bahwa sebuah modul tidak hanya ditentukan oleh decoupling dari dunia luar (meskipun itu adalah cara kita melihatnya dari perspektif luar), tetapi juga oleh kerja bagian dalamnya.
Yang ingin saya tunjukkan adalah, bahwa hal-hal yang memisahkan, yang secara inheren milik bersama tidak masuk akal. Di satu sisi itu seperti memiliki lemari dengan rak individu per cangkir.

Pentingnya terletak pada menyusun masalah besar yang kompleks menjadi subproblem yang lebih kecil dan lebih sederhana. Dan Anda harus berhenti pada titik, di mana mereka menjadi cukup sederhana tanpa subdivisi lebih lanjut, atau mereka justru akan menjadi lebih rumit. Ini bisa dilihat sebagai akibat wajar dari YAGNI. Dan itu pasti berarti desain yang bagus.

Tujuannya bukan untuk memecahkan masalah lokal dengan repositori tunggal dan pabrik tunggal. Tujuannya, agar keputusan ini tidak mempengaruhi sisa aplikasi Anda. Tentang modularitas itu.
Anda ingin rekan kerja Anda melihat modul Anda, melihat fasad dengan beberapa panggilan yang cukup jelas dan merasa percaya diri, bahwa mereka dapat menggunakannya, tanpa harus khawatir tentang semua bajak di dalam yang berpotensi canggih.

back2dos
sumber
0

Anda membuat interfacebeberapa implementasi antisipasi di masa depan. Anda mungkin juga memiliki satu I<class>untuk setiap kelas di basis kode Anda. Jangan.

Cukup gunakan kelas beton tunggal menurut YAGNI. Jika Anda merasa perlu memiliki objek "tiruan" untuk tujuan pengujian, ubah kelas asli menjadi kelas abstrak dengan dua implementasi, satu dengan kelas beton asli dan yang lainnya dengan implementasi tiruan.

Anda jelas harus memperbarui semua instantiations dari kelas asli untuk instantiate kelas beton baru. Anda dapat menyiasatinya dengan menggunakan konstruktor statis di depan.

YAGNI mengatakan untuk tidak menulis kode sebelum perlu ditulis.

Desain yang bagus mengatakan menggunakan abstraksi.

Anda dapat memiliki keduanya. Kelas adalah abstraksi.

Jesse
sumber
0

Mengapa antarmuka penanda? Itu mengejutkan saya bahwa itu melakukan tidak lebih dari "penandaan". Dengan "tag" yang berbeda untuk setiap jenis pabrik, apa gunanya?

Tujuan dari antarmuka adalah untuk memberikan kelas "bertindak seperti" perilaku, untuk memberi mereka "kemampuan repositori" untuk berbicara. Jadi, jika semua tipe repositori konkret Anda berperilaku seperti repositori yang sama (mereka semua menerapkan repositori) maka mereka semua dapat ditangani dengan cara yang sama dengan kode lain - dengan kode yang sama persis. Pada titik ini desain Anda dapat diperluas. Menambahkan lebih banyak tipe repositori konkret, semua ditangani sebagai IRepositori umum - kode yang sama menangani semua tipe konkret sebagai repositori "generik".

Antarmuka adalah untuk menangani hal-hal berdasarkan kesamaan. Tetapi antarmuka penanda kustom a) tidak menambahkan perilaku. dan b) memaksa Anda untuk menangani keunikannya.

Sejauh Anda mendesain antarmuka yang bermanfaat, Anda mendapatkan kebaikan OO karena tidak harus menulis kode khusus untuk menangani kelas, tipe, atau antarmuka marker khusus yang memiliki korelasi 1: 1 dengan kelas beton. Itu redundansi yang tidak ada gunanya.

Secara otomatis saya dapat melihat antarmuka marker jika, misalnya, Anda memerlukan koleksi banyak kelas yang sangat diketik. Dalam koleksi mereka semua "ImarkerInterface" tetapi ketika Anda menarik mereka keluar Anda harus melemparkannya ke jenis yang tepat.

radarbob
sumber
0

Bisakah Anda, saat ini, menuliskan ICustomerRepository yang masuk akal? Misalnya, (benar-benar mencapai di sini, mungkin contoh yang buruk) di masa lalu, pelanggan Anda selalu menggunakan PayPal? Atau semua orang di perusahaan itu bingung tentang berhubungan dengan Alibaba? Jika demikian, Anda mungkin ingin menggunakan desain yang lebih kompleks sekarang, dan tampak berpandangan jauh ke atasan Anda. :-)

Kalau tidak, tunggu. Menebak di antarmuka sebelum Anda memiliki satu atau dua implementasi aktual biasanya gagal. Dengan kata lain, jangan menggeneralisasi / abstrak / menggunakan pola desain mewah sampai Anda memiliki beberapa contoh untuk digeneralisasi.

pengguna949300
sumber