BAB 36. CLEAN ARCHITECTURE
Konsep
TemuBelajar mengimplementasikan Clean Architecture (Robert C. Martin) untuk memisahkan kepentingan bisnis dari detail teknis, sehingga sistem mudah diuji, diubah, dan diperluas.
Layer Diagram
flowchart TD
subgraph OUTER ["🌐 Outer Layer"]
UI["📱 Presentation\n(Flutter Pages, Widgets, Controllers)"]
API["🔌 Infrastructure\n(Laravel Controller, API Resource)"]
end
subgraph MIDDLE ["⚙️ Application Layer"]
UC["📋 Use Cases\n(Business Logic)"]
end
subgraph INNER ["🎯 Domain Layer (Core)"]
ENT["🏛️ Entities\n(Pure Business Objects)"]
RI["📄 Repository Interfaces"]
end
subgraph DATA ["🗄️ Data Layer"]
REPO["Repository Implementation"]
DS["Data Source"]
DB[("MySQL")]
end
UI --> UC
API --> UC
UC --> ENT
UC --> RI
RI --> REPO
REPO --> DS
DS --> DB
style INNER fill:#1e1b4b,color:#a5b4fc
style MIDDLE fill:#4c1d95,color:#ddd6fe
style OUTER fill:#1f2937,color:#d1d5db
style DATA fill:#064e3b,color:#a7f3d0
Penjelasan Setiap Layer
🎯 Domain Layer — Inti Sistem
Layer paling dalam. Tidak bergantung pada apapun — tidak ada import Flutter, Laravel, atau database di sini.
Berisi:
| Komponen | Deskripsi |
|---|---|
| Entities | Objek bisnis inti (Request, Booking, Meeting) |
| Repository Interfaces | Kontrak/abstraksi akses data |
| Value Objects | Tipe data bisnis (Rating, Score, Status) |
| Domain Events | Event yang terjadi di domain (RequestCreated, etc.) |
Contoh Entity (Flutter/Dart):
class RequestEntity {
final int id;
final String topic;
final String description;
final RequestStatus status;
final DateTime preferredTime;
const RequestEntity({
required this.id,
required this.topic,
required this.description,
required this.status,
required this.preferredTime,
});
}
⚙️ Application Layer — Use Cases
Berisi logika bisnis aplikasi. Hanya bergantung pada Domain Layer.
Contoh Use Case (Flutter/Dart):
class CreateRequestUseCase {
final RequestRepository _repository;
CreateRequestUseCase(this._repository);
Future<Either<Failure, RequestEntity>> call(CreateRequestParams params) {
return _repository.createRequest(params);
}
}
Contoh Service (Laravel/PHP):
class RequestService
{
public function __construct(
private RequestRepositoryInterface $repository,
private MatchingEngine $matchingEngine
) {}
public function createRequest(CreateRequestDTO $dto): Request
{
$request = $this->repository->create($dto);
$this->matchingEngine->dispatch($request);
return $request;
}
}
🌐 Presentation / Infrastructure Layer
Layer terluar. Bergantung pada semua layer di bawahnya.
Flutter:
- Pages (UI)
- Widgets (komponen UI)
- Controllers/Notifiers (state management via Riverpod)
Laravel:
- Controllers (HTTP handler)
- API Resources (JSON transformer)
- Form Requests (validasi)
Dependency Rule
:::important Aturan Utama Ketergantungan kode hanya boleh mengarah ke dalam (dari luar ke dalam). Layer dalam tidak boleh mengetahui apapun tentang layer luar. :::
✅ Presentation → Domain
✅ Application → Domain
✅ Data → Domain (implements interface)
❌ Domain → Presentation (DILARANG)
❌ Domain → Data (DILARANG)
Implementasi di Flutter
flowchart LR
Page --> Controller
Controller --> UseCase
UseCase --> RepositoryInterface
RepositoryInterface --> RepositoryImpl
RepositoryImpl --> RemoteDatasource
RemoteDatasource --> DioClient["Dio\nHTTP Client"]
style RepositoryInterface fill:#7c3aed,color:#fff
Implementasi di Laravel
flowchart LR
Controller --> Service
Service --> RepositoryInterface
RepositoryInterface --> Repository
Repository --> Model["Eloquent\nModel"]
Model --> MySQL[("MySQL")]
style RepositoryInterface fill:#7c3aed,color:#fff
Keuntungan
| Keuntungan | Dampak |
|---|---|
| Testability | Domain dan Use Case bisa diuji tanpa database |
| Flexibility | Ganti database/framework tanpa ubah bisnis logic |
| Maintainability | Perubahan terlokalisir per layer |
| Separation of Concerns | Setiap layer punya tanggung jawab yang jelas |