Bagaimana menentukan apakah suatu kelas memenuhi prinsip tanggung jawab tunggal?

34

Prinsip Tanggung Jawab Tunggal didasarkan pada prinsip kohesi yang tinggi. Perbedaan antara keduanya adalah bahwa kelas yang sangat kohesif memiliki serangkaian tanggung jawab yang sangat terkait, sedangkan kelas yang mengikuti SRP hanya memiliki satu tanggung jawab.

Tetapi bagaimana kita menentukan apakah kelas tertentu memiliki serangkaian tanggung jawab dan dengan demikian hanya sangat kohesif, atau apakah hanya memiliki satu tanggung jawab dan dengan demikian mematuhi SRP? Dengan kata lain, bukankah itu lebih atau kurang subyektif, karena beberapa mungkin menganggap kelas sangat granular (dan karena itu akan percaya kelas mematuhi SRP), sementara yang lain mungkin menganggapnya tidak cukup granular?

pengguna1483278
sumber

Jawaban:

21

Mengapa ya itu sangat subyektif, dan itu adalah subjek dari banyak programmer, debat berwajah merah masuk ke.

Sebenarnya tidak ada satu jawaban pun, dan jawabannya mungkin berubah ketika perangkat lunak Anda menjadi lebih kompleks. Apa yang dulunya tugas tunggal yang didefinisikan dengan baik pada akhirnya dapat menjadi beberapa tugas yang tidak didefinisikan dengan baik. Itu selalu menggosok juga. Bagaimana Anda memilih cara yang tepat untuk membagi program menjadi tugas?

Tentang satu-satunya saran yang bisa saya berikan adalah ini: gunakan penilaian terbaik Anda (dan rekan kerja Anda). Dan ingat bahwa kesalahan dapat (biasanya) diperbaiki jika Anda menangkapnya segera.

Jason Baker
sumber
Saya berharap ilmu komputer lebih seperti ilmu yang sebenarnya. Subjektivitas tidak memiliki tempat dalam sains nyata. Sementara prinsip-prinsip SOLID baik-baik saja dalam hak mereka sendiri, mereka perlu diulangi untuk meminimalkan subjektivitas dan memaksimalkan objektivitas. Itu belum terjadi, yang membuat saya mempertanyakan legitimasi mereka di dunia nyata.
DarkNeuron
13

Bob Martin (Paman Bob), yang berasal dari prinsip-prinsip PADAT di mana SRP adalah yang pertama, mengatakan tentang ini (saya parafrase, tidak dapat mengingat kata-kata yang sebenarnya):

Kelas seharusnya hanya memiliki satu alasan untuk berubah

Jika memiliki lebih dari satu alasan, itu tidak mematuhi SRP.

Oded
sumber
14
Itu hanya mengulangi definisi sebenarnya, tetapi sebenarnya mengikuti srp masih cukup subjektif.
Andy
7

Saya bisa memberi Anda beberapa aturan praktis.

  • Seberapa mudah untuk memberi nama kelas? Jika sebuah kelas sulit untuk disebutkan namanya, itu mungkin melakukan terlalu banyak.
  • Berapa banyak metode umum yang dimiliki kelas? 7 +/- 2 adalah aturan praktis yang baik. Jika kelas memiliki lebih dari itu, Anda harus berpikir tentang membaginya menjadi beberapa kelas.
  • Adakah kelompok metode publik yang kohesif digunakan dalam konteks yang berbeda?
  • Berapa banyak metode pribadi atau anggota data yang ada? Jika kelas memiliki struktur internal yang kompleks, Anda mungkin harus refactor sehingga internal dikemas ke dalam kelas yang lebih kecil terpisah.
  • Dan aturan praktis yang paling mudah: seberapa besar kelasnya? Jika Anda memiliki file header C ++ yang berisi satu kelas yang panjangnya lebih dari beberapa ratus baris, Anda mungkin harus membaginya.
