Komentar

Komentar #

Komentar adalah salah satu hal dalam pemrograman yang sering disepelekan oleh pemula dan disalahgunakan oleh yang lebih berpengalaman. Komentar yang baik bukan sekadar terjemahan kode ke bahasa manusia — ia menjelaskan mengapa sesuatu dilakukan, bukan apa yang dilakukan (itu sudah terlihat dari kode itu sendiri). Kotlin mendukung tiga jenis komentar: komentar satu baris, komentar multi-baris, dan komentar dokumentasi KDoc. Masing-masing punya konteks penggunaan yang tepat, dan memahami kapan menggunakan mana adalah keterampilan yang membedakan kode yang mudah dipelihara dari yang menjadi beban tim.

Komentar Satu Baris #

Komentar satu baris dimulai dengan //. Semua teks setelah // hingga akhir baris diabaikan sepenuhnya oleh compiler — tidak mempengaruhi eksekusi program sama sekali.

// Ini adalah komentar satu baris yang berdiri sendiri
val batasUmur = 18 // batas minimal untuk membuat akun

val harga = 50_000
val diskon = 0.10
val hargaAkhir = harga * (1 - diskon) // hasil: 45000.0

Komentar satu baris paling sering digunakan dalam dua posisi: di baris sendiri sebelum blok kode yang perlu penjelasan, atau di akhir baris sebagai keterangan singkat (inline comment).

Kapan Komentar Satu Baris Tepat Digunakan #

Gunakan komentar satu baris untuk menjelaskan hal-hal yang tidak langsung terlihat dari kode:

// BENAR: menjelaskan alasan di balik magic number
val TIMEOUT_MS = 5_000 // batas toleransi latensi jaringan internal per SLA

// BENAR: menjelaskan edge case yang tidak intuitif
val indeksAkhir = daftar.size - 1 // size() mengembalikan 1-based, indeks adalah 0-based

// BENAR: menandai bagian yang perlu perhatian khusus
val hash = md5(password) // TODO: ganti ke bcrypt sebelum production — lihat tiket SEC-204

// ANTI-PATTERN: komentar yang hanya mengulang kode
val nama = "Budi" // set nama ke Budi
val umur = 25     // set umur ke 25
println(nama)     // cetak nama

Komentar terakhir di atas tidak menambah informasi apa pun. Siapa pun yang membaca val nama = "Budi" sudah tahu apa yang sedang terjadi — tidak perlu ditulis ulang dalam bahasa manusia.


Komentar Multi-Baris #

Komentar multi-baris dibuka dengan /* dan ditutup dengan */. Semua teks di antara keduanya — berapa pun banyak barisnya — diperlakukan sebagai komentar.

/*
    Algoritma ini menggunakan pendekatan sliding window untuk menghitung
    rata-rata bergerak dengan kompleksitas O(n), alih-alih O(n²) jika
    menggunakan nested loop. Referensi: https://en.wikipedia.org/wiki/Sliding_window_protocol
*/
fun rataRataBergerak(data: List<Double>, window: Int): List<Double> {
    if (data.size < window) return emptyList()
    
    val hasil = mutableListOf<Double>()
    var jumlah = data.take(window).sum()
    hasil.add(jumlah / window)
    
    for (i in window until data.size) {
        jumlah += data[i] - data[i - window]
        hasil.add(jumlah / window)
    }
    
    return hasil
}

Komentar Multi-Baris Tersarang #

Salah satu keunggulan Kotlin dibanding Java: komentar multi-baris bisa tersarang (nested). Di Java, menempatkan /* ... */ di dalam /* ... */ adalah error kompilasi. Di Kotlin, ini valid.

/*
    Fungsi ini menangani tiga skenario berbeda:
    
    /* Skenario 1: data kosong */
    Jika list kosong, kembalikan emptyList() langsung
    
    /* Skenario 2: window lebih besar dari data */
    Tidak bisa menghitung rata-rata  kembalikan emptyList()
    
    /* Skenario 3: normal */
    Hitung dengan sliding window
*/
fun prosesData(data: List<Double>, window: Int): List<Double> {
    // implementasi...
    return emptyList()
}

Ini berguna terutama saat kamu perlu men-comment-out blok kode yang di dalamnya sudah mengandung komentar multi-baris.

Menonaktifkan Kode Sementara #

