Giriş: Yazılımda Entropi ve Mimari Çöküş
Yazılım projeleri ilk geliştirilme aşamasında genellikle hızlı ve esnek ilerler. Ancak zaman içinde eklenen yeni iş kuralları, veritabanı bağımlılıkları ve dış kütüphaneler ile birlikte sistemin karmaşıklığı katlanarak artar. Bu duruma yazılım mühendisliğinde Yazılım Entropisi (Code Rot) adı verilir.
Robert C. Martin (Uncle Bob) tarafından 2012 yılında resmileştirilen Clean Architecture ve Eric Evans'ın Domain-Driven Design (DDD) prensipleri, yazılımın merkezine veritabanını veya harici framework'leri değil; saf iş mantığını (Business Domain) yerleştirerek bu çöküşü engeller.

1. Bağımlılık Kuralı (The Dependency Rule)
Clean Architecture mimarisinin en temel değişmez kuralı şudur:
"Kaynak kodu bağımlılıkları yalnızca içe doğru, yani daha yüksek seviyeli politika ve iş kurallarına doğru yönelmelidir."
Dış çemberdeki hiçbir şey (Veritabanı, UI, HTTP Framework, Harici API'lar, CLI), iç çemberdeki bileşenler (Use Case, Domain Entity) hakkında doğrudan bilgi sahibi olamaz.
[ DIŞ ÇEMBER ] -> Frameworks, Drivers, DB (MySQL, Redis, Laravel, Slim)
↓
[ ADAPTÖRLER ] -> Controllers, Presenters, Repositories, Gateways
↓
[ USE CASES ] -> Application Business Rules, Interactors, DTOs
↓
[ CORE DOMAIN] -> Enterprise Entities, Value Objects, Domain Events (Zero Dependency)
2. Katmanların Derinlemesine İncelenmesi
2.1 Core Domain (Varlıklar ve Value Object'ler)
Domain katmanı, uygulamanın en kutsal ve dış dünyadan tamamen izole edilmiş bölgesidir. Burada framework sınıfları, ORM anotasyonları veya SQL sorguları kesinlikle bulunamaz. Yalnızca saf nesne yönelimli yapılar (POPO - Plain Old PHP Objects) yer alır.- Entity (Varlık): Sürekli bir kimliğe (Identity / UUID) sahip olan ve yaşam döngüsü boyunca durumu değişebilen nesnelerdir.
- Value Object (Değer Nesnesi): Kimliği olmayan, sadece taşıdığı değerlerle tanımlanan ve değiştirilemez (immutable) olan nesnelerdir (Örn: Money, Email, Slug).
<?php
declare(strict_types=1);
namespace Bilgiseli\Domain\ValueObjects;
use InvalidArgumentException;
/**
* Değiştirilemez (Immutable) Email Değer Nesnesi
*/
final readonly class EmailAddress
{
private string $value;
public function __construct(string $value)
{
$filtered = filter_var(trim($value), FILTER_VALIDATE_EMAIL);
if ($filtered === false) {
throw new InvalidArgumentException("Geçersiz e-posta formatı: '{$value}'");
}
$this->value = strtolower($filtered);
}
public function getValue(): string
{
return $this->value;
}
public function equals(self $other): bool
{
return $this->value === $other->value;
}
public function __toString(): string
{
return $this->value;
}
}
2.2 Application Katmanı (Use Case / Interactor)
Uygulamanın spesifik kullanım senaryolarını (örn:PublishArticleUseCase, RegisterUserUseCase) içerir. Domain nesnelerini koordine eder, arayüz kontratlarını (Port / Interface) çağırır ancak somut veritabanı veya e-posta gönderim kütüphanelerini doğrudan bilmez.
2.3 Interface Adapters & Infrastructure (Sürücüler ve Veritabanı)
Gelen HTTP isteklerini DTO'lara dönüştüren Controller'lar ve Use Case'in tanımladığı Repository interface'lerini somutlaştıran (örn:PdoArticleRepository) sınıflar bu katmandadır.
3. Dependency Inversion Principle (DIP) ile Veritabanı Bağımsızlığı
Klasik MVC yapılarında Controller doğrudan Model ve ORM'e bağımlıdır:
$$\text{Controller} \longrightarrow \text{Eloquent/Doctrine} \longrightarrow \text{MySQL}$$
Clean Architecture'da ise bağımlılık tersine çevrilir (Inversion of Control):
$$\text{UseCase} \longrightarrow [\text{ArticleRepositoryInterface}] \longleftarrow \text{PdoArticleRepository (Infrastructure)}$$
<?php
declare(strict_types=1);
namespace Bilgiseli\Application\Contracts;
use Bilgiseli\Domain\Entities\Article;
/**
* Port: Use Case'in ihtiyaç duyduğu veri erişim kontratı
*/
interface ArticleRepositoryInterface
{
public function findById(int $id): ?Article;
public function save(Article $article): void;
public function delete(int $id): bool;
}
4. PHP 8.4 ile Uçtan Uca Use Case İmplementasyonu
Aşağıdaki örnekte, bir makaleyi yayına alan ve denetim logunu tetikleyen saf bir Use Case yer almaktadır:
<?php
declare(strict_types=1);
namespace Bilgiseli\Application\UseCases\PublishArticle;
use Bilgiseli\Application\Contracts\ArticleRepositoryInterface;
use Bilgiseli\Core\Events\EventDispatcher;
use Bilgiseli\Domain\Events\ArticlePublishedEvent;
use RuntimeException;
final readonly class PublishArticleUseCase
{
public function __construct(
private ArticleRepositoryInterface $repository,
private EventDispatcher $dispatcher
) {}
public function execute(PublishArticleCommand $command): PublishArticleResponse
{
// 1. Domain nesnesini getir
$article = $this->repository->findById($command->articleId);
if ($article === null) {
throw new RuntimeException("Makale bulunamadı: ID {$command->articleId}");
}
// 2. İş kuralını işlet (Domain mantığı Entity içinde kapsüllenir)
$article->publish();
// 3. Veritabanına kaydet
$this->repository->save($article);
// 4. Domain Event fırlat (Örn: Arama motoru indeksleme, sitemap güncelleme)
$this->dispatcher->dispatch(new ArticlePublishedEvent($article->getId(), $article->getTitle()));
return new PublishArticleResponse(
articleId: $article->getId(),
status: $article->getStatus(),
publishedAt: $article->getPublishedAt()
);
}
}
5. Clean Architecture'ın Avantajları ve Maliyet Karşılaştırması
| Kriter | Geleneksel Monolitik / Spagetti MVC | Clean Architecture & DDD |
|---|---|---|
| Birim Test Edilebilirlik | Düşük (DB ve Mock gerektirir) | %100 Kolay (Saf PHP sınıfları, DB gerektirmez) |
| Framework Bağımlılığı | Yüksek (Framework değişimi projeyi yeniden yazdırır) | Sıfır (Framework sadece dış kabuktur) |
| İş Kuralı İzolasyonu | Controller veya Model dosyalarına dağılmış | Tamamen izole ve merkezi (Use Case) |
| İlk Geliştirme Süresi | Hızlı | Orta / Planlı |
| Uzun Vadeli Bakım Maliyeti | Çok Yüksek (Entropi artışı) | Çok Düşük (Sürdürülebilir) |
6. Güvenlik, Veritabanı ve Ağ Entegrasyonu
Clean Architecture ile geliştirdiğiniz API'ların güvenliğini sağlamak için Zero Trust ve API Güvenliği Rehberi makalemizi okuyabilir, SQL sorgularınızı optimize etmek için SQL Formatter ve HTTP durum kodları için HTTP 404 Kılavuzu sayfalarımızdan yararlanabilirsiniz.
Özet
Clean Architecture bir amaç değil, yazılımınızın değişen teknoloji dünyasında yıllarca ayakta kalmasını sağlayan disiplinler bütünüdür. Veritabanınız MySQL'den PostgreSQL'e veya HTTP katmanınız CLI'a geçse bile, işletmenizin kalbi olan iş mantığınız bir satır bile değişmeden çalışmaya devam eder.