Keterbacaan versus kemudahan pemeliharaan, kasus khusus penulisan panggilan fungsi bersarang

57

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 #.

Dominique
sumber
17
@gnat: Anda merujuk pada pertanyaan umum, sementara saya secara khusus tertarik pada kasus pemanggilan fungsi bersarang dan konsekuensi dalam kasus analisis dump dump, tetapi terima kasih atas tautannya, ini berisi beberapa informasi menarik.
Dominique
9
Perhatikan bahwa jika contoh ini diterapkan ke C ++ (seperti yang Anda sebutkan ini sedang digunakan dalam proyek Anda) maka ini bukan hanya masalah gaya, karena urutan evaluasi HXdan GXpermintaan 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.
dfri
4
Apakah nama variabel result_g1yang benar-benar Anda gunakan atau nilai ini benar-benar mewakili sesuatu dengan nama yang masuk akal; mis percentageIncreasePerSecond. Itu sebenarnya akan menjadi ujian saya untuk memutuskan di antara keduanya
Richard Tingle
3
Terlepas dari perasaan Anda pada gaya pengkodean, Anda harus mengikuti konvensi yang sudah ada kecuali itu jelas salah (sepertinya tidak ada dalam kasus ini).
n00b
4
@ t3chb0t Anda bebas memilih apa pun yang Anda suka, tetapi harap diperhatikan untuk mendorong pertanyaan yang baik, bermanfaat, sesuai topik di situs ini (dan mengecilkan yang buruk), bahwa tujuan menjawab pertanyaan dengan suara naik atau turun adalah untuk menunjukkan apakah suatu pertanyaan bermanfaat dan jelas, sehingga memberikan suara untuk alasan lain seperti menggunakan suara sebagai sarana untuk memberikan kritik pada beberapa contoh kode yang diposting untuk membantu konteks pertanyaan umumnya tidak membantu dalam menjaga kualitas situs : softwareengineering.stackexchange.com/help/privileges/vote-down
Ben Cottrell

Jawaban:

111

Jika Anda merasa harus memperluas satu liner seperti

 a = F(G1(H1(b1), H2(b2)), G2(c1));

Aku tidak akan menyalahkanmu. Itu tidak hanya sulit dibaca, tetapi juga sulit untuk di-debug.

Mengapa?

  1. Ini padat
  2. Beberapa debugger hanya akan menyoroti semuanya sekaligus
  3. Ini bebas dari nama deskriptif

Jika Anda mengembangkannya dengan hasil menengah yang Anda dapatkan

 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);

dan masih sulit dibaca. Mengapa? Ini memecahkan dua masalah dan memperkenalkan yang keempat:

  1. Ini padat
  2. Beberapa debugger hanya akan menyoroti semuanya sekaligus
  3. Ini bebas dari nama deskriptif
  4. Itu berantakan dengan nama-nama non-deskriptif

Jika Anda mengembangkannya dengan nama yang menambahkan makna baru, bagus, semantik, bahkan lebih baik! Nama yang bagus membantu saya mengerti.

 var temperature = H1(b1);
 var humidity = H2(b2);
 var precipitation = G1(temperature, humidity);
 var dewPoint = G2(c1);
 var forecast = F(precipitation, dewPoint);

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_thisdan result_thatkarena 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:

int a = 
    F(
        G1(
            H1(b1), 
            H2(b2)
        ), 
        G2(c1)
    )
;

Ini hanya bisa dibaca, jika tidak lebih, dari yang dengan nama hasil yang tidak berarti (bukan bahwa nama-nama fungsi ini sehebat itu).

  1. Ini padat
  2. Beberapa debugger hanya akan menyoroti semuanya sekaligus
  3. Ini bebas dari nama deskriptif
  4. Itu berantakan dengan nama-nama non-deskriptif

Ketika 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:

masukkan deskripsi gambar di sini

Jika itu tidak cukup, bayangkan G2()dipanggil di lebih dari satu tempat dan kemudian ini terjadi:

Exception in thread "main" java.lang.NullPointerException
    at composition.Example.G2(Example.java:34)
    at composition.Example.main(Example.java:18)

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:

var user = db.t_ST_User.Where(_user => string.Compare(domain,  
_user.domainName.Trim(), StringComparison.OrdinalIgnoreCase) == 0)
.Where(_user => string.Compare(samAccountName, _user.samAccountName.Trim(), 
StringComparison.OrdinalIgnoreCase) == 0).Where(_user => _user.deleted == false)
.FirstOrDefault();

Aku benci melihat aliran suara itu, bahkan ketika pembungkus kata tidak diperlukan. Begini tampilannya di bawah gaya ini:

