Saya memiliki metode besar yang melakukan 3 tugas, masing-masing dapat diekstraksi menjadi fungsi yang terpisah. Jika saya akan membuat fungsi tambahan untuk masing-masing tugas itu, apakah ini akan membuat kode saya lebih baik atau lebih buruk dan mengapa?
Jelas, itu akan membuat lebih sedikit baris kode di fungsi utama, tetapi akan ada deklarasi fungsi tambahan, jadi kelas saya akan memiliki metode tambahan, yang saya percaya tidak baik, karena akan membuat kelas lebih kompleks.
Haruskah saya melakukan itu sebelum saya menulis semua kode atau saya harus meninggalkannya sampai semuanya selesai dan kemudian mengekstrak fungsi?
java
design-patterns
dhblah
sumber
sumber
Jawaban:
Ini adalah buku yang sering saya tautkan, tetapi saya membahasnya lagi: Robert C. Martin Clean Code , bab 3, "Functions".
Apakah Anda lebih suka membaca fungsi dengan +150 baris, atau fungsi memanggil 3 +50 fungsi baris? Saya pikir saya lebih suka opsi kedua.
Ya , itu akan membuat kode Anda lebih baik dalam arti bahwa itu akan lebih "dapat dibaca". Buat fungsi yang melakukan satu dan hanya satu hal, mereka akan lebih mudah untuk mempertahankan dan menghasilkan test case.
Juga, hal yang sangat penting yang saya pelajari dengan buku tersebut di atas: pilih nama yang baik dan tepat untuk fungsi Anda. Semakin penting fungsinya, nama yang paling tepat seharusnya. Jangan khawatir tentang panjang nama, jika harus dipanggil
FunctionThatDoesThisOneParticularThingOnly
, maka nama itu seperti itu.Sebelum melakukan refactor Anda, tulis satu atau beberapa test case. Pastikan mereka bekerja. Setelah selesai dengan refactoring, Anda akan dapat meluncurkan kotak uji ini untuk memastikan kode baru berfungsi dengan benar. Anda dapat menulis tes "kecil" tambahan untuk memastikan fungsi baru Anda bekerja dengan baik secara terpisah.
Akhirnya, dan ini tidak bertentangan dengan apa yang baru saja saya tulis, tanyakan pada diri Anda apakah Anda benar-benar perlu melakukan refactoring ini, periksa jawaban untuk " Kapan harus refactor ?" (juga, cari pertanyaan SO pada "refactoring", ada lebih banyak dan jawaban menarik untuk dibaca)
Jika kode sudah ada di sana dan berfungsi dan Anda kekurangan waktu untuk rilis berikutnya, jangan sentuh itu. Kalau tidak, saya pikir orang harus membuat fungsi kecil bila memungkinkan dan dengan demikian, refactor setiap kali ada waktu sambil memastikan bahwa semuanya berfungsi seperti sebelumnya (uji kasus).
sumber
Ya tentu saja. Jika mudah untuk melihat dan memisahkan "tugas" yang berbeda dari fungsi tunggal.
Tetapi mungkin ada masalah dengan ini:
sumber
Masalah yang Anda ajukan bukanlah masalah pengkodean, konvensi atau praktik pengkodean, melainkan masalah keterbacaan dan cara editor teks menunjukkan kode yang Anda tulis. Masalah yang sama juga muncul di pos:
Apakah boleh membagi fungsi dan metode yang panjang menjadi yang lebih kecil meskipun tidak akan dipanggil oleh yang lain?
Membagi fungsi menjadi sub-fungsi masuk akal ketika menerapkan sistem besar dengan maksud untuk merangkum berbagai fungsi yang akan dikomposisikan. Namun, cepat atau lambat, Anda akan menemukan diri Anda dengan sejumlah fungsi besar. Beberapa dari mereka tidak dapat dihidupkan kembali dan sulit dipertahankan apakah Anda menyimpannya sebagai fungsi tunggal yang panjang atau membaginya menjadi fungsi yang lebih kecil. Ini terutama berlaku untuk fungsi-fungsi di mana operasi yang Anda lakukan, tidak diperlukan di tempat lain di sistem Anda. Memungkinkan mengambil salah satu dari fungsi yang begitu panjang dan mempertimbangkannya dalam tampilan yang lebih luas.
Pro:
Kontra:
Sekarang mari kita bayangkan untuk membagi fungsi panjang menjadi beberapa sub-fungsi dan melihatnya dengan prospektif yang lebih luas.
Pro:
Kontra:
Kedua solusi tersebut memiliki pro dan kontra. Solusi terbaik yang sebenarnya adalah memiliki editor yang memungkinkan untuk memperluas, sebaris dan untuk kedalaman penuh, setiap fungsi memanggil kontennya. Yang akan membuat, fungsi pemisahan dalam sub fungsi satu-satunya solusi terbaik.
sumber
Bagi saya ada empat alasan untuk mengekstrak blok kode ke dalam fungsi:
Anda menggunakannya kembali : Anda baru saja menyalin blok kode ke clipboard. Alih-alih hanya menempelkannya, letakkan di fungsi dan ganti blok dengan dengan pemanggilan fungsi di kedua sisi. Jadi, setiap kali Anda perlu mengubah blok kode itu, Anda hanya perlu mengubah fungsi tunggal itu alih-alih mengubah kode beberapa tempat. Jadi, setiap kali Anda menyalin blok kode, Anda harus membuat suatu fungsi.
Ini adalah panggilan balik : Ini adalah pengendali acara atau semacam kode pengguna perpustakaan atau panggilan kerangka kerja. (Saya hampir tidak bisa membayangkan ini tanpa membuat fungsi.)
Anda yakin itu akan digunakan kembali , dalam proyek saat ini atau mungkin di tempat lain: Anda baru saja menulis blok yang menghitung urutan umum terpanjang dari dua array. Bahkan jika program Anda memanggil fungsi ini hanya sekali, saya percaya saya akan membutuhkan fungsi ini pada akhirnya di proyek lain juga.
Anda ingin kode yang mendokumentasikan diri : Jadi alih-alih menulis satu baris komentar di atas satu blok kode yang meringkas apa yang dilakukannya, Anda mengekstrak semuanya menjadi sebuah fungsi, dan beri nama apa yang akan Anda tulis dalam komentar. Meskipun saya bukan penggemar ini, karena saya suka menulis nama algoritma yang digunakan, alasan mengapa saya memilih algoritma itu, dll. Nama fungsi akan terlalu lama daripada ...
sumber
Saya yakin Anda pernah mendengar saran bahwa variabel harus dicakup seketat mungkin, dan saya harap Anda setuju dengan itu. Nah, fungsi adalah wadah lingkup, dan dalam fungsi yang lebih kecil cakupan variabel lokal lebih kecil. Jauh lebih jelas bagaimana dan kapan mereka seharusnya digunakan dan lebih sulit untuk menggunakannya dalam urutan yang salah atau sebelum diinisialisasi.
Juga, fungsi adalah wadah aliran logis. Hanya ada satu jalan masuk, jalan keluar ditandai dengan jelas, dan jika fungsinya cukup pendek, aliran internal harus jelas. Ini memiliki efek mengurangi kompleksitas siklomatik yang merupakan cara yang andal untuk mengurangi tingkat cacat.
sumber
Selain itu: Saya menulis ini sebagai jawaban atas pertanyaan dallin (sekarang ditutup) tetapi saya masih merasa ini bisa bermanfaat bagi seseorang jadi begini
Saya berpikir bahwa alasan fungsi atomisasi adalah 2 kali lipat, dan seperti yang disebutkan @jozefg bergantung pada bahasa yang digunakan.
Pemisahan Kekhawatiran
Alasan utama untuk melakukan ini adalah untuk menjaga potongan kode yang berbeda terpisah, sehingga setiap blok kode yang tidak secara langsung berkontribusi pada hasil / maksud fungsi yang diinginkan adalah masalah yang terpisah dan dapat diekstraksi.
Katakanlah Anda memiliki tugas latar belakang yang juga memperbarui bilah progres, pembaruan bilah progres tidak terkait langsung dengan tugas yang berjalan lama sehingga harus diekstraksi, bahkan jika itu satu-satunya bagian dari kode yang menggunakan bilah progres.
Katakan dalam JavaScript Anda memiliki fungsi getMyData (), yang 1) membangun pesan sabun dari parameter, 2) menginisialisasi referensi layanan, 3) memanggil layanan dengan pesan sabun, 4) mem-parsing hasilnya, 5) mengembalikan hasilnya. Tampaknya masuk akal, saya telah menulis fungsi persis ini berkali-kali - tetapi sebenarnya itu dapat dibagi menjadi 3 fungsi pribadi hanya termasuk kode untuk 3 & 5 (jika itu) karena tidak ada kode lain yang secara langsung bertanggung jawab untuk mendapatkan data dari layanan .
Peningkatan Pengalaman Debugging
Jika Anda memiliki fungsi atomik sepenuhnya, jejak tumpukan Anda menjadi daftar tugas, daftar semua kode yang berhasil dieksekusi, yaitu:
akan membagikan lebih menarik kemudian menemukan bahwa ada kesalahan saat mendapatkan data. Tetapi beberapa alat bahkan lebih berguna untuk men-debug pohon panggilan terperinci dari itu, ambil contohnya Microsoft Debugger Canvas .
Saya juga memahami kekhawatiran Anda bahwa mungkin sulit untuk mengikuti kode yang ditulis dengan cara ini karena pada akhirnya, Anda harus memilih urutan fungsi dalam satu file di mana sebagai pohon panggilan Anda akan membagikan lebih rumit dari itu . Tetapi jika fungsi dinamai dengan baik (intellisense memungkinkan saya untuk menggunakan 3-4 kata kasus camal dalam fungsi apa pun yang saya harap tanpa memperlambat saya) dan terstruktur dengan antarmuka publik di bagian atas file, kode Anda akan dibaca seperti pseudo-code yang sejauh ini merupakan cara termudah untuk mendapatkan pemahaman tingkat tinggi dari basis kode.
FYI - ini adalah salah satu dari hal-hal "lakukan apa yang saya katakan tidak seperti yang saya lakukan", menjaga kode atom tidak ada gunanya kecuali Anda secara konsisten konsisten dengan itu IMHO, padahal saya tidak.
sumber