Dima
sumber
2
Mengenai poin kedua Anda, lihat uxmyths.com/post/931925744/…
Cameron Martin
7
Sangat tidak setuju tentang 7 +/- 2 - prinsip tanggung jawab tunggal adalah tentang kohesi semantik, bukan tentang angka acak.
JacquesB
1
Rule of thumbs tidak perlu bukti ilmiah independen. Metode ilmiah modern berusia berabad-abad, arsitektur dan teknik sudah berusia ribuan tahun. Aturan praktis untuk metode publik adalah "beberapa" dan tidak ada parameter adalah "beberapa." Dalam berita lain, meskipun beberapa gambar anak-anak menunjukkan kalau lengan orang tidak keluar dari kepala mereka [rujukan?]
abuzittin gillifirca
@CameronMartin Tergantung pada pengaturan Anda, antarmuka untuk kelas mungkin tersedia atau mungkin tidak tersedia untuk Anda baca. Mencari UI hampir tidak sama dengan menulis kode - jika saya harus berkonsultasi dengan dokumentasi setiap menit, saya, setidaknya, menggandakan waktu yang diperlukan untuk melakukan pekerjaan nyata.
jelas
6

Prinsip Tanggung Jawab Tunggal mengatakan bahwa setiap modul perangkat lunak hanya memiliki satu alasan untuk berubah. Pada sebuah artikel baru-baru ini Paman Bob menjelaskan "alasan untuk berubah",

Namun, ketika Anda memikirkan prinsip ini, ingatlah bahwa alasan untuk perubahan adalah orang. Orang-orang yang meminta perubahan. Dan Anda tidak ingin membingungkan orang-orang itu, atau diri Anda sendiri, dengan menggabungkan kode yang dipedulikan banyak orang dengan alasan berbeda.

Lebih lanjut ia menjelaskan konsep dengan contoh DI SINI .

theD
sumber
Itu artikel yang bagus, ditulis oleh pria itu sendiri.
MrDustpan
4

Untuk menjawab ini, mundur selangkah dan pertimbangkan niat prinsip tanggung jawab tunggal. Mengapa prinsip desain yang direkomendasikan di tempat pertama?

Tujuan dari prinsip ini adalah untuk "mengelompokkan" basis kode, sehingga kode yang berkaitan dengan "tanggung jawab" tunggal diisolasi dalam satu unit tunggal. Ini membuatnya lebih mudah untuk menemukan dan memahami kode, dan yang lebih penting, itu berarti bahwa perubahan pada "tanggung jawab" hanya akan berdampak pada satu unit kode saja.

Apa yang Anda benar-benar tidak pernah inginkan dalam suatu sistem adalah ketika satu peluang kecil menyebabkan beberapa bagian kode yang tampaknya tidak terkait gagal atau mengubah perilaku. SRP membantu mengisolasi bug dan perubahan.

Jadi, apa itu "tanggung jawab"? Itu adalah sesuatu yang bisa berubah secara independen dari perubahan lain. Katakanlah Anda memiliki program yang dapat menyimpan beberapa pengaturan ke file konfigurasi XML, dan dapat membacanya kembali dari file tersebut. Apakah ini satu tanggung jawab, atau "memuat" dan "menyelamatkan" dua tanggung jawab yang berbeda? Segala jenis perubahan pada format file atau struktur akan membutuhkan perubahan baik memuat dan menyimpan logika. Karena itu merupakan tanggung jawab tunggal yang harus diwakili oleh satu kelas. Sekarang pertimbangkan sebuah aplikasi yang dapat mengekspor beberapa data dalam format CVS, Excel dan XML. Dalam hal ini, mudah untuk membayangkan bahwa satu format dapat berubah tanpa memengaruhi lainnya. Jika Anda memutuskan untuk mengubah pembatas dalam format CVS, itu seharusnya tidak mempengaruhi output Excel.

JacquesB
sumber
2

OO mengatakan bahwa kelas adalah pengelompokan fungsionalitas data. Definisi ini menyisakan banyak ruang untuk interpretasi subyektif.

