Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. PHP

SOLID: Bagian 1 - Prinsip Single Responsibility

by
Read Time:9 minsLanguages:
This post is part of a series called The SOLID Principles.
SOLID: Part 2 - The Open/Closed Principle

Indonesian (Bahasa Indonesia) translation by Andy Nur (you can also view the original English article)

Single Responsibility (SRP), Open/Close, Liskov's Substitution, Interface Segregation, dan Dependency Inversion. Lima prinsip-prinsip agile yang sebaiknya memandu anda setiap kali anda menulis kode.

Definisi

Sebuah class sebaiknya hanya memiliki satu alasan untuk perubahan.

Didefinisikan oleh Robert C. Martin dalam bukunya Agile Software Development, Principles, Patterns, and Practices dan kemudian diterbitkan ulang dalam versi C# dalam buku Agile Principles, Patterns, and Practices in C#, ini adalah salah satu dari lima prinsip SOLID agile. Apa yang ia nyatakan sangat sederhana, namun mencapai kesederhanaan itu bisa sangat rumit. Sebuah class sebaiknya hanya memiliki satu alasan untuk perubahan.

Tetapi mengapa? Mengapa itu sangat penting untuk hanya memiliki satu alasan untuk perubahan?

Dalam tipe statis dan bahasa yang dikompilasi, beberapa alasan dapat menyebabkan beberapa, pemindahan yang tidak diinginkan. Jika ada dua alasan yang berbeda untuk perubahan, bisa dibayangkan bahwa dua tim yang berbeda mungkin bekerja pada kode yang sama untuk dua alasan yang berbeda. Masing-masing harus memaparkan solusinya, yang dalam kasus ini suatu bahasa yang dikompilasi (seperti C++, C# atau Java), dapat mengakibatkan tidak kompatibelnya modul dengan tim lain atau bagian lain dari aplikasi.

Meskipun anda mungkin tidak menggunakan bahasa yang dikompilasi, anda mungkin perlu untuk mengetes ulang class yang sama atau modul untuk alasan yang berbeda. Ini berarti lebih banyak perkerjaan tanya jawab, waktu, dan usaha.

Peserta

Menentukan satu single responsibility suatu class atau modul seharusnya lebih kompleks daripada hanya melihat daftar periksa. Misalnya, satu petunjuk untuk menemukan alasan kita melakukan perubahan adalah menganalisis peserta untuk class kita. Pengguna aplikasi atau sistem yang kita kembangkan yang dilayani oleh modul tertentu akan menjadi orang yang meminta perubahan untuk itu. Mereka yang bertugas akan meminta perubahan. Berikut adalah beberapa modul dan kemungkinan pesertanya.

  • Modul Persistent - Peserta termasuk DBA dan arsitek perangkat lunak.
  • Modul Pelaporan - Peserta termasuk juru rulis, akuntan, dan operasi.
  • Modul Perhitungan Pembayaran untuk Sistem Penggajian - Peserta mungkin termasuk pengacara, manajer, dan akuntan.
  • Modul Pencarian Buku untuk Sistem Manajemen Perpustakaan - Peserta dapat mencakup pustakawan dan/atau klien itu sendiri.

Peran dan Aktor

Mengaitkan orang yang konkrit dengan semua peran ini mungkin sulit dilakukan. Di sebuah perusahaan kecil, satu orang mungkin perlu untuk memenuhi beberapa peran sementara di sebuah perusahaan besar mungkin ada beberapa orang yang dialokasikan untuk satu peran tunggal. Jadi nampaknya jauh lebih masuk akal untuk memikirkan perannya. Tetapi perannya sendiri cukup sulit untuk didefinisikan. Apa perannya? Bagaimana kita menemukannya? Jauh lebih mudah membayangkan aktor melakukan peran tersebut dan mengaitkan peserta kita dengan para aktor tersebut.

Jadi, jika peserta kita mendefinisikan alasan perubahan, para aktor menentukan peserta. Ini sangat membantu kita untuk mengurangi konsep orang yang konkrit seperti "John the architect" untuk Arsitektur, atau "Mary the referent" untuk Pengerjaan.

Jadi responsibility adalah sebuah keluarga fungsi yang melayani satu aktor tertentu. (Robert C. Martin)

Sumber Perubahan

Dalam arti dari pemikiran ini, aktor menjadi sumber perubahan untuk keluarga fungsi yang melayani mereka. Ketika kebutuhan mereka berubah, keluarga fungsi yang spesifik juga harus berubah untuk mengakomodasi kebutuhan mereka.

Aktor untuk responsibility adalah satu-satunya sumber perubahan untuk responsibility itu. (Robert C. Martin)

Contoh Klasik

Objek Yang Dapat "Mencetak" Diri Sendiri

Mari katakan bahwa kita memiliki class Book yang mengenkapsulasi konsep buku dan fungsinya.

Ini mungkin tampak seperti sebuah class yang wajar. Kita memiliki buku, ini dapat menyediakan judul, penulis dan dapat mengubah halaman. Akhirnya, hal ini juga mampu mencetak halaman aktif pada layar. Tetapi ada sedikit masalah. Jika kita berpikir tentang aktor yang terlibat dalam operasi objek Buku, siapa mereka? Kita dapat dengan mudah memikirkan dua aktor yang berbeda di sini: Buku Manajemen (seperti pustakawan) dan Mekanisme Presentasi Data (seperti cara kita ingin menyampaikan konten ke pengguna - layar, grafis UI, hanya-teks UI, mungkin pencetakan). Berikut adalah dua aktor yang sangat berbeda.

Pencampuran logika bisnis dengan presentasi adalah buruk karena ini melawan Single Responsibility Principle (SRP). Lihatlah kode berikut:

Bahkan contoh ini sangat mendasar yang menunjukkan bagaimana memisahkan presentasi dari logika bisnis, dan mematuhi SRP, memberikan keuntungan besar dalam fleksibilitas desain kita.

Objek Yang Dapat "Menyimpan" Dirinya Sendiri

Contoh serupa dengan yang di atas adalah ketika sebuah objek dapat menyimpan dan mengambil dirinya sendiri dari presentasi.

Kita bisa, sekali lagi mengidentifikasi beberapa aktor seperti Sistem Manajemen Buku dan Persistent. Setiap kali kita ingin mengubah ketekunan, kita perlu mengubah class ini. Setiap kali kita ingin mengubah bagaimana kita mendapatkan dari satu halaman ke halaman berikutnya, kita harus memodifikasi class ini. Ada beberapa sumbu perubahan di sini.

Yang memindahkan operasi persistent untuk class lain jelas akan memisahkan responsibiliti dan kita akan bebas untuk menukar metode persistent tanpa mempengaruhi class Book kita. Misalnya mengimplementasi suatu class DatabasePersistence akan biasa saja dan logika bisnis kita dibangun di sekitar operasi dengan buku yang tidak akan berubah.

Pandangan Tingkat Tinggi

Dalam artikel saya sebelumnya sering saya singgung dan disajikan dengan skema arsitektur tingkat tinggi yang dapat dilihat di bawah ini.

HighLevelDesignHighLevelDesignHighLevelDesign

Jika kita menganalisis skema ini, Anda dapat melihat bagaimana Prinsip Single Responsibility dipatuhi. Pembuatan objek dipisahkan di sebelah kanan di Factory dan pintu masuk utama aplikasi kita, satu aktor satu tanggung jawab. Persistent juga diurus di bagian bawah. Modul terpisah untuk responsibiliti terpisah. Akhirnya, di sebelah kiri, kita memiliki presentasi atau mekanisme pengiriman jika Anda mau, dalam bentuk MVC atau tipe UI lainnya. SRP kembali dipatuhi. Yang tersisa hanyalah mencari tahu apa yang harus dilakukan dalam logika bisnis kita.

Pertimbangan Desain Perangkat Lunak

Bila kita memikirkan perangkat lunak yang perlu kita tulis, kita bisa menganalisa banyak aspek yang berbeda. Misalnya, beberapa persyaratan yang mempengaruhi class yang sama dapat mewakili sumbu perubahan. Sumbu perubahan ini mungkin merupakan petunjuk untuk single responsibility. Ada kemungkinan tinggi bahwa kelompok persyaratan yang mempengaruhi kelompok fungsi yang sama akan memiliki alasan untuk berubah atau ditentukan di tempat pertama.

Nilai utama perangkat lunak adalah kemudahan perubahan. Yang sekunder adalah fungsionalitas, dalam arti memuaskan sebanyak mungkin persyaratan, memenuhi kebutuhan pengguna. Namun, untuk mencapai nilai sekunder yang tinggi, nilai utama adalah wajib. Agar nilai utama tetap tinggi, kita harus memiliki desain yang mudah diubah, diperluas, untuk mengakomodasi fungsionalitas baru dan untuk memastikan bahwa SRP dipatuhi.

Kita bisa beralasan dengan langkah demi langkah:

  1. Nilai utama yang tinggi mengarah pada waktu ke nilai sekunder yang tinggi.
  2. Nilai sekunder berarti kebutuhan pengguna.
  3. Kebutuhan pengguna berarti kebutuhan para aktor.
  4. Kebutuhan para aktor menentukan kebutuhan perubahan aktor tersebut.
  5. Kebutuhan perubahan aktor mendefinisikan responsibiliti kita.

Jadi ketika kita merancang perangkat lunak kita, kita harus:

  1. Temukan dan definisikan para aktor.
  2. Identifikasi responsibiliti yang melayani aktor tersebut.
  3. Kelompokkan fungsi dan class kita sehingga masing-masing hanya memiliki satu tanggung jawab yang dialokasikan.

Contoh yang Kurang Jelas

Sekarang ini mungkin tampak masuk akal. Kami tidak memiliki metode yang berhubungan dengan persistence, atau presentasi. Kita memiliki fungsionalitas turnPage() dan beberapa metode untuk memberikan informasi yang berbeda tentang buku ini. Namun, kita mungkin punya masalah. Untuk mengetahuinya, kita mungkin ingin menganalisis aplikasi kita. Fungsi getLocation() mungkin menjadi masalah.

Semua metode class Book adalah tentang logika bisnis. Jadi perspektif kita harus dari sudut pandang bisnis. Jika aplikasi kita ditulis untuk digunakan oleh pustakawan nyata yang sedang mencari buku dan memberi kita buku fisik, maka SRP mungkin dilanggar.

Kita dapat beralasan bahwa operasi aktor adalah yang tertarik dengan metode getTitle(), getAuthor() dan getLocation(). Klien mungkin juga memiliki akses ke aplikasi untuk memilih buku dan membaca beberapa halaman pertama untuk mendapatkan ide tentang buku tersebut dan memutuskan apakah mereka menginginkannya atau tidak. Jadi pembaca aktor mungkin tertarik pada semua metode kecuali getLocations(). Klien biasa tidak peduli di mana buku itu disimpan di perpustakaan. Buku ini akan diserahkan ke klien oleh pustakawan. Jadi, kita memang memiliki pelanggaran terhadap SRP.

Memperkenalkan BookLocator, pustakawan akan tertarik dengan BookLocator. Klien hanya akan tertarik pada Book. Tentu saja, ada beberapa cara untuk menerapkan BookLocator. Ini bisa menggunakan penulis dan judul atau objek buku dan mendapatkan informasi yang dibutuhkan dari Book. Ini selalu tergantung pada bisnis kita. Yang penting adalah jika perpustakaan diubah, dan pustakawan harus menemukan buku di perpustakaan yang berbeda, objek Book tidak akan terpengaruh. Dengan cara yang sama, jika kita memutuskan untuk memberikan ringkasan yang telah disusun sebelumnya kepada pembaca dan bukan membiarkan mereka menelusuri halaman, itu tidak akan mempengaruhi pustakawan maupun proses menemukan rak buku-buku itu.

Namun, jika bisnis kita adalah untuk menghilangkan pustakawan dan menciptakan mekanisme ambil sendiri di perpustakaan kita, maka kita dapat mempertimbangkan bahwa SRP dipatuhi dalam contoh pertama kita. Pembaca adalah pustakawan kita juga, mereka harus pergi dan menemukan buku itu sendiri dan kemudian memeriksanya di sistem otomatis. Ini juga kemungkinan. Yang penting untuk diingat di sini adalah Anda harus selalu mempertimbangkan bisnis Anda dengan saksama.

Pemikiran Akhir

Prinsip Single Responsibility harus selalu dipertimbangkan saat kita menulis kode. Desain class dan modul sangat dipengaruhi olehnya dan ini mengarah pada desain low couple dengan dependensi yang lebih sedikit dan lebih ringan. Tetapi seperti koin, ada dua wajah. Sangat menggoda untuk merancang dari awal aplikasi kita dengan SRP. Hal ini juga menggoda untuk mengidentifikasi sebanyak mungkin aktor yang kita inginkan atau butuhkan. Tapi ini sebenarnya berbahaya - dari sudut pandang desain - untuk mencoba dan memikirkan semua pihak sejak awal. Pertimbangan SRP yang berlebihan dapat dengan mudah mengarah pada optimasi prematur dan bukannya desain yang lebih baik, hal itu dapat mengarah pada masalah yang tersebar dimana responsibiliti yang jelas dari class atau modul mungkin akan sulit dimengerti.

Jadi, setiap kali Anda mengamati bahwa class atau modul mulai berubah karena alasan yang berbeda, jangan ragu-ragu, ambillah langkah-langkah yang diperlukan untuk mematuhi SRP, namun jangan terlambat karena optimasi prematur dapat dengan mudah menipu Anda.

Advertisement
Did you find this post useful?
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.