Klarifikasi Prinsip Terbuka / Tertutup

25

Seperti yang telah saya jelaskan, prinsip terbuka / tertutup menyatakan bahwa kode yang pernah ditulis tidak boleh dimodifikasi (selain dari perbaikan bug). Tetapi jika aturan bisnis saya berubah, bukankah saya harus memodifikasi kode yang menerapkan perubahan itu? Saya kira saya tidak mengerti sesuatu tentang prinsipnya karena itu tidak masuk akal bagi saya.

Winston Ewert
sumber

Jawaban:

22

Ini mungkin yang paling sulit dari prinsip-prinsip solid untuk dijelaskan. Biarkan aku mencoba. Bayangkan Anda menulis kelas Faktur yang berfungsi sempurna dan tidak memiliki bug. Itu membuat PDF dari faktur.

Lalu seseorang berkata mereka ingin faktur HTML dengan tautan di dalamnya. Anda tidak mengubah kode apa pun dalam Faktur untuk memenuhi permintaan ini. Sebaliknya, Anda membuat kelas lain, HTMLInvoice, yang melakukan apa yang mereka inginkan sekarang. Anda meningkatkan warisan sehingga Anda tidak perlu menulis banyak kode duplikat dalam HTMLInvoice.

Kode lama yang menggunakan Faktur lama tidak rusak atau benar-benar terpengaruh. Kode baru dapat menggunakan HTMLInvoice. (Jika Anda juga melakukan Liskov Substitutability , L of solid, Anda dapat memberikan contoh HTMLInvoice ke kode yang ada yang mengharapkan contoh Faktur.) Semua orang hidup bahagia selamanya.

Faktur tertutup untuk modifikasi, terbuka untuk ekstensi. Dan Anda harus menulis Faktur dengan benar sebelum ini berfungsi, btw.

Kate Gregory
sumber
1
Jika aturan bisnis berubah, tidak ada asumsi bekerja sempurna tanpa bug, jadi prinsip buka / tutup tidak berlaku?
JeffO
Saya berjuang dengan aturan ini sendiri dan apa yang Kate sarankan pada dasarnya adalah apa yang saya simpulkan. Dalam bisnis, Anda mencoba memprogram kelas yang lebih kecil dan lebih fleksibel sehingga Anda dapat menggunakannya kembali dengan baik. Jika Anda membuatnya berfungsi dengan benar, Anda tidak ingin memodifikasinya. Tetapi mereka jarang sepenuhnya "selesai" sehingga beberapa modifikasi tidak bisa dihindari. Perhatikan bahwa teks mengatakan "modul", bukan objek. Saya sering berhasil menerapkan OCP pada level fungsi, dengan fungsi ketat yang melakukan satu hal dengan sempurna dan tidak perlu berubah.
CodexArcanum
1
@ Jeff OI membedakan antara memperbaiki bug (di mana kode tidak memenuhi persyaratan asli dan tidak ada yang menginginkannya) dan mengubah persyaratan. Jika saya memerlukan PDF dan kode membuat PDF, tidak ada bug, meskipun saya sekarang menginginkan HTML (dan biasanya orang menginginkan HTML juga, bukan sebaliknya.)
Kate Gregory
2
@ Winston - inilah yang saya maksud ketika saya mengatakan Anda harus menulis Faktur dengan benar. Idealnya sudah ada faktur yang cukup abstrak dan Anda mewarisi PDFInvoice mengharapkan ini. Jika tidak, Anda harus melanggar aturan sekali untuk mengatur diri Anda agar tidak melanggarnya di masa depan. Either way, memprediksi perubahan di masa depan adalah bagian besar dari semua ini - dan itulah bagian "menangkap dan memotong gajah" dari resep.
Kate Gregory
1
Pernyataan terakhir Anda adalah yang paling penting. Terbuka / tertutup adalah desain ideal - dan Anda harus mendapatkan desain di muka untuk mencapainya. Tidak semua kebutuhan untuk memuaskan buka / tutup, baik, tapi itu alat yang ampuh jika Anda bisa sampai di sana.
Alex Feinman
13

Sudahkah Anda membaca artikel Prinsip Terbuka-Tertutup oleh teman-teman Paman Bob di ObjectMentor? Saya pikir itu salah satu penjelasan yang lebih baik di luar sana.

