Seluruh section ini — dari memory management sampai caching — mempersenjatai kita dengan alat optimasi yang kuat. Ironisnya, senjata terpenting justru menahan diri: optimasi selalu mengorbankan sesuatu, baik waktu developer, keterbacaan kode, maupun peluang bug baru, dan tidak semua kode layak dikorbankan itu. Chapter penutup ini merangkum kapan optimasi memang perlu, urutan prioritasnya, dan — yang sering lebih sulit — kapan kita boleh berhenti.
Kutipan Knuth dan Optimasi Prematur #
Donald Knuth, salah satu tokoh ilmu komputer paling berpengaruh, menulis kalimat yang dikutip selama hampir setengah abad: premature optimization is the root of all evil — optimasi prematur adalah akar segala kejahatan. Kutipan lengkapnya lebih bernuansa: “We should forget about small efficiencies, say about 97% of the time”. Artinya bukan “jangan pernah optimasi”, melainkan “jangan buru-buru mempercepat bagian yang belum terbukti lambat”.
Optimasi prematur merugikan karena dua hal. Pertama, tebakan kita tentang lokasi bottleneck biasanya salah — kode yang “terasa” boros sering tidak terbaca di pengukuran, sementara hotspot asli bersembunyi di tempat tak terduga (kita lihat sendiri pada Chapter Profiling dengan cProfile). Kedua, kode yang sudah dilipat-lipat demi kecepatan lebih sulit diubah — padahal desain program hampir selalu berubah, dan perubahan desain bisa membuat optimasi yang mahal itu sia-sia.
Kapan Optimasi Memang Layak #
Sinyal yang layak dipercaya untuk mulai optimasi:
- Latensi terasa oleh pengguna — halaman menunggu berdetik-detik, laporan batch melewati tenggat.
- Batas teknis terlewati — memory error, timeout API, atau batas memori container yang terus tercapai.
- Biaya nyata berjalan — tagihan server CPU naik terus karena satu endpoint boros; 30 menit hemat per hari × ribuan panggilan adalah uang.
- Baseline terukur sudah ada — kita tahu angka sekarang dan target yang ingin dicapai, sehingga keberhasilan bisa dibuktikan dengan benchmark dari Chapter Benchmarking.
Tanpa salah satu sinyal ini, kode yang benar dan jelas lebih berharga daripada kode yang cepat.
Aturan 90/10 #
Pengalaman konsisten lintas domain: kurang lebih 90% waktu eksekusi program dihabiskan di kurang dari 10% kodenya. Sisanya — validasi input, format pesan, penyusunan tampilan — dijalankan sekali-sekali dan nyaris gratis. Konsekuensinya dua arah. Pertama, optimasi yang cerdas hanya menyentuh 10% itu; mengoptimasi 90% kode lain adalah membuang waktu pembacaan kode di masa depan. Kedua, struktur data dan algoritma di jalur panas layak diperjuangkan, sedangkan jalur dingin sebaiknya menulis kode paling sederhana yang benar.
Tangga Optimasi #
Ketika keputusan mengoptimasi sudah sah, urutan langkahnya tetap sama seperti yang kita praktikkan pada Chapter Optimasi Algoritma — dari yang berdampak besar ke kecil:
| Tahap | Langkah | Pertanyaan kuncinya |
|---|---|---|
| 1 | Perbaiki algoritma | Bisakah kompleksitas diturunkan, O(n²) menjadi O(n)? |
| 2 | Ganti struktur data | Apakah set/dict/deque lebih cocok untuk pola aksesnya? |
| 3 | Kurangi kerja berulang | Prekomputasi, join(), early exit, generator untuk data besar? |
| 4 | Simpan hasil | Apakah caching pada Chapter Caching cocok untuk pola panggilannya? |
| 5 | Paralelkan | Apakah pekerjaannya CPU-bound (multiprocessing) atau I/O-bound (threading/asyncio)? |
| 6 | Micro-optimize | Hanya bila 1–5 habis dan benchmark masih menuntut |
Naik tangga satu-satu sambil mengukur — sering kali langkah 1 atau 2 saja sudah menyelesaikan masalah, dan langkah 6 hampir tidak pernah diperlukan.
Trade-off Keterbacaan #
Setiap tahap di tangga menghadiahkan kecepatan dengan mata uang tertentu; tahap-tahap awal relatif murah, tahap akhir mahal. Mengganti loop pencarian dengan set biasanya membuat kode lebih jelas. Tetapi micro-optimization — menyalin method ke local variable, mengganti comprehension dengan loop terbalik, menambah __slots__ — hanya dapat dibaca oleh penulisnya, dan kadang hanya selama sepekan. Pertimbangkan dua versi fungsi yang sama:
# Versi sederhana: maksudnya jelas
def rata_rata(nilai):
return sum(nilai) / len(nilai)
# Versi "cepat": berbelit demi menghindari dua kali iterasi
def rata_rata_cepat(nilai):
total = 0
n = 0
for v in nilai:
total += v
n += 1
return total / nPengukuran pada list 10.000 elemen dengan timeit memberi pelajaran yang menjegal intuisi: versi sum() dan len() justru sekitar 8x lebih cepat daripada loop manual — meskipun versi manual “hanya iterasi sekali”, sum() dan len() berjalan sebagai kode C yang dikompilasi, bukan bytecode Python yang diinterpretasi satu per satu. Ini bukti nyata bahwa tebakan mikro tentang kecepatan sering salah arah: tulis versi paling jelas dulu, ukur, lalu hanya ganti bagian yang terbukti jadi masalah — dan simpan versi jelas itu di riwayat version control agar tidak hilang.
Checklist Sebelum dan Sesudah #
Kerangka kerja ringkas untuk sekali membaca:
- Ada keluhan nyata (latensi, batas memori, biaya) — bukan perasaan.
- Profil dengan
cProfile/tracemalloc— hotspot teridentifikasi dengan angka. - Siapkan benchmark sebelum-sesudah yang bisa diulang.
- Naik tangga optimasi dari langkah 1, satu perubahan setiap pengukuran.
- Simpan hasil pengukuran; bila tidak membaik, kembalikan kode yang lebih jelas.
Aturan Berhenti: Apakah Sudah Cukup Cepat? #
Pertanyaan penutup optimasi yang paling sehat bukan “bisakah lebih cepat lagi?”, melainkan “sudahkah memenuhi target?”. Menetapkan target dulu membuat berhenti menjadi keputusan teknis, bukan keputusan selera:
import time
def proses_laporan(nama_file):
"""Simulasi pemrosesan laporan harian."""
total = 0
for i in range(150_000):
total += (i * 31) % 977
return total
mulai = time.perf_counter()
hasil = proses_laporan("penjualan.log")
durasi = time.perf_counter() - mulai
print(f"proses_laporan selesai dalam {durasi * 1000:.1f} ms")
print(f"target SLA pengguna : 2000 ms")
print(f"lulus target? : {durasi * 1000 < 2000}")Output yang Dihasilkan (waktu bergantung pada mesin):
proses_laporan selesai dalam 12.4 ms
target SLA pengguna : 2000 ms
lulus target? : TrueLaporan selesai 12,4 ms dari jatah 2.000 ms — 160x di bawah target. Optimasi lebih lanjut di sini tidak memberi apa-apa kepada pengguna, tetapi pasti mengambil sesuatu dari waktu kita dan kejelasan kode. Begitu target tercapai dan bertahan di bawah beban nyata, pekerjaan optimasi selesai: simpan benchmark sebagai bukti, tulis satu paragraf catatan di komentar tentang angkanya, lalu alihkan energi ke fitur dan kebenaran program. Kecepatan adalah alat, bukan tujuan — dan sekarang kita tahu cara mencapainya dengan ukuran, bukan tebakan.