Apakah ada alasan bagus untuk membuat fungsi murni non-publik?

25

Saya memiliki sedikit perdebatan dengan rekan kerja. Sederhananya, apakah ada alasan bagus untuk menyembunyikan / merangkum fungsi yang murni?

Yang saya maksud dengan "murni" adalah definisi wikipedia :

  • Selalu mengembalikan hasil yang sama dari input yang sama. (Demi diskusi Foo Create(){ return new Foo(); }ini dianggap tidak murni jika Footidak memiliki nilai semantik.)
  • Tidak menggunakan keadaan bisa berubah-ubah (kecuali variabel lokal) atau I / O.
  • Tidak menghasilkan efek samping.
Telastyn
sumber
26
Mungkin ada argumen yang dibuat untuk tidak membuat fungsi anggota kelas sama sekali.
Pieter B
6
@PieterB - memang, meskipun tidak semua bahasa mendukung itu, dan beberapa bahasa memungkinkan modul internal bahkan untuk fungsi gratis.
Telastyn
3
Apa pendapatmu Saya tidak berpikir kemurnian fungsi terkait dengan apakah itu milik API publik.
Andres F.
@ danresF. - debat sebenarnya seputar apakah aturan validasi yang tidak mengikat harus dipublikasikan. Saya membuat argumen bahwa karena itu adalah fungsi murni, ada sedikit bahaya. Untuk contoh khusus ini, itu membantu testability dan kemungkinan akan digunakan kembali. Pertanyaan ini lebih lanjut tentang seberapa luas argumen itu bisa / harus diterapkan.
Telastyn
2
@ Telastyn Jika itu dapat digunakan kembali tetapi bukan bagian dari tanggung jawab kelas saat ini, itu mungkin harus di kelas / modul / apa pun bahasa Anda yang terpisah. Kemudian menjadi bagian dari tanggung jawab kelas / modul baru, tentu harus diumumkan kepada publik. Karena Anda menyebutkan pengujian, saya akan perhatikan bahwa Anda tidak perlu mengejek metode ketika Anda melakukan itu. Sebagai "detail implementasi," mengejeknya selama pengujian tidak banyak memberikan manfaat.
jpmc26

Jawaban:

76

Fungsi murni masih bisa menjadi detail implementasi. Meskipun fungsi tersebut tidak menyebabkan kerusakan (dari sudut pandang tidak melanggar invarian / kontrak penting), dengan mengeksposnya baik penulis dan pengguna kelas / modul / paket tersebut hilang. Penulis kehilangan karena sekarang dia tidak dapat menghapusnya bahkan jika implementasi berubah dan fungsinya tidak lagi berguna baginya. Pengguna kehilangan karena mereka harus menyaring dan mengabaikan fungsi tambahan yang tidak relevan untuk menggunakan API untuk memahaminya.

Doval
sumber
33
+1. Anggota publik dari kelas Anda adalah API-nya. Ini bukan pertanyaan "Bisakah itu menyakiti saya jika itu publik?", Melainkan "Haruskah itu menjadi bagian dari API?"
Ordous
1
Satu-satunya hal yang akan saya tambahkan adalah bahwa jika Anda mulai melihat fungsi serupa bermunculan di lokasi lain, refactor ke kelas lain sehingga beberapa kelas dapat memanfaatkannya. Atau jika itu merupakan masalah awal, tentukan dalam kelas terpisah untuk memulai.
jpmc26
1
Saya akan menyegel kelas-kelas publik yang tidak dimaksudkan untuk diperpanjang juga.
Den
+1 untuk menunjukkan bahwa menyembunyikan atau menunjukkan fungsi (atau kelas) adalah pertanyaan utama untuk melindungi dan memelihara API, dan tidak terkait dengan jenis kode itu.
Marco
42

Pertanyaannya terbalik.

Anda tidak mencari alasan untuk membuat suatu fungsi non-publik. Ini adalah pola pikir yang salah untuk memulai (menurut saya). Alasannya harus sebaliknya.

Dengan kata lain - jangan tanya "mengapa saya membuatnya pribadi?". Tanyakan: "mengapa saya harus mempublikasikannya?"

Jika ragu, jangan ungkapkan. Ini seperti pisau cukur Ockham - jangan gandakan hak yang melebihi kebutuhan.

EDIT: Mengatasi kontra-argumen yang diajukan oleh @Telastyn dalam komentar (untuk menghindari diskusi panjang di sana):

Saya sudah mendengarnya dari waktu ke waktu, dan bahkan mendukungnya untuk beberapa waktu, tetapi dalam pengalaman saya, banyak hal cenderung terlalu pribadi.

Ya, kadang-kadang menyakitkan jika kelas terbuka untuk warisan, tetapi Anda tidak dapat mengganti beberapa metode pribadi (yang perilakunya ingin Anda ubah).

Tetapi protectedakan cukup - dan itu masih non-publik.

Ini mengarah ke banyak duplikasi kode dan overhead untuk mendapatkan "hal-hal yang tidak boleh publik" namun diakses secara tidak langsung.

Jika menjadi bermasalah, maka cukup buat publik! Ada kebutuhan yang saya bicarakan :)

Maksud saya adalah bahwa Anda tidak harus melakukannya untuk berjaga-jaga (YAGNI dan semuanya).

Perhatikan bahwa selalu membuat fungsi pribadi menjadi publik lebih mudah daripada menariknya kembali ke privasi. Yang terakhir kemungkinan akan memecahkan kode yang ada.

