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: %.2f\n", 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: %.2f\n", 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: %.2f\n", 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!
Top comments (2)
Mantap artikelnya. Ini untuk koneksi dengan database ya.
Apa bedanya sama read dan write model mas?
cqrs ini salah satu bentuk arsitektur pattern dari read and write model mas