Prinsip tanggung jawab tunggal - apakah saya terlalu sering menggunakannya?

13

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

Tarun
sumber
2
IMHO tidak ada gunanya mencoba menjawab pertanyaan Anda secara umum, tanpa mengetahui dua hal: Seberapa besar kelas-kelas ini (berdasarkan metode dan LOC)? Dan seberapa besar / kompleks mereka diharapkan tumbuh di masa mendatang?
Péter Török
2
10 metode masing-masing adalah IMHO indikasi yang jelas untuk tidak memasukkan kode ke dalam satu kelas dengan 30 metode.
Doc Brown
6
Ini adalah wilayah batas: kelas 100 LOC dan 10 metode tidak terlalu kecil, dan satu dari 300 LOC tidak terlalu besar. Namun, 30 metode dalam satu kelas terdengar terlalu banyak bagi saya. Secara keseluruhan, saya cenderung setuju dengan @Doc bahwa lebih sedikit risiko untuk memiliki banyak kelas kecil daripada memiliki satu kelas kelebihan berat badan. Terutama dengan mempertimbangkan bahwa kelas-kelas secara alami cenderung menambah berat badan dari waktu ke waktu ...
Péter Török
1
@ PéterTörök - Saya setuju kecuali kode dapat dire-refored menjadi satu kelas yang dapat digunakan secara intuitif yang menggunakan kembali kode alih-alih menduplikasi fungsi seperti yang saya harapkan dari OP.
SoylentGray
1
Mungkin menerapkan MVC akan menghapus semuanya: tiga tampilan, satu model (Ledger), dan mungkin tiga pengontrol.
kevin cline

Jawaban:

19

Mengutip @YannisRizos di sini :

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.

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 pikirkan dalam 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 ini

LedgerLandingPage

CreateNewLedgerEntryPage

ViewLedgerEntryPage

adalah 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, Ledgerkelas 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" .

Doc Brown
sumber
itulah alasan saya menghasilkan tiga kelas berbeda daripada mendorong semuanya dalam satu kelas. Karena tidak ada fungsi umum di antara semua ini, saya tidak memiliki kelas umum. Terima kasih atas tautannya.
Tarun
2
"Kelas yang lebih kecil lebih baik dipertahankan di hampir setiap kasus yang bisa saya pikirkan." Saya pikir Kode Bersih pun tidak akan sejauh itu. Apakah Anda benar-benar berpendapat bahwa, dalam pola MVC, harus ada satu pengontrol per halaman (atau use-case, seperti yang Anda katakan), misalnya? Dalam Refactoring, Fowler memiliki dua aroma kode: satu merujuk memiliki banyak alasan untuk mengubah kelas (SRP), dan satu mengacu harus mengedit banyak kelas untuk satu perubahan.
pdr
@ pdr, OP menyatakan tidak ada fungsi umum di antara kelas-kelas ini, jadi (bagi saya) sulit membayangkan situasi ketika Anda perlu menyentuh lebih dari satu untuk membuat satu perubahan.
Péter Török
@ pdr: Jika Anda memiliki terlalu banyak kelas untuk diedit untuk satu perubahan, itu sebagian besar merupakan pertanda Anda tidak mengubah fungsi umum ke tempat yang terpisah. Tetapi dalam contoh di atas, ini mungkin akan mengarah ke kelas keempat, dan bukan hanya satu.
Doc Brown
2
@ PDR: BTW, apakah Anda benar-benar membaca "Kode Bersih" Bob Martin bertindak sangat jauh dalam memecah kode menjadi unit yang lebih kecil.
Doc Brown
11

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 :

Anda hanya perlu satu kelas, dan satu-satunya tanggung jawab kelas itu adalah mengelola buku besar.

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

yannis
sumber
1
SRP, menurut pemahaman saya, sebenarnya bukan pola desain.
Doc Brown
@DocBrown Tentu saja bukan pola desain, tetapi diskusi tentang pertanyaan ini sangat relevan ... Namun, saya sudah memperbarui jawabannya
yannis
4

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 ViewLedgerEntryPagememiliki 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 .

back2dos
sumber
Saya kira bahkan saya tidak bisa menggambarkan tanggung jawab kelas-kelas ini lebih baik daripada Anda.
Tarun
2

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:

  • Mengawasi driver untuk perubahan.
  • Memilih desain yang fleksibel, yang dapat di refactored.
  • Bersiaplah untuk kode refactor.

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.

Theo Lenndorff
sumber
1

Ada tiga alasan untuk memanggil SRP sebagai alasan untuk membagi kelas:

  • sehingga perubahan persyaratan di masa depan dapat membuat beberapa kelas tidak berubah
  • sehingga bug dapat diisolasi lebih cepat
  • untuk membuat kelas lebih kecil

Ada tiga alasan untuk menolak membagi kelas:

  • sehingga perubahan persyaratan di masa mendatang tidak akan menyebabkan Anda melakukan perubahan yang sama di beberapa kelas
  • sehingga penemuan bug tidak akan melibatkan pelacakan jalur tipuan yang panjang
  • untuk menolak teknik pemecahan enkapsulasi (properti, teman, apa pun) yang memaparkan informasi atau metode kepada semua orang ketika mereka hanya dibutuhkan oleh satu kelas terkait

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.

Kate Gregory
sumber
Bagus untuk melihat perspektif yang berbeda
Tarun
0

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.

Tandai xie
sumber
baik, buku besar adalah fitur di UI dan ada banyak operasi yang terkait dengannya yang dapat dilakukan dari halaman yang berbeda.
Tarun
0

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.

Yttrill
sumber
-1

Anda hanya perlu satu kelas, dan satu-satunya tanggung jawab kelas itu adalah mengelola buku besar .

sevenseacat
sumber
2
Bagi saya kelas '... manajer' biasanya menunjukkan bahwa Anda tidak dapat diganggu untuk memecahnya lebih jauh. Apa yang dikelola kelas? Presentasi, kegigihan?
sebastiangeiger
-1. Menempatkan 3 atau lebih kasus penggunaan ke dalam 1 kelas adalah persis hal yang coba dihindari oleh SRP - dan untuk alasan yang baik.
Doc Brown
@sebastiangeiger Jadi apa yang dilakukan tiga kelas OP? Presentasi atau kegigihan?
sevenseacat
@Karpie, saya jujur ​​berharap presentasi. Memang, contohnya tidak terlalu bagus, tetapi saya berharap bahwa '... Halaman' di situs web melakukan sesuatu yang mirip dengan tampilan.
sebastiangeiger
2
Bahkan, Anda hanya perlu satu kelas untuk seluruh aplikasi, dengan satu tanggung jawab membuat pengguna bahagia ;-)
Péter Török