Kita tahu bahwa kelas harus didefinisikan dengan jelas dan mudah. Tetapi, untuk mendefinisikan kelas seperti itu, kita harus memiliki gagasan yang jelas tentang bagaimana kelas cocok dengan keseluruhan desain. Tanpa persyaratan jenis air terjun yang, secara paradoks, dianggap sebagai anti-pola ... ini sulit dicapai.

Kita dapat mengimplementasikan desain kelas dengan arsitektur yang berfungsi dalam banyak kasus, seperti MVC. Dalam aplikasi MVC, kami hanya berasumsi memiliki data, antarmuka pengguna, dan persyaratan untuk keduanya untuk berkomunikasi.

Dengan arsitektur dasar, lebih mudah untuk mengidentifikasi kasus di mana aturan tanggung jawab tunggal dilanggar. EG Melewati instance dari Kontrol Pengguna ke Modal.

P.Brian.Mackey
sumber
1

Demi diskusi, saya akan memunculkan kelas dari JUCE bernama AudioSampleBuffer . Sekarang kelas ini ada untuk menyimpan potongan (atau mungkin potongan yang agak panjang) dari audio. Ia tahu jumlah saluran, jumlah sampel (per saluran), tampaknya berkomitmen untuk float IEEE 32-bit daripada memiliki representasi numerik variabel atau wordsize (tapi itu tidak masalah dengan saya). Ada fungsi anggota yang memungkinkan Anda untuk mendapatkan numChannels atau numSamples dan pointer ke saluran tertentu. Anda dapat membuat AudioSampleBuffer lebih lama atau lebih pendek. Saya menganggap yang pertama nol-bantalan buffer sementara yang kedua memotong.

Ada beberapa anggota pribadi dari kelas ini yang digunakan untuk mengalokasikan ruang di tumpukan khusus yang digunakan JUCE.

Tetapi inilah yang tidak ada pada AudioSampleBuffer (dan saya telah melakukan beberapa diskusi dengan Jules tentang hal itu): seorang anggota menelepon SampleRate. Bagaimana bisa melewatkan itu?

Tanggung jawab tunggal yang harus dipenuhi oleh AudioSampleBuffer adalah merepresentasikan audio fisik yang didengar oleh sampel. Saat Anda memasukkan AudioSampleBuffer dari sesuatu yang membaca file suara atau dari aliran, ada parameter tambahan yang harus Anda dapatkan dan meneruskannya bersama AudioSampleBuffer ke metode pemrosesan (katakan itu filter) yang perlu mengetahui laju sampel atau, akhirnya, ke metode yang memutar buffer keluar untuk didengar (atau streaming ke tempat lain). Terserah.

Tapi yang harus Anda lakukan adalah terus meneruskan SampleRate ini, yang melekat pada kehidupan audio tertentu di AudioSampleBuffer, berkeliling ke mana-mana. Saya telah melihat kode di mana 44100.0f konstan dilewatkan ke suatu fungsi, karena programmer tampaknya tidak tahu harus berbuat apa lagi.

Ini adalah contoh kegagalan memenuhi tanggung jawab tunggal.

robert bristow-johnson
sumber
1

Cara konkret dapat dilakukan, berdasarkan pada apa yang Anda katakan - bahwa kohesi yang tinggi memikul tanggung jawab tunggal yang dapat Anda ukur kohesi. Kelas kohesif maksimal memiliki semua bidang yang digunakan dalam semua metode. Sementara kelas kohesif maksimal tidak selalu mungkin atau diinginkan untuk memiliki yang terbaik untuk mencapai ini. Memiliki tujuan desain kelas ini, cukup mudah untuk menyimpulkan bahwa kelas Anda tidak dapat memiliki banyak metode atau bidang (ada yang mengatakan paling banyak 7).

Cara lain adalah dari dasar-dasar murni OOP - model setelah benda nyata. Jauh lebih mudah untuk melihat tanggung jawab objek nyata. Namun, jika objek nyata terlalu kompleks, pilah menjadi beberapa objek yang saling bersaing, masing-masing memiliki tanggung jawab sendiri.

m3th0dman
sumber