Bagaimana Anda menghindari iterasi tanpa henti melalui desain yang kurang optimal?

10

Jadi mungkin seperti banyak, saya sering menemukan diri saya mengalami sakit kepala dengan masalah desain di mana, misalnya, ada beberapa pola desain / pendekatan yang tampaknya sesuai dengan masalah dan memiliki manfaat yang diinginkan. Sangat sering ada beberapa peringatan yang membuatnya sulit untuk menerapkan pola / pendekatan tanpa semacam pekerjaan di sekitarnya yang kemudian meniadakan manfaat dari pola / pendekatan tersebut. Saya dapat dengan mudah berakhir iterasi melalui banyak pola / pendekatan karena diprediksi hampir semuanya memiliki beberapa peringatan yang sangat signifikan dalam situasi dunia nyata di mana tidak ada solusi yang mudah.


Contoh:

Saya akan memberi Anda contoh hipotetis berdasarkan longgar pada yang nyata yang baru-baru ini saya temui. Katakanlah saya ingin menggunakan komposisi di atas warisan karena hierarki warisan telah menghambat skala dari kode di masa lalu. Saya mungkin refactor kode tetapi kemudian menemukan bahwa ada beberapa konteks di mana superclass / baseclass hanya perlu memanggil fungsionalitas pada subclass, meskipun ada upaya untuk menghindarinya.

Pendekatan terbaik berikutnya tampaknya menerapkan setengah pola delegasi / pengamat dan pola komposisi setengah sehingga superclass dapat mendelegasikan perilaku atau sehingga subclass dapat mengamati peristiwa superclass. Kemudian kelas kurang dapat diukur dan dikelola karena tidak jelas bagaimana harus diperluas, juga sulit untuk memperluas pendengar / delegasi yang ada. Juga informasi tidak disembunyikan dengan baik karena seseorang mulai perlu mengetahui implementasinya untuk melihat cara memperluas superclass (kecuali jika Anda menggunakan komentar yang sangat luas).

Jadi setelah ini saya mungkin memilih untuk hanya menggunakan pengamat atau delegasi sepenuhnya untuk menjauh dari kelemahan yang datang dengan mencampuradukkan pendekatan untuk banyak. Namun ini datang dengan masalahnya sendiri. Sebagai contoh, saya mungkin menemukan bahwa saya pada akhirnya membutuhkan pengamat atau delegasi untuk jumlah perilaku yang meningkat sampai akhirnya saya membutuhkan pengamat / delegasi untuk hampir setiap perilaku. Salah satu opsi bisa dengan hanya memiliki satu pendengar / delegasi besar untuk semua perilaku tetapi kemudian kelas pelaksana berakhir dengan banyak metode kosong dll.

Maka saya mungkin mencoba pendekatan lain tetapi ada banyak masalah dengan itu. Kemudian yang berikutnya, dan yang berikutnya dll.


Proses berulang ini menjadi sangat sulit ketika setiap pendekatan tampaknya memiliki banyak masalah seperti yang lain dan mengarah ke semacam kelumpuhan keputusan desain . Juga sulit untuk menerima bahwa kode akan berakhir sama-sama bermasalah terlepas dari pola desain atau pendekatan yang digunakan. Jika saya berakhir dalam situasi ini, apakah itu berarti masalah itu sendiri perlu dipikirkan kembali? Apa yang dilakukan orang lain ketika mereka menghadapi situasi ini?

Sunting: Tampaknya ada sejumlah interpretasi dari pertanyaan yang ingin saya jelaskan:

  • Saya telah mengeluarkan OOP sepenuhnya dari pertanyaan karena ternyata itu sebenarnya tidak spesifik untuk OOP, ditambah terlalu mudah untuk salah menafsirkan beberapa komentar yang saya sampaikan tentang OOP.
  • Beberapa orang mengklaim saya harus mengambil pendekatan berulang dan mencoba pola yang berbeda, atau bahwa saya harus membuang pola ketika berhenti bekerja. Ini adalah proses yang saya maksudkan pada awalnya. Saya pikir ini jelas dari contoh tetapi saya bisa membuatnya lebih jelas, jadi saya telah mengedit pertanyaan untuk melakukannya.
