Sihir dalam pemrograman — apa itu, mengapa magic numbers berbahaya dan penggantinya

Penulis: IT Sectr Diterbitkan: 2026-07-27 Waktu membaca: 10 mnt

Sihir dalam pemrograman — bukanlah metafora, melainkan istilah tepat yang merujuk pada nilai (angka, string, flag) yang maknanya tidak jelas dari konteks dan memerlukan pengetahuan eksternal untuk dipahami. Jenis sihir yang paling umum — magic numbers: konstanta numerik yang ditulis langsung ke dalam kode tanpa penjelasan mengapa nilai tertentu dipilih. Menurut penelitian SonarSource Code Quality Report (2025), sekitar 8 persen dari semua peringatan penganalisis statis terkait dengan literal yang tidak dijelaskan. Nilai magis membuat code rapuh: perubahan memerlukan pencarian semua kemunculan, dan pengembang baru tidak mengerti apakah angka tersebut boleh diubah atau penting untuk kerja sistem.

Utama

  • Sihir — angka, string, dan flag tersembunyi dalam kode yang maknanya tersembunyi dari pembaca.
  • Magic numbers — literal numerik tanpa nama: 86400, 3.14, 0.85, 1024.
  • String ajaib — hardcode jalur, kunci, URL tanpa ekstraksi ke konstanta.
  • Alat pencarian: SonarQube (aturan MagicNumber), ESLint (no-magic-numbers), Detekt.
  • Solusi: ekstrak setiap nilai magis ke konstanta bernama dengan nama yang menjelaskan.

Apa itu sihir dalam pemrograman?

Sihir (magic) — adalah nilai apa pun dalam kode sumber yang maknanya tidak jelas tanpa pengetahuan tambahan tentang domain. Istilah ini mapan di komunitas: jika pengembang melihat angka dan tidak mengerti dari mana asalnya — itu adalah sihir.

Sihir terdiri dari beberapa jenis: numerik (magic numbers), string (magic strings), boolean (magic flags), dan konfigurasi (parameter hardcode yang seharusnya ada di pengaturan). Keempat jenis ini disatukan oleh satu masalah: ketika persyaratan berubah, pengembang harus menemukan semua tempat di mana nilai tersebut digunakan dan menggantinya secara manual. Melewatkan bahkan satu kemunculan menyebabkan bug.

Menurut laporan JetBrains Code Quality Survey (2025), 73 persen pengembang menganggap magic numbers sebagai indikator kualitas kode rendah, sementara 41 persen mengakui bahwa mereka sendiri kadang-kadang meninggalkannya. Alasan utama — tergesa-gesa: “Saya akan menaruh konstanta nanti” — tetapi nanti tidak pernah tiba, dan setelah sebulan angka 0.85 tetap tanpa penjelasan di badan metode.

Aturan kunci: setiap nilai literal, kecuali 0, 1, true, false, dan string kosong, harus diekstraksi ke konstanta bernama. Pengecualian: increment counter (i + 1), nol matematis (pemeriksaan 0) dan nilai awal akumulator. Sisanya — kandidat untuk penamaan.

Magic numbers dan mengapa berbahaya

Magic number — adalah literal numerik yang nilainya tidak jelas dari konteks. Contoh klasik: 86400 dalam kode yang bertanggung jawab atas timeout. Pengembang melihat angka dan harus menebak bahwa ini adalah jumlah detik dalam sehari. Jika dia salah dan menempatkan 84600 — bug akan sulit ditemukan karena timeout akan aktif 18 menit lebih awal.

Mengapa magic numbers berbahaya: pertama, mereka mengganggu keterbacaan. Angka 1024 bisa berarti ukuran kilobyte, ambang paginasi, atau jumlah maksimum elemen. Tanpa konteks — itu hanya angka. Kedua, mereka menciptakan duplikasi: jika 1024 digunakan di lima tempat, saat mengubah ambang menjadi 2048 pengembang harus menemukan kelimanya dan menggantinya. Jika satu tempat terlewat — sistem bekerja tidak benar, tetapi tanpa kesalahan yang jelas.

