Kembali ke Beranda
Umum

Arsitektur Aplikasi: Fondasi Penting di Balik Software yang Tahan Lama

Arsitektur aplikasi adalah fondasi desain yang menentukan bagaimana sebuah sistem dibangun, dikembangkan, diintegrasikan, diamankan, dan dipelihara dalam jangka panjang.

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.

arsitektur aplikasisoftware architectureclean architecturemicroservicesmonolithmodular monolithenterprise applicationsystem designsoftware engineering
Nirantara Logo

Published by Nirantara

Nirantara is an Indonesian Enterprise AI company specializing in Enterprise AI, RAG, Intelligent Search, and AI Automation. Article written by jsturana.

Learn more about Nirantara