Komentar

Komentar #

Komentar adalah salah satu fitur paling sederhana di semua bahasa pemrograman, tapi juga salah satu yang paling sering disalahgunakan. Komentar yang buruk lebih berbahaya daripada tidak ada komentar sama sekali — ia menyesatkan pembaca dan menciptakan kontradiksi ketika kode berubah tapi komentarnya tidak. Dart memiliki tiga jenis komentar dengan tujuan yang berbeda: satu untuk penjelasan inline cepat, satu untuk menonaktifkan blok kode, dan satu yang diproses oleh tooling untuk menghasilkan dokumentasi formal. Memahami kapan menggunakan masing-masing adalah keterampilan yang membedakan kode yang mudah dipelihara dari kode yang menjadi beban tim.

Mengapa Komentar Penting — dan Kapan Tidak #

Sebelum masuk ke sintaks, penting untuk memahami filosofi dasar: kode yang baik seharusnya sudah self-documenting. Nama variabel, nama fungsi, dan struktur kode yang baik seharusnya menjelaskan apa yang terjadi. Komentar ada untuk menjelaskan mengapa — konteks, keputusan desain, dan trade-off yang tidak bisa diungkapkan oleh kode itu sendiri.

// ANTI-PATTERN: komentar yang hanya mengulang kode — tidak menambah nilai
int i = 0; // set i ke 0
i++;        // tambah i sebesar 1
return i;   // kembalikan i

// BENAR: komentar yang menjelaskan MENGAPA, bukan APA
// Mulai dari 0 karena indeks halaman berbasis 0 di API eksternal,
// tapi UI menampilkan dari halaman 1 — konversi dilakukan di sini.
int halaman = 0;
halaman++;
return halaman;
// ANTI-PATTERN: komentar kompensasi untuk nama yang buruk
// Fungsi ini menghitung x berdasarkan y dan z
double hitung(double y, double z) {
  return y * z * 0.1;
}

// BENAR: nama yang ekspresif menghilangkan kebutuhan komentar penjelasan
double hitungDiskon(double hargaAsli, double persentaseDiskon) {
  return hargaAsli * persentaseDiskon * 0.01;
}

Aturan praktisnya: jika kamu merasa perlu menulis komentar untuk menjelaskan apa yang dilakukan sebaris kode, pertimbangkan dulu apakah kode itu bisa ditulis ulang dengan nama yang lebih baik. Gunakan komentar untuk menjelaskan mengapa keputusan tertentu diambil — hal yang tidak bisa diungkapkan oleh kode.