Contoh magic numbers sebelum dan sesudah

kotlin
// sebelum — sihir dalam bentuk murni
fun calculateTimeout(base: Int): Int {
    return base * 3 + 5000
}

// sesudah — nilai diganti dengan konstanta
private const val RETRY_MULTIPLIER = 3
private const val BASE_TIMEOUT_MS = 5000

fun calculateTimeout(base: Int): Int {
    return base * RETRY_MULTIPLIER + BASE_TIMEOUT_MS
}

Bahaya ketiga — ketidakmampuan pengujian. Jika nilai ambang ditanamkan dalam kode sebagai literal, pengujian tidak dapat menimpanya untuk memeriksa kondisi batas. Konstanta yang diekstraksi ke companion object atau file konfigurasi membuat kode dapat diuji: pengujian menempatkan nilai lain dan memeriksa perilaku sistem di batas.

Kembangkan kebiasaan: setiap kali Anda menulis angka selain 0, 1, 100, atau 2 — berhenti dan pikirkan apakah layak mengekstraknya ke konstanta. Jika angka terkait dengan logika bisnis (batas, ambang, timeout, ukuran) — ekstrak wajib. Jika angka adalah konstanta matematis (pi, e) — gunakan perpustakaan standar (Math.PI, Math.E).

String dan jalur ajaib

Magic strings — literal string yang tertanam dalam kode tanpa ekstraksi ke konstanta atau sumber daya. Contoh tipikal: URL endpoint, nama kunci SharedPreferences, Intent Actions, bundle keys, nama file, dan kueri SQL.

Bahaya string ajaib terletak pada tidak adanya pemeriksaan pada tahap kompilasi. Kesalahan ketik dalam string “user_prefs” tidak akan terdeteksi hingga runtime. Jika string digunakan di sepuluh tempat dan pengembang di satu tempat menulis “user_pref” (tanpa s) — aplikasi tidak crash, tetapi data tidak disimpan. Bug semacam itu bisa hidup di produksi selama berbulan-bulan karena tidak menyebabkan crash.

Untuk proyek Android, string ajaib harus diekstraksi ke sumber daya (strings.xml, arrays.xml) atau ke konstanta di companion object. Untuk iOS — ke sumber daya string (Localizable.strings) atau konstanta enum. Untuk backend — ke file konfigurasi (.env, application.properties). Tidak ada kunci, URL, atau jalur yang boleh ada dalam kode sebagai literal string.

swift
// sebelum — string ajaib di seluruh kelas
let prefs = UserDefaults.standard
prefs.set(token, forKey: "auth_token")
prefs.set(userId, forKey: "current_user_id")

// sesudah — string diekstraksi ke enum
enum PrefKeys: String {
    case authToken = "auth_token"
    case currentUserId = "current_user_id"
}

prefs.set(token, forKey: PrefKeys.authToken.rawValue)
prefs.set(userId, forKey: PrefKeys.currentUserId.rawValue)

Berikan perhatian khusus pada string yang terduplikasi. Jika kunci yang sama “user_settings” muncul di tiga file — dengan probabilitas 99 persen cepat atau lambat di salah satunya akan muncul kesalahan ketik. Ekstraksi ke enum atau konstanta memastikan bahwa semua referensi menggunakan nilai yang sama.

Magic flags dan parameter boolean

Magic flags — parameter boolean yang nilainya tidak jelas dari konteks panggilan. Anti-pola klasik: mengirim true atau false ke metode tanpa menjelaskan apa yang diaktifkan atau dinonaktifkan oleh flag ini.

Contoh: userDao.fetch(includeDeleted = false). Pengembang melihat false dan tidak mengerti apakah ini berarti “jangan sertakan yang dihapus” atau “jangan sertakan yang aktif”. Sebulan kemudian false berubah menjadi true, dan dalam hasil mulai muncul catatan yang dihapus. Bug baru terdeteksi di produksi.

