Bersihkan kode yang dapat dibaca vs kode yang sulit dibaca dengan cepat. Kapan harus melewati batas?

67

Ketika saya menulis kode, saya selalu berusaha membuat kode saya sebersih dan semudah mungkin dibaca.

Kadang-kadang ada saatnya Anda harus melewati batas dan beralih dari kode bersih yang bagus ke kode yang sedikit lebih buruk untuk membuatnya lebih cepat.

Kapan boleh melewati batas itu?

Ken Cochrane
sumber
69
Anda menjawab pertanyaan Anda sendiri, Anda melewati batas ketika Anda harus melewati batas
gnibbler
6
Juga, "kode kotor" Anda dapat bekerja secepat "kode bersih" pada perangkat keras 6 bulan dari sekarang. Namun, jangan berlebihan seperti Windows. :)
Mateen Ulhaq
21
Ada perbedaan yang signifikan antara algoritma yang sulit dipahami, dan kode yang sulit dipahami. Kadang-kadang algoritma yang Anda butuhkan untuk mengimplementasikannya rumit, dan kodenya akan membingungkan, hanya karena mengekspresikan ide yang kompleks. Tetapi jika kode itu sendiri adalah titik yang sulit, maka kode itu harus diperbaiki.
tylerl
8
Dalam banyak kasus, kompiler / juru bahasa pintar dapat mengoptimalkan kode yang bersih dan mudah dibaca sehingga memiliki kinerja yang sama dengan kode "jelek". Jadi ada sedikit alasan, kecuali profil mengatakan sebaliknya.
Dan Diplo
1
Ketika datang ke kompiler hari ini, kode jelek Anda kemungkinan besar akan sama dengan kode bersih Anda (dengan asumsi Anda tidak melakukan hal-hal yang sangat aneh). Terutama di .NET, tidak seperti hari C ++ / MFC di mana cara Anda mendefinisikan variabel Anda akan berdampak pada kinerja. Tulis kode yang bisa dipelihara. beberapa kode hanya akan menjadi rumit tetapi itu tidak berarti itu jelek.
DustinDavis

Jawaban:

118

Anda melewati batas kapan

  • Anda telah mengukur bahwa kode Anda terlalu lambat untuk penggunaan yang dimaksudkan .
  • Anda telah mencoba perbaikan alternatif yang tidak memerlukan penyiapan kode.

Berikut ini adalah contoh dunia nyata: sistem eksperimental yang saya jalankan menghasilkan data terlalu lambat, mengambil lebih dari 9 jam per proses dan hanya menggunakan 40% dari CPU. Daripada mengacaukan kode terlalu banyak, saya memindahkan semua file sementara ke sistem file dalam memori. Menambahkan 8 baris baru kode non-jelek, dan sekarang utilisasi CPU di atas 98%. Masalah terpecahkan; tidak perlu kejelekan.

Norman Ramsey
sumber
2
Anda juga memastikan Anda menyimpan kode asli, lebih lambat, dan lebih bersih, baik sebagai implementasi referensi dan untuk kembali aktif ketika perangkat keras berubah dan kode peretasan Anda yang lebih cepat dan peretasan tidak lagi berfungsi.
Paul R
4
@ PaulR Bagaimana Anda menyimpan kode itu? Dalam bentuk komentar? Itu salah, imo - komentar sudah ketinggalan zaman, tidak ada yang membacanya, dan secara pribadi jika saya melihat kode komentar saya biasanya menghapusnya - ini adalah untuk apa sumber kontrol. Komentar tentang metode yang menjelaskan apa yang dilakukannya lebih baik, imo.
Evgeni
5
@Eugene: Saya biasanya menyimpan versi asli dari suatu rutin yang dinamai foodan menamainya foo_ref- biasanya tinggal tepat foodi atas dalam file sumber. Dalam uji harness saya, saya memanggil foodan foo_refuntuk validasi dan pengukuran kinerja relatif.
Paul R
5
@ Paul jika Anda melakukan itu mungkin ide yang baik untuk gagal tes jika versi yang dioptimalkan pernah lebih lambat daripada fungsi ref. ini bisa terjadi jika asumsi yang Anda buat untuk membuatnya lebih cepat tidak lagi benar.
user1852503
58

