Gaya pengkodean saya untuk panggilan fungsi bersarang adalah sebagai berikut:
var result_h1 = H1(b1);
var result_h2 = H2(b2);
var result_g1 = G1(result_h1, result_h2);
var result_g2 = G2(c1);
var a = F(result_g1, result_g2);
Saya baru saja berubah menjadi departemen di mana gaya pengkodean berikut ini sangat banyak digunakan:
var a = F(G1(H1(b1), H2(b2)), G2(c1));
Hasil dari cara pengkodean saya adalah, jika terjadi fungsi tabrakan, Visual Studio dapat membuka dump yang sesuai dan menunjukkan baris tempat masalah terjadi (saya terutama khawatir tentang pelanggaran akses).
Saya khawatir, jika terjadi kerusakan karena masalah yang sama yang diprogram dalam cara pertama, saya tidak akan dapat mengetahui fungsi mana yang menyebabkan kerusakan.
Di sisi lain, semakin banyak pemrosesan yang Anda lakukan pada satu baris, semakin banyak logika yang Anda dapatkan pada satu halaman, yang meningkatkan keterbacaan.
Apakah ketakutan saya benar atau saya kehilangan sesuatu, dan secara umum, yang lebih disukai di lingkungan komersial? Keterbacaan atau pemeliharaan?
Saya tidak tahu apakah itu relevan, tetapi kami bekerja di C ++ (STL) / C #.
sumber
HX
danGX
permintaan dapat berubah dalam satu-baris, seperti urutan evaluasi argumen fungsi tidak ditentukan. Jika Anda karena alasan tertentu bergantung pada urutan efek samping (sadar atau tidak sadar) dalam doa, "gaya refactoring" ini akhirnya dapat menghasilkan lebih dari sekadar keterbacaan / pemeliharaan.result_g1
yang benar-benar Anda gunakan atau nilai ini benar-benar mewakili sesuatu dengan nama yang masuk akal; mispercentageIncreasePerSecond
. Itu sebenarnya akan menjadi ujian saya untuk memutuskan di antara keduanyaJawaban:
Jika Anda merasa harus memperluas satu liner seperti
Aku tidak akan menyalahkanmu. Itu tidak hanya sulit dibaca, tetapi juga sulit untuk di-debug.
Mengapa?
Jika Anda mengembangkannya dengan hasil menengah yang Anda dapatkan
dan masih sulit dibaca. Mengapa? Ini memecahkan dua masalah dan memperkenalkan yang keempat:
Ini padatBeberapa debugger hanya akan menyoroti semuanya sekaligusJika Anda mengembangkannya dengan nama yang menambahkan makna baru, bagus, semantik, bahkan lebih baik! Nama yang bagus membantu saya mengerti.
Sekarang setidaknya ini menceritakan sebuah kisah. Ini memperbaiki masalah dan jelas lebih baik daripada apa pun yang ditawarkan di sini tetapi mengharuskan Anda untuk datang dengan nama.
Jika Anda melakukannya dengan nama-nama yang tidak berarti seperti
result_this
danresult_that
karena Anda tidak bisa memikirkan nama-nama yang baik maka saya benar-benar lebih suka Anda mengacaukan nama yang tidak berarti dan mengembangkannya menggunakan ruang putih tua yang bagus:Ini hanya bisa dibaca, jika tidak lebih, dari yang dengan nama hasil yang tidak berarti (bukan bahwa nama-nama fungsi ini sehebat itu).
Ini padatBeberapa debugger hanya akan menyoroti semuanya sekaligusItu berantakan dengan nama-nama non-deskriptifKetika Anda tidak bisa memikirkan nama baik, itu sama baiknya dengan namanya.
Untuk beberapa alasan debuggers menyukai baris baru sehingga Anda harus menemukan bahwa debugging ini tidak sulit:
Jika itu tidak cukup, bayangkan
G2()
dipanggil di lebih dari satu tempat dan kemudian ini terjadi:Saya pikir itu baik karena setiap
G2()
panggilan akan berada di jalurnya sendiri, gaya ini membawa Anda langsung ke panggilan yang menyinggung di utama.Jadi tolong jangan gunakan masalah 1 dan 2 sebagai alasan untuk mempermasalahkan kami dengan masalah 4. Gunakan nama baik ketika Anda bisa memikirkannya. Hindari nama yang tidak berarti ketika Anda tidak bisa.
Lightness Races dalam komentar Orbit dengan benar menunjukkan bahwa fungsi-fungsi ini adalah buatan dan memiliki nama buruk yang mati sendiri. Jadi, inilah contoh penerapan gaya ini ke beberapa kode dari alam:
Aku benci melihat aliran suara itu, bahkan ketika pembungkus kata tidak diperlukan. Begini tampilannya di bawah gaya ini:
Seperti yang Anda lihat, saya telah menemukan gaya ini bekerja dengan baik dengan kode fungsional yang bergerak ke ruang berorientasi objek. Jika Anda dapat menemukan nama-nama baik untuk melakukan itu dalam gaya menengah maka lebih banyak kekuatan untuk Anda. Sampai saat itu saya menggunakan ini. Tetapi bagaimanapun juga, tolong, temukan beberapa cara untuk menghindari nama hasil yang tidak berarti. Mereka membuat mataku sakit.
sumber
Saya sama sekali tidak setuju dengan ini. Hanya dengan melihat dua contoh kode Anda, anggap ini tidak benar:
didengar untuk dibaca. "Keterbacaan" tidak berarti kepadatan informasi; itu berarti "mudah dibaca, dimengerti dan dipelihara".
Terkadang, kodenya sederhana dan masuk akal untuk menggunakan satu baris. Di waktu lain, melakukannya justru membuat lebih sulit untuk dibaca, karena tidak ada manfaat yang jelas selain menjejalkan lebih banyak ke satu baris.
Namun, saya juga meminta Anda untuk mengklaim bahwa "mudah mendiagnosis macet" berarti kode mudah dipelihara. Kode yang tidak macet jauh lebih mudah dipelihara. "Mudah dirawat" dicapai terutama melalui kode yang mudah dibaca dan dipahami, didukung dengan serangkaian tes otomatis yang bagus.
Jadi, jika Anda mengubah satu ekspresi menjadi multi-baris dengan banyak variabel hanya karena kode Anda sering macet dan Anda membutuhkan informasi debug yang lebih baik, maka berhentilah melakukan itu dan buatlah kodenya lebih kuat. Anda sebaiknya memilih menulis kode yang tidak perlu men-debug kode yang mudah di-debug.
sumber
F(G1(H1(b1), H2(b2)), G2(c1))
sulit dibaca, ini tidak ada hubungannya dengan dijejalkan terlalu padat. (Tidak yakin apakah Anda bermaksud mengatakan itu, tetapi bisa diartikan seperti ini.) Bersarang tiga atau empat fungsi dalam satu baris dapat dibaca dengan sempurna, khususnya jika beberapa fungsi adalah operator infiks sederhana. Ini adalah nama-nama nondeskriptif yang menjadi masalah di sini, tetapi masalah itu bahkan lebih buruk di versi multi-baris, di mana lebih banyak nama nondeskriptif diperkenalkan. Menambahkan hanya boilerplate hampir tidak pernah membantu keterbacaan.G1
dibutuhkan 3 parameter atau hanya 2 danG2
merupakan parameter lain untukF
. Saya harus menyipitkan mata dan menghitung tanda kurung.F (G1 (H1 b1) (H2 b2)) (G2 c1)
)result_h1
tidak dapat digunakan kembali jika tidak ada, dan pipa ledeng antara 4 variabel adalah jelas.Contoh pertama Anda, formulir penugasan tunggal, tidak dapat dibaca karena nama yang dipilih sama sekali tidak berarti. Itu mungkin artefak berusaha untuk tidak mengungkapkan informasi internal di pihak Anda, kode sebenarnya mungkin baik-baik saja dalam hal itu, kami tidak bisa mengatakannya. Bagaimanapun, ini bertele-tele karena kepadatan informasi yang sangat rendah, yang biasanya tidak mudah dipahami.
Contoh kedua Anda diringkas ke tingkat yang tidak masuk akal. Jika fungsi memiliki nama yang berguna, itu mungkin baik dan mudah dibaca karena tidak terlalu banyak , tetapi apa adanya membingungkan di arah lain.
Setelah memperkenalkan nama-nama yang bermakna, Anda mungkin melihat apakah salah satu dari bentuk-bentuk itu tampak alami, atau apakah ada tengah emas yang bisa diambil.
Sekarang setelah Anda memiliki kode yang dapat dibaca, sebagian besar bug akan terlihat jelas, dan yang lainnya setidaknya lebih sulit bersembunyi dari Anda.
sumber
Seperti biasa, dalam hal keterbacaan, kegagalan ada di titik ekstrem . Anda dapat mengambil setiap saran pemrograman yang baik, mengubahnya menjadi aturan agama, dan menggunakannya untuk menghasilkan kode benar-benar tidak terbaca. (Jika Anda tidak percaya saya di ini, memeriksa dua ini IOCCC pemenang borsanyi dan goren dan lihatlah betapa berbedanya mereka menggunakan fungsi untuk membuat kode benar-benar terbaca Petunjuk:. Borsanyi menggunakan tepat satu fungsi, Goren banyak lagi ...)
Dalam kasus Anda, dua ekstrem adalah 1) hanya menggunakan pernyataan ekspresi tunggal, dan 2) menggabungkan semuanya menjadi pernyataan besar, singkat, dan kompleks. Baik pendekatan yang diambil secara ekstrem membuat kode Anda tidak dapat dibaca.
Tugas Anda, sebagai seorang programmer, adalah untuk mencapai keseimbangan . Untuk setiap pernyataan yang Anda tulis, tugas Anda adalah menjawab pertanyaan: "Apakah pernyataan ini mudah dipahami, dan apakah itu berfungsi agar fungsi saya dapat dibaca?"
Intinya adalah, tidak ada kompleksitas pernyataan terukur tunggal yang dapat memutuskan, apa yang baik untuk dimasukkan dalam satu pernyataan. Ambil contoh baris:
Ini adalah pernyataan yang cukup kompleks, tetapi programmer mana pun yang sepadan dengan garam mereka harus dapat segera memahami apa yang dilakukannya. Ini adalah pola yang cukup terkenal. Dengan demikian, ini jauh lebih mudah dibaca daripada yang setara
yang memecah pola terkenal menjadi sejumlah langkah sederhana yang tampaknya tidak berarti. Namun, pernyataan dari pertanyaan Anda
tampaknya terlalu rumit bagi saya, meskipun satu operasi kurang dari perhitungan jarak . Tentu saja, itu konsekuensi langsung dari saya tidak tahu apa-apa tentang
F()
,G1()
,G2()
,H1()
, atauH2()
. Saya mungkin akan memutuskan secara berbeda jika saya tahu lebih banyak tentang mereka. Tapi justru itulah masalahnya: Kompleksitas yang disarankan dari sebuah pernyataan sangat tergantung pada konteksnya, dan pada operasi yang terlibat. Dan Anda, sebagai seorang programmer, adalah orang yang harus melihat konteks ini, dan memutuskan apa yang akan dimasukkan ke dalam satu pernyataan. Jika Anda peduli tentang keterbacaan, Anda tidak dapat menurunkan tanggung jawab ini ke beberapa aturan statis.sumber
@Dominique, saya pikir dalam analisis pertanyaan Anda, Anda membuat kesalahan bahwa "keterbacaan" dan "pemeliharaan" adalah dua hal yang terpisah.
Apakah mungkin memiliki kode yang dapat dikelola tetapi tidak dapat dibaca? Sebaliknya, jika kode sangat mudah dibaca, mengapa kode itu menjadi tidak dapat dipelihara karena dapat dibaca? Saya belum pernah mendengar ada programmer yang memainkan faktor-faktor ini terhadap satu sama lain, harus memilih satu atau yang lain!
Dalam hal memutuskan apakah akan menggunakan variabel perantara untuk panggilan fungsi bersarang, dalam kasus 3 variabel yang diberikan, panggilan ke 5 fungsi terpisah, dan beberapa panggilan bersarang 3 dalam, saya akan cenderung menggunakan setidaknya beberapa variabel perantara untuk memecahnya, seperti yang telah kamu lakukan.
Tapi saya tentu tidak pergi sejauh mengatakan panggilan fungsi tidak boleh bersarang sama sekali. Ini masalah penilaian dalam situasi seperti itu.
Saya akan mengatakan poin-poin berikut ada pada penghakiman:
Jika fungsi-fungsi yang disebut mewakili operasi matematika standar, mereka lebih mampu untuk disarangkan daripada fungsi yang mewakili beberapa logika domain yang tidak jelas yang hasilnya tidak dapat diprediksi dan tidak dapat dievaluasi secara mental oleh pembaca.
Fungsi dengan parameter tunggal lebih mampu berpartisipasi dalam sarang (baik sebagai fungsi dalam atau luar) daripada fungsi dengan beberapa parameter. Fungsi pencampuran berbagai arities pada tingkat sarang yang berbeda cenderung membuat kode tampak seperti telinga babi.
Sarang fungsi yang biasa dilihat oleh pemrogram diungkapkan dengan cara tertentu - mungkin karena ia merepresentasikan teknik atau persamaan matematika standar, yang memiliki implementasi standar - mungkin lebih sulit dibaca dan diverifikasi jika dipecah menjadi variabel perantara.
Sarang kecil panggilan fungsi yang melakukan fungsi sederhana dan sudah jelas dibaca, dan kemudian dipecah secara berlebihan dan dikabutkan, mampu menjadi lebih sulit dibaca daripada yang tidak rusak sama sekali.
sumber
Keduanya suboptimal. Pertimbangkan Komentar.
Atau fungsi spesifik daripada yang umum:
Saat memutuskan hasil mana yang harus dijabarkan, perlu diingat biaya (salinan vs referensi, nilai l vs nilai r), keterbacaan, dan risiko, secara terpisah untuk setiap pernyataan.
Misalnya, tidak ada nilai tambah dari memindahkan konversi unit / tipe sederhana ke baris mereka sendiri, karena ini mudah dibaca dan sangat tidak mungkin gagal:
Mengenai kekhawatiran Anda menganalisis crash dumps, validasi input biasanya jauh lebih penting - crash sebenarnya sangat mungkin terjadi di dalam fungsi-fungsi ini daripada garis memanggil mereka, dan bahkan jika tidak, Anda biasanya tidak perlu diberi tahu di mana tepatnya segalanya meledak. Jauh lebih penting untuk mengetahui di mana hal-hal mulai berantakan, daripada mengetahui di mana mereka akhirnya meledak, yang merupakan apa yang ditangkap validasi input.
sumber
Keterbacaan adalah bagian utama dari kemampuan pemeliharaan. Meragukan saya? Pilih proyek besar dalam bahasa yang Anda tidak tahu (baik bahasa pemrograman dan bahasa pemrogram), dan lihat bagaimana Anda akan melakukan refactoring ...
Saya akan menempatkan keterbacaan sebagai suatu tempat antara 80 dan 90 rawatan. 10-20 persen lainnya adalah seberapa setuju untuk refactoring.
Yang mengatakan, Anda secara efektif mengirimkan 2 variabel ke fungsi akhir Anda (F). 2 variabel tersebut dibuat menggunakan 3 variabel lain. Anda akan lebih baik melewati b1, b2 dan c1 ke F, jika F sudah ada, maka buat D yang melakukan komposisi untuk F dan mengembalikan hasilnya. Pada titik itu, hanya masalah memberi D nama yang bagus, dan tidak masalah gaya apa yang Anda gunakan.
Pada yang terkait tidak, Anda mengatakan bahwa lebih banyak logika pada halaman membantu keterbacaan. Itu tidak benar, metrik bukan halaman, itu metodenya, dan logika KURANG yang berisi metode, semakin mudah dibaca.
Dapat dibaca berarti bahwa programmer dapat menyimpan logika (input, output, dan algoritma) di kepala mereka. Semakin banyak, KURANG seorang programmer dapat memahaminya. Baca tentang kerumitan siklomatik.
sumber
Terlepas dari apakah Anda berada di C # atau C ++, selama Anda berada dalam build debug, solusi yang mungkin adalah membungkus fungsi
Anda dapat menulis ekspresi oneline, dan masih bisa diarahkan ke mana masalahnya hanya dengan melihat jejak stack.
Tentu saja, jika Anda memanggil fungsi yang sama beberapa kali di baris yang sama, Anda tidak dapat mengetahui fungsi yang mana, namun Anda masih dapat mengidentifikasinya:
Ini bukan peluru perak, tapi setengah jalan yang tidak terlalu buruk.
Belum lagi bahwa pembungkus grup fungsi bahkan dapat lebih bermanfaat untuk keterbacaan kode:
sumber
Menurut pendapat saya, kode dokumentasi diri lebih baik untuk pemeliharaan dan keterbacaan, terlepas dari bahasa.
Pernyataan yang diberikan di atas padat, tetapi "mendokumentasikan diri sendiri":
Ketika dipecah menjadi beberapa tahapan (lebih mudah untuk pengujian, tentunya) kehilangan semua konteks seperti yang dinyatakan di atas:
Dan jelas menggunakan nama variabel dan fungsi yang menyatakan tujuan mereka jelas sangat berharga.
Bahkan "jika" blok bisa baik atau buruk dalam mendokumentasikan diri. Ini buruk karena Anda tidak dapat dengan mudah memaksa 2 kondisi pertama untuk menguji yang ketiga ... semua tidak terkait:
Yang ini lebih masuk akal "kolektif" dan lebih mudah untuk menciptakan kondisi pengujian:
Dan pernyataan ini hanyalah serangkaian karakter acak, dilihat dari perspektif mendokumentasikan diri:
Melihat pernyataan di atas, rawatan masih merupakan tantangan besar jika fungsi H1 dan H2 keduanya mengubah "variabel status sistem" yang sama alih-alih disatukan menjadi fungsi "H" tunggal, karena seseorang akhirnya akan mengubah H1 tanpa berpikir ada H2 berfungsi untuk melihat dan bisa mematahkan H2.
Saya percaya desain kode yang baik sangat menantang karena tidak ada aturan yang sulit dan cepat yang dapat dideteksi dan ditegakkan secara sistematis.
sumber