Arsitektur Aplikasi: Fondasi Penting di Balik Software yang Tahan Lama
Banyak aplikasi gagal bukan karena programmer tidak bisa menulis kode, tetapi karena sejak awal tidak memiliki arsitektur yang jelas.
Pada tahap awal, aplikasi sering terlihat sederhana. Ada halaman login, input data, simpan ke database, tampilkan laporan, selesai. Namun setelah berjalan beberapa bulan atau tahun, kebutuhan mulai bertambah.
Ada integrasi dengan sistem lain. Ada role pengguna yang semakin kompleks. Ada laporan baru. Ada API untuk aplikasi mobile. Ada kebutuhan audit trail. Ada perubahan regulasi. Ada peningkatan jumlah pengguna. Ada bug yang semakin sulit dilacak.
Di titik inilah arsitektur aplikasi mulai terasa penting.
Arsitektur aplikasi bukan sekadar diagram kotak-kotak. Arsitektur aplikasi adalah cara berpikir tentang bagaimana sebuah sistem disusun agar tetap bisa berkembang tanpa runtuh oleh kompleksitasnya sendiri.
Apa Itu Arsitektur Aplikasi?
Arsitektur aplikasi adalah struktur dasar dari sebuah software, meliputi:
- Bagaimana kode dibagi
- Bagaimana modul saling berkomunikasi
- Bagaimana data mengalir
- Bagaimana aturan bisnis ditempatkan
- Bagaimana aplikasi berinteraksi dengan database
- Bagaimana aplikasi berinteraksi dengan sistem luar
- Bagaimana keamanan diterapkan
- Bagaimana aplikasi diuji
- Bagaimana aplikasi dideploy
- Bagaimana aplikasi dimonitor
Secara sederhana:
Arsitektur aplikasi adalah rancangan besar yang membuat software tetap teratur ketika ukurannya semakin besar.
Tanpa arsitektur, aplikasi biasanya tumbuh secara acak. Controller berisi query database. Service berisi validasi bercampur logic tampilan. Repository berisi aturan bisnis. File util menjadi tempat segala hal. Akhirnya, perubahan kecil bisa menimbulkan efek samping besar.
Mengapa Arsitektur Aplikasi Penting?
1. Memudahkan Perubahan
Software hampir pasti berubah. Kebutuhan bisnis berubah, teknologi berubah, regulasi berubah, dan pengguna juga berubah.
Arsitektur yang baik membuat perubahan lebih aman. Misalnya, ketika ingin mengganti database dari MySQL ke PostgreSQL, perubahan tidak perlu menyentuh seluruh kode aplikasi.
2. Mengurangi Kompleksitas
Aplikasi besar selalu kompleks. Arsitektur tidak menghilangkan kompleksitas, tetapi mengelolanya.
Kompleksitas yang baik ditempatkan pada tempat yang benar. Kompleksitas bisnis ada di domain layer. Kompleksitas database ada di repository layer. Kompleksitas komunikasi eksternal ada di integration layer.
3. Memudahkan Testing
Aplikasi yang arsitekturnya rapi lebih mudah dites.
Business logic bisa diuji tanpa harus menjalankan server. Service bisa diuji tanpa database asli. Controller bisa diuji tanpa memanggil sistem eksternal.
Ini penting karena testing bukan hanya soal mencari bug, tetapi juga menjaga agar perubahan baru tidak merusak fitur lama.
4. Memudahkan Kolaborasi Tim
Dalam tim besar, arsitektur menjadi bahasa bersama.
Developer backend tahu di mana menaruh logic. Developer frontend tahu kontrak API. QA tahu alur sistem. DevOps tahu kebutuhan deployment. Manager tahu batasan teknis sistem.
Tanpa arsitektur, setiap developer bisa membawa gaya masing-masing, dan aplikasi menjadi tidak konsisten.
5. Menjaga Umur Aplikasi
Aplikasi enterprise jarang hanya hidup satu atau dua tahun. Banyak sistem berjalan lebih dari 5, 10, bahkan 20 tahun.
Arsitektur yang baik membantu aplikasi tetap bisa dirawat, dimodernisasi, dan dikembangkan dalam jangka panjang.
Prinsip Dasar Arsitektur Aplikasi
1. Separation of Concerns
Setiap bagian aplikasi harus memiliki tanggung jawab yang jelas.
Contoh pembagian umum:
- Controller: menerima request
- Service: menjalankan proses bisnis
- Repository: akses data
- Entity/Model: merepresentasikan data
- DTO: membawa data antar-layer
- Config: konfigurasi aplikasi
- Integration Client: komunikasi dengan sistem eksternal
Masalah umum terjadi ketika semua dicampur.
Contoh buruk:
@GetMapping("/users")
public List<User> getUsers() {
Connection conn = DriverManager.getConnection(...);
PreparedStatement ps = conn.prepareStatement("SELECT * FROM users");
ResultSet rs = ps.executeQuery();
List<User> users = new ArrayList<>();
while (rs.next()) {
User user = new User();
user.setName(rs.getString("name"));
users.add(user);
}
return users;
}
Kode di atas mencampur controller, koneksi database, query, mapping data, dan response.
Contoh lebih rapi:
@RestController
@RequestMapping("/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping
public List<UserResponse> getUsers() {
return userService.getUsers();
}
}
Controller hanya menerima request dan mengembalikan response. Detail proses diserahkan ke service.
2. Low Coupling
Coupling adalah tingkat ketergantungan antar-komponen.
Jika satu class berubah dan banyak class lain ikut rusak, berarti coupling tinggi.
Arsitektur yang baik berusaha membuat coupling serendah mungkin.
Contoh:
public class PaymentService {
private MidtransClient midtransClient = new MidtransClient();
}
Kode di atas membuat PaymentService tergantung langsung pada MidtransClient.
Lebih baik:
public class PaymentService {
private final PaymentGateway paymentGateway;
public PaymentService(PaymentGateway paymentGateway) {
this.paymentGateway = paymentGateway;
}
}
Dengan interface PaymentGateway, sistem lebih fleksibel. Hari ini bisa memakai Midtrans, besok bisa diganti Xendit, Doku, atau gateway internal.
3. High Cohesion
Cohesion adalah seberapa fokus tanggung jawab sebuah modul.
Class yang baik mengerjakan hal yang memang berkaitan. Class yang buruk mengerjakan terlalu banyak hal.
Contoh class buruk:
public class UserService {
public void registerUser() {}
public void sendEmail() {}
public void generatePdf() {}
public void connectToFtp() {}
public void calculatePayroll() {}
}
Class ini terlalu banyak tanggung jawab.
Lebih baik dipisah:
UserService
EmailService
PdfService
FtpClient
PayrollService
Semakin fokus sebuah modul, semakin mudah dipahami, dites, dan diperbaiki.
4. Dependency Direction
Dalam arsitektur yang baik, dependency harus mengarah ke bagian yang lebih stabil.
Business logic sebaiknya tidak bergantung langsung pada framework, database, atau teknologi eksternal.
Framework bisa berganti. Database bisa berganti. Library bisa berganti. Aturan bisnis biasanya lebih stabil.
Inilah dasar dari Clean Architecture dan Hexagonal Architecture.
Layered Architecture
Layered Architecture adalah pola arsitektur yang paling umum digunakan di aplikasi enterprise.
Struktur umumnya:
Presentation Layer
Application/Service Layer
Domain Layer
Infrastructure/Data Layer
Atau dalam aplikasi Spring Boot:
Controller
Service
Repository
Database
Contoh Struktur Folder
src/main/java/com/nirantara/app
├── controller
│ └── TicketController.java
├── service
│ └── TicketService.java
├── repository
│ └── TicketRepository.java
├── entity
│ └── Ticket.java
├── dto
│ ├── TicketRequest.java
│ └── TicketResponse.java
└── config
└── SecurityConfig.java
Kelebihan Layered Architecture
- Mudah dipahami
- Cocok untuk banyak aplikasi bisnis
- Mudah diajarkan ke tim
- Cocok untuk Spring Boot, Laravel, Django, ASP.NET
- Struktur jelas
Kekurangan Layered Architecture
- Bisa menjadi terlalu prosedural
- Service layer bisa membesar
- Domain logic sering bocor ke controller atau repository
- Jika tidak disiplin, semua logic menumpuk di service
Layered Architecture cocok untuk banyak aplikasi, tetapi perlu disiplin agar tidak berubah menjadi “service besar berisi segalanya”.
Monolith
Monolith adalah arsitektur di mana seluruh aplikasi berada dalam satu kesatuan deployment.
Contoh:
Aplikasi HRD
├── Modul User
├── Modul Absensi
├── Modul Payroll
├── Modul Cuti
├── Modul Laporan
└── Satu database utama
Semua modul dibangun, dites, dan dideploy sebagai satu aplikasi.
Kelebihan Monolith
- Sederhana
- Mudah dikembangkan di awal
- Deployment lebih mudah
- Debugging lebih mudah
- Tidak perlu komunikasi antar-service
- Cocok untuk tim kecil sampai menengah
Kekurangan Monolith
- Semakin besar bisa sulit dirawat
- Build dan deployment bisa lambat
- Perubahan kecil tetap deploy seluruh aplikasi
- Batas antar-modul sering kabur
- Bisa menjadi “big ball of mud”
Monolith bukan arsitektur buruk. Banyak aplikasi besar dan sukses dimulai dari monolith. Yang bermasalah adalah monolith yang tidak terstruktur.
Modular Monolith
Modular Monolith adalah monolith yang dibagi menjadi modul-modul jelas.
Secara deployment tetap satu aplikasi, tetapi secara desain dipisahkan berdasarkan domain.
Contoh:
src/main/java/com/nirantara/app
├── user
│ ├── UserController.java
│ ├── UserService.java
│ ├── UserRepository.java
│ └── User.java
├── ticket
│ ├── TicketController.java
│ ├── TicketService.java
│ ├── TicketRepository.java
│ └── Ticket.java
├── notification
│ ├── NotificationService.java
│ └── WhatsAppClient.java
└── report
├── ReportController.java
└── ReportService.java
Setiap modul memiliki tanggung jawab sendiri.
Kelebihan Modular Monolith
- Lebih rapi daripada monolith biasa
- Deployment tetap sederhana
- Cocok untuk enterprise internal
- Lebih mudah dipisah menjadi microservices di masa depan
- Mengurangi kompleksitas operasional
Kekurangan Modular Monolith
- Butuh disiplin batas modul
- Masih satu deployment
- Jika tidak dijaga, modul bisa saling bergantung sembarangan
Bagi banyak perusahaan, Modular Monolith sering lebih realistis daripada langsung memakai Microservices.
Microservices
Microservices adalah arsitektur di mana aplikasi dipecah menjadi service-service kecil yang bisa dikembangkan dan dideploy secara independen.
Contoh:
User Service
Ticket Service
Payment Service
Notification Service
Report Service
Audit Service
Setiap service idealnya memiliki database sendiri dan API sendiri.
Kelebihan Microservices
- Setiap service bisa dikembangkan terpisah
- Deployment bisa independen
- Skalabilitas lebih fleksibel
- Cocok untuk organisasi besar
- Cocok untuk domain yang kompleks
Kekurangan Microservices
Microservices membawa kompleksitas besar:
- Network latency
- Distributed transaction
- Service discovery
- API versioning
- Observability
- Logging terdistribusi
- Monitoring lebih sulit
- Deployment pipeline lebih rumit
- Debugging lebih sulit
- Data consistency lebih kompleks
Microservices bukan solusi ajaib. Jika tim belum siap, microservices justru bisa membuat sistem lebih sulit dirawat daripada monolith.
Kapan Microservices Cocok?
Microservices cocok jika:
- Tim sudah cukup besar
- Domain bisnis kompleks
- Modul punya siklus perubahan berbeda
- Beban tiap modul berbeda
- Organisasi siap secara DevOps
- Monitoring dan logging sudah matang
- CI/CD sudah rapi
Jika belum, Modular Monolith biasanya lebih aman.
Clean Architecture
Clean Architecture adalah pendekatan yang menempatkan business logic di pusat sistem.
Struktur sederhananya:
Entities
Use Cases
Interface Adapters
Frameworks & Drivers
Prinsip utamanya:
Business logic tidak boleh bergantung pada detail teknis.
Database, framework, UI, dan API eksternal hanyalah detail.
Contoh struktur:
src/main/java/com/nirantara/app
├── domain
│ ├── model
│ │ └── Ticket.java
│ └── repository
│ └── TicketRepository.java
├── application
│ └── usecase
│ └── CreateTicketUseCase.java
├── infrastructure
│ ├── persistence
│ │ └── JpaTicketRepository.java
│ └── external
│ └── WhatsAppNotificationClient.java
└── interfaceadapter
└── controller
└── TicketController.java
Contoh Interface Repository di Domain
public interface TicketRepository {
Ticket save(Ticket ticket);
Optional<Ticket> findById(String id);
}
Domain hanya tahu ada kontrak repository. Implementasinya ada di infrastructure.
@Repository
public class JpaTicketRepository implements TicketRepository {
private final SpringDataTicketRepository springDataRepository;
public JpaTicketRepository(SpringDataTicketRepository springDataRepository) {
this.springDataRepository = springDataRepository;
}
@Override
public Ticket save(Ticket ticket) {
return springDataRepository.save(ticket);
}
}
Dengan cara ini, business logic tidak tergantung langsung ke Spring Data JPA.
Kelebihan Clean Architecture
- Business logic lebih bersih
- Mudah dites
- Tidak terlalu tergantung framework
- Cocok untuk domain kompleks
- Cocok untuk aplikasi jangka panjang
Kekurangan Clean Architecture
- Struktur lebih banyak
- Terasa berlebihan untuk aplikasi kecil
- Butuh pemahaman tim
- Bisa over-engineering jika diterapkan tanpa konteks
Clean Architecture bagus, tetapi tidak perlu dipaksakan untuk semua proyek.
Hexagonal Architecture
Hexagonal Architecture juga dikenal sebagai Ports and Adapters.
Idenya adalah aplikasi memiliki inti bisnis di tengah, lalu berkomunikasi dengan dunia luar melalui port dan adapter.
REST Controller
|
Database -- Application Core -- Message Queue
|
External API
Core aplikasi tidak peduli apakah input berasal dari REST API, CLI, scheduler, atau message queue.
Core juga tidak peduli apakah data disimpan di PostgreSQL, MySQL, Redis, atau file.
Port
Port adalah kontrak.
Contoh:
public interface NotificationPort {
void send(String target, String message);
}
Adapter
Adapter adalah implementasi teknis.
public class WhatsAppNotificationAdapter implements NotificationPort {
@Override
public void send(String target, String message) {
// kirim pesan ke WhatsApp API
}
}
Dengan pola ini, aplikasi lebih mudah diuji dan lebih fleksibel terhadap perubahan teknologi.
Event Driven Architecture
Event Driven Architecture adalah arsitektur di mana komponen sistem berkomunikasi melalui event.
Contoh event:
TicketCreated
PaymentSuccess
UserRegistered
DocumentApproved
OrderShipped
Misalnya ketika tiket dibuat:
Ticket Service membuat tiket
↓
Menerbitkan event TicketCreated
↓
Notification Service mengirim notifikasi
↓
Audit Service mencatat log
↓
Reporting Service memperbarui statistik
Kelebihan Event Driven Architecture
- Service lebih loosely coupled
- Cocok untuk proses asynchronous
- Mudah menambahkan proses baru tanpa mengubah proses utama
- Cocok untuk sistem besar
Kekurangan Event Driven Architecture
- Debugging lebih sulit
- Urutan event harus diperhatikan
- Risiko duplicate event
- Butuh message broker
- Monitoring harus matang
Teknologi yang sering digunakan:
- Kafka
- RabbitMQ
- Redis Stream
- ActiveMQ
- NATS
Event Driven cocok untuk sistem yang banyak proses background, integrasi, notifikasi, audit, dan sinkronisasi data.
CQRS
CQRS adalah singkatan dari Command Query Responsibility Segregation.
Prinsipnya:
- Command untuk mengubah data
- Query untuk membaca data
Contoh:
CreateTicketCommand
UpdateTicketStatusCommand
GetTicketDetailQuery
SearchTicketQuery
CQRS berguna ketika pola baca dan tulis sangat berbeda.
Misalnya sistem ticketing:
- Penulisan tiket butuh validasi ketat
- Pembacaan tiket butuh filter, sorting, agregasi, dashboard, statistik
Dengan CQRS, model tulis dan model baca bisa dipisah.
Kapan CQRS Cocok?
CQRS cocok jika:
- Query sangat kompleks
- Dashboard butuh performa tinggi
- Data dibaca jauh lebih sering daripada ditulis
- Ada kebutuhan audit dan event history
- Sistem sudah cukup besar
Untuk aplikasi sederhana, CQRS bisa terlalu berat.
Arsitektur Frontend
Arsitektur aplikasi tidak hanya berlaku di backend. Frontend modern juga membutuhkan arsitektur.
Contoh struktur frontend:
src
├── components
├── pages
├── layouts
├── services
├── hooks
├── stores
├── utils
└── types
Masalah umum frontend:
- Komponen terlalu besar
- Logic API bercampur dengan UI
- State management tidak jelas
- Validasi tersebar di banyak tempat
- Tidak ada standar folder
- Tidak ada pemisahan reusable component dan page component
Prinsip frontend yang baik:
- UI component fokus pada tampilan
- Business logic dipisahkan ke service/hook
- API client dipusatkan
- State management jelas
- Form validation konsisten
- Error handling seragam
Contoh:
UserPage
↓
useUserData()
↓
UserService
↓
ApiClient
Dengan pola ini, komponen tidak langsung memanggil fetch() secara acak di banyak tempat.
Arsitektur API
API adalah kontrak antar-sistem. Karena itu API harus dirancang dengan serius.
Hal yang perlu diperhatikan:
- Naming endpoint
- HTTP method
- Status code
- Pagination
- Filtering
- Sorting
- Error response
- Authentication
- Authorization
- Versioning
- Rate limiting
- Idempotency
Contoh endpoint REST:
GET /api/tickets
POST /api/tickets
GET /api/tickets/{id}
PUT /api/tickets/{id}
DELETE /api/tickets/{id}
Contoh response error yang konsisten:
{
"timestamp": "2026-06-26T10:15:30",
"status": 400,
"error": "Bad Request",
"message": "Field title wajib diisi",
"path": "/api/tickets"
}
API yang baik bukan hanya bisa berjalan, tetapi juga mudah dipahami oleh sistem lain.
Arsitektur Database
Database sering menjadi pusat aplikasi enterprise.
Kesalahan umum:
- Semua tabel dibuat tanpa standar
- Tidak ada index
- Relasi tidak jelas
- Tipe data asal pilih
- Semua field dibuat nullable
- Tidak ada audit column
- Tidak ada strategi migration
- Query berat langsung dipakai di aplikasi utama
Hal yang perlu diperhatikan:
1. Desain Tabel
Gunakan nama tabel dan kolom yang konsisten.
CREATE TABLE ticket (
id UUID PRIMARY KEY,
ticket_number VARCHAR(50) NOT NULL UNIQUE,
title VARCHAR(255) NOT NULL,
status VARCHAR(50) NOT NULL,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP
);
2. Index
Index sangat penting untuk performa query.
CREATE INDEX idx_ticket_status ON ticket(status);
CREATE INDEX idx_ticket_created_at ON ticket(created_at);
3. Migration
Gunakan tool migration seperti:
- Flyway
- Liquibase
Jangan mengubah struktur database secara manual tanpa riwayat perubahan.
4. Audit Trail
Untuk aplikasi enterprise, audit trail penting.
Minimal gunakan:
created_at
created_by
updated_at
updated_by
deleted_at
deleted_by
Untuk sistem sensitif, gunakan tabel audit khusus.
Arsitektur Security
Security bukan fitur tambahan. Security harus menjadi bagian dari arsitektur.
Aspek penting:
- Authentication
- Authorization
- Role Based Access Control
- Input validation
- Output encoding
- Password hashing
- Token expiration
- Refresh token
- HTTPS
- Rate limiting
- Audit log
- Secret management
Contoh kesalahan umum:
if (user.getRole().equals("ADMIN")) {
// allow
}
Lebih baik gunakan authorization yang terpusat, misalnya Spring Security.
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/admin/users")
public List<UserResponse> getUsers() {
return userService.getUsers();
}
Security yang tersebar di banyak tempat biasanya sulit dirawat dan rawan bolong.
Arsitektur Logging dan Monitoring
Aplikasi production tidak cukup hanya berjalan. Aplikasi harus bisa diamati.
Pertanyaan penting:
- Apakah error bisa dilacak?
- Apakah request lambat bisa diketahui?
- Apakah service mati bisa terdeteksi?
- Apakah penggunaan CPU, RAM, dan disk termonitor?
- Apakah log bisa dicari?
- Apakah ada alert?
Komponen observability:
Logs
Metrics
Traces
Alerts
Dashboards
Tools yang umum:
- Prometheus
- Grafana
- Loki
- ELK Stack
- OpenTelemetry
- Jaeger
- Tempo
Contoh log yang kurang baik:
Error terjadi
Contoh log yang lebih baik:
Failed to create ticket. userId=123, category=PAYMENT, error=Invalid billing code
Log harus cukup informatif, tetapi jangan membocorkan data sensitif.
Arsitektur Deployment
Arsitektur aplikasi juga harus memikirkan bagaimana aplikasi dijalankan.
Pilihan deployment:
- Bare metal server
- Virtual machine
- Docker
- Docker Compose
- Kubernetes
- Serverless
- PaaS
Untuk banyak aplikasi internal perusahaan, Docker Compose sudah cukup.
Contoh sederhana:
services:
app:
image: nirantara-ticket-app:1.0.0
ports:
- "8080:8080"
environment:
- DB_HOST=postgres
- DB_NAME=ticketdb
depends_on:
- postgres
postgres:
image: postgres:16
environment:
- POSTGRES_DB=ticketdb
- POSTGRES_USER=app
- POSTGRES_PASSWORD=secret
Untuk sistem besar dengan banyak service, Kubernetes bisa digunakan, tetapi jangan dipakai hanya karena terlihat modern.
Arsitektur untuk AI dan RAG
Saat ini banyak aplikasi mulai menambahkan AI, chatbot, dan RAG.
Arsitektur AI biasanya melibatkan:
User Question
↓
API Backend
↓
Intent Router
↓
Embedding Model
↓
Vector Database
↓
Context Retrieval
↓
LLM
↓
Final Answer
Komponen penting:
- Document ingestion
- Chunking
- Embedding
- Vector database
- Retrieval
- Prompting
- LLM inference
- Evaluation
- Logging
- Feedback loop
Untuk aplikasi enterprise, AI tidak boleh berdiri sendiri. AI harus masuk ke arsitektur sistem yang aman dan terkontrol.
Hal yang perlu diperhatikan:
- Sumber data jelas
- Hak akses dokumen diperiksa
- Jawaban harus berdasarkan context
- Ada fallback jika context tidak cukup
- Log pertanyaan dan jawaban
- Evaluasi kualitas jawaban
- Batasi hallucination
- Jangan membocorkan data rahasia
RAG bukan hanya memasang LLM dan vector database. RAG adalah arsitektur pencarian pengetahuan yang perlu dirancang dengan baik.
Anti-Pattern dalam Arsitektur Aplikasi
1. Big Ball of Mud
Semua logic bercampur tanpa struktur.
Ciri-ciri:
- Tidak jelas layer-nya
- Banyak dependency silang
- Sulit dites
- Perubahan kecil sering merusak fitur lain
- Developer takut menyentuh kode lama
2. God Service
Satu service mengatur terlalu banyak proses.
Contoh:
ApplicationService
UserService
MainService
CommonService
Jika satu file service berisi ribuan baris dan puluhan tanggung jawab, itu tanda bahaya.
3. Over Engineering
Terlalu banyak pola untuk masalah sederhana.
Contoh:
- Aplikasi CRUD kecil langsung memakai microservices
- Form sederhana memakai event sourcing
- Project kecil memakai Kubernetes kompleks
- Semua logic dibuat abstract padahal belum perlu
Arsitektur yang baik bukan yang paling rumit, tetapi yang paling sesuai dengan kebutuhan.
4. Database sebagai Tempat Semua Logic
Stored procedure, trigger, dan query kompleks kadang berguna. Tetapi jika semua logic bisnis disimpan di database, aplikasi menjadi sulit dites dan sulit dipindahkan.
5. Copy Paste Architecture
Meniru arsitektur perusahaan besar tanpa memahami konteksnya.
Tidak semua aplikasi perlu microservices seperti Netflix. Tidak semua aplikasi perlu Kubernetes. Tidak semua aplikasi perlu Kafka. Tidak semua aplikasi perlu Clean Architecture penuh.
Gunakan arsitektur sesuai ukuran masalah.
Cara Memilih Arsitektur yang Tepat
Tidak ada satu arsitektur terbaik untuk semua kasus.
Gunakan pertanyaan berikut:
1. Seberapa besar aplikasinya?
Jika kecil, layered architecture cukup. Jika menengah, modular monolith bagus. Jika sangat besar, microservices bisa dipertimbangkan.
2. Seberapa besar timnya?
Tim kecil biasanya lebih cocok monolith atau modular monolith. Tim besar bisa mulai butuh batas service yang lebih jelas.
3. Seberapa kompleks domain bisnisnya?
Jika domain kompleks, Clean Architecture atau Hexagonal Architecture bisa membantu.
4. Seberapa sering aplikasi berubah?
Aplikasi yang sering berubah butuh modularitas lebih baik.
5. Seberapa besar kebutuhan skalabilitas?
Jika hanya ratusan pengguna internal, jangan langsung mendesain seperti aplikasi global.
6. Seberapa matang DevOps-nya?
Microservices tanpa CI/CD, monitoring, logging, dan automation akan menjadi beban besar.
Rekomendasi Praktis
Untuk banyak aplikasi enterprise internal, pendekatan yang cukup sehat adalah:
Modular Monolith
+ Layered Architecture
+ Prinsip Clean Architecture seperlunya
+ API yang konsisten
+ Database migration
+ Logging dan monitoring
+ Docker-based deployment
Dengan pendekatan ini, aplikasi tetap sederhana tetapi tidak berantakan.
Contoh struktur:
src/main/java/com/nirantara/app
├── modules
│ ├── user
│ │ ├── controller
│ │ ├── service
│ │ ├── repository
│ │ ├── dto
│ │ └── entity
│ ├── ticket
│ │ ├── controller
│ │ ├── service
│ │ ├── repository
│ │ ├── dto
│ │ └── entity
│ └── notification
│ ├── service
│ └── client
├── common
│ ├── exception
│ ├── response
│ ├── security
│ └── util
└── config
Struktur ini mudah dipahami, mudah dikembangkan, dan masih cukup fleksibel untuk tumbuh.
Contoh Alur Aplikasi Ticketing
Misalnya ada aplikasi ticketing internal.
Request
User membuat tiket
Alur
TicketController
↓
TicketService
↓
TicketRepository
↓
Database
↓
NotificationService
↓
WhatsApp/Email
Dengan Arsitektur Lebih Rapi
CreateTicketRequest
↓
TicketController
↓
CreateTicketUseCase
↓
TicketDomainService
↓
TicketRepository
↓
NotificationPort
↓
WhatsAppNotificationAdapter
Pada versi sederhana, layered architecture cukup. Pada versi yang lebih kompleks, use case dan port-adapter bisa mulai digunakan.
Kesalahan Umum Saat Mendesain Arsitektur
1. Memilih Teknologi Dulu, Masalah Belakangan
Banyak tim memilih Kubernetes, Kafka, GraphQL, atau microservices sebelum memahami masalah bisnisnya.
Seharusnya:
Masalah bisnis → kebutuhan teknis → desain arsitektur → pilihan teknologi
Bukan sebaliknya.
2. Tidak Membuat Batas Modul
Aplikasi besar tanpa batas modul akan sulit dirawat.
Setiap modul harus punya tanggung jawab jelas.
Contoh modul:
User Management
Ticket Management
Payment
Notification
Reporting
Audit
Integration
3. Tidak Memikirkan Failure
Sistem nyata pasti mengalami kegagalan:
- Database down
- API eksternal timeout
- Network lambat
- Token expired
- Disk penuh
- Message queue tertunda
- File corrupt
Arsitektur harus memikirkan error handling, retry, timeout, circuit breaker, dan fallback.
4. Tidak Ada Observability
Tanpa log dan monitoring, production menjadi kotak hitam.
Ketika error terjadi, tim hanya bisa menebak.
5. Tidak Ada Dokumentasi Arsitektur
Dokumentasi tidak harus panjang. Minimal harus ada:
- Diagram konteks
- Diagram modul
- Alur request utama
- Penjelasan deployment
- Daftar integrasi eksternal
- Keputusan arsitektur penting
Dokumentasi Arsitektur
Dokumentasi arsitektur bisa dibuat sederhana dengan format C4 Model.
1. Context Diagram
Menjelaskan aplikasi berinteraksi dengan siapa.
User
↓
Ticketing System
↓
Database
↓
WhatsApp API
↓
Email Server
2. Container Diagram
Menjelaskan komponen besar.
Web App
Backend API
PostgreSQL
Redis
Message Broker
3. Component Diagram
Menjelaskan komponen di dalam aplikasi.
TicketController
TicketService
TicketRepository
NotificationClient
AuditService
4. Code Diagram
Menjelaskan detail class jika memang diperlukan.
Dokumentasi arsitektur yang baik harus cukup untuk membuat developer baru memahami sistem tanpa harus membaca seluruh source code.
Arsitektur yang Baik Itu Evolusioner
Arsitektur tidak harus sempurna sejak hari pertama.
Aplikasi bisa dimulai dari monolith sederhana, lalu menjadi modular monolith, lalu sebagian modul dipisah menjadi service jika benar-benar dibutuhkan.
Tahap evolusi yang sehat:
Simple Monolith
↓
Layered Monolith
↓
Modular Monolith
↓
Selected Microservices
↓
Distributed Architecture
Yang berbahaya adalah langsung melompat ke arsitektur kompleks tanpa alasan kuat.
Checklist Arsitektur Aplikasi
Sebelum membangun aplikasi, gunakan checklist berikut:
[ ] Apakah domain utama sudah jelas?
[ ] Apakah modul utama sudah ditentukan?
[ ] Apakah struktur folder disepakati?
[ ] Apakah pemisahan controller, service, repository jelas?
[ ] Apakah database migration digunakan?
[ ] Apakah API response konsisten?
[ ] Apakah error handling terpusat?
[ ] Apakah authentication dan authorization dirancang?
[ ] Apakah logging sudah distandarkan?
[ ] Apakah monitoring direncanakan?
[ ] Apakah deployment strategy jelas?
[ ] Apakah konfigurasi dipisahkan dari kode?
[ ] Apakah integrasi eksternal dibungkus adapter/client?
[ ] Apakah testing strategy disiapkan?
[ ] Apakah dokumentasi arsitektur tersedia?
Checklist sederhana ini bisa mencegah banyak masalah besar di kemudian hari.
Kesimpulan
Arsitektur aplikasi adalah fondasi dari software yang sehat.
Arsitektur yang baik bukan berarti memakai teknologi paling baru atau pola paling rumit. Arsitektur yang baik adalah arsitektur yang sesuai dengan kebutuhan, mudah dipahami tim, mudah diuji, mudah dikembangkan, dan tahan terhadap perubahan.
Untuk banyak aplikasi bisnis, pilihan terbaik sering kali bukan microservices, tetapi modular monolith yang rapi, layered architecture yang disiplin, API yang konsisten, database yang dirancang baik, serta logging dan monitoring yang matang.
Software yang baik tidak hanya dinilai dari apakah ia bisa berjalan hari ini, tetapi juga dari apakah ia masih bisa dirawat beberapa tahun ke depan.
Itulah tujuan utama arsitektur aplikasi: menjaga agar sistem tetap hidup, tumbuh, dan tidak runtuh oleh kompleksitasnya sendiri.
Published by Nirantara
Nirantara is an Indonesian Enterprise AI company specializing in Enterprise AI, RAG, Intelligent Search, and AI Automation. Article written by jsturana.