Pengoptimalan Kode: Cara Optimal untuk Mengoptimalkan

Diterbitkan: 2022-03-11

Optimalisasi kinerja adalah salah satu ancaman terbesar bagi kode Anda.

Anda mungkin berpikir, bukan salah satu dari orang- orang itu. Saya mengerti. Optimalisasi dalam bentuk apa pun jelas harus menjadi hal yang baik, dilihat dari etimologinya, jadi tentu saja, Anda ingin menjadi ahli dalam hal itu.

Bukan hanya untuk membedakan diri Anda dari yang lain sebagai pengembang yang lebih baik. Bukan hanya untuk menghindari menjadi "Dan" di The Daily WTF , tetapi karena Anda yakin pengoptimalan kode adalah Hal yang Benar untuk Dilakukan. Anda bangga dengan pekerjaan Anda.

Perangkat keras komputer terus bertambah cepat, dan perangkat lunak lebih mudah dibuat, tetapi apa pun hal sederhana yang Ingin Anda Lakukan, Sialan selalu membutuhkan waktu lebih lama daripada yang terakhir. Anda menggelengkan kepala pada fenomena ini (kebetulan, dikenal sebagai Hukum Wirth) dan memutuskan untuk melawan tren itu.

Itu mulia dari Anda, tapi berhenti.

Berhenti saja!

Anda berada dalam bahaya besar untuk menggagalkan tujuan Anda sendiri, tidak peduli seberapa berpengalaman Anda dalam pemrograman.

Bagaimana? Mari kita kembali.

Pertama-tama, apa itu optimasi kode?

Seringkali, ketika kita mendefinisikannya, kita berasumsi bahwa kita ingin kode bekerja lebih baik. Kami mengatakan bahwa pengoptimalan kode adalah menulis atau menulis ulang kode sehingga program menggunakan memori atau ruang disk seminimal mungkin, meminimalkan waktu CPU atau bandwidth jaringan, atau memanfaatkan inti tambahan sebaik mungkin.

Dalam praktiknya, terkadang kita menggunakan definisi lain secara default: Menulis lebih sedikit kode.

Tetapi kode pre-emptive badass yang Anda tulis dengan tujuan itu bahkan lebih mungkin menjadi duri di pihak seseorang. Yang? Orang sial berikutnya yang harus memahami kode Anda, yang mungkin adalah diri Anda sendiri. Dan seseorang yang cerdas dan cakap, seperti Anda, dapat menghindari sabotase diri: Pertahankan tujuan Anda tetap mulia tetapi evaluasi kembali cara Anda, terlepas dari kenyataan bahwa itu tampaknya intuitif.

Kode Golf: +197%, Performa: -398%, Kesederhanaan: -9999%

Jadi optimasi kode adalah istilah yang agak kabur. Itu bahkan sebelum kita mempertimbangkan beberapa cara lain di mana seseorang dapat mengoptimalkan kode, yang akan kita bahas di bawah ini.

Mari kita mulai dengan mendengarkan saran dari orang bijak saat kita bersama-sama menjelajahi aturan pengoptimalan kode Jackson yang terkenal:

  1. Jangan lakukan itu.
  2. (Hanya untuk ahli!) Jangan lakukan dulu .

1. Jangan Lakukan: Menyalurkan Perfeksionisme

Saya akan mulai dengan contoh ekstrem yang agak memalukan dari saat, dulu sekali, saya baru saja membuat kaki saya basah di dunia SQL yang luar biasa. Soalnya, saya kemudian menginjak kue itu dan tidak mau memakannya lagi karena basah dan mulai bau kaki.

Saya baru saja mendapatkan kaki saya basah di dunia SQL yang indah, miliki-kue-dan-makan-juga. Masalahnya, saya kemudian menginjak kue…

Tunggu. Biarkan saya keluar dari metafora bangkai mobil yang baru saja saya buat dan jelaskan.

Saya sedang melakukan R&D untuk aplikasi intranet, yang saya harap suatu hari akan menjadi sistem manajemen yang sepenuhnya terintegrasi untuk bisnis kecil tempat saya bekerja. Itu akan melacak semuanya untuk mereka, dan tidak seperti sistem mereka saat itu, itu tidak akan pernah kehilangan data mereka, karena itu akan didukung oleh RDBMS, bukan file flat yang dikembangkan sendiri yang telah digunakan pengembang lain. Saya ingin mendesain semuanya secerdas mungkin dari awal karena saya memiliki papan tulis yang kosong. Ide untuk sistem ini meledak seperti kembang api di benak saya, dan saya mulai mendesain tabel—kontak dan banyak variasi kontekstualnya untuk CRM, modul akuntansi, inventaris, pembelian, CMS, dan manajemen proyek, yang akan segera saya dogfood.

Bahwa semuanya terhenti, dari segi pengembangan dan kinerja, karena… Anda dapat menebaknya, pengoptimalan.

