Bagaimana saya bisa tahu perangkat lunak saya memiliki terlalu banyak abstraksi dan terlalu banyak pola desain, atau sebaliknya, bagaimana saya tahu jika harus memiliki lebih dari itu?
Pengembang yang bekerja dengan saya memprogram secara berbeda mengenai poin-poin ini.
Beberapa melakukan abstrak setiap fungsi kecil, menggunakan pola desain sedapat mungkin dan menghindari redundansi dengan biaya berapa pun.
Yang lain, termasuk saya, mencoba untuk menjadi lebih pragmatis, dan menulis kode yang tidak sepenuhnya pas untuk setiap pola desain, tetapi jauh lebih cepat untuk dipahami karena lebih sedikit abstraksi yang diterapkan.
Saya tahu ini adalah kompromi. Bagaimana saya bisa tahu ketika ada cukup abstraksi ke dalam proyek dan bagaimana saya tahu itu membutuhkan lebih banyak?
Contoh, ketika lapisan cache generik ditulis menggunakan Memcache. Apakah kita benar-benar membutuhkan Memcache
, MemcacheAdapter
, MemcacheInterface
, AbstractCache
, CacheFactory
, CacheConnector
, ... atau ini lebih mudah untuk mempertahankan dan kode yang baik masih bila menggunakan hanya setengah dari orang-orang kelas?
Temukan ini di Twitter:
Jawaban:
Berapa banyak bahan yang dibutuhkan untuk makan? Berapa banyak bagian yang Anda butuhkan untuk membangun kendaraan?
Anda tahu bahwa Anda memiliki terlalu sedikit abstraksi ketika sedikit perubahan implementasi mengarah ke perubahan di seluruh kode Anda. Abstraksi yang tepat akan membantu mengisolasi bagian dari kode yang perlu diubah.
Anda tahu bahwa Anda memiliki terlalu banyak abstraksi ketika sedikit perubahan antarmuka mengarah ke perubahan di seluruh kode Anda, pada level yang berbeda. Alih-alih mengubah antarmuka antara dua kelas, Anda menemukan diri Anda memodifikasi lusinan kelas dan antarmuka hanya untuk menambah properti atau mengubah jenis argumen metode.
Selain itu, benar-benar tidak ada cara untuk menjawab pertanyaan dengan memberikan nomor. Jumlah abstraksi tidak akan sama dari proyek ke proyek, dari bahasa ke bahasa lain, dan bahkan dari satu pengembang ke pengembang lainnya.
sumber
interface Doer {void prepare(); void doIt();}
), dan itu menjadi menyakitkan untuk refactor ketika abstraksi ini tidak lagi cocok. Bagian penting dari jawabannya adalah tes ini berlaku ketika sebuah abstraksi harus berubah - jika tidak, itu tidak pernah menyebabkan rasa sakit.Masalah dengan pola desain dapat disimpulkan dengan pepatah "ketika Anda memegang palu, semuanya terlihat seperti paku." Tindakan menerapkan pola desain sama sekali tidak meningkatkan program Anda. Bahkan, saya berpendapat bahwa Anda membuat program yang lebih rumit jika Anda menambahkan pola desain. Pertanyaannya tetap apakah Anda memanfaatkan dengan baik pola desain atau tidak, dan ini adalah inti dari pertanyaan, "Kapan kita memiliki terlalu banyak abstraksi?"
Jika Anda membuat antarmuka dan kelas super abstrak untuk satu implementasi tunggal, Anda telah menambahkan dua komponen tambahan ke proyek Anda yang berlebihan dan tidak perlu. Inti dari menyediakan antarmuka adalah untuk dapat menanganinya secara merata di seluruh program Anda tanpa mengetahui cara kerjanya. Inti dari kelas super abstrak adalah untuk memberikan perilaku yang mendasari implementasi. Jika Anda hanya memiliki satu implementasi, Anda mendapatkan semua antarmuka komplikasi dan kelas abstak memberikan dan tidak ada keuntungan.
Demikian pula, jika Anda menggunakan pola Factory, dan Anda menemukan diri Anda casting kelas untuk menggunakan fungsi yang hanya tersedia di kelas super, pola Factory tidak menambahkan keuntungan apa pun ke kode Anda. Anda hanya menambahkan kelas tambahan ke proyek Anda yang bisa dihindari.
TL; DR Maksud saya adalah bahwa tujuan abstraksi tidak abstrak dalam dirinya sendiri. Ini melayani tujuan yang sangat praktis dalam program Anda, dan sebelum Anda memutuskan untuk menggunakan pola desain atau membuat antarmuka, Anda harus bertanya pada diri sendiri apakah dengan melakukan itu, program ini lebih mudah dipahami meskipun ada kompleksitas tambahan atau program lebih kuat meskipun ada kompleksitas tambahan (lebih disukai keduanya). Jika jawabannya tidak atau mungkin, maka luangkan beberapa menit untuk mempertimbangkan mengapa Anda ingin melakukan itu dan jika mungkin itu dapat dilakukan dengan cara yang lebih baik, tanpa harus menambahkan abstraksi ke kode Anda.
sumber
TL: DR;
Saya tidak berpikir ada sejumlah tingkat abstrasi "perlu" di bawah ini yang terlalu sedikit atau di atasnya terlalu banyak. Seperti dalam desain grafis, desain OOP yang baik harus tidak terlihat dan harus diterima begitu saja. Desain yang buruk selalu menonjol seperti jempol yang sakit.
Jawaban panjang
Kemungkinan besar Anda tidak akan pernah tahu berapa tingkat abstraksi yang Anda bangun.
Sebagian besar level abstraksi tidak terlihat oleh kita dan kita menerima begitu saja.
Alasan itu membawa saya ke kesimpulan ini:
Salah satu tujuan utama dari abstraksi adalah menyelamatkan pemrogram kebutuhan untuk memiliki semua kerja sistem dalam pikiran setiap saat. Jika desain memaksa Anda untuk tahu terlalu banyak tentang sistem untuk menambahkan sesuatu maka mungkin ada terlalu sedikit abstraksi. Saya pikir abstraksi yang buruk (desain yang buruk, desain yang anemia atau over-engineering) juga dapat memaksa Anda untuk tahu terlalu banyak untuk menambahkan sesuatu. Dalam satu ekstrem, kami memiliki desain berdasarkan kelas dewa atau sekelompok DTO, di ekstrem lain kami memiliki beberapa kerangka kerja ATAU / ketekunan yang membuat Anda melompati lingkaran tak terhitung untuk mencapai dunia halo. Kedua kasus memaksa Anda terlalu banyak tahu.
Abstraksi yang buruk menganut lonceng Gauss dalam kenyataan bahwa begitu Anda melewati sweet spot mulai menghalangi. Abstraksi yang baik, di sisi lain, tidak terlihat dan tidak mungkin ada terlalu banyak karena Anda tidak memperhatikannya. Pikirkan berapa banyak lapisan demi lapisan API, protokol jaringan, pustaka, pustaka OS, sistem file, lapisan harware, dll. Aplikasi Anda dibangun dan diterima begitu saja.
Tujuan utama abstraksi lainnya adalah kompartementalisasi, sehingga kesalahan tidak menyebar di luar area tertentu, tidak berbeda dengan lambung ganda dan tangki terpisah yang mencegah kapal dari banjir secara lengkap ketika bagian lambung berlubang. Jika modifikasi pada kode akhirnya menciptakan bug di area yang tampaknya tidak terkait maka kemungkinan ada terlalu sedikit abstraksi.
sumber
Pola desain hanyalah solusi umum untuk masalah. Sangat penting untuk mengetahui pola desain, tetapi itu hanya gejala kode yang dirancang dengan baik (kode yang baik masih bisa batal dari geng empat set pola desain), bukan penyebabnya.
Abstraksi seperti pagar. Mereka membantu memisahkan wilayah program Anda menjadi potongan-potongan yang dapat diuji dan dipertukarkan (persyaratan untuk membuat kode tidak kaku yang tidak rapuh). Dan seperti pagar:
Anda ingin abstraksi pada titik antarmuka alami untuk meminimalkan ukurannya.
Anda tidak ingin mengubahnya.
Anda ingin mereka memisahkan hal-hal yang bisa mandiri.
Memiliki satu di tempat yang salah lebih buruk daripada tidak memilikinya.
Mereka seharusnya tidak memiliki kebocoran besar .
sumber
Refactoring
Saya tidak melihat kata "refactoring" yang disebutkan bahkan sejauh ini. Jadi, ini dia:
Jangan ragu untuk mengimplementasikan fitur baru secara langsung. Jika Anda hanya memiliki satu kelas, sederhana, kelas, Anda kemungkinan tidak memerlukan antarmuka, superclass, pabrik dll.
Jika dan ketika Anda melihat bahwa Anda memperluas kelas dengan cara yang tumbuh terlalu gemuk, maka inilah saatnya untuk merobeknya. Pada saat itu, sangat masuk akal untuk memikirkan bagaimana Anda seharusnya melakukan itu.
Pola adalah alat pikiran
Pola, atau lebih khusus buku "Pola Desain" oleh geng berempat, sangat bagus, di antara alasan-alasan lain, karena mereka membangun bahasa bagi pengembang untuk berpikir dan berbicara. Mudah untuk mengatakan "pengamat", "pabrik" atau "fasad" dan semua orang tahu persis apa artinya, segera.
Jadi pendapat saya adalah bahwa setiap pengembang harus memiliki pengetahuan yang lewat tentang setidaknya pola dalam buku asli, hanya untuk dapat berbicara tentang konsep OO tanpa harus selalu menjelaskan dasar-dasarnya. Haruskah Anda benar-benar menggunakan pola setiap kali kemungkinan untuk melakukannya muncul? Kemungkinan besar tidak.
Perpustakaan
Perpustakaan kemungkinan adalah satu area di mana ia mungkin berada di sisi terlalu banyak pilihan berbasis pola, bukan terlalu sedikit. Mengubah sesuatu dari kelas "gemuk" menjadi sesuatu dengan pola yang lebih diturunkan (biasanya itu berarti kelas yang lebih banyak dan lebih kecil) akan secara radikal mengubah antarmuka; dan itu adalah satu hal yang biasanya tidak ingin Anda ubah di perpustakaan, karena itu adalah satu-satunya hal yang sangat menarik bagi pengguna perpustakaan Anda. Mereka tidak akan peduli tentang bagaimana Anda menangani fungsionalitas Anda secara internal, tetapi mereka sangat peduli jika mereka terus-menerus mengubah program mereka ketika Anda melakukan rilis baru dengan API baru.
sumber
Poin dari abstraksi haruslah yang pertama dan terutama nilai yang dibawa ke konsumen abstraksi, yaitu klien abstraksi, programmer lain, dan seringkali diri Anda sendiri.
Jika, sebagai klien yang mengonsumsi abstraksi, Anda merasa perlu mencampur dan mencocokkan berbagai abstraksi untuk menyelesaikan pekerjaan pemrograman Anda, maka ada terlalu banyak abstraksi yang berpotensi.
Idealnya, layering harus menyatukan sejumlah abstraksi yang lebih rendah dan menggantikannya dengan abstraksi sederhana dan tingkat yang lebih tinggi yang dapat digunakan konsumennya tanpa harus berurusan dengan abstraksi yang mendasarinya. Jika mereka harus berurusan dengan abstraksi yang mendasarinya, maka lapisannya bocor (dengan cara menjadi tidak lengkap). Jika konsumen harus berurusan dengan berbagai abstraksi yang berbeda, maka layering mungkin hilang.
Setelah mempertimbangkan nilai abstraksi untuk pemrogram yang mengkonsumsi, maka kita dapat beralih untuk mengevaluasi dan mempertimbangkan implementasinya, seperti nilai DRY-ness.
Ya, ini semua tentang pelonggaran pemeliharaan, tetapi kita harus mempertimbangkan keadaan buruk pemeliharaan konsumen kita terlebih dahulu, dengan memberikan abstraksi dan lapisan yang berkualitas, kemudian mempertimbangkan pelonggaran pemeliharaan kita sendiri dalam hal aspek implementasi seperti menghindari redundansi.
Kita harus melihat perspektif klien, dan jika hidup mereka dipermudah maka itu baik. Jika hidup mereka lebih kompleks maka itu buruk. Namun, bisa jadi ada lapisan yang hilang yang membungkus semuanya menjadi sesuatu yang mudah digunakan. Secara internal, ini sangat mungkin membuat pemeliharaan implementasi lebih baik. Namun, seperti yang Anda duga, mungkin juga itu hanya rekayasa berlebihan.
sumber
Abstraksi dirancang untuk membuat kode lebih mudah dipahami. Jika lapisan abstraksi akan membuat hal-hal lebih membingungkan - jangan lakukan itu.
Tujuannya adalah untuk menggunakan jumlah abstraksi dan antarmuka yang benar untuk:
Abstrak hanya bila diperlukan
Jangan abstraksi kapan
Beberapa contoh
sumber
Saya pikir ini mungkin jawaban meta yang kontroversial, dan saya agak terlambat ke pesta, tapi saya pikir sangat penting untuk menyebutkan ini di sini, karena saya pikir saya tahu dari mana Anda berasal.
Masalah dengan cara pola desain digunakan, adalah ketika mereka diajarkan, mereka menyajikan kasus seperti ini:
Masalahnya adalah bahwa ketika Anda mulai melakukan rekayasa nyata, hal-hal yang tidak cukup cut-and-dry. Pola desain yang Anda baca tidak akan cukup sesuai dengan masalah yang Anda coba selesaikan. Belum lagi bahwa perpustakaan yang Anda gunakan benar-benar melanggar semua yang dinyatakan dalam teks yang menjelaskan pola-pola itu, masing-masing dengan caranya sendiri-sendiri. Dan sebagai hasilnya, kode yang Anda tulis "terasa salah" dan Anda mengajukan pertanyaan seperti ini.
Selain itu, saya ingin mengutip Andrei Alexandrescu, ketika berbicara tentang rekayasa perangkat lunak, yang menyatakan:
Mungkin ini sedikit berlebihan, tapi saya pikir ini dengan sempurna menjelaskan alasan tambahan mengapa Anda mungkin merasa kurang percaya diri dengan kode Anda.
Pada saat-saat seperti ini, suara kenabian Mike Acton, pemimpin mesin game di Insomniac, berteriak di kepala saya:
Dia berbicara tentang input ke program Anda, dan output yang diinginkan. Dan kemudian ada permata Fred Brooks dari Bulan Mythical Man:
Jadi jika saya adalah Anda, saya akan mempertimbangkan masalah saya berdasarkan kasus input khas saya, dan apakah itu mencapai output yang benar yang diinginkan. Dan ajukan pertanyaan seperti ini:
Ketika Anda melakukan itu, pertanyaan "berapa banyak lapisan abstraksi atau pola desain yang dibutuhkan" menjadi lebih mudah dijawab. Berapa banyak lapisan abstraksi yang Anda butuhkan? Sebanyak yang diperlukan untuk mencapai tujuan ini, dan tidak lebih. "Bagaimana dengan pola desain? Aku belum pernah menggunakannya!" Nah, jika tujuan di atas tercapai tanpa penerapan langsung suatu pola, maka itu tidak masalah. Buat itu bekerja, dan lanjutkan ke masalah berikutnya. Mulai dari data Anda, bukan dari kode.
sumber
Arsitektur Perangkat Lunak Menciptakan Bahasa
Dengan setiap lapisan perangkat lunak, Anda membuat bahasa yang Anda (atau rekan kerja Anda) ingin sampaikan dalam solusi lapisan berikutnya yang lebih tinggi (jadi, saya akan memasukkan beberapa analog bahasa alami di posting saya). Pengguna Anda tidak ingin menghabiskan waktu bertahun-tahun mempelajari cara membaca atau menulis bahasa itu.
Pandangan ini membantu saya ketika memutuskan masalah arsitektur.
Keterbacaan
Bahasa itu harus mudah dipahami (membuat kode lapisan selanjutnya dapat dibaca). Kode dibaca jauh lebih sering daripada tertulis.
Satu konsep harus diungkapkan dengan satu kata - satu kelas atau antarmuka harus memaparkan konsep tersebut. (Bahasa Slavonic biasanya memiliki dua kata yang berbeda untuk satu kata kerja bahasa Inggris, jadi Anda harus belajar dua kali kosakata. Semua bahasa alami menggunakan kata tunggal untuk beberapa konsep).
Konsep yang Anda paparkan seharusnya tidak mengandung kejutan. Itu terutama penamaan konvensi seperti get-and set-methods dll. Dan pola desain dapat membantu karena mereka memberikan pola solusi standar, dan pembaca melihat "OK, saya mendapatkan objek dari Pabrik" dan tahu apa artinya itu. Tetapi jika hanya membuat kelas beton melakukan pekerjaan, saya lebih suka itu.
Kegunaan
Bahasanya harus mudah digunakan (membuatnya mudah untuk merumuskan "kalimat yang benar").
Jika semua kelas / antarmuka MemCache ini dapat dilihat oleh lapisan berikutnya, itu menciptakan kurva pembelajaran yang curam bagi pengguna sampai ia mengerti kapan dan di mana harus menggunakan kata-kata ini untuk konsep cache.
Mengekspos hanya kelas / metode yang diperlukan memudahkan pengguna Anda untuk menemukan apa yang dia butuhkan (lihat kutipan DocBrowns dari Antoine de Saint-Exupery). Mengekspos antarmuka bukan kelas implementasi dapat membuatnya lebih mudah.
Jika Anda mengekspos fungsionalitas di mana pola desain yang ada dapat berlaku, lebih baik mengikuti pola desain itu daripada menciptakan sesuatu yang berbeda. Pengguna Anda akan memahami API mengikuti pola desain lebih mudah daripada beberapa konsep yang sama sekali berbeda (jika Anda tahu bahasa Italia, bahasa Spanyol akan lebih mudah bagi Anda daripada bahasa Cina).
Ringkasan
Memperkenalkan abstraksi jika itu membuat penggunaan lebih mudah (dan layak untuk mempertahankan abstraksi dan implementasinya).
Jika kode Anda memiliki sub-tugas (non-sepele), selesaikan "cara yang diharapkan" yaitu mengikuti pola desain yang sesuai alih-alih menciptakan kembali jenis roda yang berbeda.
sumber
Yang penting untuk dipertimbangkan adalah berapa banyak kode konsumsi yang benar-benar menangani logika bisnis Anda perlu tahu tentang kelas-kelas terkait caching ini. Idealnya kode Anda hanya peduli dengan objek cache yang ingin dibuat dan mungkin pabrik untuk membuat objek itu jika metode konstruktor tidak cukup.
Jumlah pola yang digunakan atau tingkat warisan tidak terlalu penting asalkan masing-masing tingkat dapat dibenarkan untuk pengembang lain. Ini menciptakan batas informal karena setiap level tambahan lebih sulit untuk dibenarkan. Bagian yang lebih penting adalah berapa banyak level abstraksi yang dipengaruhi oleh perubahan persyaratan fungsional atau bisnis. Jika Anda dapat membuat perubahan hanya pada satu level untuk satu persyaratan saja maka kemungkinan Anda tidak terlalu abstrak atau abstrak, jika Anda mengubah level yang sama untuk beberapa perubahan yang tidak terkait, Anda cenderung diabstraksikan dan perlu memisah lebih lanjut masalah.
sumber
Pertama, kutipan Twitter itu palsu. Pengembang baru perlu membuat model, abstraksi biasanya akan membantu mereka "mendapatkan gambar". Asalkan abstraksi masuk akal tentu saja.
Kedua, masalah Anda tidak terlalu banyak atau terlalu sedikit abstraksi, itu rupanya tidak ada yang bisa memutuskan hal-hal ini. Tidak ada yang memiliki kode, tidak ada rencana / desain / filosofi tunggal diterapkan, setiap orang berikutnya dapat melakukan apa pun yang menurutnya cocok untuk saat itu. Gaya mana pun yang Anda gunakan, itu haruslah satu.
sumber