Saya sedang mengerjakan sebuah tim di mana pemimpin tim adalah pendukung kuat prinsip-prinsip pengembangan SOLID. Namun, ia tidak memiliki banyak pengalaman dalam mengeluarkan perangkat lunak yang rumit.
Kami memiliki situasi di mana ia telah menerapkan SRP ke apa yang sudah menjadi basis kode yang cukup rumit, yang sekarang telah menjadi sangat terfragmentasi dan sulit dipahami dan didebug.
Kami sekarang memiliki masalah tidak hanya dengan fragmentasi kode, tetapi juga enkapsulasi, karena metode dalam kelas yang mungkin pribadi atau dilindungi telah dinilai untuk mewakili 'alasan untuk berubah' dan telah diekstraksi ke publik dan kelas internal dan antarmuka yang tidak sesuai dengan tujuan enkapsulasi aplikasi.
Kami memiliki beberapa konstruktor kelas yang mengambil lebih dari 20 parameter antarmuka, jadi pendaftaran dan resolusi IoC kami menjadi monster dengan caranya sendiri.
Saya ingin tahu apakah ada pendekatan 'refactor away from SRP' yang bisa kita gunakan untuk membantu memperbaiki beberapa masalah ini. Saya telah membaca bahwa itu tidak melanggar SOLID jika saya membuat sejumlah kelas kosong kasar yang 'membungkus' sejumlah kelas terkait erat untuk memberikan satu titik akses ke jumlah fungsionalitas mereka (yaitu meniru yang kurang implementasi kelas terlalu SRP'd).
Terlepas dari itu, saya tidak dapat memikirkan solusi yang akan memungkinkan kami untuk secara pragmatis melanjutkan upaya pengembangan kami, sambil membuat semua orang senang.
Ada saran?
sumber
ISomething
). IMHO, pendekatan ini jauh lebih mudah ditangani daripada injeksi ketergantungan dan menghasilkan kode yang lebih mudah dibaca.Jawaban:
Jika kelas Anda memiliki 20 parameter dalam konstruktor, itu tidak terdengar seperti tim Anda cukup tahu apa itu SRP. Jika Anda memiliki kelas yang hanya melakukan satu hal, bagaimana caranya memiliki 20 dependensi? Itu seperti pergi memancing dan membawa pancing, kotak pancing, perlengkapan quilting, bola bowling, nunchucks, pelempar api, dll .... Jika Anda membutuhkan semua itu untuk memancing, Anda tidak hanya pergi memancing.
Yang mengatakan, SRP, seperti kebanyakan prinsip di luar sana, dapat diterapkan secara berlebihan. Jika Anda membuat kelas baru untuk penambahan bilangan bulat, maka ya, itu mungkin merupakan tanggung jawab tunggal, tetapi ayolah. Itu konyol. Kita cenderung lupa bahwa hal-hal seperti prinsip SOLID ada untuk suatu tujuan. SOLID adalah sarana untuk mencapai tujuan, bukan tujuan itu sendiri. Akhirnya adalah rawatan . Jika Anda akan mendapatkan granular itu dengan Prinsip Tanggung Jawab Tunggal, itu adalah indikator bahwa semangat untuk SOLID telah membutakan tim untuk tujuan SOLID.
Jadi, saya kira yang saya katakan adalah ... SRP bukan masalah Anda. Entah itu salah paham tentang SRP, atau aplikasi yang sangat terperinci. Cobalah untuk membuat tim Anda untuk menjaga hal utama menjadi hal utama. Dan yang utama adalah rawatan.
SUNTING
Buat orang-orang merancang modul dengan cara yang mendorong kemudahan penggunaan. Pikirkan setiap kelas sebagai API mini. Pikirkan dulu, "Bagaimana saya ingin menggunakan kelas ini," dan kemudian mengimplementasikannya. Jangan hanya berpikir, "Apa yang perlu dilakukan kelas ini." SRP memang memiliki kecenderungan besar untuk membuat kelas lebih sulit digunakan, jika Anda tidak terlalu memikirkan kegunaan.
EDIT 2
Jika Anda mencari tips tentang refactoring, Anda dapat mulai melakukan apa yang Anda sarankan - buat kelas kasar untuk membungkus beberapa lainnya. Pastikan kelas berbutir kasar masih mengikuti SRP , tetapi pada tingkat yang lebih tinggi. Maka Anda memiliki dua alternatif:
Ketika Anda selesai refactoring (tetapi sebelum melakukan ke repositori), tinjau pekerjaan Anda dan tanyakan pada diri Anda apakah refactoring Anda sebenarnya merupakan peningkatan kemampuan pemeliharaan dan kemudahan penggunaan.
sumber
Customer
kelas dan memiliki kode yang lebih dapat dikelola. Lihat contoh di sini: codemonkeyism.com/…Saya pikir itu dalam Refactoring Martin Fowler bahwa saya pernah membaca aturan melawan SRP, mendefinisikan di mana itu terlalu jauh. Ada pertanyaan kedua, sama pentingnya dengan "apakah setiap kelas hanya punya satu alasan untuk berubah?" dan itu adalah "apakah setiap perubahan hanya memengaruhi satu kelas?"
Jika jawaban untuk pertanyaan pertama adalah, dalam setiap kasus, "ya" tetapi pertanyaan kedua adalah "bahkan tidak dekat," maka Anda perlu melihat lagi bagaimana Anda menerapkan SRP.
Misalnya, jika menambahkan satu bidang ke tabel berarti Anda harus mengubah DTO dan kelas validator dan kelas kegigihan dan objek model tampilan dan seterusnya, maka Anda telah membuat masalah. Mungkin Anda harus memikirkan kembali bagaimana Anda menerapkan SRP.
Mungkin Anda telah mengatakan bahwa menambahkan bidang adalah alasan untuk mengubah objek Pelanggan, tetapi mengubah lapisan kegigihan (katakanlah dari file XML ke database) adalah alasan lain untuk mengubah objek Pelanggan. Jadi, Anda memutuskan untuk membuat objek CustomerPersistence juga. Tetapi jika Anda melakukannya sedemikian rupa sehingga menambahkan bidang MASIH membutuhkan perubahan ke objek CustomerPersisitence lalu apa gunanya? Anda masih punya objek dengan dua alasan untuk berubah - hanya saja bukan Pelanggan lagi.
Namun, jika Anda memperkenalkan ORM, sangat mungkin bahwa Anda dapat membuat kelas berfungsi sehingga jika Anda menambahkan bidang ke DTO, itu akan secara otomatis mengubah SQL yang digunakan untuk membaca data itu. Maka Anda punya alasan kuat untuk memisahkan kedua masalah tersebut.
Singkatnya, inilah yang cenderung saya lakukan: jika ada keseimbangan kasar antara berapa kali saya mengatakan "tidak, ada lebih dari satu alasan untuk mengubah objek ini" dan berapa kali saya mengatakan "tidak, perubahan ini akan mempengaruhi lebih dari satu objek, "maka saya pikir saya memiliki keseimbangan antara SRP dan fragmentasi. Tetapi jika keduanya masih tinggi maka saya mulai bertanya-tanya apakah ada cara yang berbeda sehingga saya dapat memisahkan masalah.
sumber
Hanya karena suatu sistem itu kompleks tidak berarti Anda harus membuatnya rumit . Jika Anda memiliki kelas yang memiliki terlalu banyak dependensi (atau Kolaborator) seperti ini:
... maka itu menjadi terlalu rumit dan Anda tidak benar-benar mengikuti SRP , bukan? Saya berani bertaruh jika Anda menuliskan apa yang
MyAwesomeClass
terjadi pada kartu CRC, itu tidak akan muat pada kartu indeks atau Anda harus menulis dengan huruf yang sangat kecil tidak terbaca.Apa yang Anda miliki di sini adalah bahwa orang-orang Anda hanya mengikuti Prinsip Segregasi Antarmuka sebagai gantinya dan mungkin telah mengambilnya secara ekstrem tetapi itu adalah cerita lain. Anda bisa berargumen bahwa dependensi adalah objek domain (yang terjadi) namun memiliki kelas yang menangani 20 objek domain pada saat yang sama terlalu jauh.
TDD akan memberi Anda indikator yang baik tentang seberapa banyak kelas tidak. Terus terang; jika suatu metode pengujian memiliki kode pengaturan yang membutuhkan waktu lama untuk menulis (bahkan jika Anda melakukan refactor terhadap tes-tes tersebut) maka
MyAwesomeClass
kemungkinan Anda memiliki terlalu banyak hal yang harus dilakukan.Jadi bagaimana Anda memecahkan teka-teki ini? Anda memindahkan tanggung jawab ke kelas lain. Ada beberapa langkah yang dapat Anda ambil pada kelas yang memiliki masalah ini:
Contoh abstrak tentang tanggung jawab refactoring
Membiarkan
C
menjadi kelas yang memiliki beberapa dependensiD1
,D2
,D3
,D4
yang perlu Anda refactor untuk menggunakan lebih sedikit. Ketika kami mengidentifikasi metode apa yangC
memanggil dependensi, kami dapat membuat daftar sederhana tentang itu:D1
-performA(D2)
,performB()
D2
-performD(D1)
D3
-performE()
D4
-performF(D3)
Melihat daftar kita dapat melihat itu
D1
danD2
terkait satu sama lain karena kelas membutuhkannya bersama-sama. Kita juga bisa melihatD4
kebutuhan ituD3
. Jadi kami memiliki dua pengelompokan:Group 1
-D1
<->D2
Group 2
-D4
->D3
Pengelompokan adalah indikator bahwa kelas sekarang memiliki dua tanggung jawab.
Group 1
- Satu untuk menangani memanggil dua objek yang saling membutuhkan. Mungkin Anda bisa membiarkan kelas AndaC
menghilangkan kebutuhan menangani kedua dependensi dan membiarkan salah satu dari mereka menangani panggilan itu. Dalam pengelompokan ini, jelas bahwaD1
dapat memiliki referensiD2
.Group 2
- Tanggung jawab lainnya membutuhkan satu objek untuk memanggil yang lain. Tidak bisaD4
menanganiD3
bukan kelas Anda? Maka kita mungkin bisa menghilangkanD3
dari kelasC
dengan membiarkanD4
melakukan panggilan saja.Jangan mengambil jawaban saya yang sudah jelas seperti contohnya sangat abstrak dan membuat banyak asumsi. Saya cukup yakin ada lebih banyak cara untuk memperbaiki ini, tetapi setidaknya langkah-langkahnya mungkin membantu Anda mendapatkan semacam proses untuk memindahkan tanggung jawab alih-alih membagi kelas.
Sunting:
Di antara komentar @Emmad Karem mengatakan:
Memang benar bahwa objek DAO cenderung memiliki banyak parameter, yang harus Anda atur di konstruktor Anda, dan parameter biasanya adalah tipe sederhana seperti string. Namun dalam contoh
Customer
kelas, Anda masih bisa mengelompokkan properti itu di dalam kelas lain untuk membuat semuanya lebih sederhana. Seperti memilikiAddress
kelas dengan jalan danZipcode
kelas yang berisi kode pos dan akan menangani logika bisnis seperti validasi data juga:Hal ini dibahas lebih lanjut dalam posting blog "Jangan, jangan, jangan pernah menggunakan String di Java (atau paling tidak sering)" . Sebagai alternatif menggunakan konstruktor atau metode statis untuk membuat sub objek lebih mudah dibuat Anda bisa menggunakan pola pembangun fluida .
sumber
Saya setuju dengan semua jawaban tentang SRP dan bagaimana hal itu dapat dilakukan terlalu jauh. Dalam posting Anda, Anda menyebutkan bahwa karena "over-refactoring" untuk mematuhi SRP Anda menemukan enkapsulasi rusak atau sedang dimodifikasi. Satu hal yang berhasil bagi saya adalah untuk selalu berpegang pada dasar-dasar dan melakukan apa yang diperlukan untuk mencapai tujuan.
Ketika bekerja dengan sistem Legacy, "antusiasme" untuk memperbaiki segala sesuatu agar menjadi lebih baik biasanya cukup tinggi di Team Leads, terutama yang baru dalam peran itu. SOLID, tidak memiliki SRP - Itu hanya S. Pastikan bahwa jika Anda mengikuti SOLID, Anda tidak melupakan OLID juga.
Saya sedang mengerjakan sistem Legacy sekarang dan kami mulai menempuh jalan yang sama di awal. Apa yang berhasil bagi kami adalah keputusan tim kolektif untuk membuat yang terbaik dari kedua dunia - SOLID dan KISS (Keep It Simple Stupid). Kami secara kolektif membahas perubahan besar pada struktur kode dan menerapkan akal sehat dalam menerapkan berbagai prinsip pengembangan. Mereka bagus sebagai pedoman bukan "Hukum Pembangunan S / W". Tim ini bukan hanya tentang Pemimpin Tim - ini tentang semua pengembang dalam tim. Hal yang selalu berhasil bagi saya adalah membuat semua orang berada di ruangan dan menghasilkan seperangkat pedoman bersama yang disetujui seluruh tim Anda untuk diikuti.
Mengenai cara memperbaiki situasi Anda saat ini, jika Anda menggunakan VCS dan belum menambahkan terlalu banyak fitur baru ke aplikasi Anda, Anda selalu dapat kembali ke versi kode yang menurut seluruh tim dapat dimengerti, dapat dibaca, dan dipelihara. Iya! Saya meminta Anda untuk membuang pekerjaan dan mulai dari awal. Ini lebih baik daripada mencoba "memperbaiki" sesuatu yang rusak dan memindahkannya kembali ke sesuatu yang sudah ada.
sumber
Jawabannya adalah rawatan dan kejelasan kode di atas segalanya. Bagi saya itu berarti menulis lebih sedikit kode , tidak lebih. Lebih sedikit abstraksi, sedikit antarmuka, lebih sedikit opsi, lebih sedikit parameter.
Setiap kali saya mengevaluasi restrukturisasi kode, atau menambahkan fitur baru saya berpikir tentang berapa banyak boilerplate akan diperlukan dibandingkan dengan logika yang sebenarnya. Jika jawabannya lebih dari 50%, itu mungkin berarti saya terlalu memikirkannya.
Di atas SRP, ada banyak gaya pengembangan lainnya. Dalam kasus Anda itu terdengar seperti YAGNI pasti kurang.
sumber
Banyak jawaban di sini benar-benar bagus tetapi berfokus pada sisi teknis dari masalah ini. Saya hanya akan menambahkan bahwa itu terdengar seperti upaya pengembang untuk mengikuti suara SRP seolah-olah mereka benar-benar melanggar SRP.
Anda dapat melihat blog Bob di sini tentang situasi ini, tetapi ia berpendapat bahwa jika suatu tanggung jawab dioleskan di beberapa kelas maka tanggung jawab SRP dilanggar karena kelas-kelas tersebut berubah secara paralel. Saya curiga dev Anda akan sangat menyukai desain di bagian atas blog Bob, dan mungkin sedikit kecewa melihatnya robek. Terutama karena itu melanggar "Prinsip Penutupan Umum" - hal-hal yang berubah bersama tetap bersama.
Ingatlah bahwa SRP merujuk pada "alasan untuk berubah" dan bukan "melakukan satu hal", dan bahwa Anda tidak perlu memusingkan diri sendiri dengan alasan perubahan itu sampai perubahan benar-benar terjadi. Orang kedua membayar abstraksi.
Sekarang ada masalah kedua - "pendukung kuat pengembangan SOLID." Jelas tidak terdengar seperti Anda memiliki hubungan yang baik dengan pengembang ini, jadi segala upaya untuk meyakinkan dia tentang masalah dalam basis kode tidak benar. Anda harus memperbaiki hubungan sehingga Anda dapat berdiskusi tentang masalah tersebut. Apa yang saya sarankan adalah bir.
Tidak serius - jika Anda tidak minum pergi ke kedai kopi. Keluar dari kantor dan bersantai di tempat, di mana Anda dapat membicarakan hal-hal ini secara informal. Alih-alih mencoba memenangkan pertengkaran di rapat, yang tidak akan Anda lakukan, berdiskusi di tempat yang menyenangkan. Cobalah untuk mengenali bahwa dev ini, yang membuat Anda gila, adalah manusia yang berfungsi yang sebenarnya sedang mencoba untuk mendapatkan perangkat lunak "keluar dari pintu" dan tidak ingin mengirimkan omong kosong. Karena Anda mungkin memiliki kesamaan, Anda dapat mulai membahas bagaimana meningkatkan desain sambil tetap menyesuaikan diri dengan SRP.
Jika Anda berdua dapat mengakui bahwa SRP adalah hal yang baik, bahwa Anda hanya menginterpretasikan aspek yang berbeda, Anda mungkin dapat mulai melakukan percakapan yang produktif.
sumber
Saya setuju dengan keputusan pemimpin tim Anda [pembaruan = 2012.05.31] bahwa SRP umumnya merupakan pemikiran yang baik. Tetapi saya benar-benar setuju dengan komentar @ Spoike -s bahwa konstruktor dengan 20 argumen antarmuka jauh terlalu banyak. [/ Update]:
Memperkenalkan SRP dengan IoC memindahkan kompleksitas dari satu "kelas multi-bertanggung jawab" ke banyak kelas srp dan inisialisasi yang jauh lebih rumit untuk kepentingan
Saya khawatir Anda tidak dapat mengurangi penyusunan kode tanpa harus mengorbankan srp.
Tetapi Anda dapat "meringankan rasa sakit" dari inisialisasi kode dengan menerapkan kelas gula sintaksis yang menyembunyikan kompleksitas inisialisasi dalam sebuah konstruktor.
sumber