Saya melihat bahwa objek (diwakili sebagai baris tabel) dapat memiliki banyak hubungan yang berbeda satu sama lain di dunia nyata dan bahwa kami dapat mengambil manfaat dari pelacakan hubungan ini: Kami akan menyimpan lebih banyak informasi dan pada akhirnya dapat mengotomatiskan analisis bisnis di semua tempat. Melihat ini sebagai masalah teknik, saya melakukan sesuatu yang tampak seperti pengoptimalan fleksibilitas sistem.

Pada titik ini, penting untuk menjaga wajah Anda, karena saya tidak akan bertanggung jawab jika telapak tangan Anda melukainya. Siap? Saya membuat dua tabel: relationship dan satu tabel memiliki referensi kunci asing, relationship_type . relationship bisa merujuk ke dua baris mana saja di seluruh database, dan menggambarkan sifat hubungan di antara mereka.

Tabel database: karyawan, perusahaan, hubungan, tipe_hubungan

Oh man. Saya baru saja mengoptimalkan fleksibilitas itu .

Terlalu banyak, sebenarnya. Sekarang saya punya masalah baru: relationship_type yang diberikan secara alami tidak masuk akal di antara setiap kombinasi baris yang diberikan. Meskipun mungkin masuk akal bahwa person memiliki hubungan employed by dengan sebuah company , itu tidak akan pernah bisa secara semantik setara dengan hubungan antara, katakanlah, dua document s.

OK tidak masalah. Kami hanya akan menambahkan dua kolom ke relationship_type , yang menentukan tabel mana yang dapat diterapkan hubungan ini. (Poin bonus di sini jika Anda menebak bahwa saya berpikir untuk menormalkan ini dengan memindahkan dua kolom itu ke tabel baru yang merujuk ke relationship_type.id , sehingga hubungan yang secara semantik dapat diterapkan ke lebih dari satu pasang tabel tidak akan membuat nama tabel diduplikasi. Lagi pula, jika saya perlu mengubah nama tabel dan lupa memperbaruinya di semua baris yang berlaku, itu bisa membuat bug! Dalam retrospeksi, setidaknya bug akan menyediakan makanan untuk laba-laba yang menghuni tengkorak saya.)

Tabel database: relationship_type dan berlaku_to, dan data berbelit-belit dari dua kolom relationship_type yang diwakili oleh panah

Untungnya, saya pingsan dalam badai petunjuk sebelum melakukan perjalanan terlalu jauh ke jalan ini. Ketika saya bangun, saya menyadari bahwa saya telah berhasil, kurang lebih, mengimplementasikan kembali tabel RDBMS yang terkait dengan kunci asing internal di atas dirinya sendiri. Biasanya saya menikmati saat-saat yang berakhir dengan saya membuat pernyataan sombong bahwa "Saya sangat meta," tapi ini, sayangnya, bukan salah satunya. Lupakan kegagalan untuk menskalakan —penggembungan yang menghebohkan dari desain ini membuat bagian belakang aplikasi saya yang masih sederhana, yang DB-nya hampir tidak diisi dengan data pengujian apa pun, hampir tidak dapat digunakan.

Gunakan kunci asing, Luke!

Mari kita mundur sejenak dan melihat dua dari banyak metrik yang dimainkan di sini. Salah satunya adalah fleksibilitas, yang telah menjadi tujuan saya. Dalam hal ini, pengoptimalan saya, yang bersifat arsitektural, bahkan tidak terlalu dini:

Langkah Optimasi Kode: Arsitektur adalah bagian pertama dari program untuk mengoptimalkan

(Kita akan membahasnya lebih lanjut dalam artikel saya yang baru-baru ini diterbitkan, Cara Menghindari Kutukan Pengoptimalan Prematur.) Meskipun demikian, solusi saya gagal secara spektakuler karena terlalu fleksibel. Metrik lainnya, skalabilitas, adalah salah satu yang bahkan belum saya pertimbangkan tetapi berhasil menghancurkan setidaknya secara spektakuler dengan kerusakan tambahan.

Itu benar, "Oh."

Telapak tangan ganda, ketika satu telapak tangan tidak memotongnya

Ini adalah pelajaran yang kuat bagi saya tentang bagaimana pengoptimalan bisa benar-benar serba salah. Perfeksionisme saya benar-benar meledak: Kepintaran saya telah membawa saya untuk menghasilkan salah satu solusi paling objektif yang tidak cerdas yang pernah saya buat.

Optimalkan Kebiasaan Anda, Bukan Kode Anda

Ketika Anda mendapati diri Anda cenderung melakukan refactor bahkan sebelum Anda memiliki prototipe yang berfungsi dan rangkaian pengujian untuk membuktikan kebenarannya, pertimbangkan di mana lagi Anda dapat menyalurkan dorongan ini. Sudoku dan Mensa sangat bagus, tetapi mungkin sesuatu yang benar-benar akan menguntungkan proyek Anda secara langsung akan lebih baik:

  1. Keamanan
  2. Stabilitas runtime
  3. Kejelasan dan gaya
  4. Efisiensi pengkodean
  5. Keefektifan tes
  6. membuat profil
  7. Toolkit/DE Anda
  8. KERING (Jangan Ulangi Sendiri)

