Dalam kasus apa kode lebih sedikit tidak lebih baik? [Tutup]


55

Saya telah refactored beberapa kode di tempat kerja akhir-akhir ini, dan saya pikir saya melakukan pekerjaan dengan baik. Saya menurunkan 980 baris kode menjadi 450 dan mengurangi separuh jumlah kelas.

Ketika menunjukkan ini kepada kolega saya, beberapa tidak setuju bahwa ini adalah peningkatan.

Mereka berkata - "lebih sedikit baris kode belum tentu lebih baik"

Saya dapat melihat bahwa mungkin ada kasus ekstrim di mana orang menulis baris yang sangat panjang dan / atau meletakkan semuanya dalam satu metode untuk menyimpan beberapa baris, tetapi bukan itu yang saya lakukan. Kode ini menurut saya terstruktur dengan baik dan lebih mudah dipahami / dikelola karena ukurannya setengah.

Saya berjuang untuk melihat mengapa ada orang yang ingin bekerja dengan menggandakan kode yang diperlukan untuk mendapatkan pekerjaan, dan saya bertanya-tanya apakah ada yang merasa sama dengan rekan-rekan saya dan dapat membuat beberapa kasus yang baik untuk memiliki lebih banyak kode daripada lebih sedikit ?


145
Ukuran kode diukur dalam waktu Anda perlu membaca dan memahaminya, bukan garis atau jumlah karakter.
Bergi

13
Pertanyaan Anda sebagai tertulis terlalu luas. Rekomendasikan untuk menulis yang baru tentang perubahan spesifik yang Anda buat.
jpmc26

8
Pertimbangkan algoritma root kuadrat terbalik cepat . Menerapkan metode Newton penuh dengan penamaan variabel yang tepat akan jauh lebih jelas dan lebih mudah dibaca meskipun kemungkinan akan berisi lebih banyak baris kode. (Perhatikan bahwa dalam kasus khusus ini menggunakan kode pintar dibenarkan oleh karena masalah perf).
Maciej Piechotka

65
Ada seluruh situs pertukaran tumpukan yang didedikasikan untuk menjawab pertanyaan Anda: codegolf.stackexchange.com . :)
Federico Poloni

Jawaban:


123

Orang kurus belum tentu lebih sehat daripada orang gemuk.

Sebuah cerita anak-anak 980 baris lebih mudah dibaca daripada tesis fisika 450 baris.

Ada banyak atribut yang menentukan kualitas kode Anda. Beberapa hanya dihitung, seperti Kompleksitas Cyclomatik , dan Kompleksitas Halstead . Lainnya didefinisikan lebih longgar, seperti kohesi , keterbacaan, dapat dimengerti, perluasan, ketahanan, kebenaran, dokumentasi diri, kebersihan, testabilitas dan banyak lagi.

Misalnya, saat Anda mengurangi panjang keseluruhan kode - Anda memperkenalkan kompleksitas tambahan yang tidak beralasan dan membuat kode lebih samar.

Memisahkan potongan kode yang panjang menjadi metode-metode kecil bisa berbahaya seperti menguntungkan .

Mintalah kolega Anda untuk memberi Anda umpan balik spesifik mengapa mereka berpikir upaya refactoring Anda menghasilkan hasil yang tidak diinginkan.


1
@PiersyP hanya FYI, salah satu pedoman yang saya ajarkan tentang refactoring yang baik adalah kita harus melihat kompleksitas siklomatik dikurangi menjadi akar kuadrat dari apa yang semula.
MA Hanin

4
@PiersyP juga, saya tidak mengatakan bahwa kode Anda lebih buruk atau lebih baik daripada apa itu. Sebagai orang luar saya tidak bisa mengatakannya. Bisa jadi kolega Anda terlalu konservatif dan takut akan perubahan Anda hanya karena mereka tidak melakukan upaya yang diperlukan untuk meninjau dan memvalidasinya. Itu sebabnya saya menyarankan Anda meminta mereka untuk umpan balik tambahan.
MA Hanin

