Lewati ke konten utama

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:

KomponenDeskripsi
EntitiesObjek bisnis inti (Request, Booking, Meeting)
Repository InterfacesKontrak/abstraksi akses data
Value ObjectsTipe data bisnis (Rating, Score, Status)
Domain EventsEvent 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

KeuntunganDampak
TestabilityDomain dan Use Case bisa diuji tanpa database
FlexibilityGanti database/framework tanpa ubah bisnis logic
MaintainabilityPerubahan terlokalisir per layer
Separation of ConcernsSetiap layer punya tanggung jawab yang jelas