Baru-baru ini saya membaca situs web tentang pengembangan kode bersih (saya tidak menaruh tautan di sini karena tidak dalam bahasa Inggris).
Salah satu prinsip yang diiklankan oleh situs ini adalah Prinsip Terbuka Tertutup : setiap komponen perangkat lunak harus terbuka untuk ekstensi dan ditutup untuk modifikasi. Misalnya, ketika kami telah mengimplementasikan dan menguji suatu kelas, kami hanya harus memodifikasinya untuk memperbaiki bug atau untuk menambahkan fungsionalitas baru (mis. Metode baru yang tidak memengaruhi yang sudah ada). Fungsi dan implementasi yang ada tidak boleh diubah.
Saya biasanya menerapkan prinsip ini dengan mendefinisikan antarmuka I
dan kelas implementasi yang sesuai A
. Ketika kelas A
telah menjadi stabil (diimplementasikan dan diuji), saya biasanya tidak memodifikasinya terlalu banyak (mungkin, tidak sama sekali), yaitu
- Jika persyaratan baru tiba (mis. Kinerja, atau implementasi antarmuka yang sama sekali baru) yang memerlukan perubahan besar pada kode, saya menulis implementasi baru
B
, dan tetap menggunakanA
selamaB
tidak matang. SaatB
sudah matang, yang dibutuhkan hanyalah mengubah caraI
instantiated. - Jika persyaratan baru menyarankan perubahan ke antarmuka juga, saya mendefinisikan antarmuka baru
I'
dan implementasi baruA'
. JadiI
,A
dibekukan dan tetap implementasi untuk sistem produksi selamaI'
danA'
tidak cukup stabil untuk menggantikannya.
Jadi, mengingat pengamatan ini, saya sedikit terkejut bahwa halaman web kemudian menyarankan penggunaan refactoring kompleks , "... karena tidak mungkin untuk menulis kode secara langsung dalam bentuk akhirnya."
Apakah tidak ada kontradiksi / konflik antara menegakkan Prinsip Terbuka / Tertutup dan menyarankan penggunaan refactoring kompleks sebagai praktik terbaik? Atau idenya di sini adalah bahwa seseorang dapat menggunakan refactoring yang kompleks selama pengembangan suatu kelas A
, tetapi ketika kelas itu telah diuji dengan sukses, ia harus dibekukan?
Prinsip Terbuka-Tertutup lebih merupakan indikator seberapa baik perangkat lunak Anda dirancang ; bukan prinsip untuk mengikuti secara harfiah. Ini juga merupakan prinsip yang membantu menjaga kita dari mengubah antarmuka yang ada secara tidak sengaja (kelas & metode yang Anda panggil dan bagaimana Anda mengharapkannya berfungsi).
Tujuannya adalah untuk menulis perangkat lunak yang berkualitas. Salah satu kualitas ini adalah sifat dapat diperpanjang. Ini berarti mudah untuk menambah, menghapus, mengubah kode dengan perubahan-perubahan itu cenderung terbatas pada beberapa kelas yang ada sebagai praktis. Menambahkan kode baru kurang berisiko daripada mengubah kode yang ada sehingga dalam hal ini Open-Closed adalah hal yang baik untuk dilakukan. Tapi kode apa yang sebenarnya kita bicarakan? Kejahatan melanggar OC jauh lebih sedikit ketika Anda dapat menambahkan metode baru ke kelas alih-alih perlu mengubah yang sudah ada.
OC fraktal . Apel di semua kedalaman desain Anda. Semua orang menganggap itu hanya diterapkan di tingkat kelas. Tetapi ini juga berlaku di tingkat metode atau di tingkat perakitan.
Pelanggaran OC yang terlalu sering pada tingkat yang sesuai menunjukkan bahwa mungkin inilah saatnya untuk melakukan refactor . "Level yang tepat" adalah panggilan penilaian yang memiliki segalanya untuk dilakukan dengan desain keseluruhan Anda.
Mengikuti Open-Closed secara harfiah berarti jumlah kelas akan meledak. Anda akan membuat Antarmuka (huruf "I") tidak perlu. Anda akan berakhir dengan sedikit fungsionalitas yang tersebar di seluruh kelas dan Anda kemudian harus menulis lebih banyak kode untuk menyatukan semuanya. Pada titik tertentu, Anda akan menyadari bahwa mengubah kelas asli akan lebih baik.
sumber
Prinsip Terbuka-Tertutup tampaknya menjadi prinsip yang muncul sebelum TDD lebih lazim. Gagasannya adalah bahwa itu berisiko untuk memperbaiki kode karena Anda mungkin merusak sesuatu sehingga lebih aman untuk meninggalkan kode yang ada sebagaimana adanya dan hanya menambahkannya. Dengan tidak adanya tes ini masuk akal. Kelemahan dari pendekatan ini adalah atrofi kode. Setiap kali Anda memperpanjang kelas daripada refactoring, Anda berakhir dengan lapisan tambahan. Anda hanya mengunci kode di atas. Setiap kali Anda menambahkan lebih banyak kode pada Anda meningkatkan kemungkinan duplikasi. Membayangkan; ada layanan di basis kode saya yang ingin saya gunakan, saya merasa tidak memiliki apa yang saya inginkan jadi saya membuat kelas baru untuk memperluasnya dan menyertakan fungsionalitas baru saya. Pengembang lain datang kemudian dan juga ingin menggunakan layanan yang sama. Sayangnya, mereka tidak t menyadari bahwa versi saya yang diperluas ada. Mereka kode terhadap implementasi asli tetapi mereka juga membutuhkan salah satu fitur yang saya kode. Alih-alih menggunakan versi saya, mereka sekarang juga memperluas implementasi dan menambahkan fitur baru. Sekarang kita punya 3 kelas, yang asli satu dan dua versi baru yang memiliki beberapa fungsi yang digandakan. Ikuti prinsip terbuka / tertutup dan duplikasi ini akan terus membangun selama masa hidup proyek yang mengarah ke basis kode yang rumit dan tidak perlu.
Dengan sistem yang telah teruji dengan baik, Anda tidak perlu mengalami atrofi kode ini, Anda dapat dengan aman memperbaiki kode yang memungkinkan desain Anda berasimilasi dengan persyaratan baru daripada harus terus-menerus membaut kode baru. Gaya pengembangan ini disebut desain muncul dan mengarah ke basis kode yang mampu tetap dalam kondisi baik sepanjang hidup mereka daripada secara bertahap mengumpulkan cruft.
sumber
Dalam kata-kata awam:
A. Prinsip O / C berarti bahwa spesialisasi harus dilakukan dengan memperluas, bukan dengan memodifikasi kelas untuk mengakomodasi kebutuhan khusus.
B. Menambahkan fungsi yang hilang (tidak terspesialisasi) berarti desainnya tidak lengkap dan Anda harus menambahkannya ke kelas dasar, jelas tanpa melanggar kontrak. Saya pikir ini tidak melanggar prinsip.
C. Refactoring tidak melanggar prinsip.
Ketika desain matang , katakanlah, setelah beberapa waktu dalam produksi:
sumber
Bagi saya, Prinsip Terbuka-Tertutup adalah pedoman, bukan aturan yang keras dan cepat.
Berkenaan dengan bagian terbuka dari prinsip, kelas akhir di Jawa dan kelas di C ++ dengan semua konstruktor dinyatakan sebagai pribadi melanggar bagian terbuka dari prinsip buka-tutup. Ada kasus penggunaan padat yang baik (catatan: solid, bukan SOLID) untuk kelas akhir. Merancang untuk diperpanjang adalah penting. Namun, ini membutuhkan banyak tinjauan ke depan dan usaha, dan Anda selalu melewati batas melanggar YAGNI (Anda tidak akan membutuhkannya) dan menyuntikkan bau kode dari generalisasi spekulatif. Haruskah komponen perangkat lunak utama terbuka untuk ekstensi? Iya. Semua? Tidak. Itu sendiri adalah generalisasi spekulatif.
Berkenaan dengan bagian tertutup, ketika beralih dari versi 2.0 ke 2.1 ke 2.2 ke 2.3 dari beberapa produk, tidak memodifikasi perilaku adalah ide yang sangat bagus. Pengguna benar-benar tidak menyukainya ketika setiap rilis minor memecah kode mereka sendiri. Namun, di sepanjang jalan orang sering menemukan bahwa implementasi awal dalam versi 2.0 pada dasarnya rusak, atau bahwa kendala eksternal yang membatasi desain awal tidak lagi berlaku. Apakah Anda menyeringai dan menanggungnya dan mempertahankan desain itu dalam rilis 3.0, atau apakah Anda membuat 3.0 tidak kompatibel dalam beberapa hal? Kompatibilitas mundur dapat menjadi kendala besar. Batas rilis utama adalah tempat di mana melanggar kompatibilitas dapat diterima. Anda perlu berhati-hati bahwa melakukan hal ini dapat membuat pengguna Anda kesal. Harus ada alasan yang bagus mengapa perpisahan dengan masa lalu ini diperlukan.
sumber
Refactoring, menurut definisi, adalah mengubah struktur kode tanpa mengubah perilaku. Jadi ketika Anda refactor, Anda tidak menambahkan fitur baru.
Apa yang Anda lakukan sebagai contoh untuk prinsip Buka Tutup terdengar OK. Prinsip ini adalah tentang memperluas kode yang ada dengan fitur baru.
Namun, jangan salah jawab. Saya tidak menyiratkan bahwa Anda hanya harus melakukan fitur atau hanya melakukan refactoring untuk potongan besar data. Cara pemrograman yang paling umum adalah melakukan sedikit fitur daripada segera melakukan sedikit refactoring (dikombinasikan dengan tes tentu saja untuk memastikan Anda tidak mengubah perilaku apa pun). Refactoring yang kompleks tidak berarti refactoring "besar", itu berarti menerapkan teknik refactoring yang rumit dan dipikirkan dengan baik.
Tentang prinsip-prinsip SOLID. Mereka benar-benar pedoman yang baik untuk pengembangan perangkat lunak tetapi tidak ada aturan agama yang harus diikuti secara membabi buta. Terkadang, berkali-kali, setelah Anda menambahkan fitur kedua dan ketiga dan ke-n, Anda menyadari bahwa desain awal Anda, bahkan jika itu menghormati Open-Close, itu tidak menghormati prinsip-prinsip lain atau persyaratan perangkat lunak. Ada beberapa poin dalam evolusi desain dan perangkat lunak ketika perubahan yang lebih kompleks harus dilakukan. Intinya adalah untuk menemukan dan menyadari masalah ini sesegera mungkin dan menerapkan teknik refactoring sebaik mungkin.
Tidak ada yang namanya desain sempurna. Tidak ada desain seperti itu yang dapat dan harus menghormati semua prinsip atau pola yang ada. Itu adalah pengkodean utopia.
Saya harap jawaban ini membantu Anda dalam dilema Anda. Jangan ragu untuk meminta klarifikasi jika diperlukan.
sumber
B
dan, ketika sudah siap, ganti implementasi yang lamaA
dengan implementasi yang baruB
(itu adalah satu penggunaan antarmuka).A
Kode dapat berfungsi sebagai dasar untukB
kode dan kemudian saya dapat menggunakan refactoring padaB
kode selama pengembangannya, tetapi saya berpikir bahwaA
kode yang sudah diuji harus tetap beku.B
dibangun di atas kodeA
sebagai evolusiA
, daripada, ketikaB
dirilis,A
harus dihapus dan tidak pernah digunakan lagi. Klien yang sebelumnya menggunakanA
hanya akan menggunakanB
tanpa mengetahui tentang perubahan, karena antarmukaI
tidak berubah (mungkin sedikit Prinsip Substitusi Liskov di sini? ... L dari SOLID)Sesuai pemahaman saya - jika Anda menambahkan metode baru ke kelas yang ada maka tidak akan merusak OCP. Namun saya agak bingung dengan penambahan variabel baru di Kelas. Tetapi jika Anda mengubah metode dan parameter yang ada dalam metode yang ada maka pasti akan merusak OCP, karena kode sudah diuji dan lulus jika kami sengaja mengubah metode [Ketika persyaratan berubah] maka itu akan menjadi masalah.
sumber