Ada banyak heuristik yang terkait dengan desain berorientasi objek. Misalnya, "semua variabel anggota harus pribadi", atau "variabel global harus dihindari", atau "menggunakan run time type identification (RTTI) berbahaya". Apa sumber heuristik ini? Apa yang membuat mereka benar? Apakah itu selalu benar? Kolom ini menyelidiki prinsip desain yang mendasari heuristik ini - prinsip terbuka-tertutup.

Seperti yang dikatakan Ivar Jacobson: “Semua sistem berubah selama siklus hidup mereka. Ini harus diingat ketika mengembangkan sistem yang diperkirakan akan bertahan lebih lama dari versi pertama. ”Bagaimana kita bisa membuat desain yang stabil dalam menghadapi perubahan dan itu akan bertahan lebih lama dari versi pertama? Bertrand Meyer memberi kita bimbingan sejak tahun 1988 ketika dia menciptakan prinsip buka-tutup yang sekarang terkenal. Mengutip dia:

ENTITAS PERANGKAT LUNAK (KELAS, MODUL, FUNGSI, DLL) HARUS DIBUKA UNTUK PERPANJANGAN, TETAPI TERTUTUP UNTUK MODIFIKASI.

Ketika satu perubahan pada suatu program menghasilkan serangkaian perubahan pada modul-modul dependen, program itu memperlihatkan atribut-atribut yang tidak diinginkan yang telah kita asosiasikan dengan desain "buruk". Program ini menjadi rapuh, kaku, tidak dapat diprediksi dan tidak dapat digunakan kembali. Prinsip terbuka-tertutup menyerang ini dengan cara yang sangat mudah. Dikatakan bahwa Anda harus merancang modul yang tidak pernah berubah . Ketika persyaratan berubah, Anda memperluas perilaku modul tersebut dengan menambahkan kode baru, bukan dengan mengubah kode lama yang sudah berfungsi.

Deskripsi

Modul yang sesuai dengan prinsip buka-tutup memiliki dua atribut utama.

  1. Mereka adalah "Open For Extension".
    Ini berarti bahwa perilaku modul dapat diperluas. Kita dapat membuat modul berperilaku dengan cara baru dan berbeda saat persyaratan aplikasi berubah, atau untuk memenuhi kebutuhan aplikasi baru.
  2. Mereka "Ditutup untuk Modifikasi".
    Kode sumber modul tersebut tidak dapat diganggu gugat. Tidak ada yang diizinkan untuk melakukan perubahan kode sumber.

Tampaknya kedua atribut ini bertentangan satu sama lain. Cara normal untuk memperluas perilaku modul adalah dengan membuat perubahan pada modul itu. Modul yang tidak dapat diubah biasanya dianggap memiliki perilaku tetap. Bagaimana dua atribut yang berlawanan ini bisa diselesaikan?

Abstraksi adalah Kunci ...

Martijn Verburg
sumber
3
Ini adalah artikel bagus yang menjelaskan abstraksi. Namun, ada hal mendasar yang harus dipertimbangkan, dan apakah itu desain abstrak yang baik? Banyak toko memiliki banyak kode warisan bahwa satu - satunya cara untuk mengubahnya adalah "modifikasi", bukan "ekstensi". Jika ini masalahnya, maka orang mungkin harus bekerja untuk mengubahnya, tetapi sampai itu terjadi, Anda terjebak memodifikasi kode.
Michael K
@ Chris, keren - Saya juga merekomendasikan buku "Kode bersih" oleh Paman Bob jika Anda suka hal semacam ini.
Martijn Verburg
@Michael - Sepenuhnya setuju, hampir seperti harus memperbaiki kode untuk membuatnya ideal yang dapat diuji.
Martijn Verburg
Artikel ini menunjukkan pentingnya abstraksi dengan sangat baik. Tapi saya tidak memahami hubungan antara abstraksi dan berusaha untuk tidak pernah memodifikasi modul setelah saya menulisnya. Abstraksi ini berarti bahwa saya dapat memodifikasi modul X tanpa harus membuat modifikasi pada modul Y. Tetapi bukankah melakukan hal itu sehingga saya dapat memodifikasi modul X atau modul Y jika perlu?
Winston Ewert
1
Wow. Kode tidak dapat diganggu gugat? Saya tidak pernah menjadi penggemar berat Paman Bob. Prinsipal ini pedantic, sangat non-pragmatis, dan memiliki koneksi terbatas dengan kenyataan.
user949300
12

