Arsitektur Bersih di CodeIgniter: Standar Kode Terpelihara
Skuy ngab, siapa nih di sini yang masih ngerasa kalau ngoprek CodeIgniter (CI) itu kadang kayak labirin kusut? Mulai dari controller yang bengkak isinya sampai business logic nyampur aduk sama urusan database. Nah, kalau kamu punya vibes kayak gitu, berarti udah saatnya kita spill the beans tentang gimana caranya bikin CI kamu jadi rapi jali dengan Arsitektur Bersih (Clean Architecture)! Ini bukan cuma soal gaya-gayaan, tapi standar industri buat kode yang maintainable, gampang di-test, dan siap scale-up!
Apa Itu Sih Arsitektur Bersih? Gak Cuma Buat Proyek Gede Doang!
Jadi gini gaes, bayangin rumah impian kamu. Pasti pengennya tiap ruangan punya fungsi jelas, kan? Dapur buat masak, kamar buat tidur, gak ada tuh kamar mandi di tengah ruang tamu. Nah, Arsitektur Bersih itu konsepnya mirip. Ini adalah filosofi desain software yang tujuannya utama adalah separation of concerns alias memisahkan bagian-bagian kode berdasarkan tugas dan tanggung jawabnya. Intinya, kita pengen banget kode inti business logic kita itu:
- Independen dari Framework: Kalau besok CI udah gak hype, kamu gampang pindah ke framework lain karena core logic kamu gak terikat CI.
- Independen dari UI: Mau diakses dari web, mobile, atau API, business logic tetap sama.
- Independen dari Database: Ganti dari MySQL ke PostgreSQL atau NoSQL? Gak masalah, karena business logic kamu gak tahu-menahu soal database.
- Mudah di-test: Karena bagian-bagiannya terpisah, ngetes satu bagian gak ganggu bagian lain.
- Mudah di-maintain & di-scale: Udah pasti! Kalau ada bug atau mau nambah fitur, kamu tahu persis di mana harus ngopreknya.
Pakar-pakar kayak Robert C. Martin (Uncle Bob) bilang, Arsitektur Bersih itu kayak onion alias bawang. Ada lapisan-lapisan, dan lapisan paling dalam (core business rules) itu yang paling mandiri dan gak tergantung sama lapisan luar (framework, database, UI). Lapisan luar cuma adaptor buat lapisan dalam.
Kok Bisa Diterapin di CodeIgniter? Kan Udah Punya MVC?
Nah, ini pertanyaan jitu! CI kan udah pakai MVC (Model-View-Controller). Tapi seringkali, di praktik lapangan, controller jadi gemuk, model isinya query doang, atau malah business logic nyampur di controller. Ini yang bikin kode jadi "kotor" dan susah di-maintain.
Arsitektur Bersih di CI itu bukan berarti kita buang MVC ya, tapi kita refactor dan reorganize gimana kita pakai MVC-nya. Kita bikin controller itu jadi "thin" banget, cuma bertugas ngurusin request dan response. Business logic kita pindahin ke lapisan yang lebih dalam.
Skuy, kita liat gimana mapping-nya di CI:
- Entities/Domain Objects: Ini adalah representasi data dan business rules inti kamu. Ini PURE PHP object, gak ada embel-embel CI sama sekali. Contoh:
User,Product,Order. - Use Cases/Interactors: Ini adalah jantung business logic kamu. Di sini tempat kamu ngatur alur proses bisnis. Misalnya,
CreateNewUser,GetProductList,PlaceOrder. Mereka orkestrator yang berinteraksi dengan Entities dan Repositories. - Repositories (Interfaces & Implementations): Ini adalah jembatan antara Use Cases dan data persistence (database). Use Cases cuma tau ada "Repository" yang bisa nyimpan atau ngambil data, tapi gak peduli gimana caranya. Implementasinya (misal:
MySQLUserRepository,MongoProductRepository) yang tahu cara ngobrol sama database pakai Active Record CI atau Query Builder biasa. - Controllers (di CI): Nah, ini nih yang harusnya "tipis". Mereka cuma terima request dari browser, panggil Use Case yang relevan, terus handle response buat view atau JSON. Gak ada business logic di sini!
- Views (di CI): Sama kayak biasa, buat nampilin data. Mungkin perlu Presenter atau Transformer buat nyiapin data sebelum dikirim ke view.
Contoh Praktis: Bikin Fitur "Buat Pengguna Baru" dengan Arsitektur Bersih di CodeIgniter
Kita ambil contoh sederhana: membuat user baru. Biasanya, semua ada di controller, kan?
The "Old Ways" (Kurang Clean):
// app/Controllers/User.php (CodeIgniter 4)
<?php namespace App\Controllers;
use App\Models\UserModel;
class User extends BaseController
{
public function create()
{
$request = service('request');
$validation = service('validation');
if (!$this->validate([
'username' => 'required|min_length[3]|is_unique[users.username]',
'email' => 'required|valid_email|is_unique[users.email]',
'password' => 'required|min_length[6]',
])) {
return redirect()->back()->withInput()->with('errors', $validation->getErrors());
}
$userModel = new UserModel();
$userModel->save([
'username' => $request->getPost('username'),
'email' => $request->getPost('email'),
'password' => password_hash($request->getPost('password'), PASSWORD_DEFAULT),
]);
return redirect()->to('/dashboard')->with('success', 'User created successfully!');
}
}
Bisa dilihat, validasi, hashing password, dan logika penyimpanan semua numpuk di controller. Kalau mau ganti validasi atau cara hashing, controller ini harus diubah. Susah di-test.
The "Clean Ways" (Makin Kece!):
Pertama, kita siapkan struktur folder baru di app/:
app/
├── Config/
├── Controllers/
├── Database/
├── Filters/
├── Language/
├── Libraries/
├── Models/
├── ThirdParty/
├── Views/
└── Core/ <-- Folder baru untuk Clean Architecture
├── Domain/
│ └── Entities/
│ └── User.php
├── Application/
│ └── UseCases/
│ └── User/
│ └── CreateNewUser.php
│ └── CreateNewUserRequest.php
│ └── CreateNewUserResponse.php
└── Infrastructure/
└── Repositories/
└── UserRepositoryInterface.php
└── EloquentUserRepository.php (atau CIModelUserRepository.php)
1. Core/Domain/Entities/User.php (Pure PHP Object):
<?php namespace App\Core\Domain\Entities;
class User
{
private ?int $id;
private string $username;
private string $email;
private string $passwordHash;
public function __construct(string $username, string $email, string $passwordHash, ?int $id = null)
{
$this->id = $id;
$this->username = $username;
$this->email = $email;
$this->passwordHash = $passwordHash;
}
public function getId(): ?int
{
return $this->id;
}
public function getUsername(): string
{
return $this->username;
}
public function getEmail(): string
{
return $this->email;
}
public function getPasswordHash(): string
{
return $this->passwordHash;
}
// Mungkin ada metode lain untuk bisnis rule User di sini
}
2. Core/Infrastructure/Repositories/UserRepositoryInterface.php (Interface):
<?php namespace App\Core\Infrastructure\Repositories;
use App\Core\Domain\Entities\User;
interface UserRepositoryInterface
{
public function findByUsername(string $username): ?User;
public function findByEmail(string $email): ?User;
public function save(User $user): User;
}
3. Core/Infrastructure/Repositories/CIUserRepository.php (Implementasi Repository):
<?php namespace App\Core\Infrastructure\Repositories;
use App\Core\Domain\Entities\User;
use App\Models\UserModel; // Ini adalah CodeIgniter Model kita
class CIUserRepository implements UserRepositoryInterface
{
private UserModel $userModel;
public function __construct()
{
$this->userModel = new UserModel();
}
public function findByUsername(string $username): ?User
{
$userData = $this->userModel->where('username', $username)->first();
if (!$userData) {
return null;
}
return new User(
$userData['username'],
$userData['email'],
$userData['password'], // password sudah di-hash
$userData['id']
);
}
public function findByEmail(string $email): ?User
{
$userData = $this->userModel->where('email', $email)->first();
if (!$userData) {
return null;
}
return new User(
$userData['username'],
$userData['email'],
$userData['password'], // password sudah di-hash
$userData['id']
);
}
public function save(User $user): User
{
$data = [
'username' => $user->getUsername(),
'email' => $user->getEmail(),
'password' => $user->getPasswordHash(),
];
// Ini bagian interaksi dengan CI Model
if ($user->getId()) {
$this->userModel->update($user->getId(), $data);
return $user; // Asumsi ID tetap
} else {
$this->userModel->insert($data);
$userId = $this->userModel->insertID();
return new User(
$user->getUsername(),
$user->getEmail(),
$user->getPasswordHash(),
$userId
);
}
}
}
4. Core/Application/UseCases/User/CreateNewUserRequest.php & CreateNewUserResponse.php (Data Transfer Objects):
<?php namespace App\Core\Application\UseCases\User;
class CreateNewUserRequest
{
public string $username;
public string $email;
public string $password;
public string $passwordConfirm; // Untuk validasi
}
<?php namespace App\Core\Application\UseCases\User;
use App\Core\Domain\Entities\User;
class CreateNewUserResponse
{
public ?User $user;
public bool $success;
public array $errors = [];
public function __construct(?User $user, bool $success, array $errors = [])
{
$this->user = $user;
$this->success = $success;
$this->errors = $errors;
}
}
5. Core/Application/UseCases/User/CreateNewUser.php (Use Case):
<?php namespace App\Core\Application\UseCases\User;
use App\Core\Domain\Entities\User;
use App\Core\Infrastructure\Repositories\UserRepositoryInterface;
class CreateNewUser
{
private UserRepositoryInterface $userRepository;
public function __construct(UserRepositoryInterface $userRepository)
{
$this->userRepository = $userRepository;
}
public function execute(CreateNewUserRequest $request): CreateNewUserResponse
{
$errors = [];
// Validasi business rules di sini (misal: username/email unik)
if ($this->userRepository->findByUsername($request->username)) {
$errors['username'] = 'Username already taken.';
}
if ($this->userRepository->findByEmail($request->email)) {
$errors['email'] = 'Email already taken.';
}
if ($request->password !== $request->passwordConfirm) {
$errors['passwordConfirm'] = 'Passwords do not match.';
}
if (strlen($request->password) < 6) {
$errors['password'] = 'Password must be at least 6 characters.';
}
// Tambah validasi lain di sini jika perlu
if (!empty($errors)) {
return new CreateNewUserResponse(null, false, $errors);
}
$passwordHash = password_hash($request->password, PASSWORD_DEFAULT);
$user = new User($request->username, $request->email, $passwordHash);
$savedUser = $this->userRepository->save($user);
return new CreateNewUserResponse($savedUser, true);
}
}
6. app/Controllers/User.php (Controller yang "Tipis"):
<?php namespace App\Controllers;
use App\Core\Application\UseCases\User\CreateNewUser;
use App\Core\Application\UseCases\User\CreateNewUserRequest;
use App\Core\Infrastructure\Repositories\CIUserRepository; // Atau di-inject via Dependency Injection
class User extends BaseController
{
public function create()
{
$request = service('request');
// Bikin Request DTO dari input HTTP
$createNewUserRequest = new CreateNewUserRequest();
$createNewUserRequest->username = $request->getPost('username');
$createNewUserRequest->email = $request->getPost('email');
$createNewUserRequest->password = $request->getPost('password');
$createNewUserRequest->passwordConfirm = $request->getPost('password_confirm');
// Panggil Use Case (ini harusnya di-inject lewat constructor atau service locator)
$userRepository = new CIUserRepository(); // Contoh sederhana, idealnya pakai DI
$createNewUser = new CreateNewUser($userRepository);
$response = $createNewUser->execute($createNewUserRequest);
if ($response->success) {
return redirect()->to('/dashboard')->with('success', 'User created successfully!');
} else {
return redirect()->back()->withInput()->with('errors', $response->errors);
}
}
}
Gimana, Beda Vibes-nya Kan?
- Controller cuma bertugas ngambil request, bikin request object, manggil use case, dan nampilin response. Ringkas banget!
- Semua business logic (validasi username/email unik, hashing password) ada di
CreateNewUseruse case. - Interaksi ke database diisolasi di
CIUserRepository. Kalau mau ganti database, tinggal bikin implementasiUserRepositoryInterfaceyang lain. - Gampang banget di-test karena setiap komponen punya tanggung jawab jelas dan independen.
Tips Praktis Biar Gak Nyasar saat Implementasi:
- Mulai dari yang Kecil: Jangan langsung coba rombak semua proyek. Pilih satu fitur baru atau yang paling sering diutak-atik, coba terapkan di situ.
- Pahami Konsepnya, Jangan Terpaku Tools: CI memang punya MVC, tapi Arsitektur Bersih itu filosofi. Kamu bisa flexing dengan cara adaptasinya.
- Gunakan Dependency Injection (DI): Ini must-have banget buat Arsitektur Bersih. Dengan DI, kamu bisa inject repository atau use case ke controller tanpa harus
newterus. CI4 punya service container yang bisa dimanfaatkan. - Testing itu Kunci: Dengan arsitektur ini, ngetes jadi super gampang. Jangan malas bikin unit test buat use cases dan domain entities kamu.
- Dokumentasi dan Komunikasi Tim: Kalau kerja tim, pastiin semua paham flow ini. Biar gak ada yang nyasar bikin business logic di controller lagi.
- Jangan Over-Engineer: Gak semua proyek butuh Clean Architecture yang super ketat dari awal. Untuk proyek kecil dan cepat, mungkin overhead-nya terlalu besar. Tapi kalau kamu udah mikir scale dan maintainability jangka panjang, this is the way, ngab!
Kesimpulan: Siap Jadi Developer Jempolan?
Menerapkan Arsitektur Bersih di CodeIgniter itu adalah skill up yang bakalan bikin kamu makin percaya diri ngadepin proyek yang kompleks. Kode jadi rapi, gampang di-test, dan siap banget buat masa depan. Ini bukan cuma coding biasa, tapi art of software design! Jadi, jangan ragu buat eksplorasi dan coba sendiri. Bakalan capek di awal, tapi vibes setelahnya itu lho, kepuasan tersendiri melihat kode yang bersih dan profesional! Skuy, kita bikin CodeIgniter jadi lebih powerfull dan elegant!
Berikan Rating
Komentar (0)
Silakan login untuk memberikan komentar.
Login SekarangKata Kunci
Menyukai Artikel (0)
Belum ada siswa yang menyukai artikel ini.
Pembaca (0)
Belum ada user yang membaca artikel ini.
Belum ada komentar. Jadilah yang pertama!