Tapi berhati-hatilah: Mengoptimalkan salah satu dari ini akan merugikan orang lain. Paling tidak, itu datang dengan mengorbankan waktu.

Di sinilah mudah untuk melihat seberapa banyak seni yang ada dalam kode kerajinan. Untuk salah satu dari hal di atas, saya dapat menceritakan kisah tentang seberapa banyak atau terlalu sedikitnya dianggap sebagai pilihan yang salah. Siapa yang melakukan pemikiran di sini juga merupakan bagian penting dari konteksnya.

Misalnya, mengenai KERING: Pada satu pekerjaan yang saya miliki, saya mewarisi basis kode yang setidaknya 80% pernyataan yang berlebihan, karena pembuatnya tampaknya tidak mengetahui bagaimana dan kapan harus menulis suatu fungsi. 20% lainnya dari kode itu sangat mirip dengan diri sendiri.

Saya ditugaskan untuk menambahkan beberapa fitur ke dalamnya. Salah satu fitur seperti itu perlu diulang di seluruh kode yang akan diimplementasikan, dan kode apa pun di masa mendatang harus disalin dengan hati-hati untuk memanfaatkan fitur baru.

Jelas, itu perlu di-refactored hanya untuk kewarasan saya sendiri (nilai tinggi) dan untuk pengembang masa depan. Tapi, karena saya baru mengenal basis kode, saya pertama kali menulis tes sehingga saya bisa memastikan refactoring saya tidak menimbulkan regresi apa pun. Faktanya, mereka melakukan hal itu: Saya menemukan dua bug di sepanjang jalan yang tidak akan saya perhatikan di antara semua keluaran gobbledygook yang dihasilkan skrip.

Pada akhirnya, saya pikir saya telah melakukannya dengan cukup baik. Setelah refactoring, saya membuat bos saya terkesan karena telah mengimplementasikan apa yang dianggap sebagai fitur yang sulit dengan beberapa baris kode sederhana; selain itu, kode ini secara keseluruhan lebih berkinerja. Tetapi tidak lama setelah itu bos yang sama memberi tahu saya bahwa saya terlalu lambat, dan proyek itu seharusnya sudah selesai. Terjemahan: Efisiensi pengkodean adalah prioritas yang lebih tinggi.

Hati-hati: Mengoptimalkan [aspek] tertentu akan merugikan orang lain. Paling tidak, itu datang dengan mengorbankan waktu.

Saya masih berpikir saya mengambil kursus yang benar di sana, bahkan jika pengoptimalan kode tidak dihargai secara langsung oleh bos saya saat itu. Tanpa refactoring dan tes, saya pikir itu akan memakan waktu lebih lama untuk benar-benar mendapatkan benar-yaitu, berfokus pada kecepatan pengkodean akan benar-benar menggagalkan itu. (Hei, itu tema kita!)

Bandingkan ini dengan beberapa pekerjaan yang saya lakukan di proyek sampingan kecil saya. Dalam proyek ini, saya mencoba mesin template baru, dan ingin membiasakan diri dari awal, meskipun mencoba mesin template baru bukanlah tujuan akhir proyek.

Segera setelah saya menyadari bahwa beberapa blok yang saya tambahkan sangat mirip satu sama lain, dan lebih jauh lagi, setiap blok harus mengacu pada variabel yang sama tiga kali, lonceng KERING berbunyi di kepala saya, dan saya mulai mencari yang benar. cara untuk melakukan apa yang saya coba lakukan dengan mesin template ini.

Ternyata, setelah beberapa jam debugging yang sia-sia, saat ini tidak mungkin dengan mesin template seperti yang saya bayangkan. Tidak hanya tidak ada solusi KERING yang sempurna ; tidak ada solusi KERING sama sekali!

Mencoba mengoptimalkan nilai saya yang satu ini, saya benar-benar menggagalkan efisiensi pengkodean dan kebahagiaan saya, karena jalan memutar ini membuat proyek saya kehilangan kemajuan yang bisa saya dapatkan hari itu.

Bahkan kemudian, apakah saya sepenuhnya salah? Terkadang perlu sedikit investasi, terutama dengan konteks teknologi baru, untuk mengenal praktik terbaik lebih awal daripada nanti. Lebih sedikit kode untuk ditulis ulang dan kebiasaan buruk untuk dibatalkan, bukan?

Tidak, saya pikir tidak bijaksana bahkan mencari cara untuk mengurangi pengulangan dalam kode saya—sangat kontras dengan sikap saya di anekdot sebelumnya. Alasannya adalah bahwa konteks adalah segalanya: Saya sedang mengeksplorasi teknologi baru pada proyek permainan kecil, tidak menetap untuk jangka panjang. Beberapa baris tambahan dan pengulangan tidak akan menyakiti siapa pun, tetapi kehilangan fokus menyakiti saya dan proyek saya.