6
Kerja bagus, kawan - Anda telah menetapkan bahwa ada bobot "benar" di suatu tempat (angka pastinya mungkin berbeda). Bahkan postingan asli @Neil mengatakan "OVERweight" sebagai kebalikan dari "semakin berat seseorang", dan itu karena ADA sweet spot, sama halnya dengan pemrograman. Menambahkan kode di luar "ukuran yang tepat" itu hanya berantakan, dan menghapus garis di bawah titik itu hanya mengorbankan pemahaman demi singkatnya. Mengetahui di mana tepatnya titik itu berada ... ITU agak sulit.
AC

1
Hanya karena itu tidak perlu, tidak berarti itu tidak memiliki nilai.
Chris Wohlert

1
@Neil Secara umum Anda benar, tetapi "keseimbangan" yang selalu Anda singgung adalah mitos, secara objektif . Setiap orang memiliki gagasan berbeda tentang "keseimbangan yang baik". Jelas, OP mengira ia telah melakukan sesuatu yang baik, dan rekan kerjanya tidak, tetapi saya yakin mereka semua berpikir bahwa mereka memiliki "keseimbangan yang tepat" ketika mereka menulis kode.
code_dredd

35

Menariknya, seorang kolega dan saya saat ini berada di tengah-tengah refactor yang akan meningkatkan jumlah kelas dan fungsi sedikit kurang dari dua kali lipat, meskipun garis kode akan tetap sama. Jadi saya kebetulan punya contoh yang bagus.

Dalam kasus kami, kami memiliki satu lapisan abstraksi yang seharusnya adalah dua. Semuanya dijejalkan ke dalam lapisan ui. Dengan membaginya menjadi dua lapisan, semuanya menjadi lebih kohesif, dan menguji dan mempertahankan masing-masing bagian menjadi lebih sederhana.

Ini bukan ukuran kode yang mengganggu kolega Anda, itu sesuatu yang lain. Jika mereka tidak dapat mengartikulasikannya, cobalah untuk melihat kode itu sendiri seolah-olah Anda belum pernah melihat implementasi yang lama, dan mengevaluasinya sendiri dan bukan hanya sebagai perbandingan. Kadang-kadang ketika saya melakukan refactor panjang, saya agak kehilangan tujuan asli dan mengambil hal-hal yang terlalu jauh. Ambil tampilan "gambaran besar" yang kritis dan kembalikan ke jalurnya, mungkin dengan bantuan sepasang programmer yang sarannya Anda hargai.


1
Ya, jelas memisahkan UI dari hal lain, ini selalu bermanfaat. Pada titik Anda tentang kehilangan pandangan terhadap tujuan awal, saya agak setuju, tetapi Anda juga dapat mendesain ulang untuk sesuatu yang lebih baik, atau dalam perjalanan ke yang lebih baik. Seperti argumen lama tentang Evolusi ("apa gunanya bagian dari sayap?") Hal-hal tidak membaik jika Anda tidak pernah meluangkan waktu untuk memperbaikinya. Anda tidak selalu tahu ke mana Anda akan pergi sampai baik di jalan. Saya setuju dengan mencoba mencari tahu mengapa rekan kerja tidak nyaman, tetapi mungkin itu benar-benar "masalah mereka", bukan milik Anda.

17

Kutipan, yang sering dikaitkan dengan Albert Einstein, muncul di benak:

Buat semuanya sesederhana mungkin, tetapi tidak sederhana.

Ketika Anda berlebihan dalam memotong berbagai hal, itu bisa membuat kode lebih sulit dibaca. Karena "mudah / sulit dibaca" bisa menjadi istilah yang sangat subyektif, saya akan menjelaskan dengan tepat apa yang saya maksudkan dengan ini: ukuran tingkat kesulitan yang akan dimiliki pengembang yang terampil dalam menentukan "apa yang dilakukan kode ini?" dengan hanya melihat sumbernya, tanpa bantuan alat khusus.

Bahasa-bahasa seperti Java dan Pascal terkenal karena verbositasnya. Orang sering menunjuk ke elemen sintaksis tertentu dan dengan mengejek mengatakan bahwa "mereka ada di sana untuk membuat pekerjaan kompiler lebih mudah." Ini kurang lebih benar, kecuali untuk bagian "adil". Semakin jelas informasi yang ada, semakin mudah kodenya untuk dibaca dan dipahami, tidak hanya oleh kompiler tetapi juga oleh manusia.