Konrad Morawski
sumber
Saya sudah mendengarnya dari waktu ke waktu, dan bahkan mendukungnya untuk beberapa waktu, tetapi dalam pengalaman saya, banyak hal cenderung terlalu pribadi. Ini mengarah ke banyak duplikasi kode dan overhead untuk mendapatkan "hal-hal yang tidak boleh publik" namun diakses secara tidak langsung.
Telastyn
3
@Telastyn IMHO, itu terdengar seperti aplikasi menderita beberapa kesalahan langkah desain; jika Anda mendapati diri Anda cenderung mengekspos suatu metode karena Anda perlu menjalankannya di jalur kode yang berbeda, itu mungkin pertanda bahwa metode ini harus dipecah menjadi modulnya sendiri yang dapat disuntikkan atau dimasukkan jika perlu, terutama jika itu adalah fungsi murni .
leo
@leo - maaf, saya tidak mengikuti. Pertimbangkan fungsi seperti integer kurang dari. Ini adalah fungsi murni yang bagus yang terpapar secara khusus karena dapat kemudian disuntikkan dan dimasukkan (atau hanya digunakan) jika sesuai.
Telastyn
5
@Telastyn Menurut pendapat saya itu adalah gejala dari filosofi "semuanya adalah objek / kelas" yang dikombinasikan dengan fakta bahwa beberapa bahasa OOP tidak memiliki tipe data komposit selain kelas. Segera setelah seseorang harus memberikan dua nilai pada saat yang sama mereka akhirnya menulis sebuah kelas, dan kemudian setiap rekan kerja dan perangkat lunak pengecekan gaya akan meminta Anda untuk membuat bidang-bidang itu pribadi.
Doval
@ Telastyn Benar. Yang saya maksudkan adalah, jika metode 'integerLessThan' Anda dimulai sebagai detail implementasi terenkapsulasi dari metode publik, tetapi Anda menemukan bahwa Anda perlu memanggil metode pribadi di tempat lain, itu mungkin merupakan tanda bahwa metode pribadi termasuk dalam metode yang berbeda. modul / paket / kelas sehingga dapat diimpor secara independen dari logika yang memanggilnya. Cukup mempublikasikan metode apa adanya berarti metode tersebut secara sewenang-wenang terletak di modul pertama di mana Anda merasa berguna.
leo
6

Saya tidak berpikir keputusan untuk menyembunyikan / merangkum fungsi harus bergantung pada kemurniannya. Hanya karena suatu fungsi murni tidak berarti bahwa pihak eksternal perlu tahu tentang hal itu. Cukup menarik meskipun jika fungsinya murni dan dimaksudkan untuk umum mungkin bahkan tidak perlu menjadi contoh anggota antarmuka sama sekali mungkin lebih cocok sebagai statis. Tetapi sekali lagi semua ini tergantung pada maksud kontrak dan dalam hal ini pengelompokan fungsionalitas logis, bukan kemurnian fungsi.

pamit
sumber
5

Kelas harus mematuhi Prinsip Tanggung Jawab Tunggal . Sementara sebuah kelas mungkin perlu memanggil fungsionalitas lain untuk mencapai tujuannya, ia seharusnya hanya mengekspos fungsi yang merupakan bagian dari tanggung jawab tunggal.

Berikut ini hanya satu contoh kasus di mana visibilitas dapat menyebabkan masalah.

Pertimbangkan kelas yang mengatur widget. Mungkin sebagai bagian dari kode frobasinya, diperlukan fungsi utilitas yang mem-parsing sebuah string: mungkin ia perlu mengubah nama widget dengan cara yang tidak didukung fungsi string standar.

Karena ini adalah fungsi murni (string masuk, mengubahnya entah bagaimana, mengembalikan string baru), itu bisa publik atau pribadi tanpa konsekuensi. Atau mungkinkah itu?

Jika Anda membuatnya publik, sekarang kelas Anda memiliki dua tanggung jawab: widget frobnicating, dan mentransformasikan string. Ini melanggar SRP, dan dapat menyebabkan masalah jika kelas lain mengandalkan fungsi tersebut. Karena ini adalah sesuatu yang Anda pikir hanya digunakan di dalam kelas, mungkin Anda mengubah antarmuka atau visibilitasnya. Sekarang kelas di bagian lain dari sistem rusak.

Dengan menjaga fungsi pribadi, tidak ada yang pernah memiliki kesempatan untuk mengandalkan kode yang bukan bagian dari tanggung jawab tunggal kelas.


sumber
2
Saya berpendapat bahwa itu seharusnya hanya berisi fungsi-fungsi yang merupakan bagian dari tanggung jawab tunggal, bukan hanya mengekspos.
Telastyn
1
Saya pikir ada area abu-abu. Apakah Anda benar-benar membutuhkan StringTransformerkelas terpisah untuk merangkum dua atau tiga baris kode yang hanya digunakan di satu tempat? Saya setuju bahwa begitu kode digunakan di banyak tempat, yang terbaik adalah memisahkannya menjadi kelas baru dengan satu tanggung jawab, tetapi ada tradeoff.
Pasti. Pedoman adalah pedoman, bukan aturan.
Telastyn
@snowman di non java Anda hanya membuat perpustakaan fungsi.
Pieter B
@ PeterB ini bukan tentang Java v. Apa pun. Untuk membuatnya benar-benar OO, Anda akan memerlukan pabrik, beberapa kelas abstrak, dll.