Ini dikotomi yang salah. Anda dapat membuat kode dengan cepat dan mudah dirawat.

Cara Anda melakukannya adalah menulisnya bersih, terutama dengan struktur data sesederhana mungkin.

Kemudian Anda mencari tahu di mana waktu pengeringan (dengan menjalankannya, setelah Anda menulisnya, bukan sebelumnya), dan memperbaikinya satu per satu. (Ini sebuah contoh.)

Ditambahkan: Kami selalu mendengar tentang pengorbanan, benar, seperti pengorbanan antara waktu dan memori, atau pengorbanan antara kecepatan dan rawatan? Meskipun kurva seperti itu mungkin ada, tidak boleh diasumsikan bahwa program tertentu ada pada kurva , atau bahkan di dekat itu.

Program apa pun yang ada di kurva dapat dengan mudah (dengan memberikannya kepada programmer jenis tertentu) dibuat jauh lebih lambat, dan jauh lebih sedikit perawatannya, dan kemudian tidak akan berada di dekat kurva. Program seperti itu kemudian memiliki banyak ruang untuk dibuat lebih cepat dan lebih dapat dipelihara.

Dalam pengalaman saya, di situlah banyak program dimulai.

Mike Dunlavey
sumber
Saya setuju. Memang kode cepat yang tidak bersih pada akhirnya akan semakin lambat karena Anda tidak dapat memodifikasinya dengan benar.
edA-qa mort-ora-y
22
Saya tidak setuju itu adalah dikotomi yang salah; IMO ada skenario terutama dalam kode perpustakaan (tidak begitu banyak dalam kode aplikasi ) di mana perpecahannya sangat nyata. Lihat jawaban saya untuk lebih lanjut.
Marc Gravell
1
Marc, Anda dapat menautkan ke jawaban dalam komentar dengan URL "tautan". programmers.stackexchange.com/questions/89620/…
Kami telah menemukan semua waktu yang kami butuhkan untuk mencoba dan membuat kode lebih cepat. Tetapi setelah bereksperimen dengan profiler untuk menemukan solusi terbaik (jika kodenya jelek) ini tidak berarti kodenya harus tetap jelek. Ini adalah masalah menemukan solusi terbaik yang mungkin awalnya tidak tampak jelas tetapi sekali ditemukan biasanya dapat dikodekan dengan bersih. Jadi saya percaya itu adalah dikotomi palsu dan hanya alasan untuk tidak merapikan kamar Anda setelah Anda bersenang-senang dengan mainan Anda. Saya katakan menyedot dan merapikan kamar Anda.
Martin York
Saya tidak setuju itu dikotomi palsu. Karena saya melakukan banyak pekerjaan grafis, contoh yang paling jelas bagi saya adalah di loop grafis yang ketat: Saya tidak tahu seberapa sering ini masih dilakukan, tetapi dulu umum untuk mesin permainan yang ditulis dalam C menggunakan Majelis untuk rendering inti loop untuk memeras setiap tetes kecepatan terakhir. Itu juga membuat saya berpikir tentang situasi di mana Anda memprogram dengan Python tetapi menggunakan modul yang ditulis dalam C ++. "Sulit dibaca" selalu relatif; setiap kali Anda beralih ke bahasa tingkat rendah untuk kecepatan, kode itu lebih sulit dibaca daripada yang lain.
jhocking
31

Dalam keberadaan OSS saya, saya melakukan banyak pekerjaan perpustakaan yang bertujuan untuk kinerja, yang sangat terkait dengan struktur data pemanggil (yaitu eksternal ke perpustakaan), dengan (dengan desain) tidak ada mandat atas jenis yang masuk. Di sini, cara terbaik untuk membuat ini performant adalah meta-programming, yang (karena saya di NET-tanah) berarti IL-memancarkan. Itu adalah beberapa kode jelek, jelek, tapi sangat cepat.

Dengan cara ini, saya dengan senang hati menerima kode perpustakaan mungkin "lebih jelek" daripada kode aplikasi , hanya karena ia memiliki lebih sedikit (atau mungkin tidak ada) kontrol atas input , sehingga perlu mencapai beberapa tugas melalui mekanisme yang berbeda. Atau seperti yang saya ungkapkan kemarin:

"coding di atas tebing kegilaan, jadi kamu tidak perlu "