Jika saya katakan var x = 2 + 2;, itu sudah jelas bahwa xseharusnya merupakan bilangan bulat. Tetapi jika saya katakan var foo = value.Response;, itu jauh kurang jelas apa yang foomewakili atau apa sifat dan kemampuannya. Bahkan jika kompilator dapat dengan mudah menyimpulkannya, ia menempatkan lebih banyak upaya kognitif pada seseorang.

Ingatlah bahwa program harus ditulis untuk dibaca orang, dan hanya secara kebetulan untuk dijalankan oleh mesin. (Ironisnya, kutipan ini berasal dari buku teks yang dikhususkan untuk bahasa terkenal karena sangat sulit dibaca!) Ini adalah ide yang baik untuk menghapus hal-hal yang berlebihan, tetapi jangan mengambil kode yang membuatnya lebih mudah bagi sesama manusia untuk mencari tahu apa yang terjadi, bahkan jika itu tidak sepenuhnya diperlukan untuk program yang sedang ditulis.


7
yang varcontohnya adalah tidak yang sangat baik dari penyederhanaan karena sebagian besar waktu membaca dan memahami kode melibatkan mencari tahu perilaku pada tingkat tertentu abstraksi, sehingga mengetahui jenis sebenarnya dari variabel tertentu biasanya tidak mengubah apa pun (hanya membantu Anda memahami abstraksi yang lebih rendah). Contoh yang lebih baik adalah beberapa baris kode sederhana yang digabungkan menjadi satu pernyataan yang berbelit-belit - misalnya if ((x = Foo()) != (y = Bar()) && CheckResult(x, y)) membutuhkan waktu untuk melakukan grok, dan mengetahui jenis xatau ytidak membantu sedikit pun.
Ben Cottrell

15

Kode yang lebih panjang mungkin lebih mudah dibaca. Biasanya sebaliknya, tetapi ada banyak pengecualian - beberapa di antaranya diuraikan dalam jawaban lain.

Tapi mari kita lihat dari sudut yang berbeda. Kami menganggap kode baru akan dianggap unggul oleh sebagian besar programmer yang terampil yang melihat 2 buah kode tanpa memiliki pengetahuan tambahan tentang budaya perusahaan, basis kode, atau peta jalan. Meski begitu, ada banyak alasan untuk menolak kode baru. Untuk singkatnya saya akan memanggil "Orang yang mengkritik kode baru" Pecritenc :

  • Stabilitas. Jika kode lama diketahui stabil, stabilitas kode baru tidak diketahui. Sebelum kode baru dapat digunakan, masih perlu diuji. Jika karena alasan tertentu pengujian yang tepat tidak tersedia, perubahannya adalah masalah yang agak besar. Bahkan jika pengujian tersedia, Pecritenc mungkin berpikir upaya itu tidak sebanding dengan perbaikan (kecil) dari kode.
  • Performa / penskalaan. Kode lama mungkin telah ditingkatkan dengan lebih baik, dan Pecritenc mengasumsikan bahwa kinerja akan menjadi masalah saat klien dan fitur segera * menumpuk.
  • Kemungkinan diperpanjang. Kode lama mungkin memudahkan pengenalan beberapa fitur yang diasumsikan oleh Pecritenc segera ditambahkan *.
  • Keakraban. Kode lama mungkin memiliki pola yang digunakan kembali yang digunakan di 5 tempat lain dari basis kode perusahaan. Pada saat yang sama, kode baru menggunakan pola mewah yang hanya separuh dari perusahaan yang pernah mendengarnya saat ini.
  • Lipstik pada babi. Pecritenc mungkin menganggap kode lama dan baru itu sampah, atau tidak relevan, sehingga membuat perbandingan apa pun di antara mereka tidak ada gunanya.
  • Kebanggaan. Pecritenc mungkin merupakan pembuat kode asli dan tidak suka orang membuat perubahan besar pada kodenya. Dia bahkan mungkin melihat perbaikan sebagai penghinaan ringan, karena itu menyiratkan bahwa dia seharusnya melakukan yang lebih baik.

4
+1 untuk 'Pecritenc', dan ringkasan yang sangat bagus dari keberatan yang masuk akal yang harus dipertimbangkan sebelumnya sebelum melakukan praaktivasi.