Salah satu penggunaan komentar multi-baris yang sangat praktis adalah menonaktifkan blok kode sementara selama debugging atau eksperimen, tanpa menghapusnya.

fun hitungTotal(items: List<Int>): Int {
    /*
    // Implementasi lama — terlalu lambat untuk dataset besar
    var total = 0
    for (item in items) {
        total += item
    }
    return total
    */
    
    // Implementasi baru dengan reduce
    return items.reduce { acc, item -> acc + item }
}
Jangan biarkan kode yang di-comment-out dalam waktu lama di codebase production. Jika kode lama masih relevan sebagai referensi, simpan di version control (Git history) — bukan sebagai komentar. Kode yang di-comment-out menambah noise dan membingungkan developer lain.

Komentar Dokumentasi — KDoc #

KDoc adalah sistem dokumentasi resmi Kotlin, setara dengan Javadoc di Java. Komentar KDoc dimulai dengan /** dan diakhiri dengan */. Setiap baris di dalamnya biasanya diawali dengan * (spasi, asterisk, spasi) meskipun ini bukan keharusan.

KDoc bukan sekadar komentar biasa — ia dibaca oleh tool seperti Dokka untuk menghasilkan dokumentasi HTML otomatis, dan ditampilkan langsung di IntelliJ IDEA saat kamu hover ke atas fungsi atau kelas.

/**
 * Menghitung bunga majemuk berdasarkan modal awal, suku bunga, dan durasi.
 *
 * Formula yang digunakan: A = P(1 + r/n)^(nt)
 * di mana P adalah modal awal, r adalah suku bunga tahunan (desimal),
 * n adalah frekuensi penggandaan per tahun, dan t adalah durasi dalam tahun.
 *
 * @param modal Modal awal dalam Rupiah
 * @param sukuBunga Suku bunga tahunan dalam bentuk desimal (contoh: 0.05 untuk 5%)
 * @param tahun Durasi investasi dalam tahun
 * @param frekuensi Frekuensi penggandaan per tahun (default: 12 untuk bulanan)
 * @return Total nilai investasi setelah periode yang ditentukan
 */
fun bungaMajemuk(
    modal: Double,
    sukuBunga: Double,
    tahun: Int,
    frekuensi: Int = 12
): Double {
    return modal * Math.pow(1 + sukuBunga / frekuensi, (frekuensi * tahun).toDouble())
}

Tag KDoc yang Tersedia #

KDoc mendukung berbagai tag untuk mendokumentasikan aspek yang berbeda dari sebuah deklarasi:

TagKegunaanContoh
@param namaMendokumentasikan parameter fungsi@param id ID unik pengguna
@returnMenjelaskan nilai yang dikembalikan@return null jika tidak ditemukan
@throws KelasExceptionMendokumentasikan exception yang mungkin dilempar@throws IOException jika file tidak bisa dibaca
@property namaMendokumentasikan property di data class@property nama Nama lengkap pengguna
@constructorMendokumentasikan primary constructor@constructor Buat instance dengan konfigurasi awal
@seeReferensi ke deklarasi atau URL lain@see Pengguna
@sinceVersi sejak fitur ini tersedia@since 1.2.0
@suppressMenyembunyikan peringatan IDE tertentu@suppress("UNCHECKED_CAST")
@sampleMenyertakan contoh kode dari tempat lain@sample contoh.PenggunaContoh.buatPengguna

KDoc untuk Kelas #

/**
 * Representasi seorang pengguna dalam sistem.
 *
 * Kelas ini adalah data class yang digunakan sebagai model utama
 * untuk operasi CRUD pengguna. Setiap pengguna memiliki ID unik
 * yang di-generate saat pembuatan dan tidak bisa diubah.
 *
 * @property id ID unik pengguna — di-generate otomatis oleh database
 * @property nama Nama lengkap pengguna, minimal 2 karakter
 * @property email Alamat email terverifikasi, harus unik di seluruh sistem
 * @property peran Peran pengguna dalam sistem, default [Peran.PENGGUNA]
 * @property aktif Status aktif akun, false berarti akun di-suspend
 *
 * @see PenggunaRepository
 * @see Peran
 * @since 1.0.0
 */
data class Pengguna(
    val id: Long,
    val nama: String,
    val email: String,
    val peran: Peran = Peran.PENGGUNA,
    val aktif: Boolean = true
)