Tunggu, jadi mencari praktik terbaik bisa menjadi kebiasaan buruk? Kadang-kadang. Jika tujuan utama saya adalah mempelajari mesin baru, atau belajar secara umum, maka itu akan menghabiskan waktu dengan baik: Bermain-main, menemukan batasan, menemukan fitur yang tidak terkait, dan mendapatkan melalui penelitian. Tetapi saya lupa bahwa ini bukan tujuan utama saya, dan itu merugikan saya.

Ini adalah seni, seperti yang saya katakan. Dan pengembangan seni itu mendapat manfaat dari pengingat, Jangan lakukan itu . Setidaknya ini membuat Anda mempertimbangkan nilai mana yang berperan saat Anda bekerja, dan nilai mana yang paling penting bagi Anda dalam konteks Anda .

Bagaimana dengan aturan kedua itu? Kapan kita bisa benar-benar mengoptimalkan?

2. Jangan Lakukan Ini: Seseorang Telah Melakukan Ini

Oke, baik oleh Anda atau orang lain, Anda menemukan arsitektur Anda telah ditetapkan, aliran data telah dipikirkan dan didokumentasikan, dan saatnya untuk membuat kode.

Ayo lakukan Jangan lakukan itu selangkah lebih jauh: Bahkan belum mengkodekannya .

Ini sendiri mungkin berbau seperti pengoptimalan prematur, tetapi ini merupakan pengecualian penting. Mengapa? Untuk menghindari NIHS yang ditakuti, atau Sindrom "Tidak Diciptakan Di Sini"—dengan asumsi bahwa prioritas Anda mencakup kinerja kode dan meminimalkan waktu pengembangan. Jika tidak, jika tujuan Anda sepenuhnya berorientasi pada pembelajaran, Anda dapat melewati bagian berikut ini.

Meskipun ada kemungkinan bahwa orang menemukan kembali roda persegi dari keangkuhan belaka, saya percaya bahwa orang-orang yang jujur ​​dan rendah hati, seperti Anda dan saya, dapat membuat kesalahan ini hanya dengan tidak mengetahui semua pilihan yang tersedia bagi kita. Mengetahui setiap opsi dari setiap API dan alat di tumpukan Anda dan terus mengikutinya saat mereka tumbuh dan berkembang tentu saja membutuhkan banyak pekerjaan.

Tapi, memasukkan waktu ini adalah apa yang membuat Anda menjadi ahli dan membuat Anda tidak menjadi orang ke-sejuta di CodeSOD yang dikutuk dan diejek karena jejak kehancuran yang ditinggalkan oleh pandangan menarik mereka tentang kalkulator tanggal-waktu atau manipulator string.

(Sebuah tandingan yang baik untuk pola umum ini adalah Java Calendar API lama, tetapi sejak itu telah diperbaiki.)

Periksa Perpustakaan Standar Anda, Periksa Ekosistem Kerangka Anda, Periksa FOSS yang Sudah Memecahkan Masalah Anda

Kemungkinannya adalah, konsep yang Anda hadapi memiliki nama yang cukup standar dan terkenal, jadi pencarian cepat di internet akan menghemat banyak waktu Anda.

Sebagai contoh, saya baru-baru ini bersiap untuk melakukan beberapa analisis strategi AI untuk permainan papan. Saya terbangun di suatu pagi menyadari bahwa analisis yang saya rencanakan dapat dilakukan dengan lebih efisien jika saya hanya menggunakan konsep kombinatorik tertentu yang saya ingat. Tidak tertarik untuk mencari tahu sendiri algoritma untuk konsep ini, saya sudah berada di depan dengan mengetahui nama yang tepat untuk dicari. Namun, saya menemukan bahwa setelah sekitar 50 menit penelitian dan mencoba beberapa kode awal, saya tidak berhasil mengubah kode semu setengah jadi yang saya temukan menjadi implementasi yang benar. (Dapatkah Anda percaya ada posting blog di luar sana di mana penulis mengasumsikan keluaran algoritma yang salah, mengimplementasikan algoritma secara tidak benar agar sesuai dengan asumsi, komentator menunjukkan ini, dan kemudian bertahun-tahun kemudian, itu masih belum diperbaiki?) Pada saat itu, teh pagi saya menendang, dan saya mencari [name of concept] [my programming language] . 30 detik kemudian, saya memiliki kode yang terbukti benar dari GitHub dan beralih ke apa yang sebenarnya ingin saya lakukan. Hanya menjadi spesifik dan memasukkan bahasa, alih-alih berasumsi saya harus mengimplementasikannya sendiri, berarti segalanya.

Saatnya Merancang Struktur Data Anda dan Menerapkan Algoritma Anda