1
Dan +1 untuk 'ekstensibilitas' - Saya berpikir kode asli mungkin memiliki fungsi atau kelas yang dimaksudkan untuk digunakan dalam proyek masa depan, sehingga abstraksi mungkin tampak berlebihan atau tidak perlu tetapi hanya dalam konteks satu program.
Darren Ringer

Juga, kode yang dimaksud mungkin bukan kode kritis, jadi dianggap pemborosan sumber daya rekayasa untuk membersihkannya.
Erik Eidt

@nocomprende Apa alasan Anda menggunakan yang wajar, dipikirkan sebelumnya, dan prefaktoring? Metode yang mirip dengan Pecritenc mungkin?
Milind R

@MilindR Mungkin prasangka, kecenderungan, atau mungkin preferensi pribadi? Atau, mungkin hanya tanpa alasan sama sekali, pertemuan kosmik kofaktor, mengacaukan kondisi konspirasi. Tidak tahu, sungguh. Bagaimana dengan kamu?

1

Jenis kode apa yang lebih baik mungkin tergantung pada keahlian pemrogram dan juga pada alat yang mereka gunakan. Sebagai contoh, inilah mengapa apa yang biasanya dianggap sebagai kode yang ditulis dengan buruk mungkin lebih efektif dalam beberapa situasi daripada kode berorientasi objek yang ditulis dengan baik yang memanfaatkan warisan secara penuh:

(1) Beberapa programmer tidak memiliki pemahaman intuitif tentang pemrograman berorientasi objek. Jika metafora Anda untuk proyek perangkat lunak adalah rangkaian listrik, maka Anda akan mengharapkan banyak duplikasi kode. Anda akan suka melihat metode yang kurang lebih sama di banyak kelas. Mereka akan membuat Anda merasa di rumah. Dan sebuah proyek di mana Anda harus mencari metode di kelas orang tua atau bahkan di kelas kakek-nenek untuk melihat apa yang terjadi mungkin terasa bermusuhan. Anda tidak ingin memahami bagaimana kelas induk bekerja dan kemudian memahami bagaimana kelas saat ini berbeda. Anda ingin memahami secara langsung bagaimana kelas saat ini bekerja, dan Anda menemukan fakta bahwa informasi tersebar di beberapa file yang membingungkan.

Juga, ketika Anda hanya ingin memperbaiki masalah tertentu di kelas tertentu, Anda mungkin tidak suka harus memikirkan apakah akan memperbaiki masalah secara langsung di kelas dasar atau menimpa metode di kelas minat Anda saat ini. (Tanpa warisan Anda tidak perlu mengambil keputusan sadar. Standarnya adalah hanya mengabaikan masalah yang sama di kelas yang sama sampai mereka dilaporkan sebagai bug.) Aspek terakhir ini tidak benar-benar argumen yang valid, meskipun mungkin menjelaskan beberapa berlawanan.

(2) Beberapa programmer sering menggunakan debugger. Meskipun secara umum saya sendiri dengan kuat di sisi pewarisan kode dan mencegah duplikasi, saya berbagi beberapa frustrasi yang saya jelaskan dalam (1) ketika debugging kode berorientasi objek. Ketika Anda mengikuti eksekusi kode, kadang-kadang terus melompat-lompat di antara kelas (leluhur) meskipun tetap di objek yang sama. Juga, ketika menetapkan breakpoint dalam kode yang ditulis dengan baik, itu lebih cenderung untuk memicu ketika itu tidak membantu, jadi Anda mungkin harus menghabiskan upaya membuatnya bersyarat (jika praktis), atau bahkan secara manual terus berkali-kali sebelum pemicu yang relevan.


3
"Kelas kakek-nenek"! haw haw! Berhati-hatilah dengan kelas Adam dan Hawa. (Dan kelas Dewa tentu saja) Sebelum itu, itu tanpa bentuk, dan batal.

1

Itu sangat tergantung. Saya telah mengerjakan sebuah proyek yang tidak mengizinkan variabel boolean sebagai parameter fungsi, tetapi sebaliknya membutuhkan khusus enumuntuk setiap opsi.

Begitu,

