Katmanlı Mimariden Temiz Mimariye
Bağımlılıkların neden içe doğru yönelmesi gerektiğini anlayın.
Katmanlı Mimariden Temiz Mimariye, CoddyKit'te ücretsiz bir PHP Academy dersidir. Bu, 4 dersinin 1. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, PHP Academy öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. PHP Academy kursu toplamda 4 dersten oluşur.
Temiz Mimari Neden
Klasik üç katmanlı PHP yığınını zaten biliyorsunuz: Denetleyici → Servis → Depo → Veritabanı. Bu yaklaşım işe yarar; ancak iş mantığı Eloquent'e, Doctrine'a, HTTP isteğine ve çerçevenin yaşam döngüsüne bağımlı hale gelir. Temiz Mimari, bağımlılıkların yönünü tersine çevirir; böylece alan altyapı hakkında hiçbir şey bilmez. Kazancınız: sınanabilir kullanım senaryoları, değiştirilebilir uyarlayıcılar ve çerçeve yükseltmelerine dayanıklı bir kod tabanıdır.
Bağımlılık Kuralı
Temiz Mimari'nin tek kuralı şudur: kaynak kodu bağımlılıkları yalnızca içeriye yönelir. İç çemberler (varlıklar, kullanım senaryoları) dış çemberlere (denetleyiciler, nesne-ilişkisel eşleyiciler, çerçeveler) hiçbir zaman başvurmamalıdır. Çalışma zamanında denetim, arayüzler üzerinden dışarıya doğru ilerler; ancak derleme/içe aktarma zamanında içteki hiçbir şey dıştakini içe aktaramaz.
- Varlıklar: işletme kuralları
- Kullanım Senaryoları: uygulama kuralları
- Uyarlayıcılar: denetleyiciler, sunum bileşenleri, geçitler
- Çerçeveler ve Sürücüler: veritabanı, HTTP, web
Sıkı Bağımlı Katmanlı Örnek
Çoğu PHP uygulamasının sunduğu türden bir servis aşağıdadır. Alan mantığının Eloquent ve HTTP yanıtıyla nasıl iç içe geçtiğine dikkat edin. İndirim kuralını, veritabanı ve çerçeve olmadan birim sınamasından geçiremezsiniz.
<?php
class OrderService
{
public function place(Request $request)
{
$user = User::find($request->user_id); // Eloquent
$total = 0;
foreach ($request->items as $i) {
$total += Product::find($i['id'])->price * $i['qty'];
}
if ($user->is_vip) {
$total *= 0.9; // business rule trapped in infra code
}
Order::create(['user_id' => $user->id, 'total' => $total]);
return response()->json(['total' => $total]);
}
}Varlıklar: Çerçeveden Bağımsız Alan
Bir varlık, işletme çapındaki kuralları kodlar ve hiçbir şeye bağımlı değildir. Sade PHP; açıklama ekleri yok, nesne-ilişkisel eşleyiciden gelen temel sınıf yok. Bir sınama içinde tamamen oluşturulabilir.
<?php
final class Money
{
public function __construct(public readonly int $cents) {
if ($cents < 0) throw new InvalidArgumentException('negative money');
}
public function multiply(float $factor): self {
return new self((int) round($this->cents * $factor));
}
}
final class Order
{
/** @param array<int,int> $lineCents */
public function __construct(private array $lineCents, private bool $vip) {}
public function total(): Money {
$sum = array_sum($this->lineCents);
$money = new Money($sum);
return $this->vip ? $money->multiply(0.9) : $money;
}
}
echo (new Order([1000, 2000], true))->total()->cents, PHP_EOL; // 2700Kullanım Senaryoları İş Akışına Sahiptir
Bir kullanım senaryosu (etkileşimci), varlıkları orkestre eder ve dış dünyayla yalnızca arayüzler (bağlantı noktaları) üzerinden iletişim kurar. Bir istek veri aktarım nesnesi alır ve bir yanıt veri aktarım nesnesi döndürür — hiçbir zaman HTTP nesnesi döndürmez.
<?php
interface OrderRepository {
public function save(Order $order): void;
}
final class PlaceOrder
{
public function __construct(private OrderRepository $orders) {}
public function execute(array $lineCents, bool $vip): int {
$order = new Order($lineCents, $vip);
$this->orders->save($order);
return $order->total()->cents;
}
}Sınır Bir Arayüzdür
Kullanım senaryosu, ihtiyaç duyduğu OrderRepository arayüzünü bildirir. Arayüz iç çemberde bulunur; somut Eloquent/Doctrine uygulaması dışarıda bulunur ve içeriye bağımlıdır. Bu, Bağımlılıkların Tersine Çevrilmesi İlkesinin bir mimari sınırda uygulanmasıdır.
Kaynak bağımlılığının yönü: EloquentOrderRepository → OrderRepository (arayüz), tersi asla değil.
<?php
// Lives in infrastructure layer, points INWARD to the domain interface
final class EloquentOrderRepository implements OrderRepository
{
public function save(Order $order): void {
OrderModel::create(['total' => $order->total()->cents]);
}
}Altyapı Olmadan Sınama
Kullanım senaryosu bir arayüze bağlı olduğundan, sınamalar sahte bir nesne enjekte eder. Veritabanı yok, çerçeveyi başlatma yok — saf iş davranışını doğrulayan mikrosaniye hızında birim sınamaları.
<?php
final class InMemoryOrders implements OrderRepository {
public array $saved = [];
public function save(Order $o): void { $this->saved[] = $o; }
}
$repo = new InMemoryOrders();
$useCase = new PlaceOrder($repo);
$total = $useCase->execute([1000, 2000], true);
assert($total === 2700);
assert(count($repo->saved) === 1);
echo "PASS total=$total saved=" . count($repo->saved) . PHP_EOL;Denetleyiciler İnce Uyarlayıcılara Dönüşür
Denetleyici artık bir uyarlayıcıdır: HTTP'yi bir kullanım senaryosu çağrısına, sonucu da HTTP'ye çevirir. Hiçbir iş kuralı barındırmaz. REST'i CLI veya kuyruk işçisiyle değiştirseniz bile kullanım senaryosu olduğu gibi kalır.
<?php
final class OrderController
{
public function __construct(private PlaceOrder $placeOrder) {}
public function store(Request $request): JsonResponse {
$total = $this->placeOrder->execute(
lineCents: $request->input('lineCents'),
vip: (bool) $request->input('vip'),
);
return new JsonResponse(['total' => $total], 201);
}
}Haykıran Mimari
Klasör yapısı çerçeveyi değil, alanı haykırmalıdır. En üst düzeyde Controllers/ ve Models/ kullanmaktan kaçının. capability'ye göre düzenleyin; böylece yeni gelen biri uygulamanın ne yaptığını görebilir.
src/Ordering/Domain/— varlıklar, değer nesnelerisrc/Ordering/Application/— kullanım senaryoları, bağlantı noktası arayüzlerisrc/Ordering/Infrastructure/— Eloquent depoları, HTTP denetleyicileri
Her sınırlı bağlam en üst düzeyde bir klasördür; çerçeve sınırda yaşar.
Bağımlılık Kuralını Uygulama
Araçlar olmadan disiplin aşınır. Alan, Altyapıyı içe aktardığında derlemenin başarısız olması için sürekli tümleştirmede deptrac veya phparkitect kullanın. Böylece kural, kod incelemesine duyulan bir umut olmaktan çıkıp derleme zamanı güvencesine dönüşür.
# deptrac.yaml
deptrac:
layers:
- name: Domain
collectors: [{ type: directory, value: src/.*/Domain/.* }]
- name: Application
collectors: [{ type: directory, value: src/.*/Application/.* }]
- name: Infrastructure
collectors: [{ type: directory, value: src/.*/Infrastructure/.* }]
ruleset:
Domain: [] # Domain may depend on nothing
Application: [Domain]
Infrastructure: [Application, Domain]Veri Aktarım Nesneleriyle Sınırları Aşma
Varlıkların dışarı sızmasını önlemek için sınırı aşan veriler, varlık veya nesne-ilişkisel eşleyici modeli olarak değil, basit bir veri aktarım nesnesi olarak taşınır. Kullanım senaryosu, uyarlayıcının serileştirebileceği düz bir yapı döndürür; böylece alan nesnesi çekirdekten hiç çıkmaz ve dış katman iç durumun denetimini ele geçiremez.
<?php
final class OrderSummary // boundary DTO, no behavior, no domain types
{
public function __construct(
public readonly string $orderId,
public readonly int $totalCents,
) {}
}
final class PlaceOrderV2 {
public function __construct(private OrderRepository $orders) {}
public function execute(array $lineCents, bool $vip): OrderSummary {
$order = new Order($lineCents, $vip);
$this->orders->save($order);
return new OrderSummary('ord_1', $order->total()->cents);
}
}Hızlı Kontrol
Bağımlılık Kuralı kapsamında hangi bağımlılık yönüne izin verilir?
Özet
Sıkı bağımlı katmanlı yığından Temiz Mimari'ye geçtiniz:
- Bağımlılık Kuralı: kaynak bağımlılıkları yalnızca içeriye yönelir.
- Varlıklar, çerçeveden bağımsız PHP içinde işletme kurallarını barındırır.
- Kullanım senaryoları, bağlantı noktası arayüzleri aracılığıyla orkestrasyon yapar; HTTP yerine veri aktarım nesneleri döndürür.
- Denetleyiciler ve nesne-ilişkisel eşleyici depoları, içeriye bağımlı dış uyarlayıcılardır (DIP).
- Yapı alanı haykırmalı; deptrac gibi araçlar da bu kuralı sürekli tümleştirmede uygular.
Sıkça Sorulan Sorular
“Katmanlı Mimariden Temiz Mimariye” dersi ücretsiz mi?
Evet — “Katmanlı Mimariden Temiz Mimariye” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve PHP Academy kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. PHP Academy kursu toplamda 4 dersten oluşur.
“Katmanlı Mimariden Temiz Mimariye” dersinde ne öğreneceğim?
Bağımlılıkların neden içe doğru yönelmesi gerektiğini anlayın. PHP Academy ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.
PHP Academy öğrenmeye başlamak için deneyim gerekli mi?
Önceden deneyim gerekmez. CoddyKit'te PHP Academy, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 1. dersidir.
“Katmanlı Mimariden Temiz Mimariye” dersi ne kadar sürer?
Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.
Bu PHP Academy dersinde kod yazıp çalıştırabilir miyim?
Evet. Her PHP Academy dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.
Bu kursun tüm dersleri
- Katmanlı Mimariden Temiz Mimariye
- Portlar ve Adaptörler Açıklaması
- Kullanım Durumları ve Uygulama Hizmetleri
- Bağımlılığın Tersine Çevrilmesi Uygulamada