…sekali lagi, jangan main golf kode. Prioritaskan kebenaran dan kejelasan dalam proyek dunia nyata.

Investasi Waktu: 10 jam, Waktu Eksekusi: +25%, Penggunaan Memori: +3%, Kebingungan: 100%

Oke, jadi Anda sudah melihat, dan tidak ada yang menyelesaikan masalah Anda yang terpasang di rantai alat Anda, atau dilisensikan secara bebas di web. Anda menggulung sendiri.

Tidak masalah. Sarannya sederhana, dalam urutan ini:

  1. Rancang sedemikian rupa sehingga mudah untuk dijelaskan kepada programmer pemula.
  2. Tulis tes yang sesuai dengan harapan yang dihasilkan oleh desain itu.
  3. Tulis kode Anda sehingga programmer pemula dapat dengan mudah mendapatkan desain dari kode tersebut.

Sederhana, tapi mungkin sulit untuk diikuti. Di sinilah kebiasaan pengkodean dan bau kode dan seni dan kerajinan dan keanggunan ikut bermain. Jelas ada aspek rekayasa untuk apa yang Anda lakukan saat ini, tetapi sekali lagi, jangan bermain golf kode. Prioritaskan kebenaran dan kejelasan dalam proyek dunia nyata.

Jika Anda menyukai video, inilah salah satu dari seseorang yang mengikuti langkah-langkah di atas, kurang lebih. Untuk video-averse, saya akan meringkas: Ini adalah tes pengkodean algoritma pada wawancara kerja Google. Orang yang diwawancarai pertama-tama mendesain algoritme dengan cara yang mudah untuk dikomunikasikan. Sebelum menulis kode apa pun, ada contoh output yang diharapkan oleh desain yang berfungsi. Kemudian kode secara alami mengikuti.

Mengenai tes itu sendiri, saya tahu bahwa di beberapa kalangan, pengembangan yang didorong oleh tes bisa jadi kontroversial. Saya pikir sebagian alasannya adalah bisa berlebihan, dikejar secara religius sampai mengorbankan waktu pembangunan. (Sekali lagi, menembak diri kita sendiri dengan mencoba mengoptimalkan bahkan satu variabel terlalu banyak sejak awal.) Bahkan Kent Beck tidak menganggap TDD terlalu ekstrem, dan dia menemukan pemrograman ekstrem dan menulis buku tentang TDD. Jadi mulailah dengan sesuatu yang sederhana untuk memastikan output Anda benar. Lagi pula, Anda akan melakukannya secara manual setelah pengkodean, bukan? (Saya minta maaf jika Anda seorang programmer rockstar sehingga Anda bahkan tidak menjalankan kode Anda setelah pertama kali menulisnya. Dalam hal ini, mungkin Anda akan mempertimbangkan untuk meninggalkan pengelola kode Anda di masa depan dengan sebuah tes supaya Anda tahu bahwa mereka tidak akan melakukannya. hancurkan implementasi mengagumkan Anda.) Jadi, alih-alih melakukan manual, visual diff, dengan tes di tempat Anda sudah membiarkan komputer melakukan itu untuk Anda.

Selama proses yang agak mekanis dalam menerapkan algoritme dan struktur data Anda, hindari membuat pengoptimalan baris demi baris, dan jangan pernah berpikir untuk menggunakan eksternal bahasa tingkat rendah khusus (Assembly jika Anda membuat kode dalam C, C jika Anda sedang coding di Perl, dll) pada saat ini. Alasannya sederhana: Jika algoritme Anda diganti seluruhnya—dan Anda tidak akan mengetahui sampai nanti dalam proses apakah itu diperlukan—maka upaya pengoptimalan tingkat rendah Anda pada akhirnya tidak akan berpengaruh.

Contoh Skrip ECMA

Di situs ulasan kode komunitas exercism.io yang luar biasa, saya baru-baru ini menemukan latihan yang menyarankan secara eksplisit untuk mencoba mengoptimalkan de-duplikasi atau untuk kejelasan. Saya mengoptimalkan deduplikasi, hanya untuk menunjukkan betapa konyolnya hal itu jika Anda menggunakan DRY—pola pikir pengkodean yang bermanfaat, seperti yang saya sebutkan di atas—terlalu jauh. Berikut tampilan kode saya:

 const zeroPhrase = "No more"; const wallPhrase = " on the wall"; const standardizeNumber = number => { if (number === 0) { return zeroPhrase; } return '' + number; } const bottlePhrase = number => { const possibleS = (number === 1) ? '' : 's'; return standardizeNumber(number) + " bottle" + possibleS + " of beer"; } export default class Beer { static verse(number) { const nextNumber = (number === 0) ? 99 : (number - 1); const thisBottlePhrase = bottlePhrase(number); const nextBottlePhrase = bottlePhrase(nextNumber); let phrase = thisBottlePhrase + wallPhrase + ", " + thisBottlePhrase.toLowerCase() + ".\n"; if (number === 0) { phrase += "Go to the store and buy some more"; } else { const bottleReference = (number === 1) ? "it" : "one"; phrase += "Take " + bottleReference + " down and pass it around"; } return phrase + ", " + nextBottlePhrase.toLowerCase() + wallPhrase + ".\n"; } static sing(start = 99, end = 0) { return Array.from(Array(start - end + 1).keys()).map(offset => { return this.verse(start - offset); }).join('\n'); } }

