Apakah praktik yang baik untuk menggunakan fungsi hanya untuk memusatkan kode umum?

20

Saya sering mengalami masalah ini. Sebagai contoh, saya saat ini menulis fungsi baca dan fungsi tulis, dan mereka berdua memeriksa apakah bufadalah pointer NULL dan bahwa modevariabel berada dalam batas-batas tertentu.

Ini duplikasi kode. Ini dapat diatasi dengan memindahkannya ke fungsinya sendiri. Tetapi haruskah saya melakukannya? Ini akan menjadi fungsi yang cukup anemia (tidak banyak melakukan), agak terlokalisasi (jadi bukan tujuan umum), dan tidak berdiri sendiri (tidak tahu apa yang Anda butuhkan kecuali Anda melihat di mana itu berada bekas). Pilihan lain adalah dengan menggunakan makro, tetapi saya ingin berbicara tentang fungsi dalam posting ini.

Jadi, haruskah Anda menggunakan fungsi untuk hal seperti ini? Apa pro dan kontra?

EpsilonVector
sumber
2
Barang baris tunggal membutuhkan lebih dari sekadar digunakan di banyak tempat untuk menjamin pemindahan ke fungsi terpisah.
1
Pertanyaan bagus Sudah banyak kali saya bertanya-tanya sama.
rdasxy

Jawaban:

31

Ini adalah besar penggunaan fungsi.

Ini akan menjadi fungsi yang cukup anemia (tidak banyak) ...

Itu bagus. Fungsi seharusnya hanya melakukan satu hal.

agak terlokalisasi ...

Dalam bahasa OO, jadikan ini pribadi.

(jadi bukan tujuan umum)

Jika menangani lebih dari satu kasus, itu adalah tujuan umum. Selain itu, generalisasi bukan satu-satunya penggunaan fungsi. Mereka memang ada di sana untuk (1) menghemat Anda menulis kode yang sama lebih dari sekali, tetapi juga (2) memecah kode menjadi potongan-potongan kecil untuk membuatnya lebih mudah dibaca. Dalam hal ini mencapai (1) dan (2). Namun, bahkan jika fungsi Anda dipanggil dari satu tempat, itu mungkin masih membantu (2).

dan tidak berdiri sendiri dengan baik (tidak bisa mencari tahu apa yang Anda butuhkan kecuali Anda melihat di mana ia digunakan).

Datang dengan nama yang bagus untuk itu, dan itu berdiri sendiri. "ValidateFileParameters" atau sesuatu. Sekarang berdiri sendiri.

Kramii Reinstate Monica
sumber
6
Poin barang bagus. Saya akan menambahkan (3) mencegah Anda dari berburu bug duplikat di seluruh basis kode Anda ketika Anda dapat memperbaiki di satu tempat. Duplikasi kode dapat menyebabkan neraka pemeliharaan sangat cepat.
deadalnix
2
@deadalnix: Poin bagus. Ketika saya sedang menulis, saya menyadari bahwa poin saya terlalu menyederhanakan. Menulis dan debugging yang lebih mudah tentu merupakan keuntungan dari memecah hal menjadi fungsi (seperti kemampuan untuk menguji fungsi yang terpisah).
Kramii Reinstate Monica
11

Itu benar-benar harus menjadi fungsi.

if (isBufferValid(buffer)) {
    // ...
}

Jauh lebih mudah dibaca, dan lebih bisa dipelihara (jika logika cek berubah, Anda hanya mengubahnya di satu tempat).

Selain itu, hal-hal seperti ini dapat diuraikan dengan mudah sehingga Anda bahkan tidak perlu khawatir tentang overhead panggilan fungsi.

Izinkan saya mengajukan pertanyaan yang lebih baik. Bagaimana tidak melakukan ini praktik yang baik?

Lakukan hal yang benar. :)

Yam Marcovic
sumber
4
Jika isBufferValid sederhana return buffer != null;maka saya pikir Anda menyakiti keterbacaan di sana.
pdr
5
@ pdr: Dalam kasus sederhana itu hanya menyakitkan keterbacaan jika Anda memiliki pola pikir kontrol aneh dan benar-benar, sungguh, BENAR-BENAR ingin tahu bagaimana kode memeriksa apakah buffer valid. Jadi itu subjektif dalam kasus-kasus sederhana itu.
Spoike
4
@ pdr Saya tidak tahu bagaimana itu menyakitkan keterbacaan oleh standar apa pun. Anda membebaskan pengembang lain agar tidak peduli tentang bagaimana Anda melakukan sesuatu, dan berfokus pada apa yang Anda lakukan. isBufferValidjelas lebih mudah dibaca (dalam buku saya) daripada buffer != null, karena itu mengkomunikasikan tujuannya dengan lebih jelas. Dan lagi, belum lagi itu menyelamatkan Anda dari duplikasi juga di sini. Apa lagi yang kamu butuhkan?
Yam Marcovic
5