Jonathan
sumber
3
Jangan "berlangganan filosofi OO". Ini alat, bukan keputusan hidup utama. Gunakan saat itu membantu dan jangan gunakan saat tidak.
user253751
Jika Anda terjebak dalam pemikiran tentang pola-pola tertentu, mungkin mencoba menulis beberapa proyek yang cukup kompleks di C, akan menarik untuk mengalami seberapa banyak yang dapat Anda lakukan tanpa pola-pola itu.
user253751
2
Oh C memiliki pola. Mereka hanya pola yang sangat berbeda. :)
candied_orange
Saya telah membereskan sebagian besar salah tafsir ini dalam edit
Jonathan
Memiliki masalah ini muncul sesekali adalah hal yang normal. Memiliki mereka sering terjadi seharusnya tidak menjadi masalah. Kemungkinan besar, Anda menggunakan paradigma pemrograman yang salah untuk masalah atau desain Anda adalah campuran dari paradigma di tempat yang salah.
Dunk

Jawaban:

8

Ketika saya sampai pada keputusan sulit seperti itu, saya biasanya bertanya pada diri saya sendiri tiga pertanyaan:

  1. Apa pro dan kontra dari semua solusi yang tersedia?

  2. Apakah ada solusinya, saya belum mempertimbangkan?

  3. Yang paling penting:
    Apa sebenarnya persyaratan saya? Bukan persyaratan di atas kertas, yang mendasar?
    Bisakah saya merumuskan kembali masalah / menyesuaikan persyaratannya, sehingga memungkinkan solusi sederhana dan mudah?
    Dapatkah saya merepresentasikan data saya dengan cara yang berbeda, sehingga memungkinkan solusi yang sederhana dan mudah?

    Ini adalah pertanyaan tentang dasar-dasar masalah yang dirasakan. Mungkin ternyata, bahwa Anda benar-benar mencoba menyelesaikan masalah yang salah. Masalah Anda mungkin memiliki persyaratan khusus yang memungkinkan solusi yang jauh lebih sederhana daripada kasus umum. Pertanyakan rumusan masalah Anda!

Saya merasa sangat penting untuk memikirkan ketiga pertanyaan itu dengan keras sebelum melanjutkan. Berjalan-jalanlah, mondar-mandir di kantor Anda, lakukan apa yang diperlukan untuk benar-benar memikirkan jawaban atas pertanyaan-pertanyaan ini. Namun, menjawab pertanyaan-pertanyaan ini seharusnya tidak memakan banyak waktu. Waktu yang tepat dapat berkisar dari 15 menit hingga sekitar satu minggu, tergantung pada buruknya solusi yang telah Anda temukan, dan pengaruhnya terhadap keseluruhan.

Nilai dari pendekatan ini adalah, bahwa Anda terkadang akan menemukan solusi yang sangat bagus. Solusi elegan. Solusi sepadan dengan waktu yang Anda investasikan dalam menjawab tiga pertanyaan ini. Dan Anda tidak akan menemukan solusi itu, jika Anda langsung memasukkan iterasi berikutnya.

Tentu saja, terkadang tidak ada solusi yang baik. Dalam hal ini, Anda terjebak dengan jawaban Anda untuk pertanyaan pertama, dan yang baik adalah yang paling tidak buruk. Dalam hal ini, nilai meluangkan waktu untuk menjawab pertanyaan-pertanyaan ini adalah bahwa Anda mungkin menghindari iterasi yang pasti gagal. Pastikan Anda kembali ke pengkodean dalam waktu yang tepat.

cmaster - mengembalikan monica
sumber
Saya mungkin menandai ini sebagai jawabannya, ini paling masuk akal bagi saya dan tampaknya ada konsensus tentang menilai kembali masalah itu sendiri.
Jonathan
Saya juga suka bagaimana Anda memecahnya menjadi langkah-langkah sehingga ada semacam prosedur longgar untuk menilai situasi.
Jonathan
OP, saya melihat Anda terjebak dalam mekanisme solusi kode, jadi ya Anda "mungkin juga menandai jawaban ini." Kode terbaik yang kami tulis adalah setelah melakukan analisis yang sangat hati-hati terhadap persyaratan, persyaratan turunan, diagram kelas, interaksi kelas, dll. Syukurlah kami menolak semua heckling dari kursi murah (baca manajemen & rekan kerja): "Anda menghabiskan terlalu banyak waktu dalam desain "," cepat dan dapatkan koding! "," itu terlalu banyak kelas! ", dll. Begitu kita sampai di sana, pengkodean adalah kegembiraan - lebih dari kesenangan. Secara obyektif itu adalah kode terbaik di seluruh proyek.
radarbob
13

