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 ?
sumber
Jawaban:
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.
sumber
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.
sumber
Kutipan, yang sering dikaitkan dengan Albert Einstein, muncul di benak:
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 bahwax
seharusnya merupakan bilangan bulat. Tetapi jika saya katakanvar foo = value.Response;
, itu jauh kurang jelas apa yangfoo
mewakili 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.
sumber
var
contohnya 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 - misalnyaif ((x = Foo()) != (y = Bar()) && CheckResult(x, y))
membutuhkan waktu untuk melakukan grok, dan mengetahui jenisx
atauy
tidak membantu sedikit pun.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 :
sumber
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.
sumber
Itu sangat tergantung. Saya telah mengerjakan sebuah proyek yang tidak mengizinkan variabel boolean sebagai parameter fungsi, tetapi sebaliknya membutuhkan khusus
enum
untuk setiap opsi.Begitu,
jauh lebih banyak verbose daripada
Namun,
jauh lebih mudah dibaca daripada
Kompiler harus menghasilkan kode yang sama untuk keduanya, jadi tidak ada yang bisa diperoleh dengan menggunakan formulir yang lebih pendek.
sumber
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.
sumber
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.
sumber
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.
sumber
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).
sumber