/**
 * Peran yang tersedia dalam sistem otorisasi.
 *
 * @property ADMIN Akses penuh ke seluruh fitur dan manajemen pengguna
 * @property MODERATOR Bisa mengelola konten tapi tidak bisa mengubah pengguna lain
 * @property PENGGUNA Akses standar ke fitur yang tersedia untuk publik
 */
enum class Peran {
    ADMIN, MODERATOR, PENGGUNA
}

KDoc untuk Interface #

/**
 * Kontrak untuk semua repository yang mengelola data pengguna.
 *
 * Implementasi interface ini harus thread-safe karena bisa dipanggil
 * dari coroutine yang berjalan di thread berbeda secara bersamaan.
 *
 * @see Pengguna
 * @see PenggunaRepositoryImpl
 */
interface PenggunaRepository {
    
    /**
     * Mencari pengguna berdasarkan ID-nya.
     *
     * @param id ID pengguna yang dicari
     * @return Objek [Pengguna] jika ditemukan, null jika tidak ada
     */
    suspend fun cariById(id: Long): Pengguna?
    
    /**
     * Mencari pengguna berdasarkan alamat email.
     *
     * Pencarian bersifat case-insensitive — "[email protected]" dan
     * "[email protected]" dianggap email yang sama.
     *
     * @param email Alamat email yang dicari
     * @return Objek [Pengguna] jika ditemukan, null jika tidak ada
     */
    suspend fun cariByEmail(email: String): Pengguna?
    
    /**
     * Menyimpan pengguna baru ke dalam database.
     *
     * @param pengguna Data pengguna yang akan disimpan. Field [Pengguna.id]
     *                 akan diabaikan — ID di-generate oleh database.
     * @return Objek [Pengguna] lengkap dengan ID yang baru di-generate
     * @throws IllegalArgumentException jika email sudah terdaftar
     * @throws IllegalArgumentException jika nama lebih pendek dari 2 karakter
     */
    suspend fun simpan(pengguna: Pengguna): Pengguna
    
    /**
     * Menghapus pengguna secara permanen dari database.
     *
     * Operasi ini tidak bisa di-undo. Semua data terkait pengguna
     * (profil, riwayat transaksi, dll) ikut terhapus karena foreign key
     * constraint dengan CASCADE DELETE.
     *
     * @param id ID pengguna yang akan dihapus
     * @return true jika pengguna berhasil dihapus, false jika ID tidak ditemukan
     */
    suspend fun hapus(id: Long): Boolean
}

Formatting Teks dalam KDoc #

KDoc mendukung subset dari Markdown untuk memformat teks deskripsi:

/**
 * Memvalidasi kekuatan password berdasarkan kriteria berikut:
 *
 * - Minimal **8 karakter**
 * - Mengandung minimal satu **huruf besar**
 * - Mengandung minimal satu **angka**
 * - Mengandung minimal satu **karakter spesial** (`!@#$%^&*`)
 *
 * Contoh penggunaan:
 * ```kotlin
 * val kuat = validasiPassword("P@ssw0rd!")  // true
 * val lemah = validasiPassword("password")  // false
 * ```
 *
 * > **Catatan:** Fungsi ini hanya memvalidasi format, bukan memeriksa
 * > apakah password pernah bocor di database credential leak.
 *
 * @param password Password yang akan divalidasi
 * @return true jika memenuhi semua kriteria, false jika tidak
 * @see [HaveIBeenPwned](https://haveibeenpwned.com/API/v3) untuk cek credential leak
 */
fun validasiPassword(password: String): Boolean {
    val hurufBesar = Regex("[A-Z]")
    val angka = Regex("[0-9]")
    val karakterSpesial = Regex("[!@#\$%^&*]")
    
    return password.length >= 8 &&
        hurufBesar.containsMatchIn(password) &&
        angka.containsMatchIn(password) &&
        karakterSpesial.containsMatchIn(password)
}

Referensi Silang dalam KDoc #

Kamu bisa mereferensikan kelas, fungsi, atau property lain dengan notasi [NamaDeklarasi]:

/**
 * Mengirim notifikasi ke semua pengguna dengan peran [Peran.ADMIN].
 *
 * Fungsi ini memanggil [kirimEmail] secara internal untuk setiap admin.
 * Pastikan konfigurasi SMTP sudah benar di [KonfigurasiEmail] sebelum
 * memanggil fungsi ini.
 *
 * @param pesan Isi notifikasi yang akan dikirim
 * @throws [EmailException] jika koneksi SMTP gagal
 */
fun notifikasiAdmin(pesan: String) {
    // implementasi...
}

Menghasilkan Dokumentasi dengan Dokka #

Dokka adalah tool resmi untuk menghasilkan dokumentasi HTML dari KDoc. Cara menggunakannya di proyek Gradle:

Tambahkan plugin ke build.gradle.kts:

plugins {
    kotlin("jvm") version "2.0.0"
    id("org.jetbrains.dokka") version "1.9.20"
}

Generate dokumentasi:

./gradlew dokkaHtml

Hasilnya berupa situs HTML lengkap di build/dokka/html/ yang bisa di-host di mana saja — GitHub Pages, internal server, atau mana pun.

flowchart LR
    A["File .kt\n(dengan KDoc)"] --> B["Dokka\nProcessor"]
    B --> C["HTML\nbuild/dokka/html/"]
    B --> D["Markdown\nbuild/dokka/gfm/"]
    B --> E["Javadoc format\nbuild/dokka/javadoc/"]
    C --> F["GitHub Pages /\nInternal Server"]

Filosofi Komentar yang Baik #

Memahami sintaks komentar hanyalah separuh dari ceritanya. Separuh lagi adalah tahu kapan menulis komentar dan apa yang layak dikomentar.

Kode yang Baik Adalah Dokumentasi Terbaik #

Nama variabel, fungsi, dan kelas yang deskriptif mengurangi kebutuhan komentar secara drastis.

// ANTI-PATTERN: nama tidak deskriptif, butuh komentar untuk menjelaskan
// Hitung d berdasarkan formula bisnis
fun calc(p: Double, r: Double, t: Int): Double {
    return p * Math.pow(1 + r, t.toDouble())
}

// BENAR: nama yang deskriptif — komentar tidak diperlukan
fun hitungNilaiAkhirInvestasi(modalAwal: Double, sukuBungaTahunan: Double, tahun: Int): Double {
    return modalAwal * Math.pow(1 + sukuBungaTahunan, tahun.toDouble())
}

Jelaskan “Mengapa”, Bukan “Apa” #

// ANTI-PATTERN: menjelaskan apa yang sudah jelas
val batasHalaman = 20 // set batas halaman ke 20

// BENAR: menjelaskan mengapa angka ini dipilih
val batasHalaman = 20 // dikalibrasi berdasarkan median waktu scroll pengguna mobile — lihat riset UX Q3

// ANTI-PATTERN: menjelaskan yang sudah terlihat dari kode
// Loop dari 0 sampai panjang list
for (i in 0 until daftar.size) { ... }

// BENAR: tidak perlu komentar sama sekali jika kodenya sudah jelas
for (item in daftar) { ... }

Komentar sebagai Tanda Bahaya #

Jika kamu merasa perlu komentar panjang untuk menjelaskan sepotong kode, itu sering kali sinyal bahwa kodenya perlu di-refactor.

// ANTI-PATTERN: komentar panjang menutupi kode yang kompleks
// Fungsi ini mengambil data dari cache jika ada,
// kalau tidak ada ambil dari database, simpan ke cache,
// kemudian kembalikan hasilnya, tapi kalau database juga error,
// coba fallback ke file lokal, kalau semua gagal return null
fun ambilData(id: String): Data? {
    // ... 80 baris kode kompleks ...
}

// BENAR: ekstrak ke fungsi-fungsi kecil yang namanya berbicara sendiri
fun ambilData(id: String): Data? {
    return ambilDariCache(id)
        ?: ambilDariDatabaseDanCache(id)
        ?: ambilDariFallbackLokal(id)
}

TODO dan FIXME #

Kotlin (dan IntelliJ IDEA) mengenali komentar dengan prefix khusus sebagai penanda tugas:

// TODO: tambahkan validasi input sebelum memanggil API eksternal
fun kirimData(payload: String) { ... }

// FIXME: ada race condition di sini ketika dua thread memanggil ini bersamaan
fun updateKonter() { ... }

// HACK: workaround untuk bug di library pihak ketiga versi 2.3.1
// Hapus ini setelah mereka release fix di versi 2.4.0
val hasil = library.prosesData(input.trim() + "\n")