IMO, cuplikan kode layak dipindahkan ke fungsi mereka sendiri setiap kali ini membuat kode lebih mudah dibaca , terlepas dari apakah fungsinya akan sangat singkat atau hanya akan digunakan sekali.

Tentu saja ada batasan yang ditentukan oleh akal sehat. Anda tidak ingin memiliki WriteToConsole(text)metode dengan tubuh yang sederhana Console.WriteLine(text), misalnya. Tetapi berbuat salah di sisi keterbacaan adalah praktik yang baik.

Konamiman
sumber
2

Ini umumnya ide yang baik untuk menggunakan fungsi untuk menghapus duplikasi dalam kode.

Namun itu bisa terlalu jauh. Ini adalah panggilan penghakiman.

Untuk mengambil contoh pemeriksaan buffer nol Anda, saya mungkin akan mengatakan bahwa kode berikut cukup jelas dan tidak boleh diekstraksi menjadi fungsi terpisah, bahkan jika pola yang sama digunakan di beberapa tempat.

if (buf==null) throw new BufferException("Null read buffer!");

Jika Anda memasukkan pesan kesalahan sebagai parameter ke fungsi pemeriksaan null generik, dan juga mempertimbangkan kode yang diperlukan untuk mendefinisikan fungsi, maka itu bukan penghematan LOC bersih untuk menggantikannya dengan:

checkForNullBuffer(buf, "Null read buffer!");

Selain itu, harus menyelami fungsi untuk melihat apa yang dilakukannya ketika debugging berarti bahwa panggilan fungsi kurang "transparan" bagi pengguna, dan karenanya dapat dianggap kurang mudah dibaca / dikelola.

mikera
sumber
Dapat diperdebatkan, contoh Anda mengatakan lebih banyak tentang kurangnya dukungan kontrak dalam bahasa daripada kebutuhan nyata duplikasi. Tapi pokoknya bagus.
deadalnix
1
Anda agak merindukan intinya seperti yang saya lihat. Tidak harus melangkah atau harus mempertimbangkan logika setiap kali Anda men-debug adalah apa yang saya cari. Jika saya ingin tahu bagaimana melakukannya, saya memeriksanya sekali. Harus melakukannya setiap waktu benar-benar konyol.
Yam Marcovic
Jika pesan kesalahan ("Null read buffer") diulang, duplikasi itu harus dihilangkan.
kevin cline
Yah itu hanya sebuah contoh tetapi mungkin Anda akan memiliki pesan yang berbeda di setiap situs panggilan fungsi - misalnya "Null read buffer" dan "Null write buffer" misalnya. Kecuali Anda menginginkan pesan log / kesalahan yang sama untuk setiap situasi, Anda tidak dapat menduplikatnya .......
mikera
-1 Preconditions.checkNotNull adalah praktik yang baik, bukan yang buruk. Tidak perlu memasukkan pesan string. google-collections.googlecode.com/svn/trunk/javadoc/com/google/…
ripper234
2

Memusatkan kode biasanya selalu merupakan ide yang bagus. Kita harus menggunakan kembali kode sebanyak mungkin.

Namun, penting untuk dicatat bagaimana melakukannya. Misalnya, ketika Anda memiliki kode yang melakukan compute_prime_number () atau check_if_packet_is_bad () itu bagus. Kemungkinannya adalah bahwa algoritma fungsi itu sendiri akan berkembang yang akan diuntungkan.

Namun, setiap bagian dari kode yang diulang sebagai prosa tidak memenuhi syarat untuk terpusat segera. Ini buruk. Anda dapat menyembunyikan baris kode sewenang-wenang di dalam suatu fungsi hanya untuk menyembunyikan kode, seiring waktu, ketika beberapa bagian aplikasi mulai digunakan, mereka semua harus tetap kompatibel dengan kebutuhan semua fungsi yang ada.

Inilah beberapa pertanyaan yang harus Anda tanyakan sebelum bertanya

  1. Apakah fungsi yang Anda buat memiliki makna yang melekat sendiri atau hanya sekelompok garis?

  2. Konteks lain mana yang akan membutuhkan penggunaan fungsi yang sama? Apakah Anda mungkin perlu sedikit menyamaratakan API sebelum menggunakan ini?

  3. Apa yang akan menjadi harapan aplikasi (bagian yang berbeda dari) ketika Anda melemparkan pengecualian?

  4. Apa skenario untuk melihat bahwa fungsi akan berkembang?

