Saya suka SOLID, dan saya mencoba yang terbaik untuk menggunakannya dan menerapkannya ketika saya sedang berkembang. Tapi saya merasa seolah-olah pendekatan SOLID mengubah kode Anda menjadi kode 'kerangka kerja' - yaitu kode yang akan Anda desain jika Anda membuat kerangka kerja atau pustaka untuk digunakan pengembang lain.
Saya secara umum telah mempraktekkan 2 mode pemrograman - membuat kurang lebih persis apa yang diminta melalui persyaratan dan KISS (pemrograman tipikal), atau membuat logika yang sangat umum dan dapat digunakan kembali, layanan, dll yang memberikan fleksibilitas yang mungkin dibutuhkan pengembang lain (kerangka pemrograman) .
Jika pengguna benar-benar hanya ingin aplikasi untuk melakukan hal-hal x dan y, masuk akal untuk mengikuti SOLID dan menambahkan sejumlah besar titik masuk abstraksi, ketika Anda bahkan tidak tahu apakah itu bahkan masalah yang valid untuk memulai dengan? Jika Anda menambahkan titik entri abstraksi ini, apakah Anda benar-benar memenuhi persyaratan pengguna, atau apakah Anda membuat kerangka kerja di atas kerangka kerja dan tumpukan teknologi yang ada untuk membuat penambahan di masa mendatang lebih mudah? Dalam hal apa Anda melayani kepentingan pelanggan, atau pengembang?
Ini adalah sesuatu yang tampaknya umum di dunia Java Enterprise, di mana rasanya seolah-olah Anda sedang merancang kerangka kerja Anda sendiri di atas J2EE atau Spring sehingga itu adalah UX yang lebih baik untuk pengembang, daripada berfokus pada UX untuk pengguna?
sumber
Jawaban:
Pengamatan Anda benar, prinsip-prinsip SOLID adalah IMHO dibuat dengan pustaka yang dapat digunakan kembali atau kode kerangka kerja dalam pikiran. Ketika Anda hanya mengikuti semuanya secara membabi buta, tanpa bertanya apakah itu masuk akal atau tidak, Anda berisiko untuk membuat generalisasi yang berlebihan dan menginvestasikan lebih banyak upaya ke dalam sistem Anda daripada yang mungkin diperlukan.
Ini adalah trade-off, dan perlu beberapa pengalaman untuk membuat keputusan yang tepat tentang kapan harus digeneralisasi dan kapan tidak. Pendekatan yang mungkin untuk ini adalah dengan berpegang pada prinsip YAGNI - jangan membuat kode Anda SOLID "untuk berjaga-jaga" - atau, untuk menggunakan kata-kata Anda: jangan
alih-alih, berikan fleksibilitas yang sebenarnya dibutuhkan pengembang lain segera setelah mereka membutuhkannya , tetapi tidak lebih awal.
Jadi, setiap kali Anda memiliki satu fungsi atau kelas dalam kode Anda, Anda tidak yakin apakah itu dapat digunakan kembali, jangan memasukkannya ke dalam kerangka kerja Anda sekarang. Tunggu hingga Anda memiliki kasing untuk reusage dan refactor menjadi "SOLID cukup untuk kasing itu". Jangan menerapkan lebih banyak konfigurabilitas (mengikuti OCP), atau titik masuk abstraksi (menggunakan DIP) ke dalam kelas yang Anda perlukan untuk kasing ulang yang sebenarnya. Tambahkan fleksibilitas berikutnya ketika persyaratan reusage berikutnya benar-benar ada.
Tentu saja, cara kerja ini akan selalu membutuhkan sejumlah refactoring pada basis kode kerja yang ada. Itulah mengapa tes otomatis penting di sini. Jadi, membuat kode Anda SOLID sejak awal hingga dapat diuji unitnya bukan merupakan pemborosan waktu, dan melakukannya tidak bertentangan dengan YAGNI. Tes otomatis adalah kasus yang valid untuk "penggunaan kembali kode", karena kode yang dipertaruhkan digunakan dari kode produksi serta dari tes. Namun perlu diingat, tambahkan saja fleksibilitas yang sebenarnya Anda butuhkan untuk membuat tes bekerja, tidak kurang, tidak lebih.
Ini sebenarnya kebijaksanaan lama. Dahulu sebelum istilah SOLID menjadi populer, seseorang mengatakan kepada saya sebelum kita mencoba menulis kode yang dapat digunakan kembali , kita harus menulis kode yang dapat digunakan . Dan saya masih berpikir ini adalah rekomendasi yang bagus.
sumber
Dari pengalaman saya, saat menulis aplikasi, Anda memiliki tiga pilihan:
Dalam kasus pertama, biasanya berakhir dengan kode berpasangan ketat yang tidak memiliki tes unit. Tentu itu cepat untuk ditulis, tetapi sulit untuk diuji. Dan sakit kerajaan yang tepat untuk berubah nanti ketika persyaratan berubah.
Dalam kasus kedua, sejumlah besar waktu dihabiskan untuk mengantisipasi kebutuhan masa depan. Dan terlalu sering persyaratan yang diantisipasi di masa depan tidak pernah terwujud. Ini sepertinya skenario yang Anda gambarkan. Sebagian besar waktu hanya buang-buang waktu dan menghasilkan kode rumit yang tidak perlu yang masih sulit diubah ketika persyaratan yang tidak diantisipasi untuk muncul.
Kasus terakhir adalah yang saya tuju dalam pandangan saya. Gunakan TDD atau teknik serupa untuk menguji kode saat Anda pergi dan Anda akan berakhir dengan kode yang digabungkan secara longgar, itu mudah untuk dimodifikasi namun masih cepat untuk menulis. Dan masalahnya adalah, dengan melakukan ini, Anda secara alami mengikuti banyak prinsip SOLID: kelas dan fungsi kecil; antarmuka dan dependensi yang disuntikkan. Dan Nyonya Liskov pada umumnya tetap senang juga karena kelas-kelas sederhana dengan tanggung jawab tunggal jarang melanggar prinsip substitusi.
Satu-satunya aspek SOLID yang tidak benar-benar berlaku di sini adalah prinsip terbuka / tertutup. Untuk perpustakaan dan kerangka kerja, ini penting. Untuk aplikasi mandiri, tidak terlalu banyak. Benar-benar ini adalah kasus penulisan kode yang mengikuti " SLID ": mudah untuk menulis (dan membaca), mudah untuk diuji dan mudah untuk dipelihara.
sumber
Perspektif yang Anda miliki dapat dipengaruhi oleh pengalaman pribadi. Ini adalah kemiringan yang licin dari fakta yang secara individual benar, tetapi kesimpulan yang dihasilkan tidak, meskipun tampak benar pada pandangan pertama.
Ini berarti bahwa ketika Anda berinteraksi dengan kerangka kerja dan pustaka yang lebih kecil, kode praktik yang baik yang akan berinteraksi dengan Anda akan lebih umum ditemukan dalam kerangka kerja yang lebih besar.
Kekeliruan ini sangat umum, misalnya setiap dokter yang saya rawat sombong. Karena itu saya menyimpulkan bahwa semua dokter sombong. Kesalahan-kesalahan ini selalu menderita membuat selimut inferensi berdasarkan pengalaman pribadi.
Dalam kasus Anda, mungkin Anda sebagian besar mengalami praktik yang baik dalam kerangka kerja yang lebih besar dan tidak di perpustakaan yang lebih kecil. Pengamatan pribadi Anda tidak salah, tetapi merupakan bukti anekdotal dan tidak berlaku secara universal.
Anda agak mengkonfirmasi ini di sini. Pikirkan apa itu kerangka kerja. Ini bukan aplikasi. Ini adalah "template" umum yang dapat digunakan orang lain untuk membuat semua jenis aplikasi. Secara logis, itu berarti bahwa suatu kerangka kerja dibangun dalam logika yang jauh lebih abstrak untuk dapat digunakan oleh semua orang.
Pembuat kerangka tidak dapat mengambil jalan pintas, karena mereka bahkan tidak tahu apa persyaratan dari aplikasi selanjutnya. Membangun kerangka kerja secara inheren memberi insentif kepada mereka untuk membuat kode mereka dapat digunakan untuk orang lain.
Pembuat aplikasi, bagaimanapun, memiliki kemampuan untuk berkompromi pada efisiensi logis karena mereka berfokus pada memberikan produk. Tujuan utama mereka bukanlah cara kerja kode melainkan pengalaman pengguna.
Untuk suatu kerangka kerja, pengguna akhir adalah pengembang lain, yang akan berinteraksi dengan kode Anda. Kualitas kode Anda penting bagi pengguna akhir Anda.
Untuk aplikasi, pengguna akhir adalah non-pengembang, yang tidak akan berinteraksi dengan kode Anda. Kualitas kode Anda tidak penting bagi mereka.
Inilah sebabnya mengapa arsitek dari tim pengembangan sering bertindak sebagai penegak praktik yang baik. Mereka adalah satu langkah dihapus dari pengiriman produk, yang berarti mereka cenderung melihat kode secara objektif, daripada berfokus pada pengiriman aplikasi itu sendiri.
Ini adalah poin yang menarik, dan ini (menurut pengalaman saya) adalah alasan utama mengapa orang masih mencoba untuk membenarkan untuk menghindari praktik yang baik.
Untuk meringkas poin-poin di bawah ini: Melewati praktik yang baik hanya dapat dibenarkan jika persyaratan Anda (seperti yang diketahui saat ini) tidak dapat diubah, dan tidak akan pernah ada perubahan / penambahan pada basis kode. Peringatan spoiler: Itu jarang terjadi.
Misalnya, ketika saya menulis aplikasi konsol 5 menit untuk memproses file tertentu, saya tidak menggunakan praktik yang baik. Karena saya hanya akan menggunakan aplikasi hari ini, dan itu tidak perlu diperbarui di masa depan (akan lebih mudah untuk menulis aplikasi yang berbeda jika saya membutuhkannya lagi).
Katakanlah Anda dapat membuat aplikasi dengan kurang hati-hati dalam 4 minggu, dan Anda dapat membuatnya dengan benar dalam 6 minggu. Pada pandangan pertama, bangunan yang jelek sepertinya lebih baik. Pelanggan mendapatkan aplikasi mereka lebih cepat, dan perusahaan harus menghabiskan lebih sedikit waktu untuk upah pengembang. Menang / menang, kan?
Namun, ini adalah keputusan yang dibuat tanpa berpikir ke depan. Karena kualitas basis kode, membuat perubahan besar untuk yang dibangun dengan shoddily akan memakan waktu 2 minggu, sementara membuat perubahan yang sama dengan yang dibangun dengan benar membutuhkan waktu 1 minggu. Mungkin ada banyak dari perubahan ini yang muncul di masa depan.
Selain itu, ada kecenderungan perubahan yang tidak terduga membutuhkan lebih banyak pekerjaan daripada yang Anda bayangkan dalam basis kode yang dibangun dengan buruk, sehingga kemungkinan mendorong waktu pengembangan Anda menjadi tiga minggu, bukannya dua.
Dan kemudian ada juga kecenderungan untuk membuang waktu berburu serangga. Ini sering terjadi dalam proyek-proyek di mana penebangan telah diabaikan karena keterbatasan waktu atau semata-mata karena tidak mau menerapkannya karena Anda tanpa sadar bekerja dengan asumsi bahwa produk akhir akan bekerja seperti yang diharapkan.
Bahkan tidak perlu menjadi pembaruan besar. Di perusahaan saya saat ini, saya telah melihat beberapa proyek yang dibangun dengan cepat dan kotor, dan ketika bug / perubahan terkecil perlu dilakukan karena miskomunikasi dalam persyaratan, yang mengarah pada reaksi berantai tentang perlunya refactor modul demi modul . Beberapa proyek ini akhirnya runtuh (dan meninggalkan kekacauan yang tidak dapat dipertahankan) bahkan sebelum mereka merilis versi pertama mereka.
Keputusan pintasan (pemrograman cepat dan kotor) hanya bermanfaat jika Anda dapat secara meyakinkan menjamin bahwa persyaratannya benar dan tidak perlu diubah. Dalam pengalaman saya, saya tidak pernah menemukan proyek di mana itu benar.
Menginvestasikan waktu ekstra dalam praktik yang baik adalah berinvestasi di masa depan. Bug dan perubahan di masa mendatang akan jauh lebih mudah ketika basis kode yang ada dibangun berdasarkan praktik yang baik. Itu sudah akan membayar dividen setelah hanya dua atau tiga perubahan dilakukan.
sumber
Bagaimana SOLID mengubah kode sederhana menjadi kode kerangka kerja? Saya bukan stan untuk SOLID dengan cara apa pun tetapi benar-benar tidak jelas apa yang Anda maksud di sini.
Saya akui saya tidak berpikir dalam istilah SOLID sendiri, karena saya datang melalui sekolah pemrograman Gang of Four dan Josh Bloch , bukan sekolah Bob Martin. Tapi saya benar-benar berpikir bahwa jika Anda berpikir "SOLID" = "menambahkan lebih banyak lapisan ke tumpukan teknologi", Anda salah membaca.
PS Jangan menjual keuntungan dari "UX yang lebih baik untuk pengembang" singkat. Kode menghabiskan sebagian besar hidupnya dalam pemeliharaan. Pengembang adalah Anda .
sumber
class A{ int X; int Y; } class A_setX{ f(A a, int N) { a.X = N; }} class A_getX{ int f(A a) { return X; }} class A_setY ... etc.
Saya pikir Anda melihatnya dari sudut pandang yang terlalu meta dengan klaim pabrik Anda. Inisialisasi bukan merupakan aspek dari masalah domain.