// NOTE: fungsi ini sengaja tidak menggunakan coroutine karena
// perlu diblok sampai selesai — konteks pemanggil mengharapkan nilai sinkron
fun ambilKonfigurasi(): Config { ... }

IntelliJ IDEA menampilkan semua TODO dan FIXME dalam panel khusus (View → Tool Windows → TODO), sehingga kamu bisa melacak semua pekerjaan yang tertunda tanpa perlu mencari manual di seluruh codebase.


Komentar di Berbagai Konteks #

Komentar di Header File #

Untuk file yang berisi fungsi-fungsi utilitas atau konstanta, komentar di awal file berguna untuk menjelaskan tujuan file secara keseluruhan.

/*
 * Utilitas untuk operasi kriptografi yang digunakan di seluruh aplikasi.
 *
 * Semua fungsi di file ini menggunakan algoritma yang sudah diaudit keamanannya.
 * JANGAN menambahkan implementasi kriptografi kustom — gunakan yang sudah ada di sini.
 *
 * Penulis: Tim Security
 * Terakhir diperbarui: 2024-03
 */

package com.myapp.util.crypto

import javax.crypto.Cipher
// ...

Komentar di Blok Kompleks #

fun kompresiData(data: ByteArray): ByteArray {
    val output = ByteArrayOutputStream()
    
    // GZIPOutputStream harus di-flush dan close secara eksplisit
    // sebelum mengambil bytes dari ByteArrayOutputStream.
    // Memanggil output.toByteArray() sebelum gzip.close() menghasilkan
    // data yang corrupt — ini perilaku yang tidak intuitif dari Java IO.
    GZIPOutputStream(output).use { gzip ->
        gzip.write(data)
    }
    
    return output.toByteArray()
}

Komentar untuk Regex #

Regex adalah salah satu konteks di mana komentar hampir selalu diperlukan karena sintaksnya tidak mudah dibaca.

// Format: +62-XXX-XXXX-XXXX atau 08XX-XXXX-XXXX
// Mendukung spasi, dash, atau tanpa pemisah
val REGEX_NOMOR_TELEPON_ID = Regex(
    """^(\+62|0)[0-9]{2,3}[-\s]?[0-9]{3,4}[-\s]?[0-9]{4}$"""
)

// Format email standar — tidak mendukung quoted string atau IP literal
// karena use case kami tidak memerlukannya
val REGEX_EMAIL = Regex("""^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$""")

Ringkasan #

  • Tiga jenis komentar// untuk satu baris, /* */ untuk multi-baris, /** */ untuk KDoc. Masing-masing punya konteks yang tepat.
  • Komentar multi-baris Kotlin bisa tersarang — berbeda dari Java, /* /* */ */ valid di Kotlin. Ini berguna saat men-comment-out kode yang sudah mengandung komentar.
  • KDoc adalah standar dokumentasi resmi — gunakan /** */ dengan tag @param, @return, @throws, dan lainnya untuk mendokumentasikan public API. Ini dibaca IDE dan tool Dokka.
  • Jelaskan “mengapa”, bukan “apa” — komentar terbaik menjelaskan niat, alasan, atau konteks yang tidak terlihat dari kode itu sendiri. Kode yang sudah ekspresif tidak butuh komentar yang sekadar menerjemahkannya.
  • Kode bersih mengurangi kebutuhan komentar — nama yang deskriptif untuk variabel, fungsi, dan kelas adalah dokumentasi terbaik. Jika kamu perlu komentar panjang untuk menjelaskan satu fungsi, pertimbangkan untuk me-refactor fungsinya.
  • Hapus kode yang di-comment-out — simpan di Git history, bukan di codebase aktif. Komentar berupa kode mati menambah noise dan membingungkan.
  • Gunakan TODO dan FIXME secara konsisten — IntelliJ IDEA dan sebagian besar tool CI bisa melacaknya secara otomatis, sehingga tidak ada tugas yang terlupakan.
  • Dokka untuk dokumentasi otomatis — dengan plugin Dokka dan KDoc yang baik, kamu bisa generate situs dokumentasi HTML lengkap hanya dengan satu perintah Gradle.

← Sebelumnya: Sintaks Utama   Berikutnya: Variabel →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact