Laravel’de “Fat Controller” (şişman kontrolcü) refactoring’i, büyüyen bir kod tabanında yapabileceğiniz en etkili iyileştirmelerden biridir. Projeler geliştikçe, kontrolcüler genellikle doğrulama, iş mantığı ve yan etkilerle aşırı yüklenir ve bu da bakımı ve test edilmesini zorlaştırır.
Bir kontrolcü küçük başlar. Temiz. Okunaklı.
Sonra özellikler eklenir.
Taksit süreleri zorlayıcı olur.
Yani, aniden 500 satırlık bir kontrolcüye bakıyorsunuz; bu kontrolcü, doğrulama, iş mantığı, veritabanı kayıtları, API çağrıları ve belki de “şimdilik” biraz formatlama yapmakta.
Biz buna Fat Controller diyoruz — ve bu, Laravel uygulamalarında en yaygın bakımı zorlaştıran sorunlardan biridir.
Bu yazıda, gerçek bir dünya yaklaşımı ile bir fat controller’ı daha temiz ve ölçeklenebilir bir yapıya nasıl refactor edeceğimizi, Clean Architecture’dan ilham alan prensipler kullanarak ele alacağız.
Bol teoriden kaçınacağız. Sadece pratik adımlar.
Tanıdık bir şeyle başlayalım:
class OrderController extends Controller
{
public function store(Request $request)
{
// Validation
$validated = $request->validate([
'user_id' => 'required|exists:users,id',
'items' => 'required|array',
]);
// Business logic
$total = 0;
foreach ($validated['items'] as $item) {
$product = Product::find($item['id']);
if (!$product) {
throw new Exception('Product not found');
}
if ($product->stock $item['quantity']) {
throw new Exception('Not enough stock');
}
$total += $product->price * $item['quantity'];
$product->stock -= $item['quantity'];
$product->save();
}
// Save order
$order = Order::create([
'user_id' => $validated['user_id'],
'total' => $total,
]);
// Save items
foreach ($validated['items'] as $item) {
OrderItem::create([
=> $order->id,
=> $item[],
=> $item[],
]);
}
// External API call
Http::post(, [
=> $order->id,
]);
return response()->json($order);
}
}
Burada ne yanlış?
Burada ne yanlış?
- Kontrolcü çok fazla sorumluluk taşıyor
- İş mantığı yeniden kullanılabilir değil
- Test edilmesi zor
- Eloquent ve harici API’ler ile yakın bağlılık
- Değişiklikler riskli
Biz daha çok şuna yönelmek istiyoruz:
- İnce kontrolcüler
- İzolasyonlu iş mantığı
- Test edilebilir hizmetler
- Konular arasında net sınırlar
Tam anlamıyla akademik Clean Architecture’a yönelmiyoruz. Sadece mümkün olduğunca yapılandırma yapacağız.
Öncelikle, ana mantığı kontrolcünün dışına çıkaralım.
class CreateOrderService
{
public function handle(array $data): Order
{
$total = 0;
foreach ($data[] as $item) {
$product = Product::find($item[]);
if (!$product) {
throw new Exception();
}
if ($product->stock $item[]) {
throw new Exception();
}
$total += $product->price * $item[];
$product->stock -= $item[];
$product->save();
}
$order = Order::create([
=> $data[],
=> $total,
]);
foreach ($data[] as $item) {
OrderItem::create([
=> $order->id,
=> $item[],
=> $item[],
]);
}
Http::post(, [
=> $order->id,
]);
return $order;
}
}
Kontrolcü artık şöyle:
class OrderController extends Controller
{
public function store(Request $request, CreateOrderService $service)
{
$validated = $request->validate([
=> ,
=> ,
]);
$order = $service->handle($validated);
return response()->json($order);
}
}
İyileştirme:
İyileştirme:
İyileştirme:
- Kontrolcü artık ince
- Mantık yeniden kullanılabilir
- Test edilmesi daha kolay
Ama henüz işimizi bitirmedik.
Ham dizeler geçirmek güvenli değil.
Hadi bunu düzeltelim.
class CreateOrderData
{
public function __construct(
public int $userId,
public array $items
) {}
public static function fromArray(array $data): self
{
return new self(
$data[],
$data[]
);
}
}
Kontrolcüyü güncelleyin:
$data = CreateOrderData::fromArray($validated);
$order = $service->handle($data);
Servisi güncelleyin:
public function handle(CreateOrderData $data): Order
İyileştirme:
İyileştirme:
İyileştirme:
- Daha güçlü tipler
- Daha güvenli refaktörizasyon
- Net bir sözleşme
Şu anda servisi şuna yakın olarak ilişkilendirmiş oldunuz:
- Eloquent modelleri
- HTTP istemcisi
Webhook mantığını çıkaralım.
class OrderWebhookService
{
public function send(Order $order): void
{
Http::post(, [
=> $order->id,
]);
}
}
Bunu enjekte edelim:
class CreateOrderService
{
public function __construct(
private OrderWebhookService $webhook
) {}
public function handle(CreateOrderData $data): Order
{
// logic...
$this->webhook->send($order);
return $order;
}
}
İyileştirme:
İyileştirme:
İyileştirme:
- Harici yan etkiler izole edilmiştir
- Testlerde taklit edilmesi daha kolaydır
Artık servisi bağımsız olarak test edebilirsiniz:
public function test_it_creates_order()
{
$service = app(CreateOrderService::class);
$data = new CreateOrderData(
userId: 1,
items: [
[=> 1, => 2],
]
);
$order = $service->handle($data);
$this->assertNotNull($order->id);
}
Refaktör etmeden önce, bu şunları gerektiriyordu:
- HTTP taklidi
- Kontrolcü testi
- Karmaşık kurulum
Artık izole edildi.
Bununla birlikte, aşırı mühendislik yapmayın.
Ancak uygulamanız büyüdüğünde, şunları çıkarabilirsiniz:
class ProductRepository
{
public function find(int $id): ?Product
{
return Product::find($id);
}
}
Sonra bunu servise enjekte edin.
Ne zaman yapılmalı:
Ne zaman yapılmalı:
- Birden fazla veri kaynağı
- Karmaşık sorgular
- Alan mantığı tekrar kullanımı
Ne zaman yapılmamalı:
Ne zaman yapılmamalı:
| Aspet | Önce | Sonra |
|---|---|---|
| Kontrolcü boyutu | Devasa | Minimal |
| Test edilebilirlik | Zor | Kolay |
| Yeniden kullanılabilirlik | Yok | Yüksek |
| Bağlantılılık | Yüksek | Azaltılmış |
| Bakımlılık | Ağrılı | Ölçeklenebilir |
1. Her şeyi körü körüne hizmetlere taşımak
1. Her şeyi körü körüne hizmetlere taşımak
Sadece şişman servisler yerine şişman kontrolcüler yaratmış olursunuz.
Hizmetlerinizi odaklı tutun.
2. Çok fazla katmanla aşırı mühendislik yapmak
2. Çok fazla katmanla aşırı mühendislik yapmak
Şunlara ihtiyacınız yok:
- 10 arayüz
- 5 soyutlama
- kurumsal mimari™
Basit başlayın. Gerekirse evrim geçirin.
3. Sınırları yok saymak
3. Sınırları yok saymak
Kontrolcüler = HTTP
Hizmetler = iş mantığı
Modeller = kalıcı
Bunları karıştırmak, kaosa geri dönmektir.
- Fat controllerlar bir belirtidir, kök problem değildir
- Gerçek sorun karıştırılmış sorumluluklardır
- Başlangıçta hizmet çıkarımı yapın
- Güvenlik için DTO’lar ekleyin
- Yan etkileri izole edin (API’ler, olaylar)
- Sadece gerekli olduğunda daha fazla soyutlama ekleyin
Laravel’da Clean Architecture, uygulamanızı bir ders kitabı diyagramına yeniden yazmak anlamına gelmez.
Bir anlamı vardır:
Kodunuzu korkmadan değiştirmeyi kolaylaştırmak.
Oraya ulaşmanın en hızlı yolu?
Şişman kontrolcülerden kurtulmaya başlamak — her seferinde bir yöntemle.
Eğer şu anda üstlendiğiniz bir şeyse, bir sonraki adımınız basit:
En kötü kontrolcünüzü seçin ve yalnızca bir eylemi bir hizmete çıkarın.
İşte temiz mimari aslında böyle başlar.
Kaynak: Orijinal Makale