Hampir tidak ada duplikasi string sama sekali! Dengan menulis seperti ini, saya secara manual menerapkan bentuk kompresi teks untuk lagu bir (tetapi hanya untuk lagu bir). Apa manfaatnya, tepatnya? Nah, katakanlah Anda ingin bernyanyi tentang minum bir dari kaleng, bukan botol. Saya dapat melakukannya dengan mengubah satu contoh bottle menjadi can .

Bagus!

…Baik?

Tidak, karena dengan begitu semua tes akan rusak. Oke, itu mudah untuk memperbaikinya: kami hanya akan melakukan pencarian dan penggantian bottle di spesifikasi unit test. Dan itu sama mudahnya dengan melakukan itu pada kode itu sendiri sejak awal dan membawa risiko yang sama untuk merusak sesuatu secara tidak sengaja.

Sementara itu, variabel saya akan diberi nama aneh setelahnya, dengan hal-hal seperti bottlePhrase tidak ada hubungannya dengan botol sama sekali. Satu-satunya cara untuk menghindari ini adalah dengan meramalkan dengan tepat jenis perubahan yang akan dibuat dan menggunakan istilah yang lebih umum seperti vessel atau container sebagai pengganti bottle dalam nama variabel saya.

Kebijaksanaan pemeriksaan masa depan dengan cara ini cukup dipertanyakan. Seberapa besar kemungkinan Anda ingin mengubah apa pun? Dan jika Anda melakukannya, apakah yang Anda ubah akan berhasil dengan mudah? Dalam contoh bottlePhrase , bagaimana jika Anda ingin melokalkan ke dalam bahasa yang memiliki lebih dari dua bentuk jamak? Itu benar, waktu refactor, dan kodenya mungkin terlihat lebih buruk sesudahnya.

Tetapi ketika persyaratan Anda benar-benar berubah, dan Anda tidak hanya mencoba mengantisipasinya, mungkin inilah saatnya untuk melakukan refactor. Atau mungkin Anda masih bisa menundanya: Berapa banyak jenis kapal atau lokalisasi yang akan Anda tambahkan, secara realistis? Bagaimanapun, ketika Anda perlu menyeimbangkan deduplikasi Anda dengan kejelasan, ada baiknya menonton demonstrasi oleh Katrina Owen ini.

Kembali ke contoh buruk saya sendiri: Tak perlu dikatakan lagi, manfaat deduplikasi bahkan tidak terlalu disadari di sini. Sementara itu, berapa biayanya?

Selain membutuhkan waktu lebih lama untuk menulis, sekarang membaca, men-debug, dan memelihara menjadi lebih mudah. Bayangkan tingkat keterbacaan dengan jumlah duplikasi yang diizinkan. Misalnya, masing-masing dari empat variasi ayat dieja.

Tapi Kami Masih Belum Optimal!

Sekarang setelah algoritme Anda diimplementasikan, dan Anda telah membuktikan hasilnya benar, selamat! Anda memiliki dasar!

Akhirnya, saatnya untuk…mengoptimalkan, bukan? Tidak, masih belum melakukannya . Saatnya untuk mengambil baseline Anda dan melakukan benchmark yang bagus. Tetapkan ambang batas untuk ekspektasi Anda seputar ini dan tempelkan di rangkaian pengujian Anda. Kemudian jika sesuatu tiba-tiba membuat kode ini lebih lambat—bahkan jika masih berfungsi—Anda akan mengetahuinya sebelum keluar dari pintu.

Tetap tunda pengoptimalan, hingga Anda menerapkan seluruh pengalaman pengguna yang relevan. Sampai saat itu, Anda mungkin menargetkan bagian kode yang sama sekali berbeda dari yang Anda butuhkan.

Selesaikan aplikasi Anda (atau komponen), jika Anda belum melakukannya, tetapkan semua garis dasar tolok ukur algoritmik saat Anda melakukannya.

Setelah ini selesai, ini adalah waktu yang tepat untuk membuat dan membandingkan pengujian ujung ke ujung yang mencakup skenario penggunaan dunia nyata yang paling umum dari sistem Anda.

Mungkin Anda akan menemukan bahwa semuanya baik-baik saja.

Atau mungkin Anda telah menentukan bahwa, dalam konteks kehidupan nyata, ada sesuatu yang terlalu lambat atau terlalu banyak memori.

Oke, Sekarang Anda Dapat Mengoptimalkan