Anda juga harus memeriksa apakah sudah ada barang seperti ini. Saya telah melihat begitu banyak orang selalu cenderung mendefinisikan-ulang macro mereka MIN, MAX daripada mencari apa yang sudah ada.

Pada dasarnya, pertanyaannya adalah, "Apakah fungsi baru ini benar-benar layak untuk digunakan kembali atau ini hanya copy-paste ?" Jika itu yang pertama, itu baik untuk pergi.

Dipan Mehta
sumber
1
Nah, jika kode duplikat tidak memiliki makna sendiri, kode Anda memberi tahu Anda bahwa itu perlu refactoring. Karena tempat di mana duplikasi terjadi mungkin juga tidak memiliki arti sendiri.
deadalnix
1

Dupliaksi kode harus dihindari. Setiap kali Anda mengantisipasinya, Anda harus menghindari duplikasi kode. Jika Anda tidak mengantisipasinya, terapkan aturan 3: refactor sebelum potongan kode yang sama digandakan 3 kali, buat anotasi kekhasan saat digandakan 2 kali.

Apa itu duplikasi kode?

  • Sebuah rutin yang diulangi di beberapa tempat dalam basis kode. Turin ini harus lebih kompleks daripada panggilan fungsi sederhana (selain itu, Anda tidak akan memperoleh apa-apa dengan faktorisasi).
  • Tugas yang sangat umum, bahkan yang sepele (seringkali ujian). Ini akan meningkatkan enkapsulasi dan semantik dalam kode.

Pertimbangkan contoh di bawah ini:

if(user.getPrileges().contains("admin")) {
    // Do something
}

menjadi

if(user.isAdmin()) {
    // Do something
}

Anda meningkatkan enkapsulasi (sekarang Anda dapat mengubah kondisi menjadi admin secara transparan) dan semantik kode. Jika bug ditemukan dalam cara Anda memeriksa bahwa pengguna adalah admin, Anda tidak perlu membuang seluruh basis kode Anda dan membuat perbaikan di mana-mana (dengan risiko melupakannya dan mendapatkan kelemahan keamanan dalam aplikasi Anda).

deadalnix
sumber
1
Contoh Btw menggambarkan Hukum Demeter.
MaR
1

KERING adalah tentang menyederhanakan manipulasi kode. Anda baru saja menyentuh titik baik tentang prinsip ini: Ini bukan tentang meminimalkan jumlah token dalam kode Anda, melainkan menciptakan satu titik modifikasi untuk kode yang setara secara semantik . Kedengarannya seperti cek Anda selalu memiliki semantik yang sama, sehingga harus dimasukkan ke dalam fungsi jika Anda perlu memodifikasinya.

l0b0
sumber
0

Jika Anda melihatnya digandakan, Anda harus menemukan cara untuk memusatkannya.

Fungsinya adalah cara yang baik (mungkin bukan yang terbaik tetapi itu tergantung pada bahasanya) Bahkan jika fungsinya anemia seperti yang Anda katakan itu tidak berarti itu akan tetap seperti itu.

Bagaimana jika Anda harus memeriksa sesuatu yang lain juga?

Apakah Anda akan menemukan semua tempat Anda harus menambahkan cek tambahan atau hanya mengubah fungsi?

Thanos Papathanasiou
sumber
... di sisi lain, bagaimana jika ada kemungkinan yang sangat tinggi bahwa Anda tidak akan pernah menambahkan sesuatu padanya. Apakah saran Anda masih merupakan tindakan terbaik dalam kasus itu juga?
EpsilonVector
1
@ EpsilonVector aturan praktis saya adalah bahwa jika saya harus mengubahnya sekali maka saya mungkin juga refactor. Jadi, dalam kasus Anda, saya akan meninggalkannya dan jika saya harus mengubahnya, itu akan menjadi fungsi.
Thanos Papathanasiou
0

Hampir selalu baik jika kondisi berikut dipenuhi:

  • meningkatkan keterbacaan
  • digunakan dalam lingkup terbatas

Dalam ruang lingkup yang lebih besar Anda harus mempertimbangkan duplikasi vs ketergantungan secara hati-hati. Contoh teknik pembatasan ruang lingkup: bersembunyi di bagian pribadi atau modul tanpa memaparkannya kepada publik.

Merusak
sumber