Sekarang kode aplikasi sedikit berbeda, karena di situlah pengembang "biasa" (waras) biasanya menginvestasikan banyak waktu kolaboratif / profesional mereka; tujuan dan harapan masing-masing (IMO) sedikit berbeda.

IMO, jawaban di atas yang menyarankan itu bisa cepat dan mudah dipelihara mengacu pada kode aplikasi di mana pengembang memiliki kontrol lebih besar atas struktur data, dan tidak menggunakan alat seperti meta-programming. Yang mengatakan, ada berbagai cara melakukan pemrograman meta, dengan berbagai tingkat kegilaan dan berbagai tingkat overhead. Bahkan di arena itu Anda harus memilih level abstraksi yang sesuai. Tetapi ketika Anda secara aktif, positif, benar-benar ingin itu menangani data tak terduga dengan cara tercepat mutlak; itu bisa jadi jelek. Menghadapinya; hlm

Marc Gravell
sumber
4
Hanya karena kodenya jelek, bukan berarti harus dipelihara. Komentar dan lekukan gratis, dan kode jelek biasanya dapat dienkapsulasi menjadi entitas yang dapat dikelola (kelas, modul, paket, fungsi, tergantung pada bahasanya). Kode mungkin sama jeleknya, tetapi setidaknya orang akan dapat menilai dampak dari perubahan yang akan mereka buat terhadapnya.
tdammers
6
@Dammers memang, dan saya mencoba melakukannya sejauh mungkin; tapi ini agak seperti memakai lipstik pada babi.
Marc Gravell
1
Yah, mungkin orang harus membuat perbedaan antara sintaksis jelek dan algoritma jelek - kadang-kadang algoritma jelek diperlukan, tetapi sintaksis jelek biasanya IMO yang tidak bisa dimaafkan.
Pelaku
4
@IMO sintaks jelek cukup tidak dapat dihindari jika apa yang Anda lakukan adalah sifat beberapa tingkat abstraksi di bawah tingkat bahasa yang biasa.
Marc Gravell
1
@marc ... itu menarik. Reaksi pertama saya terhadap meta / abstrak menjadi jelek adalah kecurigaan tentang bahasa / bentuk plat yang tidak kondusif untuk meta coding daripada beberapa hukum dasar yang menghubungkan keduanya. Hal yang membuat saya percaya itu adalah contoh dari metalevel progresif dalam matematika yang berakhir dengan teori-set yang ekspresinya hampir tidak jelek daripada aljabar atau bahkan aritmatika konkret. Tapi kemudian set-notasi mungkin bahasa yang berbeda sama sekali dan setiap tingkat abstration bawah memiliki bahasa sendiri ....
explorest
26

Ketika Anda telah membuat profil kode dan memverifikasi bahwa itu sebenarnya menyebabkan pelambatan yang signifikan.

Joel Rein
sumber
3
Dan apa yang "signifikan"?
Benteng
2
@ hotpaw2: ini adalah jawaban yang cerdas - mengasumsikan pengembang setidaknya kompeten. Kalau tidak ya, menggunakan sesuatu yang lebih cepat daripada semacam gelembung adalah (biasanya) ide yang bagus. Tetapi terlalu sering seseorang akan (untuk menyortir) menukar quicksort untuk heapsort dengan selisih 1%, hanya untuk melihat orang lain menukarnya kembali enam bulan kemudian dengan alasan yang sama.
1
Tidak pernah ada alasan untuk membuat kode tidak bersih. Jika Anda tidak dapat membuat kode efisien Anda bersih dan mudah dirawat, Anda melakukan sesuatu yang salah.
edA-qa mort-ora-y
2
@ SF. - pelanggan akan selalu merasa terlalu lambat, jika bisa lebih cepat. Dia tidak peduli dengan "bersih" dari kode.
Benteng
1
@Rook: Pelanggan mungkin menganggap kode antarmuka (sepele) terlalu lambat. Beberapa trik psikologis yang cukup sederhana meningkatkan pengalaman pengguna tanpa benar-benar mempercepat kode - tunda acara tombol ke rutinitas latar belakang alih-alih melakukan tindakan dengan cepat, tampilkan bilah progres atau sesuatu seperti itu, ajukan beberapa pertanyaan tidak penting saat aktivitas dilakukan di latar belakang ... ketika ini tidak cukup, Anda dapat mempertimbangkan optimasi yang sebenarnya.
SF.
13