Hal pertama yang pertama - pola adalah abstraksi yang berguna bukan akhirnya semuanya desain, apalagi desain OO.

Kedua - OO modern cukup pintar untuk mengetahui bahwa tidak semuanya adalah objek. Terkadang menggunakan fungsi lama yang sederhana, atau bahkan beberapa skrip gaya imperatif akan menghasilkan solusi yang lebih baik untuk masalah tertentu.

Sekarang untuk daging hal:

Ini menjadi sangat sulit ketika masing-masing pendekatan tampaknya memiliki banyak masalah seperti yang lain.

Mengapa? Ketika Anda memiliki banyak opsi serupa, keputusan Anda seharusnya lebih mudah! Anda tidak akan kehilangan banyak dengan memilih opsi "salah". Dan sungguh, kode tidak diperbaiki. Cobalah sesuatu, lihat apakah itu baik. Iterate .

Juga sulit untuk menerima bahwa kode tersebut akan berakhir sangat bermasalah terlepas dari pola atau pendekatan desain yang digunakan.

Kacang sulit. Masalah sulit - masalah matematika yang sebenarnya sulit hanya sulit. Terbukti sulit. Tidak ada solusi yang baik untuk mereka. Dan ternyata, masalah yang mudah itu tidak begitu berharga.

Tapi berhati-hatilah. Terlalu sering saya melihat orang frustrasi dengan tidak ada pilihan yang baik karena mereka terjebak melihat masalah dengan cara tertentu, atau bahwa mereka telah memotong tanggung jawab mereka dengan cara yang tidak wajar dengan masalah yang ada. "Tidak ada pilihan yang baik" bisa menjadi bau bahwa ada sesuatu yang secara fundamental salah dengan pendekatan Anda.

Ini mengakibatkan hilangnya motivasi karena kode "bersih" tidak lagi menjadi pilihan.

Sempurna adalah musuh kebaikan. Dapatkan sesuatu yang berfungsi, kemudian perbaiki.

Apakah ada pendekatan untuk desain yang dapat membantu meminimalkan masalah ini? Apakah ada praktik yang diterima untuk apa yang harus dilakukan seseorang dalam situasi seperti ini?

Seperti yang saya sebutkan, pengembangan berulang umumnya meminimalkan masalah ini. Setelah Anda mendapatkan sesuatu yang berfungsi, Anda lebih terbiasa dengan masalah yang menempatkan Anda pada posisi yang lebih baik untuk menyelesaikannya. Anda memiliki kode aktual untuk dilihat dan dievaluasi, bukan beberapa desain abstrak yang tampaknya tidak benar.

Telastyn
sumber
Hanya berpikir saya harus mengatakan bahwa saya telah membereskan beberapa kesalahan penafsiran dalam pengeditan. Saya biasanya melakukan "membuatnya bekerja" dan pendekatan refactor. Namun, sering kali ini berakhir dengan banyak hutang teknis dalam pengalaman saya. Sebagai contoh, jika saya hanya membuat sesuatu berfungsi, tetapi kemudian saya atau orang lain membangun di atasnya, beberapa hal itu mungkin memiliki dependensi yang tidak dapat dihindari yang kemudian juga membutuhkan satu ton refactoring. Tentu saja Anda tidak selalu dapat mengetahui hal ini sebelumnya. Tetapi jika Anda sudah tahu pendekatannya cacat, haruskah seseorang membuatnya bekerja dan kemudian secara berulang-ulang refactor sebelum membangun kode?
Jonathan
@ Jonathan - semua desain adalah serangkaian trade off. Ya, Anda harus segera beralih jika desain cacat dan Anda memiliki cara yang jelas untuk memperbaikinya. Jika tidak ada peningkatan yang jelas, berhentilah bercinta.
Telastyn
"Mereka telah memangkas tanggung jawab mereka dengan cara yang tidak wajar dengan masalah yang dihadapi. Tidak ada pilihan yang baik untuk mencium bahwa ada sesuatu yang secara fundamental salah dengan pendekatanmu." Saya bertaruh untuk yang ini. Beberapa pengembang tidak pernah mengalami masalah yang dijelaskan OP dan yang lain tampaknya cukup sering melakukannya. Seringkali solusinya tidak mudah dilihat ketika diajukan oleh pengembang asli karena mereka sudah bias desain dalam cara mereka membingkai masalah. Kadang-kadang satu-satunya cara untuk menemukan solusi yang cukup jelas adalah mulai dari jauh ke belakang pada persyaratan untuk desain.
Dunk
8