Solusi — mengganti flag boolean dengan enum atau sealed class. Alih-alih parameter Boolean, gunakan UserFilter.includeDeleted atau UserFilter.activeOnly. Dengan demikian kode mendokumentasikan sendiri tujuannya, dan IDE menyarankan opsi yang tersedia saat pelengkapan otomatis.

Jika flag boolean melewati beberapa lapisan — ini sinyal lain bahwa abstraksi salah. Alih-alih menarik flag melalui tiga tingkat panggilan, pikirkan apakah pilihan filter harus diambil di tingkat atas dan dikirim sebagai konfigurasi siap pakai. Semakin sedikit flag boolean dalam kode — semakin sedikit sihir.

Terapkan aturan: tidak ada parameter boolean yang dikirim ke metode tanpa argumen bernama (jika bahasa mendukung named arguments). Di Kotlin dan Swift persyaratan ini terpenuhi secara otomatis. Di Java gunakan Builder atau konstanta enum alih-alih true/false.

Alat deteksi sihir

Pencarian nilai magis diotomatiskan oleh penganalisis statis yang dikonfigurasi untuk mengidentifikasi literal di tempat yang tidak terduga. Setiap bahasa menawarkan alatnya sendiri dengan pengecualian yang dapat dikonfigurasi.

AlatBahasaAturan
SonarQubeJava, Kotlin, Swift, Python, JSMagicNumber, HardcodedString
ESLintJavaScript, TypeScriptno-magic-numbers, no-hardcoded-strings
DetektKotlinMagicNumber, ComplexCondition
SwiftLintSwiftmagic_number (diaktifkan opt-in)
PMDJava, Apex, PLSQLMagicNumber (daftar yang diizinkan dapat dikonfigurasi)
PhpStorm InspectionsPHPNumericLiteralWithContext (inspeksi bawaan)

Konfigurasi pengecualian sangat penting — tanpanya penganalisis akan memberikan peringatan pada setiap increment (-1, +1) dan nol matematis. Untuk SonarQube daftar angka yang diizinkan: 0, 1, -1, 2 (untuk pelipatan), 100 (persen), 60 dan 24 (waktu). Untuk semua nilai lainnya — minta konstanta bernama dengan pengubah public static final (Java) atau const val (Kotlin).

Untuk analisis di tingkat CI, tambahkan langkah dengan pemeriksaan sihir sebagai peringatan, tetapi tidak memblokir build. Eksekusi pertama akan menunjukkan ratusan peringatan di kode lama. Secara bertahap, tiket demi tiket, pindahkan kode ke konstanta dan naikkan ambang kualitas. Ketika jumlah magic numbers menjadi kurang dari 10 — aktifkan aturan sebagai kesalahan build.

Refactoring: mengganti sihir dengan konstanta

Refactoring sihir — salah satu operasi paling aman: mengganti literal dengan konstanta tidak mengubah perilaku kode. Meskipun demikian, pendekatan harus sistematis agar tidak melewatkan ketergantungan tersembunyi (misalnya, jika magic number yang sama digunakan dalam konteks yang tidak terkait tetapi secara kebetulan memiliki nilai yang sama).

Proses langkah demi langkah: temukan semua kemunculan nilai magis, pahami konteks masing-masing, pisahkan ke konstanta berbeda (bahkan jika nilainya sama — konteksnya berbeda dan konstanta harus dinamai berbeda), ganti literal dengan konstanta, periksa melalui pengujian. Kesalahan pada langkah 2 — yang paling umum: dua konsep berbeda (timeout dalam milidetik dan ambang dalam byte) mungkin secara numerik sama (misalnya 5000), tetapi secara semantik ini adalah besaran yang berbeda dan tidak dapat digabungkan menjadi satu konstanta.

java
// sebelum — angka yang sama dalam konteks berbeda
public class Config {
    public void setupCache() {
        cache.setMaxSize(5000); // 5 MB
    }
    public void setupTimeout() {
        client.setReadTimeout(5000); // 5 detik
    }
}