Kode bersih tidak harus eksklusif dengan kode yang dapat dijalankan dengan cepat. Biasanya kode yang sulit dibaca ditulis karena lebih cepat ditulis, bukan karena dieksekusi lebih cepat.

Menulis kode "kotor" dalam upaya membuatnya lebih cepat bisa dibilang tidak bijaksana, karena Anda tidak tahu pasti bahwa perubahan Anda sebenarnya meningkatkan apa pun. Knuth mengatakan yang terbaik:

"Kita harus melupakan efisiensi kecil, katakanlah sekitar 97% dari waktu: optimasi prematur adalah akar dari semua kejahatan . Namun kita tidak boleh melewatkan peluang kita dalam 3% kritis itu. Seorang programmer yang baik tidak akan terbuai oleh kepuasan seperti itu. dengan alasan, ia akan bijaksana untuk melihat dengan cermat kode kritis; tetapi hanya setelah kode itu diidentifikasi . "

Dengan kata lain, tulis kode bersih-bersih terlebih dahulu. Kemudian, buat profil program yang dihasilkan dan lihat apakah segmen itu, sebenarnya, merupakan hambatan kinerja. Jika demikian, optimalkan bagian sebagaimana diperlukan, dan pastikan untuk menyertakan banyak komentar dokumentasi (mungkin termasuk kode asli) untuk menjelaskan optimisasi. Kemudian buat profil hasil untuk memverifikasi bahwa Anda benar-benar melakukan peningkatan.

tylerl
sumber
10

Karena pertanyaannya mengatakan "cepat sulit membaca kode", jawaban sederhana tidak pernah. Tidak pernah ada alasan untuk menulis kode yang sulit dibaca. Mengapa? Dua alasan.

  1. Apa yang terjadi jika Anda ditabrak bus dalam perjalanan pulang malam ini? Atau (lebih optimis, dan lebih khas) melepas proyek ini dan dipindahkan ke sesuatu yang lain? Keuntungan kecil yang Anda bayangkan telah Anda buat dengan kode Anda yang kusut benar-benar kalah dengan fakta bahwa tidak ada orang lain yang bisa memahaminya . Risiko yang ditimbulkan proyek-proyek perangkat lunak sulit untuk dilebih-lebihkan. Saya pernah bekerja dengan PBX besarprodusen (jika Anda bekerja di kantor Anda mungkin memiliki salah satu telepon mereka di meja Anda). Manajer proyek mereka mengatakan kepada saya suatu hari bahwa produk inti mereka - perangkat lunak berpemilik yang mengubah kotak Linux standar menjadi pertukaran telepon berfitur lengkap - dikenal di dalam perusahaan sebagai "gumpalan". Tidak ada yang memahaminya lagi. Setiap kali mereka menerapkan fitur baru. mereka menekan kompilasi lalu mundur, menutup mata, menghitung sampai dua puluh, lalu mengintip melalui jari-jari mereka untuk melihat apakah itu berhasil. Tidak ada bisnis yang membutuhkan produk inti yang tidak lagi mereka kendalikan, tetapi ini adalah skenario yang menakutkan.
  2. Tapi saya perlu mengoptimalkan! OK, jadi Anda telah mengikuti semua saran luar biasa dalam jawaban lain untuk pertanyaan ini: kode Anda gagal dalam kasus pengujian kinerjanya, Anda telah memprofilinya dengan hati-hati, mengidentifikasi kemacetan, menemukan solusi ... dan itu akan melibatkan sedikit-twiddling . Baik: sekarang maju dan optimalkan. Tapi inilah rahasianya (dan Anda mungkin ingin duduk untuk yang ini): optimasi dan pengurangan ukuran kode sumber bukanlah hal yang sama. Komentar, ruang putih, tanda kurung, dan nama variabel yang bermakna adalah bantuan besar untuk keterbacaan yang sama sekali tidak menimbulkan biaya karena kompiler akan membuangnya. (Atau jika Anda sedang menulis bahasa yang tidak dikompilasi seperti JavaScript - dan ya, ada alasan yang sangat valid untuk mengoptimalkan JavaScript - mereka dapat ditangani oleh kompresor .) Garis panjang kode minimalis yang sempit (seperti yang dimiliki muntoo memiliki diposting di sini ) tidak ada hubungannya dengan optimasi: itu adalah seorang programmer mencoba untuk menunjukkan seberapa pintar mereka dengan mengemas kode sebanyak mungkin ke dalam karakter sesedikit mungkin. Itu tidak pintar, itu bodoh. Seorang programmer yang benar-benar pintar adalah orang yang dapat mengkomunikasikan ide-ide mereka dengan jelas kepada orang lain.
