İçeriğe geç
Muhammet Şafak
en
Soran: Gizem Cevaplandı:

Sorgu iş kurallarını Eloquent local scope'larda mı yoksa repository katmanında mı tutmalıyım?


Soru

Laravel ile bir uygulama geliştiriyorum ve sorgu mantığı controller'larıma yayılmaya başladı; aynı `where` bloklarını birden çok yerde tekrar ediyorum ve bu beni rahatsız ediyor. İki seçenek arasında kaldım: akıcı Eloquent local scope'ları mı kullanmalıyım, yoksa test edilebilirlik uğruna repository katmanı mı eklemeliyim? Repository'lerin sorgu mantığını soyutlayıp mock'lanabilir kıldığını duyuyorum ama bunun bu proje için gereğinden ağır olmasından da korkuyorum.

Cevap

Kısa cevap

Çoğu Laravel uygulaması için doğru varsayılan local scope’lardır — test edilebilir, birleştirilebilir ve idiomatic’tirler.

Bağlam

Repository’ye ancak gerçek bir sebebiniz varsa uzanın (veri kaynağını değiştirmek ya da bir domain sınırını korumak gibi); “test edilebilirlik” için refleksle değil.

Neden

  1. Asıl sorun controller’daki sorgu mantığı ve ikisi de bunu çözer. where bloklarını controller’dan çıkarmak kazancın %80’idir. Scope’lar bunu repository katmanından çok daha az tören ile yapar.
  2. Local scope: idiomatic, birleştirilebilir, ucuz. Order::active()->forCustomer($id)->recent() domain gibi okunur. Bunları gerçek bir test DB’sinde (in-memory sqlite ya da test transaction’ı) rahatça test edersiniz; sorgunuzu test etmek için Eloquent’i mock’lamanız gerekmez.
    class Order extends Model
    {
        public function scopeActive(Builder $query): void
        {
            $query->where('status', 'active');
        }
    
        public function scopeForCustomer(Builder $query, int $customerId): void
        {
            $query->where('customer_id', $customerId);
        }
    }
    // Kullanım: Order::active()->forCustomer($id)->get();
  3. “Test için repository” argümanı Laravel’de göründüğünden zayıftır. Eloquent tasarım gereği bir Active Record’dur, DB’ye sıkı bağlıdır. Bir repository interface’ini mock’lamak, sorgunuzun doğru olduğunu değil, bir metodu çağırdığınızı test eder. Daha değerli test, gerçek veritabanına giden testtir.

Ne yapmalı

  1. Repository ne zaman yerini hak eder? Arkadaki veri kaynağını gerçekten değiştirmeniz gerektiğinde (Eloquent → dış API / arama index’i), Eloquent modelinden ayrı bir domain modeliyle DDD yapıyorsanız ya da sorgu kurma mantığının domain katmanına sızmasını yasaklamak istediğinizde. Bunlar mimari kararlardır, test kararları değil.
  2. Eloquent’i 1:1 saran repository yazmayın. UserRepository::find() içinde User::find() çağırmak bir katman ekler ama dolaylılıktan başka hiçbir şey satın almaz. En sık gördüğüm anti-pattern budur.
  3. Ara yol: sorgu (query) sınıfları / action’lar. Karmaşık, çok bloklu sorgular için özel bir query sınıfı (ya da Spatie’nin query builder’ı) tam repository soyutlamasına girmeden isimlendirilmiş, test edilebilir bir nesne verir.

Sonuç: Ben olsam sorgu mantığını scope’larda tutar ve onları gerçek bir (sqlite/pgsql) test DB’sine karşı test ederdim. Repository’yi yalnızca domain’in Eloquent’ten gerçekten ayrışması gerektiğinde eklerim — o zaman da Eloquent modeli değil, domain nesnesi döndürürler. Sırf mock’lamayı mümkün kılmak için repository eklemek, çoğu zaman gerçek bir testi sahte bir testle takas etmektir.

Yorumlar

Yorum yapmak için GitHub hesabınızla giriş yapmanız yeterli. Yorumlar GitHub Discussions üzerinde saklanır.

Diğer Sorular

Tüm sorular

Sitede Ara

Yazı, proje ve sayfalarda arama yapmak için yazmaya başlayın.

Esc ile kapat Pagefind ile güçlendirildi