enum OPTION1 { OPTION1_OFF, OPTION1_ON };
enum OPTION2 { OPTION2_OFF, OPTION2_ON };

void doSomething(OPTION1, OPTION2);

jauh lebih banyak verbose daripada

void doSomething(bool, bool);

Namun,

doSomething(OPTION1_ON, OPTION2_OFF);

jauh lebih mudah dibaca daripada

doSomething(true, false);

Kompiler harus menghasilkan kode yang sama untuk keduanya, jadi tidak ada yang bisa diperoleh dengan menggunakan formulir yang lebih pendek.


0

Saya akan mengatakan kohesi bisa menjadi masalah.

Misalnya dalam aplikasi web, Katakanlah Anda memiliki halaman Admin di mana Anda mengindeks semua produk, yang pada dasarnya adalah kode yang sama (indeks) seperti yang akan Anda gunakan dalam situasi beranda, untuk .. hanya mengindeks produk.

Jika Anda memutuskan untuk mem-parsialkan semuanya sehingga Anda dapat tetap KERING dan ramping, Anda harus menambahkan banyak kondisi mengenai apakah pengguna menjelajah adalah admin atau tidak dan mengacaukan kode dengan hal-hal yang tidak perlu yang akan membuatnya sangat tidak dapat dibaca dari katakanlah seorang perancang!

Jadi dalam situasi seperti ini bahkan jika kodenya hampir sama, hanya karena bisa menskalakan ke hal lain dan kasus penggunaan bisa sedikit berubah, akan lebih buruk untuk mengejar masing-masing dengan menambahkan kondisi dan seandainya. Jadi strategi yang baik adalah membuang konsep KERING dan memecah kode menjadi bagian yang dapat dipertahankan.


0
  • Ketika lebih sedikit kode tidak melakukan pekerjaan yang sama dengan lebih banyak kode. Refactoring untuk kesederhanaan itu baik, tetapi Anda harus berhati-hati untuk tidak menyederhanakan ruang masalah yang ditemui solusi ini. 980 baris kode mungkin menangani lebih banyak kasus sudut dari 450.
  • Ketika kode lebih sedikit tidak gagal anggun kode lebih banyak. Saya telah melihat beberapa pekerjaan "ref *** toring" dilakukan pada kode untuk menghapus "tidak perlu" try-catch dan penanganan kasus kesalahan lainnya. Hasil yang tak terhindarkan adalah bukannya menampilkan kotak dialog dengan pesan yang bagus tentang kesalahan dan apa yang bisa dilakukan pengguna, aplikasi macet atau YSODed.
  • Ketika lebih sedikit kode kurang dapat dipelihara / extensible dari lebih banyak kode. Refactoring untuk keringkasan kode sering menghilangkan konstruksi kode yang "tidak perlu" untuk kepentingan LoC. Masalahnya adalah, konstruksi kode tersebut, seperti deklarasi antarmuka paralel, metode / subkelas yang diekstraksi dll diperlukan jika kode ini perlu melakukan lebih dari yang dilakukannya saat ini, atau melakukannya secara berbeda. Secara ekstrim, solusi tertentu yang dibuat khusus untuk masalah spesifik mungkin tidak berfungsi sama sekali jika definisi masalah berubah sedikit.

    Satu contoh; Anda memiliki daftar bilangan bulat. Masing-masing bilangan bulat ini memiliki nilai duplikat dalam daftar, kecuali satu. Algoritme Anda harus menemukan nilai tidak berpasangan itu. Solusi kasus umum adalah membandingkan setiap angka terhadap setiap angka lainnya hingga Anda menemukan nomor yang tidak memiliki dupe dalam daftar, yang merupakan operasi N ^ 2 kali. Anda juga bisa membuat histogram menggunakan hashtable, tapi itu sangat tidak efisien ruang. Namun, Anda dapat membuatnya waktu linear dan ruang konstan dengan menggunakan operasi XOR bitwise; XOR setiap integer terhadap "total" yang berjalan (dimulai dengan nol), dan pada akhirnya, jumlah yang berjalan akan menjadi nilai integer tidak berpasangan Anda. Sangat elegan. Sampai persyaratan berubah, dan lebih dari satu nomor dalam daftar bisa tidak berpasangan, atau bilangan bulat termasuk nol. Sekarang program Anda mengembalikan hasil sampah atau ambigu (jika mengembalikan nol, apakah itu berarti semua elemen dipasangkan, atau bahwa elemen yang tidak berpasangan adalah nol?). Tersebut adalah masalah implementasi "pintar" dalam pemrograman dunia nyata.

  • Ketika lebih sedikit kode kurang mendokumentasikan diri dari lebih banyak kode. Mampu membaca kode itu sendiri dan menentukan apa yang dilakukannya sangat penting untuk pengembangan tim. Memberikan algoritma brain-f *** yang Anda tulis yang berkinerja bagus untuk pengembang junior dan memintanya untuk mengubah sedikit perubahan output tidak akan membuat Anda terlalu jauh. Banyak dev senior yang akan mengalami masalah dengan situasi itu juga. Mampu memahami kapan saja kode apa yang dilakukan, dan apa yang salah dengan itu, adalah kunci untuk lingkungan pengembangan tim kerja (dan bahkan solo; saya jamin Anda bahwa kilasan kejeniusan yang Anda miliki ketika Anda menulis 5 Metode-line untuk menyembuhkan kanker akan lama hilang ketika Anda kembali ke fungsi itu untuk membuatnya menyembuhkan Parkinson juga.)