Mark Whitaker
sumber
2
Saya tidak setuju bahwa jawabannya adalah "tidak pernah". Beberapa algoritma secara inheren sangat sulit untuk dipahami dan / atau diterapkan secara efisien. Membaca kode, terlepas dari jumlah komentar, mungkin merupakan proses yang sangat sulit.
Rex Kerr
4

Ketika itu adalah kode membuang. Maksud saya secara harfiah: ketika Anda menulis skrip untuk melakukan perhitungan atau tugas satu kali, dan tahu dengan pasti Anda tidak akan pernah harus melakukan tindakan itu lagi bahwa Anda dapat 'rm source-file' tanpa ragu-ragu, maka Anda dapat memilih rute yang buruk.

Kalau tidak, itu adalah dikotomi yang salah - jika Anda merasa harus melakukannya dengan jelek untuk melakukannya lebih cepat, Anda salah melakukannya. (Atau prinsip Anda tentang apa kode yang baik perlu direvisi. Menggunakan goto sebenarnya cukup elegan ketika itu adalah solusi yang tepat untuk masalah tersebut. Namun jarang terjadi.)

maaku
sumber
5
Tidak ada yang namanya kode membuang. Jika saya memiliki satu sen untuk setiap kali "membuang kode" membuatnya menjadi produksi karena "itu berfungsi, kami tidak punya waktu untuk menulis ulang", saya akan menjadi seorang jutawan. Setiap baris kode yang Anda tulis harus ditulis sedemikian rupa sehingga programmer lain yang kompeten dapat mengambilnya besok setelah Anda tersambar petir malam ini. Kalau tidak, jangan tulis itu.
Mark Whitaker
Saya tidak setuju itu adalah dikotomi yang salah; IMO ada skenario terutama dalam kode perpustakaan (tidak begitu banyak dalam kode aplikasi) di mana perpecahannya sangat nyata. Lihat jawaban saya untuk lebih lanjut.
Marc Gravell
@mark, jika "programmer kompeten lain" benar-benar kompeten, maka kode yang dibuang juga tidak akan menjadi masalah :)
@ Mark - Mudah. Cukup tulis kode yang dibuang sehingga akan gagal dalam pengujian produksi, mungkin dengan cara yang tidak dapat diperbaiki.
hotpaw2
@ Mark, jika "kode buang" Anda membuatnya menjadi produksi, maka itu bukan kode buang. Perhatikan bahwa saya meluangkan waktu dalam jawaban saya untuk mengklarifikasi bahwa saya berbicara tentang kode yang benar - benar dibuang: yaitu, hapus setelah digunakan pertama kali. Kalau tidak, saya setuju dengan sentimen Anda dan mengatakan sebanyak mungkin dalam jawaban saya.
maaku
3

Kapan pun perkiraan biaya kinerja yang lebih rendah di pasar lebih besar daripada perkiraan biaya pemeliharaan kode untuk modul kode yang dimaksud.

Orang-orang masih memutar SSE / NEON / etc. perakitan untuk mencoba dan mengalahkan beberapa perangkat lunak pesaing pada chip CPU populer tahun ini.

hotpaw2
sumber
Perspektif bisnis yang baik, terkadang programmer perlu melihat lebih dari sekadar teknis.
this.josh
3

Jangan lupa Anda bisa membuat kode yang sulit dibaca mudah dimengerti dengan dokumentasi dan komentar yang sesuai.

Secara umum, profil setelah Anda menulis kode yang mudah dibaca yang melakukan fungsi yang diinginkan. Kemacetan mungkin mengharuskan Anda melakukan sesuatu yang membuatnya terlihat lebih rumit, tetapi Anda memperbaikinya dengan menjelaskan diri Anda sendiri.

