Çözüldü Generic repository nedir?

Bu konu çözüldü olarak işaretlenmiştir. Çözülmediğini düşünüyorsanız konuyu rapor edebilirsiniz.
Çözüm
OOP kullanan sistemlerde elindeki data objesini repository'e kaydetme islemini abstract etmene yarar her ikisi de.

Generic ile generic olmayanin farki adi ustunde birinin generic olmasi.

Bir tane Generic Repository class'i tanimlarsin ( gerekirse abstract ) ve repo'ya kaydetmek istedigin objeyi buna verirsin. Repo her ne ise o da adaptif olarak kaydeder. Istersen Redis, istersen postgresql vs.

Repository Pattern ile, o objenin kendisinden sorumlu bir repository implementasyonu olur. Java tarafinda Spring bunu kendi interface'leri ile yapiyor. .NET icin de eminim cok benzeri vardir.


Bunun yapilmasindaki esas mantik su, repository islemlerini kodun geri kalanindan ayirmak istiyoruz. Al bunu kaydet, bana bunlari getir gibi islemleri DRY ve SOLID prensiplerine uygun sekilde yapmamiza olanak sagliyor.

Yine ornegi Java tarafindan vericem .NET API'sine hakim olmadigim icin:

Kod:
interface UserRepository extends CrudRepository<User, Long>


interface ProductRepository extends JpaRepository<Product, String>

Ustte hem "user" hem de "product" icin 2 tane Repository interface tanimi yaptim. Bunlar "Repository Pattern" e uygun.

Tanimlamadaki interface'lere dikkat edersen bir tanesi "CrudRepository" extend ediyor, diger "JpaRepository". Bunlar framework'un kendisinin yazdigi "Generic Repository" patternine uygun.

Boylece demis oluyorum ki bana bir UserRepository implemente et ve bununla sadece Crud operasyonlari yapacagim.

Digerinde de daha gelismis ozelliklere sahip JPA repository ozellikleri yapacagim.

JPA Repository si de polimorfik olarak zaten Crud repository'sinin super-seti.

Karisik gibi gelebilir ama aslinda tum bu islemler ustte yazdigim gibi neredeyse her ORM class'i icin ortak kullanilan save, update, delete, page, query vs operasyonlarina ayri ayri kod yazmamak ve projenin geri kalaninda decouple etmek icin yaptigimiz tanimlamalar.

ORM kullaniliyorsa kullanilmali, cunku daha standardize hale getiriyor kodu.
@bitwise Hocam repository pattern'in bazi durumlarda anti-pattern oldugu ve gereksiz soyutlamalar ile performans dusurdugu soyleniyor. Buna nasil karar veriyoruz peki? Bu soyutlamalar ciddi anlamda bir performans kaybina sebep olur mu?

Ben performans sorunu olusturacagini hic dusunmuyorum. Zaten DB operasyonlari bir uygulamanin genel performansini direkt belirleyen zincirin en "zayif" halkasi. Uygulama katmaninda bu tarz abstraction'lar yapmanin performansa anlamli zarar vermesi cok zor.

Elbette burada istisnai durumlar var, ornegin DB'den kastettigimiz Redis ya da Dynamo gibi zaten 10ms altinda std. operasyon yapan bir DB ise bu tarz abstraction'a ihtiyac yok. Zaten her her objeyi bu DB'lere yazmayiz. Veya bazi ORM library'leri bazi query'leri cok suboptimal yazarlar, direkt ORM kullanmamak istenebilir.

Yine de anti-pattern oldugu durumlar var:

- Ornegin her data objesi icin standart CRUD, pagination, sorting, findByX query disinda islemler yapilmasi gerekiyorsa repository pattern'i anlamsiz yere araya yerlestiriyoruz. Ornegin soyle kullanimlar goruyorum bazen:

Java:
@Repository
class UserDAO {
    private UserRepository userRepo; // spring repository pattern
    private EntityManager entityManager; // JPA entity manager
   
    public complexOperasyon(){
        entityManager.hedeHodo() // kompleks isler icin entity
    }
   
    public complex2(){
        // HQL ile query
        return entityManager
        .createQuery("FROM User u WHERE u.name = :name", User.class)
    }
   
    // Native DB layer query
    @Query("select bilmem ne", native=true)
    public findAggregateSortBilmemne(){
        //
    }
   
}

Adamlara standard repository pattern yetmemis, onu kapsayacak yeni bir class olusturmak zorunda kalmislar. O da yetmemis, entityManager ile session ve transaction yonetimi yapmak durumunda kalmislar. HQL yetmemis Query ile native query yazmak zorunda kalmislar.

Repositorynin kendisini baska bir repository component i wrap etmek zorunda kaliyorsaniz o halde zaten repository pattern e ihtiyac yok demektir.

- Bir baska anti pattern oldugu durum da AOP ile transaction yonetmek durumunda kalindigi zaman.

Yani sizin yapacaginiz DB operasyonu specifik bir transaction icinde olacaktir, bunu da okunabilir olmasi icin repository cagrisina yakin konumlandirirsiniz. Bu da repository isteklerinin atomik hale gelmesine ve dolayisiyla performansa ve hatta bug'lara yol acar. Cunku repository pattern tasarim olarak transaction management gorevini soyutlar, kodda gorunmez. Buna da ornek:

Java:
interface UserRepo extends JpaRepository<User, ID>

@Transactional(readonly = false, isolation = Serializable,
              propagation = Requires.NEW)
public void saveUser(){
    // User save islemi yeni bir transaction ve yuksek serializable
    // kullanimi gerektirir. Uygulama bu konuda hassas.
    // dolayisiyla repo.save islemi transaction yoneten save icine alinmis.  
    userRepo.save();
}

Bu yapi da zaten transaction iceren baska bir operasyon'dan saveUser cagirisi yapildiginda transaction icinde transaction icinde transaction gibi sacmaliklara sebep olabiliyor. Bunlarla karsilastim ve debug etmesi inanilmaz kulfetli islemler. Ayrica sadece yuk altinda sacmaladigini gozlemliyorsunuz bazen.

Uzun bir mesaj oldu ama ben aslinda genel olarak OOP'nin bu problemi karisik hale getirdigini dusunuyorum. Functional sekilde transaction pass etmek cok daha okunabilir, takip edilebilir, abstract hale getirilebilinir.

Ornek GO: ( Technopat'a GO ve Kotlin destegi gelsin lutfen )

Kod:
func WithCtx(f func(*sql.Tx) (any, error)) (any, error) {
  tx, err := db.BeginTx()
  defer rollBack // roll back defer hemen
  if err != nil // err handle et
  data, err = f(tx) // op
  commit
  return data, nil // sonuc
}

Bu sekilde acik sekilde Tx management yapan fonksiyonlar ve buna bagli Clojure tanimlari ile cok daha net kod takip edilebilip basitlestirilebiliyor. OOP'nin AbstractTransactionManagerFactoryBean gibi absurdlesen kullanimlarina ihtiyac kalmiyor.
 
Son düzenleme:

Technopat Haberler

Yeni konular

Geri
Yukarı