Günümüzde, Observer’ları neden bıraktığımı ele almak istiyorum.
Yıllardır, ben doğal bir Laravel kullanıcıydım. Dokümanlarda belirtilen bir özellik varsa, onu kullanırdım. Observers, sanki bir süper güç gibiydi. Controller’larınızı ince tutarak, tüm mantığı bir UserObserver içinde saklayabiliyordunuz.
Ancak projelerim basit CRUD’lardan daha karmaşık iş alanlarına geçince, Observer’ların gerçekten temiz kod olmadığını fark ettim. Onlar görünmez bir mantık. Ve görünmez mantık, istikrarın düşmanıdır.
“Temiz” kod yanılsaması
“Temiz” kod yanılsaması
Observer’ların çekiciliği açıktır. Controller’a bakarsınız ve harika görünür:
public function store(UserData $userData)
{
// Ne kadar temiz! Karışıklık yok!
$user = User::create($userData->toArray());
return response()->json($user);
}
Güzel görünüyor – ama ciddi sorunları saklıyor.
Geliştirici, bu dosyayı altı ay sonra okumaya çalıştığında, bu tek User::create() satırı bir zincir reaksiyonu tetikler. Bir hoş geldin e-postası gönderir, bir Stripe müşteri kimliği oluşturur, bir aktivite kaydeder ve belki de bir Slack kanalını bilgilendirir.
Buna “Uzakta Gizemli Etki” diyorum. Veritabanında bir yeri değiştiriyorsunuz ve kod, var olduğunu bile bilmediğiniz bir yerden çalışıyor.
İşlem sırası tuzağı
İşlem sırası tuzağı
Observer’ların bir diğer büyük problemi de yarış koşullarıdır.
Diyelim ki, oluşturulmuş bir olayda, bir ilişkiye bağımlı bir mantık var. User::create() kullandığınızda, oluşturulan olay hemen tetiklenir – çoğu zaman ilişkili modelleri (Roller veya Ekipler gibi) ekleme şansınız olmadan.
Bu durumu aşmak için yamalı kodlar yazmak zorunda kalıyorsunuz:
public function created(User $user)
{
// İlişkinin yüklü olup olmadığını tahmin etmeye çalışıyorum...
if ($user->relationLoaded('team')) {
// ...
}
}
Bu – olduğu gibi – oldukça kırılgan. İş kurallarınız:
Eloquent olaylarının rastgele yürütme sırasına bağımlı olmamalısınız.
Çözüm: Açık olan, örtük olandan üstündür
Çözüm: Açık olan, örtük olandan üstündür
Form Requests’ı DTO’lar ile değiştirdiğim gibi, Observer’ları açık Servisler (veya Eylemler) ile değiştirdim. Evet, bu, birkaç satır daha fazla kod yazmak anlamına geliyor. Ama bu kod bir hikaye anlatıyor.
İşte yeniden yapılandırılmış yaratma akışı. Hiçbir sihir yok. Kodu okuduğunuzda, tam olarak ne olduğunu biliyorsunuz:
class CreateUserService
{
public function handle(UserData $data): User
{
return DB::transaction(function () use ($data) {
// 1. Kullanıcıyı oluştur
$user = User::create($data->toArray());
// 2. Yan etkileri açıkça ele al
// Bunu görüyorum! Bunun olduğunu biliyorum!
$this->billingService->createCustomer($user);
// 3. Bildirim gönder
// Eğer bunu bir içe aktarımdan devre dışı bırakmak istersem,
// bu satırı sadece ÇAĞIRMAM.
// Model::withoutEvents() kullanmaya gerek yok.
$user->notify(new WelcomeNotification());
return $user;
});
}
}
Observer’lar ne zaman kabul edilebilir?
Observer’lar ne zaman kabul edilebilir?
Bu, Observer’ların gereksiz olduğu anlamına mı geliyor? Hiç de değil.
Ben hala (ya da kullanmıyorum) onları tamamen teknik endişeler için kullanıyorum. Bunların, her zaman bağlamdan bağımsız olarak gerçekleşmesi gerekir ve iş kurallarını etkilemez.
Örnekler:
- Bir model için UUID oluşturma
- Önbellek anahtarlarını silme
- Arama dizinlerini güncelleme (Elasticsearch / Meilisearch)
Ancak iş mantığı (e-posta gönderme, kredi kartı ücretlendirme, ekip atama) için? Asla.
Sonuç: Olgunluk, öngörülebilirliktir
Sonuç: Olgunluk, öngörülebilirliktir
Junior geliştiriciler olarak, bizim için bir şeyler yapan araçları severiz.
Sihirli olanı severiz.
Kıdemli (ve mimar) olarak ilerledikçe, tam olarak ne olduğunu söyleyebilmemizi sağlayan araçları değerli buluruz.
Observer’ları bırakmak başlangıçta acı vericiydi. “Boilerplate” yazdığımı hissettim. Ama o “boilerplate” aslında canlı dokümantasyon. Gelecekteki kendimin okuyabileceği, anlayabileceği ve uygulamanın tüm etkinlik sisteminin haritasını çıkarmadan hata ayıklayabileceği bir kod.
Eğer yan etkilerin uygulamanızı bozmasından bıktıysanız, oluşturulmuş olaya bağımlı kalmayı bırakın. Kodunuzu açık hale getirin.
Kaynak: Orijinal Makale