Hanya ada satu cara untuk bersikap objektif tentang hal itu. Saatnya untuk memecahkan grafik api dan alat profil lainnya. Insinyur berpengalaman mungkin atau mungkin tidak menebak lebih baik daripada pemula, tetapi bukan itu intinya: Satu-satunya cara untuk mengetahui dengan pasti adalah dengan membuat profil. Ini selalu menjadi hal pertama yang harus dilakukan dalam proses pengoptimalan kode untuk kinerja.

Anda dapat membuat profil selama pengujian ujung-ke-ujung yang diberikan untuk mendapatkan apa yang benar-benar akan membuat dampak terbesar. (Dan kemudian, setelah penerapan, memantau pola penggunaan adalah cara yang bagus untuk tetap mengetahui aspek mana dari sistem Anda yang paling relevan untuk diukur di masa mendatang.)

Perhatikan bahwa Anda tidak mencoba menggunakan profiler secara maksimal—Anda lebih mencari profil level fungsi daripada profil level pernyataan, umumnya, karena tujuan Anda saat ini hanya untuk mengetahui algoritme mana yang menjadi penghambat .

Sekarang Anda telah menggunakan pembuatan profil untuk mengidentifikasi hambatan sistem Anda, sekarang Anda benar-benar dapat mencoba untuk mengoptimalkan, yakin bahwa pengoptimalan Anda layak dilakukan. Anda juga dapat membuktikan seberapa efektif (atau tidak efektif) upaya Anda, berkat tolok ukur dasar yang Anda lakukan selama ini.

Teknik keseluruhan

Pertama, ingatlah untuk tetap berada di level tinggi selama mungkin:

Pada tingkat keseluruhan-algoritma, salah satu teknik adalah pengurangan kekuatan. Namun, dalam hal mengurangi loop ke rumus, berhati-hatilah untuk meninggalkan komentar. Tidak semua orang mengetahui atau mengingat setiap rumus kombinatorik. Juga, berhati-hatilah dengan penggunaan matematika Anda: Terkadang apa yang Anda pikir mungkin pengurangan kekuatan tidak, pada akhirnya. Sebagai contoh, anggaplah x * (y + z) memiliki beberapa arti algoritmik yang jelas. Jika otak Anda telah dilatih pada suatu saat, untuk alasan apa pun, untuk secara otomatis memisahkan suku-suku sejenis, Anda mungkin tergoda untuk menulis ulang sebagai x * y + x * z . Untuk satu hal, ini menempatkan penghalang antara pembaca dan makna algoritmik yang jelas yang telah ada. (Lebih buruk lagi, sekarang sebenarnya kurang efisien karena operasi perkalian ekstra diperlukan. Ini seperti membuka gulungan baru saja menutupi celananya.) Bagaimanapun, catatan singkat tentang niat Anda akan sangat membantu, dan bahkan mungkin membantu Anda melihat tujuan Anda. kesalahan sendiri sebelum Anda melakukan itu.

Baik Anda menggunakan rumus atau hanya mengganti algoritme berbasis loop dengan algoritme berbasis loop lain, Anda siap mengukur perbedaannya.

Tapi mungkin Anda bisa mendapatkan kinerja yang lebih baik hanya dengan mengubah struktur data Anda. Ajari diri Anda tentang perbedaan kinerja di antara berbagai operasi yang perlu Anda lakukan pada struktur yang Anda gunakan, dan pada alternatif apa pun. Mungkin hash terlihat sedikit lebih berantakan untuk bekerja dalam konteks Anda, tetapi apakah waktu pencarian yang superior sepadan dengan array? Ini adalah jenis trade-off yang terserah Anda untuk memutuskan.

Anda mungkin memperhatikan bahwa ini bermuara pada mengetahui algoritme mana yang dieksekusi atas nama Anda saat Anda memanggil fungsi kenyamanan. Jadi pada akhirnya sama saja dengan pengurangan kekuatan. Dan mengetahui apa yang dilakukan perpustakaan vendor Anda di belakang layar sangat penting tidak hanya untuk kinerja tetapi juga untuk menghindari bug yang tidak disengaja.

Optimasi Mikro

Oke, fungsionalitas sistem Anda sudah selesai, tetapi dari sudut pandang UX, kinerja dapat disempurnakan sedikit lebih jauh. Dengan asumsi Anda telah melakukan semua yang Anda bisa lebih tinggi, inilah saatnya untuk mempertimbangkan pengoptimalan yang telah kami hindari sepanjang waktu hingga sekarang. Pertimbangkan, karena tingkat optimasi ini masih merupakan trade-off terhadap kejelasan dan rawatan. Tapi Anda telah memutuskan sudah waktunya, jadi lanjutkan dengan pembuatan profil tingkat pernyataan, sekarang Anda berada dalam konteks keseluruhan sistem, di mana itu benar-benar penting.

