Çok Katmanlı Mimari Örnek Proje(2)

Samet Çınar
SabancıDx
Published in
4 min readMar 10, 2021
Çok katmanlı mimari

Çok katmanlı mimari örnek projemizin ilk yazısında Corex’in bize sağladığı faydalardan, örnek projemizinde “Core, Model” katmanlarından bahsettim.

Bu yazımda sırasıyla “Data, Serializer, Mapper, Encryptor, EmailSender” katmanlarından bahsedeceğim.

03.Corex.Sample.Data

Projemizin data katmanında repository pattern kullanacağız. Belirlediğimiz ara yüzden EFCore implemente ederek MSSQL veri tabanını migration ile oluşturacağız.

Corex.Sample.Data.Infrastructure

Sample projesini incelediğinizde her katmanın bir “inftrastructure” bölümünün olduğunu göreceksiniz, bunu çok katmanlı mimari yazımda da anlatmıştım. Buradaki amacımız tüm ihtiyaçlarımı karşılayacak alt yapıyı oluşturup türeyen class librarylerin tüm methodlarımızı implemente etmesini beklemektir.

Repository ara yüzlerini oluştururken Corex’den gelen repository ara yüzleri göreceksiniz. Kodlarını buraya yapıştırıp gereksiz kalabalık yapmak istemiyorum.

Repository Pattern kullanımında bence yapılan en büyük yalnış “BaseEntityRepository” kullanımıdır. Bir tane base yapılır ve tüm repositoryler bunu base alarak tüm methodları kullanılır.

Peki ben bir mimar olarak kod tarafında developerın X entity üzerinde “delete” methodunu cağırmasını engelleyecek bir dizayn yapmak istediğimde ne yapacağım?

Bu kural setleri için her işlem özelinde “IRepository” belirliyoruz. Yani repositorylere “BaseEntityRepository”den hangi methodları kullanabileceğinin yetkinliğini veriyoruz.Bunları Corex üzerinden implemente edeceğiz.

ISelectableRepository
Get, GetList, Count v.b sadece select sorgusu yapılmasını istediğimiz repository için bu ara yüzü tercih etmeliyiz.

IInsertableRepository
Yeni kayıt yapabilir.

IUpdatableRepository
Kayıt güncelleme yapabilir.

IDeletableRepository
Kayıt silebilir.(IsDeleted:true)

Örn : IOrderRepository

IOrderRepository ara yüzünü implemente eden bir repository kayıt yapabilir, select yapabilir, güncelleme yapabilir. Ancak delete yapmasını istemediğim için “IDeletableRepository” eklemiyorum. Bu yetki kontrolünüde “DataOperation” yapacak bunu da operation katmanında detaylıca anlatacağım.

Corex.Sample.Data.Derived.EFSQL

Corex.Data.Derived.EntityFramework paketi bizlere “BaseConfiguration, BaseEntityRepository” verecek bunları kullanarak geliştirmelerimizi yapacağız. Ancak yine de bu paketleri direkt alıp classlarınıza base yapmanızı tavsiye etmem. Sizlerinde bu Corex’den gelen base classların önüne bir abstract class kolayarak gerektiğinde esnek olmayı sağlamanızı tavsiye ederim. CorexSample’da da böyle yapıyoruz.

Artık bu katmanda “IOrderRepository” gibi ara yüzlerimizin somut nesnesini oluşturuyoruz. OrderConfiguration’da alanlarımızın kurallarını bağlayarak zorunlu alanlarımızı, karakter sınırlarımızı v.s belirliyoruz.

Burada en çok işinize yaracak sorgulardan bir tanesi base classdan gele “GetList”in “ListExpression” methodunu override etme konusu. GetList methodunu direkt cağırdığınızda ilgili entity table’da ne kadar data varsa hepsini getirecektir. Sayfalama yapmak için her hangi bir ekstra kod yazmanıza gerek yok. Ancak sayfalama yaparken koşul belirtmek için “ListExpression” override edip queryable olan nesneye sorgu eklemeniz gerekiyor.

Örn : UserRepository

IPagerInputModel parametresi bizim gönderdiğimiz “UserPagerInputModel” olduğunu biliyoruz. Bu parametrelerde gönderilen değerleri entity table’ın tüm dataları döndüren query nesnesine koşul olarak ekliyoruz. Böylece sayfalama yapısına istediğimiz sorguyuda eklemiş oluyoruz.

