Memahami CQRS (Command Query Responsibility Segregation) Kenapa dan Bagaimana Menggunakannya

Memahami CQRS (Command Query Responsibility Segregation) Kenapa dan Bagaimana Menggunakannya

Apa Itu CQRS?

CQRS atau Command Query Responsibility Segregation adalah pola desain arsitektur yang memisahkan operasi data menjadi dua kategori: command dan query. Ini berarti operasi untuk mengubah data (command) dipisahkan dari operasi untuk membaca data (query). Tujuannya adalah meningkatkan performa, skalabilitas, dan maintainability aplikasi.

Kenapa Perlu CQRS?

1. Performance Lebih Nendang
Dengan memisahkan command dan query, kita bisa mengoptimalkan masing-masing proses secara terpisah. Misalnya, untuk query, kita bisa menggunakan database yang dioptimasi untuk kecepatan baca (read). Sebaliknya, untuk command, kita bisa fokus pada konsistensi data.

2. Scalability Lebih Mudah
Dalam aplikasi besar, kebutuhan untuk membaca data seringkali jauh lebih tinggi dibandingkan dengan mengubah data. Dengan CQRS, kita bisa menskalakan bagian query dan command secara independen. Jika tiba-tiba ada lonjakan permintaan untuk membaca data, kita bisa menambah instance query tanpa mengubah bagian command.

3. Keamanan dan Konsistensi
Dengan memisahkan command dan query, kita bisa lebih mudah mengatur akses. Misalnya, hanya bagian command yang bisa menulis (create, update, delete) ke database, sementara bagian query hanya bisa membaca (read). Ini membantu menjaga konsistensi dan integritas data.

Cara Kerja CQRS

Misalnya, kita punya aplikasi e-commerce. Operasi utamanya bisa dibagi menjadi:

Command: Menambah produk, mengubah harga, menghapus produk.
Query: Menampilkan daftar produk, menampilkan detail produk.

Dengan CQRS, kita akan membuat dua model yang terpisah untuk menangani operasi ini.

Implementasi CQRS dengan Go

Mari kita lihat bagaimana kita bisa mengimplementasikan CQRS dalam bahasa pemrograman Go.

Command Side
Pertama, kita akan membuat bagian untuk menangani command, yaitu operasi yang mengubah data.

package main

import (
“fmt”
)

type Command interface {
Execute() error
}

type AddProductCommand struct {
ProductName string
Price float64
}

func (c *AddProductCommand) Execute() error {
// Logika buat nambah produk ke database
fmt.Printf(“Menambah produk: %s dengan harga: %.2fn, c.ProductName, c.Price)
// Misalnya kita simpan ke database di sini
return nil
}

type UpdateProductCommand struct {
ProductName string
NewPrice float64
}

func (c *UpdateProductCommand) Execute() error {
// Logika buat update produk di database
fmt.Printf(“Mengupdate produk: %s menjadi harga: %.2fn, c.ProductName, c.NewPrice)
// Misalnya kita update database di sini
return nil
}

func main() {
addCmd := &AddProductCommand{ProductName: “Kaos Keren”, Price: 150000}
addCmd.Execute()

updateCmd := &UpdateProductCommand{ProductName: “Kaos Keren”, NewPrice: 175000}
updateCmd.Execute()
}

Di sini, kita punya dua command: AddProductCommand untuk menambah produk baru dan UpdateProductCommand untuk memperbarui harga produk yang sudah ada.

Query Side
Sekarang, kita buat bagian untuk menangani query, yaitu operasi yang mengambil data.

package main

import (
“fmt”
)

type Product struct {
Name string
Price float64
}

type Query interface {
Execute() ([]Product, error)
}

type GetProductsQuery struct{}

func (q *GetProductsQuery) Execute() ([]Product, error) {
// Logika buat fetch data produk dari database
// Misalnya ini data dari database
products := []Product{
{Name: “Kaos Keren”, Price: 150000},
{Name: “Celana Jeans”, Price: 200000},
}

return products, nil
}

func main() {
getProductsQuery := &GetProductsQuery{}
products, _ := getProductsQuery.Execute()

for _, product := range products {
fmt.Printf(“Produk: %s, Harga: %.2fn, product.Name, product.Price)
}
}

Di sini, kita punya query GetProductsQuery yang mengambil data produk dari database (ini masih simulasi, bro).

Studi Kasus: Toko Online

Bayangkan temen-temen punya toko online yang super rame. User pada ngecek produk terus, tapi ada juga yang sering nambahin atau update produk. Dengan CQRS, kita bisa handle skenario ini dengan efisien:

1. Scalability
Jika tiba-tiba ada lonjakan permintaan untuk membaca data (misalnya saat ada promo besar-besaran), kita bisa menambah instance query service tanpa harus mengubah bagian command. Kita juga bisa menggunakan read-replica database untuk bagian query, sehingga bisa menangani lebih banyak permintaan baca.

2. Performance
Bagian query bisa dioptimasi untuk kecepatan. Misalnya, kita bisa menggunakan teknik caching untuk menyimpan hasil query yang sering diakses. Dengan begitu, user mendapatkan respons yang lebih cepat. Di sisi lain, bagian command bisa fokus pada validasi data tanpa terganggu oleh query yang berat.

3. Maintainability
Dengan memisahkan command dan query, tim pengembang bisa bekerja secara paralel tanpa saling mengganggu. Misalnya, tim yang bekerja pada fitur baru untuk menambah produk (command) tidak perlu khawatir tentang performa query yang sedang dioptimasi oleh tim lain.

Kesimpulan

CQRS adalah pola desain yang powerful untuk aplikasi skala besar. Dengan memisahkan command dan query, kita bisa mencapai performa yang lebih baik, skalabilitas yang lebih mudah, dan maintainability yang lebih baik. Implementasi CQRS dalam Go cukup sederhana, tetapi dampaknya pada performa dan skalabilitas aplikasi sangat signifikan.

Semoga penjelasan ini membantu memahami CQRS lebih dalam dan bagaimana mengimplementasikannya dalam aplikasi nyata. Selamat ngoding dan jangan lupa ngoding itu diketik jangan dipikir! Sampai jumpa di artikel yang lain ya broo!