// sesudah — konstanta berbeda untuk konteks berbeda
public class Config {
    private static final int CACHE_MAX_SIZE_MB = 5;
    private static final int READ_TIMEOUT_SECONDS = 5;

    public void setupCache() {
        cache.setMaxSize(CACHE_MAX_SIZE_MB * 1024 * 1024);
    }
    public void setupTimeout() {
        client.setReadTimeout(
            READ_TIMEOUT_SECONDS * 1000
        );
    }
}

Untuk kode baru aturannya sederhana: setiap literal, kecuali 0, 1, -1, true, false, null, dan string kosong, diekstraksi ke konstanta. Pengecualian: konstanta matematis (selalu melalui perpustakaan standar), data pengujian (literal boleh dibiarkan dalam pengujian, tetapi dengan nama variabel yang menjelaskan) dan nilai batas untuk increment (i + 1 dalam loop — normal).

Pertanyaan yang Sering Diajukan

Apakah 100 adalah magic number jika itu 100 persen?

Ya, 100 juga magic number jika digunakan tanpa konteks. Alih-alih 100 tulis MAX_PERCENT atau PROBABILITY_SCALE. Pengecualian: ketika 100 adalah persen yang jelas dalam konteks (misalnya, dalam rumus perhitungan persen), tetapi bahkan dalam kasus ini konstanta meningkatkan keterbacaan.

Bagaimana dengan angka dalam pengujian?

Dalam pengujian juga lebih baik menggunakan variabel bernama. Alih-alih assertEquals(42, result) tulis val expected = 42; assertEquals(expected, result). Pengecualian: pengujian pada nilai batas (0, null, string kosong) — dapat dibiarkan sebagai literal karena terbaca dalam konteks pengujian.

Apakah layak mengekstrak angka ke sumber daya Android?

Ya, angka yang terkait dengan UI (ukuran, margin, durasi animasi) harus ada di sumber daya (dimens.xml, integers.xml). Konstanta bisnis (timeout, batas) — di companion object atau file konfigurasi. Kriteria utama: jika angka dapat berubah tanpa mengubah logika — itu adalah sumber daya.

Bagaimana menemukan magic numbers di proyek lama?

Jalankan SonarQube dengan aturan MagicNumber atau ESLint dengan no-magic-numbers. Dapatkan laporan, urutkan berdasarkan frekuensi penggunaan dan mulai dengan angka yang muncul di tiga atau lebih tempat. Angka-angka tersebut dengan probabilitas tertinggi adalah kandidat untuk ekstraksi ke konstanta.

Apakah setiap angka dalam kode harus diekstrak ke konstanta?

Tidak. Literal yang diizinkan: 0, 1, -1 (increment/decrement, pemeriksaan kekosongan), true, false, null, string kosong. Semua lainnya memerlukan penamaan. Jika angka 0 digunakan bukan sebagai pemeriksaan kekosongan (misalnya, 0 — adalah ID kategori root), maka 0 juga harus menjadi konstanta: ROOT_CATEGORY_ID = 0.

Kesimpulan

  • Sihir — literal tanpa penjelasan: angka, string, flag yang maknanya tersembunyi dari pembaca kode.
  • Magic numbers — konstanta numerik tanpa nama (86400, 1024, 0.85, 5000) yang memerlukan pengetahuan domain untuk dipahami.
  • Magic strings — hardcode kunci, URL, dan jalur, tidak terlihat oleh kompiler dan menyebabkan bug runtime.
  • Magic flags — parameter boolean yang nilainya tidak jelas (true/false dalam panggilan metode).
  • Alat: SonarQube, ESLint, Detekt, SwiftLint, PMD — semuanya mendukung aturan MagicNumber.
  • Solusi: setiap literal (kecuali 0, ±1, true, false, null, “”) diekstraksi ke konstanta bernama dengan nama yang menjelaskan.
  • Konteks berbeda — konstanta berbeda: 5000 sebagai timeout dan 5000 sebagai ukuran cache — adalah entitas yang berbeda.

Kami akan mengembangkan aplikasi seluler turnkey

IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.

Diskusikan proyek

Baca juga