Situasi yang Anda gambarkan terlihat seperti pendekatan dari bawah ke atas. Anda mengambil daun, mencoba memperbaikinya dan mencari tahu itu terhubung ke cabang yang juga terhubung ke cabang lain dll.

Ini seperti mencoba membuat mobil dimulai dengan ban.

Yang Anda butuhkan adalah mengambil langkah mundur dan melihat gambar yang lebih besar. Bagaimana daun itu berada dalam desain keseluruhan? Apakah itu masih terkini dan benar?

Bagaimana tampilan modul jika Anda akan merancang dan mengimplementasikannya dari awal? Seberapa jauh dari "ideal" itu adalah implementasi Anda saat ini.

Dengan begitu Anda memiliki gambaran yang lebih besar tentang apa yang harus dilakukan. (Atau jika Anda memutuskan terlalu banyak bekerja, apa masalahnya).

Pieter B
sumber
4

Contoh Anda menggambarkan situasi yang muncul secara khas dengan potongan kode warisan yang lebih besar, dan ketika Anda mencoba membuat refactoring yang "terlalu besar".

Saran terbaik yang dapat saya berikan kepada Anda untuk situasi ini adalah:

  • jangan mencoba mencapai tujuan utama Anda dalam satu "big bang" ,

  • pelajari cara meningkatkan kode Anda dalam langkah-langkah kecil!

Tentu saja, itu lebih mudah ditulis daripada dilakukan, jadi bagaimana melakukannya dalam kenyataan? Nah, Anda perlu latihan dan pengalaman, itu sangat tergantung pada kasusnya, dan tidak ada aturan yang keras dan cepat mengatakan "lakukan ini-atau-itu" yang cocok untuk setiap kasus. Tetapi izinkan saya menggunakan contoh hipotetis Anda. "komposisi-atas-warisan" bukan tujuan desain semua atau tidak sama sekali, itu adalah kandidat yang sempurna untuk dicapai dalam beberapa langkah kecil.

Katakanlah Anda perhatikan "komposisi-lebih-warisan" adalah alat yang tepat untuk kasus ini. Pasti ada beberapa indikasi untuk ini menjadi tujuan yang masuk akal, jika tidak Anda tidak akan memilih ini. Jadi mari kita asumsikan ada banyak fungsi dalam superclass yang baru saja "dipanggil" dari subclass, jadi fungsi ini adalah kandidat untuk tidak tinggal di superclass itu.

Jika Anda melihat Anda tidak dapat langsung menghapus superclass dari subclass, Anda dapat mulai dengan refactoring superclass menjadi komponen yang lebih kecil merangkum fungsi yang disebutkan di atas. Mulailah dengan buah-buahan yang paling rendah penggantinya, ekstrak beberapa komponen yang lebih sederhana terlebih dahulu, yang akan membuat superclass Anda lebih kompleks. Semakin kecil superclass, semakin mudah refactoring tambahan menjadi. Gunakan komponen-komponen ini dari subclass dan juga dari superclass.

Jika Anda beruntung, kode yang tersisa dalam superclass akan menjadi sangat sederhana selama proses ini sehingga Anda dapat menghapus superclass dari subclass tanpa masalah lebih lanjut. Atau, Anda akan melihat bahwa menjaga superclass tidak menjadi masalah lagi, karena Anda sudah cukup mengekstraksi kode ke dalam komponen yang ingin Anda gunakan kembali tanpa warisan.

Jika Anda tidak yakin harus mulai dari mana, karena Anda tidak tahu apakah refactoring akan berubah menjadi sederhana, terkadang pendekatan terbaik adalah dengan melakukan beberapa refactoring awal .