04.Corex.Sample.Serializer

JsonSerializer için bu katmanı kullanacağız. Yahu json serializer içinde katman mı oluşturulur? Dediğinizi duyar gibiyim :) Tüm projede her parçayı rahatlıkla takıp, çıkartmak istiyorsak bunu yapmalıyız. Corex.Sample.Serializer.Inftrastructure’de serializer alt yapımızın sağlamasını istediğimiz ara yüzünü burada belirliyoruz.

Corex.Sample.Serializer.Derived.NewtonSerializer ile türettiğimiz class library kendi içerisinde “BaseNewtonsoftSerializer” kullanarak zaten basit olan newtonsoft kullanımını daha da basit hale getiriyor.

05.Corex.Sample.Mapper

Serializer’da olduğu gibi farklı katmana gerek duyulmayan bir yapıda Mapper, ayrı katman yaparak aslında mapper kütüphanelerinin kendi özelliklerin mazur kalıyoruz diyebiliriz. Neden?

Corex.Sample.Mapper.Infrastructure’da alt yapı ara yüzümüzü belirtiyoruz, biz bir mapper’dan ne yapmasını bekleriz?

public interface IMapping : ISingletonDependecy{TDestination Map<TSource, TDestination>(TSource source);}

Bir kaynağım var bir de hedefim, entity verip dto almak isterim ya da tam tersi. Mapper özetle bu amaçla kullanılır ancak örneğin AutoMapper’de bir sürü farklı profile var, bir çok işlemlerde fayda sağladığı oldukça doğru. Peki biz bunu projemizde kullanmaya başladığımızda ne yapmış oluyoruz ? AutoMapper’in bu özelliklerine bağımlı kalıyoruz, artık iş kurallarımızda automapper’da yaptığımız ve bu yüzden automapper’dan vazgeçemediğimiz bir durum yaratmış oluyoruz.

Canlı bir örneği başıma geldi, AutoMapper vs Mapster yaptık ve Mapster’a geçmeye karar verdik. Tek yapmamız gereken türettiğimiz Mapper class library değiştirmek oldu. Ancak AutoMapper’ın kendine has özelliklerine bağımlı olsaydık bunu yapamayacaktık. Bu tamamıyla bir tercih meselesi.

06.Corex.Sample.Encryptor

Kullanıcı kayıt ederken şifresini veri tabanına şifreleyerek yazmalıyız. Bu katman bize bu konuda yardımcı oluyor. Corex.Sample.Encryptor.Infrastructure’da belirlediğimiz alt yapı ara yüzünü Corex.Sample.Encryptor.Derived.SHAEncryptor class library ile türeterek projemizde kullandım.

07.Corex.Sample.EmailSender

Proje içerisinde bir çok aksiyonda mail gönderimi kullanabiliriz. Bu katmanın tek görevi mail göndermek olacak, template render edeyim ya da X yerden template okuyayım sonra mail atayım değil. Sadece mail göndermeyi bilecek. Operation katmanlarına gelene kadar bu durumlara oldukça dikkat etmeliyiz.

Mail gönderiminde bir SMTPEmailSender türettim bizden sadece from, password, host, port v.b bilgiler talep edecek bunlarıda “BaseSMTPEmailSender” base classı bizden talep ediyor. Appsettings üzerine girdiğim bilgiler geçersiz, siz kendi SMTP bilgilerini girmelisiniz.

Yazıları çok fazla uzun yapıp okunabilirliğini azaltmak istemediğim için yazıyı burada tamamlıyoruz.

08.Corex.Sample.Caching
09.Corex.Sample.Validation
10.Corex.Sample.Operation

Cache için memory kullanacağız bu hepimizin bildiği, kullandığı standart methodlar olsada bizim bir alt yapıda birleşmesi oldukça değerli. Yarın memory yerine Redis kullanabiliriz?

Validation katmanında tüm DTO’ların CRUD operasyonların bizim bildiğimiz dahilinde hata vermemesi için server side validation yapacağız.

Yavaş yavaş “Operation” katmanına geliyoruz, bir çok katman burada birleşecek, bir çok aksiyon burada dönecek. Yakın zamanda son yazımıda yayımlayacağım.

Görüşmek üzere..

--

--