Exception bukan satu-satunya cara melaporkan kegagalan. Alternatifnya disebut result pattern: method mengembalikan nilai yang menggambarkan hasil — bool, tuple, atau tipe data khusus — dan pemanggil memeriksa nilainya sebelum lanjut. Kedua pendekatan sah di dunia nyata; tugas kita adalah memahami perbedaannya dan memilih dengan sadar.

Pendekatan Result: Kegagalan sebagai Nilai #

csharp
Dictionary<string, int> stok = new Dictionary<string, int>
{
    { "Kopi", 24 },
    { "Teh", 0 }
};

(bool sukses, string pesan, int jumlahStok) = CekStokResult("Kopi", stok);
Console.WriteLine($"Result (tuple) - sukses: {sukses}, pesan: {pesan}, stok: {jumlahStok}");

(bool suksesTeh, string pesanTeh, int stokTeh) = CekStokResult("Teh", stok);
Console.WriteLine($"Result (tuple) - sukses: {suksesTeh}, pesan: {pesanTeh}, stok: {stokTeh}");

HasilCekStok hasilPenghapus = CekStokRecord("Penghapus", stok);
Console.WriteLine($"Result (record) - sukses: {hasilPenghapus.Sukses}, pesan: {hasilPenghapus.Pesan}");

static (bool Sukses, string Pesan, int Stok) CekStokResult(string nama, Dictionary<string, int> stok)
{
    if (!stok.TryGetValue(nama, out int jumlah))
    {
        return (false, $"Produk '{nama}' tidak terdaftar", 0);
    }

    if (jumlah == 0)
    {
        return (false, $"Produk '{nama}' sedang kosong", 0);
    }

    return (true, "Tersedia", jumlah);
}

static HasilCekStok CekStokRecord(string nama, Dictionary<string, int> stok)
{
    if (!stok.TryGetValue(nama, out int jumlah) || jumlah == 0)
    {
        return new HasilCekStok(false, $"Produk '{nama}' tidak tersedia");
    }

    return new HasilCekStok(true, "Tersedia");
}

public sealed record HasilCekStok(bool Sukses, string Pesan);

Output yang Dihasilkan:

text
Result (tuple) - sukses: True, pesan: Tersedia, stok: 24
Result (tuple) - sukses: False, pesan: Produk 'Teh' sedang kosong, stok: 0
Result (record) - sukses: False, pesan: Produk 'Penghapus' tidak tersedia

Mari kita telaah bagian pentingnya:

  1. Baris 7-8 (dekonstruksi tuple): Method CekStokResult mengembalikan tiga informasi sekaligus — bool, pesan, dan stok — dan dekonstruksi tuple memecahnya ke variabel terpisah; kegagalan “Teh kosong” diterima sebagai nilai biasa, tanpa lompatan alur.
  2. Baris 13-14 (record): record adalah tipe referensi ringkas untuk membungkus data; satu baris deklarasi menghasilkan tipe HasilCekStok dengan properti Sukses dan Pesan — bahasannya menyeluruh di section Pemrograman Berorientasi Objek.
  3. Baris 16-29 (method CekStokResult): Setiap kemungkinan gagal dikembalikan sebagai nilai dengan false plus pesan; method tidak pernah melempar exception.

Pendekatan Exception: Kegagalan yang Melompat #

Versi yang sama dengan exception memindahkan alur kegagalan ke blok catch:

csharp
try
{
    int jumlah = AmbilStokDenganException("Gula", stok);
    Console.WriteLine($"Exception - stok terbaca: {jumlah}");
}
catch (KeyNotFoundException ex)
{
    Console.WriteLine($"Exception - ditangkap: {ex.Message}");
}

static int AmbilStokDenganException(string nama, Dictionary<string, int> stok)
{
    if (!stok.TryGetValue(nama, out int jumlah))
    {
        throw new KeyNotFoundException($"Produk '{nama}' tidak terdaftar");
    }

    return jumlah;
}

Output yang Dihasilkan:

text
Exception - ditangkap: Produk 'Gula' tidak terdaftar

Kapan Memilih yang Mana #

SituasiPendekatan yang tepat
Kegagalan yang diharapkan dan sering terjadi (validasi input, data tidak ada)Result pattern
Kondisi yang menandakan bug atau kondisi tak terdugaException
Alur harus berhenti dan kegagalan perlu mencapai lapisan atas dengan cepatException
Pemanggil harus ditegaskan untuk memeriksa hasilResult pattern