Bab 4: Desain dan Arsitektur Backend
4.1. MVC (Model-View-Controller)
Apa itu MVC?
MVC adalah pola arsitektur yang memisahkan logika aplikasi menjadi tiga komponen utama:
-
Model: Bertanggung jawab mengelola data dan logika bisnis.
-
View: Menangani tampilan yang dilihat pengguna.
-
Controller: Menjembatani antara model dan view, mengelola permintaan dari pengguna.
Keuntungan MVC -
Pemisahan tanggung jawab mempermudah pengelolaan dan pengembangan.
-
Mendukung modularitas, membuat kode lebih mudah diuji dan dirawat.
Contoh MVC dalam Express.js:// Model class User { static async findAll() { return db.query("SELECT * FROM users"); } } // Controller const UserController = { index: async (req, res) => { const users = await User.findAll(); res.json(users); }, }; // View app.get("/users", UserController.index);
4.2. Microservices vs Monolith
Monolith
- Aplikasi dalam satu unit tunggal, mencakup semua komponen (frontend, backend, database).
- Kelebihan:
- Sederhana untuk memulai.
- Tidak memerlukan pengelolaan layanan terpisah.
- Kekurangan:
- Sulit untuk skala besar.
- Perubahan kecil dapat memengaruhi seluruh sistem.
Microservices
- Memecah aplikasi menjadi layanan kecil yang independen, masing-masing menangani fungsi spesifik.
- Kelebihan:
- Skalabilitas tinggi: Layanan dapat dikembangkan dan di-deploy secara independen.
- Toleransi kesalahan: Gangguan pada satu layanan tidak memengaruhi layanan lain.
- Kekurangan:
- Kompleksitas tinggi dalam komunikasi antar layanan.
- Membutuhkan lebih banyak sumber daya (pengelolaan dan infrastruktur).
Kapan Memilih?
- Monolith untuk proyek kecil atau MVP.
- Microservices untuk aplikasi berskala besar yang memerlukan skalabilitas.
4.3. Event-Driven Architecture
Apa itu Event-Driven Architecture?
Pendekatan di mana aplikasi merespons “event” (kejadian) yang terjadi di sistem, seperti perubahan data atau permintaan pengguna.
Komponen Utama
-
Producer: Menghasilkan event (misalnya, perubahan status order).
-
Event Broker: Menyebarkan event (contoh: Apache Kafka, RabbitMQ).
-
Consumer: Merespons atau memproses event.
Keuntungan
-
Memungkinkan aplikasi menjadi lebih fleksibel dan scalable.
-
Mendukung asynchronous processing.
Contoh Implementasi dengan Node.js:const EventEmitter = require("events"); const eventBus = new EventEmitter(); // Listener eventBus.on("orderCreated", order => { console.log(`Processing order: ${order.id}`); }); // Emit Event eventBus.emit("orderCreated", { id: 123, status: "new" });
4.4. Design Patterns untuk Backend
1. Singleton
Membatasi instansiasi suatu kelas ke satu objek saja.
-
Contoh: Pool koneksi database.
class Database { constructor() { if (!Database.instance) { this.connection = this.connect(); Database.instance = this; } return Database.instance; } connect() { return "Connected to DB"; } } const db1 = new Database(); const db2 = new Database(); console.log(db1 === db2); // true
2. Repository Pattern
Memisahkan logika bisnis dari akses data. -
Contoh:
class UserRepository { getAllUsers() { return db.query("SELECT * FROM users"); } } class UserService { constructor(userRepo) { this.userRepo = userRepo; } async listUsers() { return await this.userRepo.getAllUsers(); } }
3. Factory Pattern
Menyediakan cara untuk membuat objek tanpa menentukan kelasnya secara eksplisit. -
Contoh:
class UserFactory { static createUser(type) { if (type === "admin") return new AdminUser(); if (type === "guest") return new GuestUser(); } }
4.5. Testing Backend (Unit Test, Integration Test)
Mengapa Testing Penting?
-
Memastikan kode bebas dari kesalahan.
-
Membantu mengidentifikasi masalah lebih awal.
Jenis-Jenis Testing
-
Unit Test: Menguji fungsi kecil atau modul secara terisolasi.
-
Integration Test: Menguji interaksi antar modul atau layanan.
-
End-to-End Test: Menguji seluruh alur aplikasi dari awal hingga akhir.
Contoh Unit Test dengan Jest (Node.js):const sum = (a, b) => a + b; test("adds 1 + 2 to equal 3", () => { expect(sum(1, 2)).toBe(3); });
Contoh Integration Test dengan Supertest (Express.js):
const request = require("supertest"); const app = require("./app"); describe("GET /users", () => { it("should return a list of users", async () => { const res = await request(app).get("/users"); expect(res.statusCode).toBe(200); expect(res.body).toBeInstanceOf(Array); }); });
Kesimpulan:
Bab ini membahas berbagai pendekatan desain dan arsitektur yang penting untuk pengembangan backend yang efisien, skalabel, dan dapat dipelihara. Dengan memahami konsep-konsep seperti MVC, microservices, event-driven architecture, design patterns, dan testing, pengembang dapat merancang aplikasi yang robust dan siap untuk produksi.