The jawaban dengan Kate Gregory sangat baik, tapi mempertimbangkan situasi yang berbeda di mana persyaratan baru dapat dipenuhi oleh perubahan yang relatif kecil di yang ada Invoicekelas. Misalnya, katakanlah bidang baru harus ditambahkan ke Faktur PDF. Menurut OCP, kita harus tetap membuat subkelas baru, bahkan jika bidang baru dapat ditambahkan dalam implementasi yang ada dengan mengubah beberapa baris kode.

Dalam pemahaman saya, OCP mencerminkan realitas tahun 80-an dan awal 90-an, di mana proyek-proyek sering bahkan tidak menggunakan kontrol versi, apalagi memiliki tes regresi otomatis atau manfaat dari alat refactoring canggih. OCP adalah upaya untuk menghindari risiko melanggar kode yang telah diuji secara manual dan dimasukkan ke dalam produksi. Saat ini, kami memiliki cara yang lebih baik untuk mengelola risiko kerusakan perangkat lunak yang berfungsi (yaitu, sistem kontrol versi, TDD dan pengujian otomatis, dan alat refactoring).

Rogério
sumber
2
Ya, karena dalam praktiknya, tidak mungkin membuat kelas yang dapat diperluas sesuai dengan semua masa depan yang mungkin, kecuali Anda membuat semua metode terlindungi (yang menyebalkan dan juga melanggar prinsip YAGNI, yang jauh lebih penting daripada O / C) Dita).
Martin Wickman
"Menurut OCP, kita harus tetap membuat subclass baru, bahkan jika bidang baru dapat ditambahkan dalam implementasi yang ada dengan mengubah beberapa baris kode.": Benarkah? Mengapa tidak menambahkan bidang baru atau metode baru? Poin pentingnya adalah Anda hanya menambahkan (memperluas) dan tidak mengubah apa yang sudah ada.
Giorgio
Saya pikir prinsipnya masuk akal ketika berhadapan dengan pustaka / kerangka kerja standar. Anda tidak ingin membuka dan memodifikasi potongan kode yang sudah mapan. Kalau tidak, ini semua tentang refactoring konstan dan uji, uji, uji.
mastaBlasta
@ Giorgio Tentu, menambahkan bidang atau metode baru adalah apa yang saya sarankan, dalam banyak kasus. Tapi itu bukan ekstensi , itu "modifikasi"; Inti dari OCP adalah bahwa kode harus "ditutup untuk modifikasi" (yaitu, tidak ada perubahan pada file sumber yang sudah ada sebelumnya) ketika sedang "terbuka untuk ekstensi"; dan ekstensi dalam OCP dicapai melalui warisan implementasi.
Rogério
@ Rogério: Mengapa Anda menentukan batas antara ekstensi dan modifikasi di tingkat kelas? Apakah ada alasan khusus untuk ini? Saya lebih suka mengaturnya di tingkat metode: mengubah metode mengubah perilaku aplikasi Anda, menambahkan metode (publik) memperluas antarmuka-nya.
Giorgio
6

Secara pribadi saya pikir prinsip ini harus diambil dengan sedikit garam. Kode bersifat organik, perubahan bisnis, dan perubahan kode sesuai dengan kebutuhan bisnis seiring berjalannya waktu.

Saya merasa sangat sulit untuk memahami fakta bahwa abstraksi adalah kunci. Bagaimana jika abstraksi itu semula salah? Bagaimana jika fungsi bisnis telah berubah secara signifikan?

Prinsip ini pada dasarnya memastikan bahwa niat dan perilaku ASLI suatu desain tidak boleh berubah. Itu mungkin bekerja untuk mereka yang memiliki API publik dan klien mereka mengalami kesulitan mengikuti rilis baru, dan beberapa kasus tepi lainnya. Namun, jika perusahaan memiliki SEMUA kode, maka saya menantang prinsip ini.

Memiliki cakupan tes yang baik dari kode Anda harus membuat refactoring basis kode Anda mudah. Itu berarti tidak masalah jika ada yang salah - tes Anda akan membantu memandu Anda ke desain yang lebih baik.

Mengatakan itu, jika tidak ada tes, maka prinsip ini masuk akal.

pengguna126776
sumber