0

Kode komputer perlu melakukan beberapa hal. Kode "minimalis" yang tidak melakukan hal-hal ini bukanlah kode yang baik.

Misalnya, program komputer harus mencakup semua kemungkinan (atau minimal, semua kasus yang mungkin). Jika sepotong kode hanya mencakup satu "kasus dasar" dan mengabaikan yang lain, itu bukan kode yang baik, meskipun singkat.

Kode komputer harus "scalable." Kode cryptic dapat berfungsi hanya untuk satu aplikasi khusus, sementara yang lebih lama, tetapi program yang lebih terbuka dapat membuatnya lebih mudah untuk ditambahkan pada aplikasi baru.

Kode komputer harus jelas. Seperti yang ditunjukkan penjawab lain, adalah mungkin bagi hard-core coder untuk menghasilkan fungsi tipe "algoritmik" satu baris yang berfungsi. Tetapi kalimat satu baris harus dipecah menjadi lima "kalimat" yang berbeda sebelum jelas bagi programmer rata-rata.


Tugas ada di mata yang melihatnya.

-2

Kinerja komputasi. Ketika mengoptimalkan pipa-lining atau menjalankan bagian dari kode Anda secara paralel mungkin bermanfaat, misalnya tidak loop dari 1 hingga 400, tetapi dari 1 hingga 50 dan menempatkan 8 contoh kode yang serupa di setiap loop. Saya tidak berasumsi ini adalah kasus dalam situasi Anda, tetapi ini adalah contoh di mana lebih banyak garis lebih baik (berdasarkan kinerja).


4
Kompiler yang baik harus tahu lebih baik daripada programmer rata-rata bagaimana membuka gulungan untuk arsitektur komputer tertentu, tetapi titik umum valid. Saya pernah melihat kode sumber untuk matriks multiply rutin dari perpustakaan kinerja tinggi Cray. Multiply matriks adalah tiga loop bersarang dan sekitar 6 baris kode secara total, bukan? Salah - rutinitas perpustakaan berlari ke sekitar 1100 baris kode, ditambah jumlah baris komentar yang sama menjelaskan mengapa begitu lama!
alephzero

1
@ alephzero wow, saya akan senang melihat kode itu, pasti hanya Cray Cray.

@ alephzero, kompiler yang baik dapat melakukan banyak hal, tetapi sayangnya tidak semuanya. Sisi baiknya adalah hal-hal itulah yang membuat pemrograman tetap menarik!
Hans Janssen

2
@alephzero Memang, kode perkalian matriks yang baik tidak hanya mencukur sedikit waktu istirahat (yaitu menguranginya dengan faktor konstan), ia menggunakan algoritma yang sama sekali berbeda dengan kompleksitas asimtotik yang berbeda misalnya algoritma Strassen kira-kira O (n ^ 2.8) daripada O (n ^ 3).
Arthur Tacca
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.