flowchart TD
    A{Apakah komentar ini perlu?} -- Menjelaskan APA yang dilakukan kode --> B{Bisakah kode ditulis\nlebih jelas?}
    B -- Ya --> C[Refactor nama/struktur kode\nJangan tulis komentar]
    B -- Tidak --> D[Tulis komentar satu baris //]
    A -- Menjelaskan MENGAPA\nkeputusan diambil --> E[Tulis komentar //]
    A -- Mendokumentasikan\nAPI publik --> F[Tulis komentar DartDoc ///]
    A -- Menonaktifkan kode\nsementara --> G[Gunakan /* */ multi-baris]

Komentar Satu Baris (//) #

Komentar satu baris adalah jenis yang paling sering digunakan. Dimulai dengan // dan berlaku hingga akhir baris — apapun setelah // diabaikan oleh compiler. Dart juga mendukung penempatan komentar di akhir baris kode (inline comment), yang berguna untuk penjelasan singkat yang terikat erat pada satu statement tertentu.

// Komentar di baris tersendiri — untuk penjelasan sebelum blok kode
void prosesOrder(Order order) {
  // Validasi dilakukan sebelum menyentuh database agar tidak ada
  // data parsial yang tersimpan jika validasi gagal di tengah jalan.
  validasiOrder(order);

  // Simpan ke database
  simpanOrder(order);

  kirimEmail(order.email); // Notifikasi ke pelanggan setelah order tersimpan
}

Kapan Menggunakan Komentar Satu Baris #

// ✓ Menjelaskan keputusan non-obvious
// Gunakan ceiling bukan floor agar pengguna tidak merasa "dirugikan"
// saat jumlah tidak habis dibagi.
int jumlahHalaman = (totalItem / itemPerHalaman).ceil();

// ✓ Menandai bagian yang perlu perhatian khusus
// TODO: Ganti dengan cache setelah endpoint /v2/produk tersedia
List<Produk> produk = await apiLama.ambilProduk();

// ✓ Menjelaskan nilai magic number
const int batasRetry = 3;        // Standar industri untuk HTTP retry
const int timeoutDetik = 30;     // Batas maksimum dari SLA kontrak

// ✗ Jangan: komentar yang noise tanpa informasi baru
String nama = 'Budi'; // nama = 'Budi'
int umur = 25;         // umur adalah 25

Komentar TODO, FIXME, dan HACK #

Dart (dan editor seperti VS Code) mengenali beberapa prefix konvensional yang bisa disorot secara khusus:

// TODO: Implementasikan pagination sebelum rilis ke production
List<Produk> semuaProduk = await repository.ambilSemua();

// FIXME: Ada kondisi race ketika dua request datang bersamaan —
// perlu mutex atau atomic operation di sini.
stok -= jumlahPesan;

// HACK: Workaround untuk bug di library pihak ketiga versi 2.1.0
// Hapus ini setelah mereka merilis patch — lihat issue #4521
response = response.copyWith(headers: {'Content-Type': 'application/json'});

// DEPRECATED: Gunakan hitungDiskonV2() yang sudah mendukung diskon bertingkat
double hitungDiskon(double harga) => harga * 0.1;
VS Code dengan ekstensi Todo Tree atau Better Comments bisa memvisualisasikan semua TODO dan FIXME dalam project dalam satu panel, sehingga tidak ada yang terlewat saat code review.

Komentar Multi-baris (/* */) #

Komentar multi-baris membungkus semua teks di antara /* dan */ — bisa mencakup satu baris atau ratusan baris. Tidak seperti beberapa bahasa lain, Dart mendukung nested block comments — artinya /* */ bisa bersarang di dalam /* */ lainnya. Ini sangat berguna saat kamu perlu menonaktifkan sementara blok kode yang di dalamnya sudah ada komentar multi-baris.

/*
  Ini komentar multi-baris standar.
  Bisa mencakup berapa baris pun yang diperlukan.
  Dart juga mendukung nested block comment seperti ini:
  /*
    Ini nested comment — valid di Dart, tidak valid di C/Java.
  */
  Kembali ke komentar luar.
*/

Penggunaan Utama: Menonaktifkan Kode Sementara #

Penggunaan paling praktis dari /* */ adalah menonaktifkan blok kode saat debugging atau eksperimen, tanpa harus menghapusnya:

void main() {
  var data = ambilData();

  /*
  // Kode lama yang sedang dibandingkan performanya:
  var hasil = prosesLambat(data);
  print('Metode lama: ${stopwatch.elapsedMilliseconds}ms');
  */

  // Metode baru yang sedang diuji:
  var hasil = prosesCepat(data);
  print('Metode baru: ${stopwatch.elapsedMilliseconds}ms');
}

Karena Dart mendukung nested comment, menonaktifkan blok yang sudah berisi /* */ tidak menyebabkan error:

/*
  Blok ini dinonaktifkan sementara untuk A/B testing.
  Di dalamnya ada komentar multi-baris lain:
  /*
    Catatan tentang algoritma sebelumnya.
  */
  Dan ini tetap bagian dari komentar luar  valid di Dart.
*/
// ANTI-PATTERN: menggunakan /* */ untuk dokumentasi fungsi/kelas
/*
  Menghitung luas lingkaran.
  Parameter: radius — jari-jari lingkaran.
*/
double hitungLuasLingkaran(double radius) {
  return 3.14159 * radius * radius;
}
// Komentar ini tidak akan diproses oleh dart doc — tidak muncul di dokumentasi

// BENAR: gunakan /// untuk dokumentasi yang akan diproses tooling
/// Menghitung luas lingkaran berdasarkan jari-jari yang diberikan.
///
/// [radius] adalah jari-jari lingkaran dalam satuan meter.
/// Mengembalikan luas dalam meter persegi.
double hitungLuasLingkaran(double radius) {
  return 3.14159 * radius * radius;
}
Jenis Komentar Diproses DartDoc Nested Cocok untuk
// N/A Penjelasan inline, TODO/FIXME
/* */ Menonaktifkan blok kode sementara
/// Dokumentasi API publik
/** */ Dokumentasi API publik (alternatif)

Komentar Dokumentasi (///) #

Komentar dokumentasi adalah fitur Dart yang paling powerful dari ketiganya, tapi juga yang paling jarang dimanfaatkan secara penuh. Setiap baris dimulai dengan ///, dan semua komentar /// yang berurutan tepat sebelum sebuah deklarasi akan diproses oleh dart doc untuk menghasilkan halaman HTML dokumentasi. Editor seperti VS Code dan IntelliJ juga menampilkan komentar ini sebagai tooltip saat hover di atas simbol.

/// Menghitung nilai diskon berdasarkan harga asli dan persentase.
///
/// Fungsi ini mengikuti aturan pembulatan ke atas (ceiling) agar
/// hasil diskon tidak pernah melebihi nilai yang seharusnya.
///
/// Contoh penggunaan:
/// ```dart
/// double diskon = hitungDiskon(150000, 20);
/// print(diskon); // 30000.0
/// ```
///
/// Parameter:
/// - [hargaAsli] — harga sebelum diskon, harus bernilai positif
/// - [persentase] — nilai diskon dalam persen (0–100)
///
/// Throws [ArgumentError] jika [hargaAsli] atau [persentase] negatif.
/// Returns nilai diskon dalam satuan yang sama dengan [hargaAsli].
double hitungDiskon(double hargaAsli, double persentase) {
  if (hargaAsli < 0) throw ArgumentError('hargaAsli tidak boleh negatif');
  if (persentase < 0 || persentase > 100) {
    throw ArgumentError('persentase harus antara 0 dan 100');
  }
  return hargaAsli * persentase / 100;
}

Mendokumentasikan Kelas #

Dokumentasi kelas harus menjelaskan tujuan kelas dan kapan ia digunakan — bukan implementasi internalnya. Properti dan method publik masing-masing didokumentasikan tersendiri:

/// Merepresentasikan produk dalam katalog toko.
///
/// [Produk] menyimpan informasi dasar produk dan menyediakan
/// method untuk operasi umum seperti pengecekan ketersediaan stok
/// dan perhitungan harga setelah diskon.
///
/// Contoh penggunaan:
/// ```dart
/// var produk = Produk(
///   id: 'P001',
///   nama: 'Laptop Gaming',
///   harga: 15000000,
///   stok: 5,
/// );
///
/// if (produk.tersedia) {
///   print('Harga setelah diskon: ${produk.hargaSetelahDiskon(10)}');
/// }
/// ```
class Produk {
  /// Identifikasi unik produk dalam sistem.
  ///
  /// Format: huruf kapital diikuti angka, contoh `P001`, `PRD-042`.
  final String id;

  /// Nama produk yang ditampilkan ke pelanggan.
  String nama;

  /// Harga produk dalam Rupiah tanpa pajak.
  double harga;

  /// Jumlah unit yang tersedia di gudang.
  ///
  /// Nilai negatif tidak diizinkan — gunakan [tambahStok] dan
  /// [kurangiStok] untuk memodifikasinya dengan validasi otomatis.
  int stok;

  /// Membuat instance [Produk] baru.
  ///
  /// [id] dan [nama] wajib diisi. [stok] default ke 0 jika tidak diberikan.
  Produk({
    required this.id,
    required this.nama,
    required this.harga,
    this.stok = 0,
  });

  /// Mengembalikan `true` jika produk masih tersedia (stok > 0).
  bool get tersedia => stok > 0;

  /// Menghitung harga setelah potongan diskon.
  ///
  /// [diskonPersen] adalah persentase diskon (0–100).
  /// Throws [ArgumentError] jika nilai diskon di luar rentang yang valid.
  double hargaSetelahDiskon(double diskonPersen) {
    if (diskonPersen < 0 || diskonPersen > 100) {
      throw ArgumentError('diskonPersen harus antara 0 dan 100');
    }
    return harga * (1 - diskonPersen / 100);
  }

  /// Menambah stok produk sebanyak [jumlah].
  ///
  /// Throws [ArgumentError] jika [jumlah] tidak positif.
  void tambahStok(int jumlah) {
    if (jumlah <= 0) throw ArgumentError('jumlah harus lebih dari 0');
    stok += jumlah;
  }
}

Mendokumentasikan Enum #

Enum juga bisa dan sebaiknya didokumentasikan — terutama ketika nilai-nilainya tidak self-explanatory:

/// Status pemrosesan sebuah order dari dibuat hingga selesai.
///
/// Urutan status normal: [menunggu] → [diproses] → [dikirim] → [selesai].
/// Status [dibatalkan] bisa terjadi dari [menunggu] atau [diproses].
enum StatusOrder {
  /// Order baru dibuat, belum diproses oleh tim gudang.
  menunggu,

  /// Order sedang disiapkan di gudang.
  diproses,

  /// Order sudah diserahkan ke kurir, dalam perjalanan.
  dikirim,

  /// Order sudah diterima pelanggan dan transaksi selesai.
  selesai,

  /// Order dibatalkan — bisa oleh pelanggan atau sistem.
  dibatalkan,
}

Tag DartDoc #

Komentar /// mendukung beberapa tag khusus yang dirender secara berbeda di output HTML dokumentasi. Tag ini membuat dokumentasi jauh lebih terstruktur dan mudah di-scan.

Referensi Simbol dengan [namaSimbol] #

Tanda kurung siku membuat link otomatis ke simbol Dart lain di dokumentasi:

/// Mengambil produk berdasarkan ID dari repository.
///
/// Gunakan [ProdukRepository.ambilSemua] jika kamu butuh daftar lengkap.
/// Kembalikan [Produk] jika ditemukan, atau `null` jika tidak ada.
///
/// Lihat juga [CacheService] untuk strategi caching yang direkomendasikan.
Future<Produk?> ambilProduk(String id);

Blok Kode dalam Dokumentasi #

Contoh kode di dalam dokumentasi menggunakan triple backtick dengan label bahasa — ini dirender sebagai blok kode syntax-highlighted di output HTML:

/// Memformat angka sebagai mata uang Rupiah.
///
/// Contoh:
/// ```dart
/// print(formatRupiah(150000));    // Rp 150.000
/// print(formatRupiah(1500000.5)); // Rp 1.500.001 (dibulatkan ke atas)
/// ```
///
/// Untuk format internasional, gunakan [NumberFormat] dari package `intl`.
String formatRupiah(double jumlah) {
  // implementasi
}

Tag @param, @returns, @throws (Gaya Alternatif) #

Selain format deskriptif bebas, DartDoc juga mengenali beberapa tag gaya Javadoc:

/// Membagi dua bilangan.
///
/// @param pembilang bilangan yang dibagi
/// @param penyebut bilangan pembagi, tidak boleh nol
/// @returns hasil pembagian sebagai double
/// @throws [ArgumentError] jika penyebut adalah nol
double bagi(double pembilang, double penyebut) {
  if (penyebut == 0) throw ArgumentError('penyebut tidak boleh nol');
  return pembilang / penyebut;
}

Namun, gaya deskriptif dengan [namaParameter] dalam teks lebih umum di ekosistem Dart karena lebih mudah dibaca di source code:

/// Membagi dua bilangan.
///
/// [pembilang] adalah angka yang ingin dibagi.
/// [penyebut] tidak boleh nol — throws [ArgumentError] jika nol.
/// Mengembalikan hasil pembagian sebagai [double].
double bagi(double pembilang, double penyebut) {
  if (penyebut == 0) throw ArgumentError('penyebut tidak boleh nol');
  return pembilang / penyebut;
}

@deprecated — Menandai API yang Akan Dihapus #

/// Menghitung diskon sederhana.
///
/// **Deprecated:** Gunakan [hitungDiskonV2] yang mendukung diskon bertingkat.
/// Fungsi ini akan dihapus di versi 3.0.0.
@Deprecated('Gunakan hitungDiskonV2() — akan dihapus di v3.0.0')
double hitungDiskon(double harga) => harga * 0.1;

/// Menghitung diskon dengan dukungan diskon bertingkat.
///
/// Menggantikan [hitungDiskon] dengan kemampuan tambahan:
/// diskon bisa berbeda per kategori produk.
double hitungDiskonV2(double harga, {double persentase = 10}) {
  return harga * persentase / 100;
}

Menghasilkan Dokumentasi dengan dart doc #

Setelah kamu menulis komentar /// yang baik, menghasilkan dokumentasi HTML hanyalah satu perintah:

# Jalankan dari root direktori project
dart doc

# Dokumentasi dihasilkan di folder doc/api/
# Buka di browser:
open doc/api/index.html        # macOS
xdg-open doc/api/index.html    # Linux
start doc/api/index.html       # Windows

Struktur output yang dihasilkan:

doc/
  └── api/
      ├── index.html            ← halaman utama
      ├── produk/               ← satu folder per library
      │   ├── Produk-class.html
      │   ├── StatusOrder.html
      │   └── ...
      └── ...

Konfigurasi dart doc #

Kamu bisa mengkonfigurasi output dart doc melalui file dartdoc_options.yaml di root project:

dartdoc:
  # Halaman tambahan (changelog, contributing guide, dll.)
  categories:
    "Panduan":
      markdown: doc/panduan.md
      name: "Panduan Penggunaan"

  # Exclude file/folder tertentu dari dokumentasi
  exclude:
    - "lib/src/internal/**"

  # Nama package yang ditampilkan
  name: "MyApp API Documentation"
# Lihat semua opsi yang tersedia
dart doc --help

Anti-Pattern Komentar yang Harus Dihindari #

Komentar buruk lebih berbahaya dari tidak ada komentar. Berikut pola yang paling sering ditemui dan cara memperbaikinya.

Komentar yang Bohong #

Komentar yang tidak sinkron dengan kode adalah akar dari banyak bug sulit dilacak:

// ANTI-PATTERN: komentar sudah tidak sesuai kode setelah refactoring
// Menghitung diskon 10%
double diskon = harga * 0.15; // kode sudah diubah ke 15% tapi komentar lupa diupdate

// BENAR: jika logika sudah jelas dari kode, hapus komentar sama sekali
double diskon = harga * PERSENTASE_DISKON; // nama konstanta sudah cukup jelas

Komentar yang Menonaktifkan Kode Terlalu Lama #

// ANTI-PATTERN: kode lama yang "mungkin nanti diperlukan" dikomentari bertahun-tahun
// var hasil = metodeLama(input);
// print('debug: $hasil');
// if (hasil > threshold) return;
var hasil = metodeBar(input);

// BENAR: hapus kode yang tidak dipakai — version control (Git) menyimpan riwayatnya
// Jika kamu takut kehilangan kode lama, tambahkan tag Git atau catatan commit
var hasil = metodeBaru(input);

Over-dokumentasi Internal #

// ANTI-PATTERN: mendokumentasikan detail implementasi private yang sering berubah
class _KeranjangBelanjaState extends State<KeranjangBelanja> {
  /// List internal yang menyimpan item dalam keranjang.
  /// Diinisialisasi sebagai list kosong dan diisi saat pengguna menambahkan produk.
  /// Tidak boleh diakses langsung dari luar kelas.
  List<Item> _items = [];  // private, tidak perlu DartDoc

  // BENAR: dokumentasi DartDoc hanya untuk API publik
  // Variabel private cukup dengan // jika memang perlu komentar
  List<Item> _items = []; // cache lokal, di-sync dengan CartRepository
}
// ANTI-PATTERN: blok komentar besar sebagai "header file" gaya C
//===========================================================
// File: produk_repository.dart
// Author: Budi Santoso
// Date: 2024-01-15
// Description: Repository untuk operasi CRUD produk
// Version: 1.0.0
//===========================================================

// BENAR: informasi ini sudah ada di Git history dan pubspec.yaml
// Mulai langsung dengan kode atau DartDoc kelas

Kapan Menulis Komentar, Kapan Tidak #

Panduan praktis untuk memutuskan apakah sebuah komentar perlu ditulis:

TULIS KOMENTAR ketika:
  ✓ Kode melakukan sesuatu yang counter-intuitive — jelaskan mengapa
  ✓ Ada workaround untuk bug library eksternal — cantumkan nomor issue
  ✓ Ada keputusan desain yang diperdebatkan — catat alasannya
  ✓ Ada batasan non-obvious — misalnya "harus dipanggil setelah init()"
  ✓ Kamu mendokumentasikan API publik — gunakan ///
  ✓ Ada TODO/FIXME yang perlu ditindaklanjuti

JANGAN TULIS KOMENTAR ketika:
  ✗ Kode sudah jelas terbaca — nama fungsi/variabel sudah cukup
  ✗ Komentar hanya mengulang apa yang dilakukan kode (noise)
  ✗ Komentar menjelaskan kode yang seharusnya di-refactor
  ✗ Mendokumentasikan properti/method private dengan DartDoc
  ✗ Komentar header file dengan informasi yang ada di Git

Ringkasan #

  • Tiga jenis komentar Dart// untuk penjelasan inline, /* */ untuk menonaktifkan blok kode sementara, dan /// untuk dokumentasi API yang diproses dart doc.
  • Komentar menjelaskan MENGAPA, bukan APA — jika kamu perlu menjelaskan apa yang dilakukan kode, itu sinyal bahwa kode perlu di-refactor, bukan diberi komentar.
  • /// adalah investasi tim — komentar dokumentasi muncul sebagai tooltip di editor dan dihasilkan menjadi halaman HTML oleh dart doc. Setiap API publik wajib didokumentasikan.
  • Tag [namaSimbol] di dalam /// menghasilkan link otomatis antar simbol di dokumentasi HTML — gunakan ini untuk membangun web dokumentasi yang saling terhubung.
  • Nested block comment /* /* */ */ valid di Dart, berbeda dari C/Java — ini berguna saat menonaktifkan kode yang sudah berisi komentar multi-baris.
  • @Deprecated dipadukan dengan /// adalah cara standar menandai API yang akan dihapus sambil memandu pengguna ke alternatifnya.
  • Komentar yang tidak diupdate lebih berbahaya dari tidak ada komentar — komentar yang berbohong menyesatkan pembaca dan menyembunyikan bug.
  • Hapus kode yang dikomentari — version control (Git) menyimpan riwayat perubahan. Kode mati yang dikomentari hanya menambah noise dan membingungkan pembaca.
  • dart doc dijalankan dari root project dan menghasilkan dokumentasi HTML di folder doc/api/ — satu perintah untuk dokumentasi profesional.

← Sebelumnya: Sintaks Utama   Berikutnya: Variabel →

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