Async Callback Pattern #

Dalam pengembangan sistem modern, khususnya aplikasi backend, event-driven system, dan aplikasi dengan kebutuhan performa tinggi, pengelolaan proses asynchronous menjadi hal yang sangat krusial. Operasi seperti pemanggilan API eksternal, akses database, pemrosesan file, atau background task sering kali membutuhkan waktu yang tidak singkat dan tidak ideal jika dijalankan secara blocking.

Salah satu pola concurrency yang sudah lama digunakan untuk menangani kondisi tersebut adalah Async Callback Pattern. Pattern ini memungkinkan sebuah proses dijalankan secara asynchronous, lalu hasilnya diproses melalui fungsi callback ketika pekerjaan tersebut selesai.

Meskipun pada bahasa modern (termasuk Go) callback sering “tersamarkan” oleh abstraction lain seperti goroutine dan channel, pemahaman Async Callback Pattern tetap penting karena menjadi fondasi dari banyak concurrency dan event-based design.

Apa itu Async Callback Pattern? #

Async Callback Pattern adalah pola di mana sebuah fungsi menjalankan pekerjaan secara asynchronous dan menerima callback function sebagai parameter. Callback tersebut akan dipanggil ketika proses asynchronous selesai, baik dalam kondisi sukses maupun error.

Secara konsep:

  1. Caller memanggil fungsi asynchronous
  2. Caller menyertakan callback
  3. Proses dijalankan di background (thread, goroutine, worker, dsb.)
  4. Ketika selesai, callback dipanggil dengan hasil atau error

Pattern ini sangat umum ditemukan pada:

  • Event-driven programming
  • Network programming
  • I/O non-blocking
  • Legacy concurrency model

Tujuan Pattern #

Tujuan utama Async Callback Pattern adalah:

  • Non-blocking execution: Proses panjang tidak menghentikan flow utama aplikasi
  • Responsiveness: Aplikasi tetap responsif saat pekerjaan berat berjalan
  • Decoupling: Pemanggil tidak perlu tahu detail eksekusi internal
  • Event-based handling: Hasil diproses saat event selesai

Dengan callback, kita memindahkan logika lanjutan (continuation) ke fungsi lain yang akan dipanggil kemudian.


Kapan Cocok Digunakan? #

Async Callback Pattern cocok digunakan ketika:

  • Operasi bersifat I/O bound (HTTP request, database, file system)
  • Hasil tidak perlu langsung digunakan saat pemanggilan
  • Sistem berbasis event-driven atau reactive
  • Ingin menjalankan banyak task paralel tanpa blocking
  • Mengelola background job sederhana

Namun, pattern ini kurang cocok jika:

  • Flow bisnis kompleks dan berlapis (raw callback bisa membuat code sulit dibaca)
  • Membutuhkan error handling terstruktur
  • Membutuhkan chaining panjang (callback hell)

Contoh Implementasi (Golang) #

Meskipun Go lebih identik dengan channel dan goroutine, callback tetap bisa digunakan untuk merepresentasikan Async Callback Pattern.

Contoh Kasus: Async Fetch Data #

package main

import (
    "fmt"
    "time"
)

// Callback signature
type FetchCallback func(result string, err error)

func fetchDataAsync(id int, callback FetchCallback) {
    go func() {
        // Simulasi proses berat
        time.Sleep(2 * time.Second)

        if id <= 0 {
            callback("", fmt.Errorf("invalid id"))
            return
        }

        callback(fmt.Sprintf("data for id %d", id), nil)
    }()
}

func main() {
    fmt.Println("Start fetching data...")

    fetchDataAsync(1, func(result string, err error) {
        if err != nil {
            fmt.Println("Error:", err)
            return
        }
        fmt.Println("Success:", result)
    })

    // Mencegah program exit terlalu cepat
    time.Sleep(3 * time.Second)
}

Penjelasan #

  • fetchDataAsync menjalankan proses di goroutine
  • Callback dipanggil setelah proses selesai
  • main tidak menunggu hasil secara blocking
  • Flow lanjutan ditangani di dalam callback

Ini adalah bentuk paling sederhana dari Async Callback Pattern di Go.


Perbandingan dengan Channel di Go #

Async CallbackChannel
Event-basedMessage-based
Cocok untuk simple asyncCocok untuk orchestration
Rentan callback hellLebih readable
Umum di bahasa lainIdiomatic Go

Dalam praktiknya, Go developer sering menggunakan channel sebagai evolusi alami dari callback.


Best Practice #

Beberapa best practice yang penting diperhatikan:

1. Definisikan Callback Signature dengan Jelas #

Gunakan type alias untuk callback agar mudah dibaca dan konsisten.

type Callback func(result T, err error)

2. Selalu Sertakan Error di Callback #

Callback harus memiliki parameter error untuk menangani kegagalan secara eksplisit.

3. Hindari Callback Hell #

Jika callback mulai bersarang terlalu dalam:

  • Refactor ke function terpisah
  • Gunakan channel atau worker pool
  • Pertimbangkan Future / Promise abstraction

4. Jangan Memanggil Callback Lebih dari Sekali #

Pastikan callback hanya dipanggil sekali untuk setiap eksekusi asynchronous.

5. Dokumentasikan Lifecycle Callback #

Jelaskan:

  • Kapan callback dipanggil
  • Apakah dijalankan di goroutine terpisah
  • Apakah thread-safe

6. Pertimbangkan Context untuk Cancellation #

Gunakan context.Context untuk membatalkan operasi asynchronous jika diperlukan.


Penutup #

Async Callback Pattern adalah pola concurrency fundamental yang menjadi dasar dari banyak sistem asynchronous dan event-driven. Meskipun di Go penggunaan callback tidak sepopuler channel dan goroutine orchestration, pattern ini tetap relevan dan berguna dalam kasus tertentu, terutama untuk API asynchronous sederhana dan integrasi dengan sistem event-based.

Dengan memahami Async Callback Pattern, developer akan lebih mudah:

  • Memahami library atau framework berbasis callback
  • Mendesain sistem non-blocking
  • Bertransisi ke pattern concurrency yang lebih advanced

Pemahaman pattern ini juga membantu dalam membaca dan memelihara code concurrency lintas bahasa.

Catatan Tambahan: Banyak pattern concurrency modern seperti Future/Promise, Reactive Stream, dan async/await pada dasarnya adalah abstraction tingkat tinggi dari Async Callback Pattern.

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