var user = db
    .t_ST_User
    .Where(
        _user => string.Compare(
            domain, 
            _user.domainName.Trim(), 
            StringComparison.OrdinalIgnoreCase
        ) == 0
    )
    .Where(
        _user => string.Compare(
            samAccountName, 
            _user.samAccountName.Trim(), 
            StringComparison.OrdinalIgnoreCase
        ) == 0
    )
    .Where(_user => _user.deleted == false)
    .FirstOrDefault()
;

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.

candied_orange
sumber
20
@Steve dan saya tidak memberitahu Anda untuk tidak melakukannya. Saya memohon nama yang bermakna. Semua sering saya melihat gaya menengah dilakukan tanpa berpikir. Nama-nama buruk membakar otak saya jauh melebihi kode jarang per baris. Saya tidak membiarkan pertimbangan lebar atau panjang memotivasi saya untuk membuat kode saya padat atau nama saya pendek. Saya membiarkan mereka memotivasi saya untuk membusuk lebih banyak. Jika nama baik tidak akan terjadi, pertimbangkan ini untuk menghindari kebisingan yang tidak berarti.
candied_orange
6
Saya menambahkan ke posting Anda: Saya punya sedikit aturan: Jika Anda tidak dapat memberi nama, itu mungkin tanda bahwa itu tidak didefinisikan dengan baik. Saya menggunakannya pada entitas, properti, variabel, modul, menu, kelas pembantu, metode, dll. Dalam banyak situasi aturan kecil ini telah mengungkapkan kesalahan serius dalam desain. Jadi, penamaan yang baik tidak hanya berkontribusi pada keterbacaan dan pemeliharaan, ini membantu Anda memverifikasi desain. Tentu saja ada pengecualian untuk setiap aturan sederhana.
Alireza
4
Versi yang diperluas terlihat jelek. Ada terlalu banyak ruang putih di sana yang mengurangi sefektivene karena semua yang dihadapinya tidak ada, artinya tidak ada.
Mateen Ulhaq
5
@MateenUlhaq Satu-satunya ruang kosong tambahan ada beberapa baris baru dan beberapa lekukan, dan semuanya ditempatkan dengan hati-hati pada batas yang berarti . Sebaliknya komentar Anda menempatkan spasi kosong pada batas yang tidak bermakna. Saya sarankan Anda melihat lebih dekat dan lebih terbuka.
jpmc26
3
Tidak seperti @MateenUlhaq, saya berada di pagar tentang spasi putih dalam contoh khusus ini dengan nama-nama fungsi seperti itu, tetapi dengan nama fungsi nyata (yang panjangnya lebih dari dua karakter, bukan?) Bisa jadi itu yang saya inginkan.
Lightness Races dengan Monica
50

Di sisi lain, semakin banyak pemrosesan yang Anda lakukan pada satu baris, semakin banyak logika yang Anda dapatkan pada satu halaman, yang meningkatkan keterbacaan.

Saya sama sekali tidak setuju dengan ini. Hanya dengan melihat dua contoh kode Anda, anggap ini tidak benar:

var a = F(G1(H1(b1), H2(b2)), G2(c1));

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.

David Arno
sumber
37
Sementara saya setuju itu 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.
leftaroundabout
23
@leftaroundabout: Bagi saya, kesulitannya adalah tidak jelas apakah G1dibutuhkan 3 parameter atau hanya 2 dan G2merupakan parameter lain untuk F. Saya harus menyipitkan mata dan menghitung tanda kurung.
Matthieu M.
4
@ MatthieuM. ini bisa menjadi masalah, meskipun jika fungsinya terkenal sering kali jelas yang membutuhkan berapa banyak argumen. Secara khusus, seperti yang saya katakan, untuk fungsi infix segera jelas bahwa mereka mengambil dua argumen. (Juga, sintaks-kurung tupel yang digunakan sebagian besar bahasa memperparah masalah ini; dalam bahasa yang lebih memilih Currying secara otomatis lebih jelas:. F (G1 (H1 b1) (H2 b2)) (G2 c1))
leftaroundabout
5
Secara pribadi saya lebih suka bentuk yang lebih kompak, asalkan ada styling di sekitarnya seperti di komentar saya sebelumnya, karena itu menjamin lebih sedikit keadaan untuk melacak secara mental - result_h1tidak dapat digunakan kembali jika tidak ada, dan pipa ledeng antara 4 variabel adalah jelas.
Izkata
8
Saya telah menemukan bahwa kode yang mudah di-debug umumnya adalah kode yang tidak perlu di-debug.
Rob K
25

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.

Deduplicator
sumber
17

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:

double d = sqrt(square(x1 - x0) + square(y1 - y0));

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

