Untuk referensi - http://en.wikipedia.org/wiki/Single_responsibility_principle
Saya memiliki skenario pengujian di mana dalam satu modul aplikasi bertanggung jawab untuk membuat entri buku besar. Ada tiga tugas dasar yang bisa dilakukan -
- Lihat entri buku besar yang ada dalam format tabel.
- Buat entri buku besar baru menggunakan tombol buat.
- Klik pada entri buku besar di tabel (disebutkan dalam pointer pertama) dan lihat detailnya di halaman berikutnya. Anda bisa membatalkan entri buku besar di halaman ini.
(Ada beberapa operasi / validasi lebih di setiap halaman tetapi demi singkatnya saya akan membatasi ini untuk ini)
Jadi saya memutuskan untuk membuat tiga kelas yang berbeda -
- LedgerLandingPage
- BuatNewLedgerEntryPage
- ViewLedgerEntryPage
Kelas-kelas ini menawarkan layanan yang dapat dilakukan di halaman-halaman itu dan tes Selenium menggunakan kelas-kelas ini untuk membawa aplikasi ke keadaan di mana saya bisa membuat pernyataan tertentu.
Ketika saya memeriksanya bersama rekan saya, dia merasa kesal dan meminta saya membuat satu kelas untuk semua. Meskipun saya merasa desain saya jauh lebih bersih, saya ragu apakah saya menggunakan prinsip Single Responsibility
Jawaban:
Mengutip @YannisRizos di sini :
Saya tidak setuju, setidaknya sekarang, setelah sekitar 30 tahun pengalaman pemrograman. Kelas yang lebih kecil IMHO lebih baik dipertahankan
di hampir setiap kasus yang dapat saya pikirkandalam kasus seperti ini. Semakin banyak fungsi yang Anda masukkan ke dalam satu kelas, semakin sedikit struktur yang Anda miliki, dan kualitas kode Anda menurun - setiap hari sedikit. Ketika saya mengerti Tarun dengan benar, masing-masing dari 3 operasi iniadalah kasus penggunaan, masing-masing kelas ini terdiri dari lebih dari satu fungsi untuk melakukan tugas terkait, dan masing-masing dapat dikembangkan dan diuji secara terpisah. Jadi membuat kelas untuk masing-masing kelompok mengelompokkan hal-hal bersama yang menjadi satu, sehingga lebih mudah untuk mengidentifikasi bagian dari kode yang akan diubah jika sesuatu ingin diubah.
Jika Anda memiliki fungsi umum di antara 3 kelas tersebut, mereka termasuk dalam kelas dasar yang sama,
Ledger
kelas itu sendiri (saya berasumsi Anda memiliki satu, setidaknya, untuk operasi CRUD) atau dalam kelas pembantu yang terpisah.Jika Anda memerlukan lebih banyak argumen untuk membuat banyak kelas yang lebih kecil, saya sarankan untuk membaca buku Robert Martin "Clean Code" .
sumber
Tidak ada implementasi pasti dari Prinsip Tanggung Jawab Tunggal, atau prinsip lainnya. Anda harus memutuskan berdasarkan pada apa yang lebih mungkin untuk diubah.
Seperti @Karpie menulis dalam jawaban sebelumnya :
Itu pendekatan instingtual dan mungkin benar, karena apa yang lebih mungkin untuk diubah adalah logika bisnis mengelola buku besar. Jika itu terjadi, akan jauh lebih mudah untuk mempertahankan satu kelas daripada tiga.
Tapi itu harus diperiksa dan diputuskan per kasus. Anda seharusnya tidak benar-benar peduli dengan masalah dengan kemungkinan perubahan yang sangat kecil dan berkonsentrasi menerapkan prinsip pada apa yang lebih mungkin berubah. Jika logika mengelola buku besar adalah proses multilayer dan lapisan cenderung berubah secara mandiri atau kekhawatiran yang harus dipisahkan secara prinsip (logika dan presentasi), maka Anda harus menggunakan kelas yang terpisah. Ini adalah permainan probabilitas.
Pertanyaan serupa tentang masalah prinsip-prinsip desain yang terlalu sering digunakan, yang menurut saya menarik bagi Anda: Pola desain: kapan harus digunakan dan kapan harus berhenti melakukan semuanya menggunakan pola
sumber
Mari kita periksa kelas-kelas ini:
LedgerLandingPage: Peran kelas ini adalah untuk menampilkan daftar buku besar. Saat aplikasi tumbuh, Anda mungkin ingin menambahkan metode untuk menyortir, memfilter, menyorot, dan sekering transparan dalam data dari sumber data lainnya.
ViewLedgerEntryPage: Halaman ini menunjukkan buku besar secara detail. Tampaknya cukup lurus ke depan. Selama datanya lurus ke depan. Anda dapat membatalkan buku besar di sini. Anda juga bisa memperbaikinya. Atau berkomentar, atau lampirkan file, tanda terima atau nomor pemesanan eksternal atau apa pun. Dan begitu Anda mengizinkan pengeditan, Anda pasti ingin menunjukkan riwayat.
CreateLedgerEntryPage: Jika
ViewLedgerEntryPage
memiliki kemampuan pengeditan penuh, tanggung jawab kelas ini mungkin dapat dipenuhi dengan mengedit "entri kosong", yang mungkin atau mungkin tidak masuk akal.Contoh-contoh tesis ini mungkin agak sedikit mengada-ada, tetapi intinya adalah bahwa dari UX kita berbicara fitur di sini. Satu fitur jelas berbeda, tanggung jawab tunggal. Karena persyaratan untuk fitur itu dapat berubah dan persyaratan dua fitur yang berbeda dapat berubah menjadi dua arah yang berlawanan, dan kemudian Anda berharap Anda terjebak dengan SRP dari awal.
Tetapi sebaliknya, Anda selalu dapat menampar fasad ke tiga kelas, jika memiliki antarmuka tunggal lebih nyaman untuk alasan apa pun yang dapat Anda pikirkan.
Ada yang namanya SRP terlalu sering digunakan : Jika Anda membutuhkan selusin kelas untuk membaca konten file, agak aman untuk menganggap Anda melakukan hal itu.
Jika Anda melihat SRP dari sisi lain, sebenarnya dikatakan, bahwa satu tanggung jawab harus diurus oleh satu kelas. Harap dicatat bahwa tanggung jawab hanya ada dalam level abstraksi. Jadi masuk akal bagi kelas dari tingkat abstraksi yang lebih tinggi untuk melaksanakan tanggung jawabnya dengan mendelegasikan pekerjaan ke komponen tingkat yang lebih rendah, yang paling baik dicapai melalui inversi ketergantungan .
sumber
Apakah kelas-kelas itu hanya punya satu alasan untuk berubah?
Jika Anda tidak mengetahuinya (belum), maka Anda mungkin telah melangkah ke dalam desain spekulatif / jebakan teknik (terlalu banyak kelas, pola desain yang terlalu rumit diterapkan). Anda belum memuaskan YAGNI . Pada tahap awal siklus hidup perangkat lunak (beberapa) persyaratan mungkin tidak jelas. Dengan demikian arah perubahan saat ini tidak terlihat untuk Anda. Jika Anda menyadarinya, simpan dalam satu atau sedikit kelas. Namun ini disertai dengan kewajiban: Segera setelah persyaratan dan arah perubahan lebih jelas, Anda perlu memikirkan kembali desain saat ini dan melakukan refactoring untuk memenuhi alasan perubahan.
Jika Anda sudah tahu bahwa ada tiga alasan berbeda untuk perubahan dan mereka memetakan ke tiga kelas tersebut, maka Anda baru saja menerapkan dosis SRP yang tepat. Sekali lagi ini disertai dengan beberapa tanggung jawab: Jika Anda salah atau persyaratan di masa depan berubah secara tak terduga, Anda perlu memikirkan kembali desain saat ini dan melakukan refactoring untuk memenuhi alasan perubahan.
Intinya adalah:
Jika Anda memiliki pola pikir ini, Anda akan membentuk kode tanpa banyak rasa takut akan desain spekulatif / rekayasa berlebihan.
Namun selalu ada faktor waktu: Untuk banyak perubahan Anda tidak akan memiliki waktu yang Anda butuhkan. Refactoring membutuhkan waktu dan tenaga. Saya sering menghadapi situasi di mana saya tahu saya harus mengubah desain, tetapi karena kendala waktu saya harus menundanya. Ini akan terjadi dan tidak dapat dihindari. Saya menemukan bahwa lebih mudah untuk refactor di bawah kode rekayasa daripada kode rekayasa. YAGNI memberi saya panduan yang baik: Jika ragu, pertahankan jumlah kelas dan penerapan pola desain seminimal mungkin.
sumber
Ada tiga alasan untuk memanggil SRP sebagai alasan untuk membagi kelas:
Ada tiga alasan untuk menolak membagi kelas:
Ketika saya melihat kasus Anda dan membayangkan perubahan, beberapa di antaranya akan menyebabkan perubahan ke beberapa kelas (misalnya menambahkan bidang ke buku besar, Anda harus mengubah ketiganya) tetapi banyak yang tidak akan - misalnya menambahkan pengurutan ke daftar buku besar atau mengubah aturan validasi saat menambahkan entri buku besar baru. Reaksi kolega Anda mungkin karena sulit untuk mengetahui di mana mencari bug. Jika ada sesuatu yang salah pada daftar buku besar, apakah itu karena ditambahkan secara salah, atau ada yang salah dengan daftar tersebut? Jika ada perbedaan antara ringkasan dan detailnya, mana yang salah?
Mungkin juga kolega Anda berpikir bahwa perubahan dalam persyaratan yang berarti Anda harus mengubah ketiga kelas jauh lebih mungkin daripada perubahan di mana Anda akan lolos dengan mengubah hanya satu. Itu bisa menjadi percakapan yang sangat berguna untuk dimiliki.
sumber
Saya berpikir bahwa jika buku besar adalah tabel di db, saya sarankan menempatkan tugas thress ini ke satu kelas (misalnya DAO). Jika buku besar memiliki lebih banyak logika dan bukan tabel di db, saya sarankan kita harus membuat lebih banyak kelas untuk melakukan tugas-tugas ini (mungkin dua atau kelas thress) dan menyediakan kelas fasad hanya untuk pelanggan.
sumber
IMHO Anda seharusnya tidak menggunakan kelas sama sekali. Tidak ada abstraksi data di sini. Buku besar adalah tipe data konkret. Metode untuk memanipulasi dan menampilkannya adalah fungsi dan prosedur. Pasti akan ada banyak fungsi yang umum digunakan untuk dibagikan seperti memformat tanggal. Ada sedikit tempat untuk data yang akan diabstraksi dan disembunyikan di kelas dalam rutinitas tampilan dan pemilihan.
Ada beberapa kasus untuk menyembunyikan status di kelas untuk mengedit buku besar.
Apakah Anda menyalahgunakan SRP atau tidak, Anda menyalahgunakan sesuatu yang lebih mendasar: Anda terlalu sering menggunakan abstraksi. Ini adalah masalah yang khas, yang ditimbulkan oleh gagasan mitos OO adalah paradigma pembangunan yang waras.
Pemrogramannya 90% konkret: penggunaan abstraksi data harus jarang dan direkayasa dengan cermat. Abstraksi fungsional, di sisi lain harus lebih umum, karena detail bahasa dan pilihan algoritma perlu dipisahkan dari semantik operasi.
sumber
Anda hanya perlu satu kelas, dan satu-satunya tanggung jawab kelas itu adalah mengelola buku besar .
sumber