Carlos
sumber
0

Bagi saya itu adalah proporsi stabilitas (seperti dalam semen beton, tanah liat yang dipanggang dalam oven, dibuat dari batu, ditulis dengan tinta permanen). Semakin tidak stabil kode Anda, karena semakin tinggi kemungkinan Anda perlu mengubahnya di masa mendatang, semakin mudah kelenturannya, seperti tanah liat basah, agar tetap produktif. Saya juga menekankan kelenturan dan bukan keterbacaan. Bagi saya kemudahan mengubah kode lebih penting daripada kemudahan membacanya. Kode bisa mudah dibaca dan mimpi buruk berubah, dan apa gunanya bisa membaca dan dengan mudah memahami detail implementasi jika mereka mimpi buruk untuk berubah? Kecuali itu hanya latihan akademis, biasanya titik untuk dapat dengan mudah memahami kode dalam basis kode produksi adalah dengan maksud untuk dapat lebih mudah mengubahnya sesuai kebutuhan. Jika sulit diubah, maka banyak manfaat keterbacaan keluar jendela. Keterbacaan umumnya hanya berguna dalam konteks kelenturan, dan kelenturan hanya berguna dalam konteks ketidakstabilan.

Tentu saja bahkan yang paling sulit untuk mempertahankan kode yang bisa dibayangkan, terlepas dari seberapa mudah atau sulitnya untuk membaca, tidak menimbulkan masalah jika tidak pernah ada alasan untuk mengubahnya, hanya gunakan saja. Dan dimungkinkan untuk mencapai kualitas seperti itu, terutama untuk kode sistem tingkat rendah di mana kinerja sering cenderung paling menghitung. Saya memiliki kode C yang masih saya gunakan secara teratur yang tidak berubah sejak akhir 80-an. Tidak perlu berubah sejak saat itu. Kode ini jelek, ditulis pada masa-masa sulit, dan saya hampir tidak memahaminya. Namun itu masih berlaku hari ini, dan saya tidak perlu memahami implementasinya untuk mendapatkan banyak manfaat darinya.

Tes penulisan yang menyeluruh adalah salah satu cara untuk meningkatkan stabilitas. Lainnya adalah decoupling. Jika kode Anda tidak bergantung pada hal lain, maka satu-satunya alasan untuk mengubahnya adalah jika itu sendiri perlu diubah. Kadang-kadang sejumlah kecil duplikasi kode dapat berfungsi sebagai mekanisme decoupling untuk secara dramatis meningkatkan stabilitas dengan cara yang membuatnya menjadi pertukaran yang layak jika, sebagai gantinya, Anda mendapatkan kode yang sekarang benar-benar independen dari hal lain. Sekarang kode itu kebal terhadap perubahan ke dunia luar. Sementara itu kode yang bergantung pada 10 pustaka eksternal yang berbeda memiliki 10 kali alasan untuk mengubahnya di masa depan.

Hal lain yang bermanfaat dalam praktik adalah untuk memisahkan perpustakaan Anda dari bagian basis kode Anda yang tidak stabil, bahkan mungkin membangunnya secara terpisah, seperti yang mungkin Anda lakukan untuk perpustakaan pihak ketiga (yang juga dimaksudkan untuk hanya digunakan, tidak diubah, setidaknya tidak oleh Anda tim). Jenis organisasi seperti itu dapat mencegah orang merusaknya.

Lain adalah minimalis. Semakin sedikit kode yang Anda coba lakukan, semakin besar kemungkinan dapat melakukan apa yang dilakukannya dengan baik. Desain monolitik hampir tidak stabil secara permanen, karena semakin banyak fungsi ditambahkan ke dalamnya, semakin tidak lengkap tampaknya.

Stabilitas harus menjadi tujuan utama Anda setiap kali Anda ingin menulis kode yang pasti akan sulit diubah, seperti kode SIMD paralel yang telah disetel mikro hingga mati. Anda menangkal kesulitan mempertahankan kode dengan memaksimalkan kemungkinan Anda tidak perlu mengubah kode, dan karenanya tidak harus mempertahankannya di masa mendatang. Itu membuat biaya pemeliharaan turun ke nol tidak peduli betapa sulitnya kode untuk dipelihara.


sumber