double dx = x1 - x0;
double dy = y1 - y0;
double dxSquare = square(dx);
double dySquare = square(dy);
double dSquare = dxSquare + dySquare;
double d = sqrt(dSquare);

yang memecah pola terkenal menjadi sejumlah langkah sederhana yang tampaknya tidak berarti. Namun, pernyataan dari pertanyaan Anda

var a = F(G1(H1(b1), H2(b2)), G2(c1));

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(), atau H2(). 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.

cmaster
sumber
14

@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:

  1. 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.

  2. 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.

  3. 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.

  4. 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.

Steve
sumber
3
+1 ke "Apakah mungkin memiliki kode yang dapat dikelola tetapi tidak dapat dibaca?". Itu juga pikiran pertama saya.
RonJohn
4

Keduanya suboptimal. Pertimbangkan Komentar.

// Calculating torque according to Newton/Dominique, 4th ed. pg 235
var a = F(G1(H1(b1), H2(b2)), G2(c1));

Atau fungsi spesifik daripada yang umum:

var a = Torque_NewtonDominique(b1,b2,c1);

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:

var radians = ExtractAngle(c1.Normalize())
var a = Torque(b1.ToNewton(),b2.ToMeters(),radians);

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.

Peter
sumber
Kembali biaya melewati argumen: Ada dua aturan optimasi. 1) Jangan. 2) (hanya untuk ahli) Jangan dulu .
RubberDuck
1

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.

jmoreno
sumber
1
Saya setuju dengan semua yang Anda katakan tentang keterbacaan. Tapi saya tidak setuju bahwa cracking operasi logis menjadi metode yang terpisah, tentu membuatnya lebih mudah dibaca daripada cracking menjadi baris yang terpisah (kedua teknik yang dapat , ketika digunakan secara berlebihan, membuat logika sederhana kurang mudah dibaca, dan membuat seluruh program lebih berantakan) - jika Anda memecahkan hal-hal yang terlalu jauh ke dalam metode, Anda akhirnya meniru makro bahasa rakitan dan lupa bagaimana mereka mengintegrasikan secara keseluruhan. Juga, dalam metode terpisah ini, Anda masih akan dihadapkan dengan masalah yang sama: membuat panggilan, atau memecahnya menjadi variabel perantara.
Steve
@Steve: Saya tidak mengatakan untuk selalu melakukannya, tetapi jika Anda berpikir tentang menggunakan 5 baris untuk mendapatkan nilai tunggal, ada peluang bagus bahwa suatu fungsi akan lebih baik. Adapun beberapa baris vs garis kompleks: jika itu fungsi dengan nama baik keduanya akan bekerja sama baiknya.
jmoreno
1

Terlepas dari apakah Anda berada di C # atau C ++, selama Anda berada dalam build debug, solusi yang mungkin adalah membungkus fungsi

var a = F(G1(H1(b1), H2(b2)), G2(c1));

Anda dapat menulis ekspresi oneline, dan masih bisa diarahkan ke mana masalahnya hanya dengan melihat jejak stack.

returnType F( params)
{
    returnType RealF( params);
}

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:

  • Melihat parameter fungsi
  • Jika parameter identik dan fungsi tidak memiliki efek samping, maka dua panggilan identik menjadi 2 panggilan identik, dll.

Ini bukan peluru perak, tapi setengah jalan yang tidak terlalu buruk.

Belum lagi bahwa pembungkus grup fungsi bahkan dapat lebih bermanfaat untuk keterbacaan kode:

type CallingGBecauseFTheorem( T b1, C b2)
{
     return G1( H1( b1), H2( b2));
}

var a = F( CallingGBecauseFTheorem( b1,b2), G2( c1));
GameDeveloper
sumber
1

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":

double d = sqrt(square(x1 - x0) + square(y1 - y0));

Ketika dipecah menjadi beberapa tahapan (lebih mudah untuk pengujian, tentunya) kehilangan semua konteks seperti yang dinyatakan di atas:

double dx = x1 - x0;
double dy = y1 - y0;
double dxSquare = square(dx);
double dySquare = square(dy);
double dSquare = dxSquare + dySquare;
double d = sqrt(dSquare);

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:

if (Bill is the boss) && (i == 3) && (the carnival is next weekend)

Yang ini lebih masuk akal "kolektif" dan lebih mudah untuk menciptakan kondisi pengujian:

if (iRowCount == 2) || (iRowCount == 50) || (iRowCount > 100)

Dan pernyataan ini hanyalah serangkaian karakter acak, dilihat dari perspektif mendokumentasikan diri:

var a = F(G1(H1(b1), H2(b2)), G2(c1));

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.

Ozymandias
sumber