Tentu saja, situasi Anda yang sebenarnya mungkin lebih rumit. Jadi belajar, kumpulkan pengalaman, dan bersabarlah, mendapatkan hak ini membutuhkan waktu bertahun-tahun. Ada dua buku yang bisa saya rekomendasikan di sini, mungkin Anda merasa terbantu:

  • Refactoring oleh Fowler: menggambarkan katalog lengkap refactoring yang sangat kecil .

  • Bekerja secara efektif dengan kode lama oleh Feathers: memberikan saran yang sangat baik bagaimana menangani potongan besar kode yang dirancang dengan buruk dan membuatnya lebih dapat diuji dalam langkah-langkah kecil

Doc Brown
sumber
1
Ini juga sangat membantu. Langkah-langkah kecil atau awal refactoring adalah ide yang bagus karena kemudian menjadi sesuatu yang dapat diselesaikan secara progresif bersama dengan pekerjaan lain tanpa menghalangi terlalu banyak. Saya berharap saya bisa menyetujui beberapa jawaban!
Jonathan
1

Terkadang dua prinsip desain terbaik adalah KISS * dan YAGNI **. Jangan merasa perlu menjejalkan setiap pola desain yang diketahui ke dalam program yang hanya perlu mencetak "Halo dunia!".

 * Keep It Simple, Stupid
 ** You Ain't Gonna Need It

Edit setelah pembaruan pertanyaan (dan mencerminkan apa yang Pieter B katakan sampai batas tertentu):

Kadang-kadang Anda mengambil keputusan arsitektur sejak awal yang mengarahkan Anda ke desain tertentu yang mengarah ke segala macam kejelekan ketika Anda mencoba menerapkannya. Sayangnya, pada titik itu, solusi "tepat" adalah mundur dan mencari tahu bagaimana Anda sampai pada posisi itu. Jika Anda belum dapat melihat jawabannya, terus melangkah mundur sampai Anda menemukannya.

Tetapi jika pekerjaan untuk melakukan itu tidak proporsional, dibutuhkan keputusan pragmatis untuk hanya menghasilkan solusi yang paling buruk untuk masalah tersebut.

Simon B
sumber
Saya telah menjelaskan beberapa hal ini dalam pengeditan, tetapi secara umum saya merujuk pada masalah-masalah tersebut di mana tidak ada solusi sederhana yang tersedia.
Jonathan
Ah bagus ya sepertinya ada konsensus yang muncul tentang mundur dan menilai kembali masalah. Ini ide yang bagus.
Jonathan
1

Ketika saya dalam situasi ini, hal pertama yang saya lakukan adalah berhenti. Saya beralih ke masalah lain dan mengatasinya untuk sementara waktu. Mungkin satu jam, mungkin sehari, mungkin lebih. Itu tidak selalu menjadi pilihan, tetapi alam bawah sadar saya akan bekerja pada hal-hal sementara otak sadar saya melakukan sesuatu yang lebih produktif. Akhirnya, saya kembali ke sana dengan mata segar dan mencoba lagi.

Hal lain yang saya lakukan adalah meminta seseorang yang lebih pintar dari saya. Ini bisa dalam bentuk bertanya di Stack Exchange, membaca artikel di web tentang topik tersebut, atau bertanya pada kolega yang memiliki lebih banyak pengalaman di bidang ini. Seringkali metode yang saya pikir adalah pendekatan yang tepat ternyata sepenuhnya salah untuk apa yang saya coba lakukan. Saya telah salah mengidentifikasi beberapa aspek dari masalah dan itu tidak benar-benar cocok dengan pola yang saya pikir tidak. Ketika itu terjadi, meminta orang lain berkata, "Anda tahu, ini lebih mirip ..." bisa sangat membantu.

Terkait dengan hal di atas adalah desain atau debugging oleh pengakuan. Anda pergi ke seorang kolega dan berkata, "Saya akan memberi tahu Anda masalah yang saya alami, dan kemudian saya akan menjelaskan kepada Anda solusi yang saya miliki. Anda menunjukkan masalah dalam setiap pendekatan dan menyarankan pendekatan lain . " Seringkali bahkan sebelum orang lain berbicara, seperti yang saya jelaskan, saya mulai menyadari bahwa satu jalan yang tampak sama dengan orang lain sebenarnya jauh lebih baik atau lebih buruk daripada yang saya pikir sebelumnya. Percakapan yang dihasilkan dapat memperkuat persepsi itu, atau menunjukkan hal-hal baru yang tidak saya pikirkan.

Jadi TL; DR: Istirahatlah, jangan memaksanya, minta bantuan.

pengguna1118321
sumber