Sama seperti perpustakaan yang Anda gunakan, jam teknis yang tak terhitung jumlahnya telah dimasukkan untuk keuntungan Anda di tingkat kompiler atau juru bahasa Anda. (Lagi pula, pengoptimalan kompiler dan pembuatan kode adalah topik besar mereka sendiri). Ini bahkan berlaku di tingkat prosesor. Mencoba mengoptimalkan kode tanpa menyadari apa yang terjadi pada level terendah adalah seperti berpikir bahwa memiliki penggerak empat roda menyiratkan bahwa kendaraan Anda juga dapat berhenti dengan lebih mudah.

Sulit untuk memberikan saran umum yang baik di luar itu karena itu benar-benar tergantung pada tumpukan teknologi Anda dan apa yang ditunjukkan oleh profiler Anda. Tetapi, karena Anda mengukur, Anda sudah berada dalam posisi yang sangat baik untuk meminta bantuan, jika solusi tidak muncul secara organik dan intuitif kepada Anda dari konteks masalah. (Tidur dan waktu yang dihabiskan untuk memikirkan hal lain juga dapat membantu.)

Pada titik ini, tergantung pada konteks dan persyaratan penskalaan, Jeff Atwood mungkin menyarankan hanya menambahkan perangkat keras, yang bisa lebih murah daripada waktu pengembang.

Mungkin Anda tidak menempuh jalan itu. Dalam hal ini, mungkin membantu untuk menjelajahi berbagai kategori teknik pengoptimalan kode:

  • Cache
  • Peretasan bit dan yang khusus untuk lingkungan 64-bit
  • Pengoptimalan lingkaran
  • Optimalisasi hierarki memori

Lebih spesifik:

  • Kiat pengoptimalan kode dalam C dan C++
  • Kiat pengoptimalan kode di Java
  • Mengoptimalkan penggunaan CPU di .NET
  • Cache pertanian web ASP.NET
  • Penyetelan basis data SQL atau penyetelan Microsoft SQL Server khususnya
  • Scala Play! kerangka
  • Pengoptimalan kinerja WordPress tingkat lanjut
  • Pengoptimalan kode dengan prototipe JavaScript dan rantai cakupan
  • Mengoptimalkan kinerja React
  • efisiensi animasi iOS
  • Kiat kinerja Android

Bagaimanapun , saya memiliki beberapa Larangan untuk Anda:

Jangan menggunakan kembali variabel untuk berbagai tujuan berbeda. Dalam hal perawatan, ini seperti menjalankan mobil tanpa oli. Hanya dalam situasi tertanam yang paling ekstrim hal ini masuk akal, dan bahkan dalam kasus-kasus itu, saya berpendapat bahwa itu tidak lagi masuk akal. Ini adalah tugas kompiler untuk mengatur. Lakukan sendiri, lalu pindahkan satu baris kode, dan Anda telah memperkenalkan bug. Apakah ilusi menyimpan memori berharga bagi Anda?

Jangan gunakan makro dan fungsi sebaris tanpa mengetahui alasannya. Ya, overhead panggilan fungsi adalah biaya. Tetapi menghindarinya sering kali membuat kode Anda lebih sulit untuk di-debug, dan terkadang malah membuatnya lebih lambat. Menggunakan teknik ini di mana-mana hanya karena itu ide yang baik sesekali adalah contoh palu emas.

Jangan membuka gulungan dengan tangan. Sekali lagi, bentuk optimasi loop ini adalah sesuatu yang hampir selalu lebih baik dioptimalkan oleh proses otomatis seperti kompilasi, bukan dengan mengorbankan keterbacaan kode Anda.

Ironisnya dalam dua contoh pengoptimalan kode terakhir adalah bahwa mereka sebenarnya bisa menjadi anti-kinerja. Tentu saja, karena Anda melakukan tolok ukur, Anda dapat membuktikan atau menyangkalnya untuk kode khusus Anda. Tetapi bahkan jika Anda melihat peningkatan kinerja, kembalilah ke sisi seni, dan lihat apakah keuntungannya sebanding dengan kerugiannya dalam keterbacaan dan perawatan.

Milik Anda: Pengoptimalan yang Dioptimalkan Secara Optimal

Mencoba optimasi kinerja dapat bermanfaat. Lebih sering daripada tidak, hal itu dilakukan sangat dini, disertai dengan serangkaian efek samping yang buruk, dan yang paling ironis, menyebabkan kinerja yang lebih buruk. Saya harap Anda datang dengan apresiasi yang diperluas untuk seni dan ilmu pengoptimalan dan, yang paling penting, konteksnya yang tepat.

Saya senang jika ini membantu kita membuang gagasan menulis kode yang sempurna dari awal dan sebagai gantinya menulis kode yang benar. Kita harus ingat untuk mengoptimalkan dari atas ke bawah, membuktikan di mana letak hambatannya, dan mengukur sebelum dan sesudah memperbaikinya. Itulah optimal, strategi optimal untuk mengoptimalkan optimasi. Semoga berhasil.