Tag Archives: design pattern

Unit of Work Pattern

Uzundur yazılım tasarım kalıpları hakkında yazmayalı olmuştu. Bu sefer size benim de çok işime yarayan ve büyük üstan Martin Fowler tarafından bize yönlendirilen – aslında tam kaynağı konusunda tam bir fikrim yok ama Fowler’ın PoEAA1 kitabında bahsi geçmekte – bir pattern.

Bu tasarım kalıbının amacı ve uygulaması çok basit, bu yüzden projelerimde kullanmaya özen gösteriyorum, aslında basit bir sorunu gidermesine rağmen uygulama açısından çok büyük bir amaca hizmet etmekte. Sonuçta tasarım kalıbı dediğimiz şeyler de kusura bakmayın gereksiz şeyler değiller.

Nedir, Amacı, Katmanı

Çok basit bir amacı var;

Veritabanında yapılan tüm işlemlerin tek bir bağlantı üzerinden yürümesi ve bir yerde hafızada tutulması.

Farkına vardığınız gibi bu bir DAL (Data Access Layer) kalıbı. Adından da anlaşılabileceği gibi her yapılan işlemin bir işlem birimi (unit of work) olarak ele alınmasını, bunların saklanmasını ele alan sınıf. Daha sonrasında bu işlemlerin toplu olarak kaydedilmesini (Save), geri alınmasını (Rollback), ya da iptal edilmesini (Dispose) sağlamaktadır. Detaylı açıklamayı Unit of Work Design Pattern makalesinde bulabilirsiniz.

Kullanımı

Kullanımı için çoğu kaynak Repository Pattern (Depolama tasarım kalıbı) kullanılmasını önermektedir. Aksine bir repository nesnesine ihtiyacınız yoktur. Her hangi bir bağlantı için, gerekli işlemleri içeren bir Unit of Work yazılabilir. Hiç de zor değil sonuçta. Ama tam olarak nasıl yazılması gerektiğini anlatayım.

Öncelikle elinizin altında, DAL için yazılmış bir data işlemleri nesnesi olmalı. Bu Repository Pattern olur, Generic Repository Pattern olur ya da CRUD işlemlerinin toplandığı bir sınıf olabilir. Bu sınıfın temel bağlantı alan yerini, dışarıdan bir kaynaktan alacak şekilde ayarlarsanız işlemlerimiz neredeyse tamamlanmış olur. Esas kafa karıştıran noktaları özetlersek;

  • Bağlantı dışarıdan, içerideki CRUD işlemi yapan sınıfa girmeli,
  • CRUD işlemi yapan sınıf kaydetme işlemlerini anlık olarak yapmamalı, kendi içinde Commit yapacak bir fonksiyon kullanmalı ve bu fonksiyon çağırılmadan işlem yapmamalı,
  • Transaction kullanılacaksa Rollback işlemleri için gerekli fonksiyonları içermeli,
  • CRUD fonksiyonlarını içeren sınıflar birden fazla olabilirler ki olmaları her zaman tercih edilendir.

Repository Pattern ile yazılmış sınıflar otomatikman Unit of Work için uygun olduğundan bu örneklerin hepsi onun üzerinden veriliyor. Fakat elinizde yukarıda yazdığım dört özelliğe sahip bir nesneniz varsa – teorik olarak zaten bu da repository pattern kullanmanızı sağlar fakat isminde repository yazmıyor diye kabul etmeyen arkadaşlarınız olabilir, oluyor öyle – siz de gayet Unit of Work kullanabilirsiniz.

Mimarisi

Basitçe yapılacak işlemi anlatayım; Tüm data işlemi yapan sınıflarınız Unit of Work içerisinde birer property olarak tutulur. Bu propertylere aynı DB connection ya da DB Context gönderilir. Property olarak gösterdiğimiz her sınıf kendi içinde değişmiş tüm datayı saklar. Unit of Work içinde bir “Save Changes” methodu olur. Bu method çağırıldığında tüm propertyler üzerindeki Save işlemleri çağırılır. Bu sayede işlemler yapılmış olur.

Avantaj olarak konuşursak, tüm DB işlemleri için dağıtık yapılarınızı tek bir sınıfta toplarsınız, transaction için rollback fonskiyonlarını ve kaydetme için save fonksiyonlarını tek bir method içinde kullanmış olursunuz. Bu da bir üst katman olan Service Layer ya da Business Intelligance Layer üzerinde işlem yaparken kolaylık sağlar. Eğer Dependency Injection kullanıyorsanız, küçük bir modifikasyonla hemen tüm DAL katmanınızı bu yapıya uygun hale getirebilirsiniz, zira çözülmesi gereken sadece DBContext nesnenizdir ve bu işlemlerin hepsi için sadece Unit of Work sınıfını güncellemeniz yeterli olacaktır. Ayrıca bir loglama yapısı kuracaksanız bunu da Unit of Work içerisine koyabilirsiniz. Hatta ve hatta DB’niz yoksa ve sadece XML işlemler yapıyorsanız, Service katmanının istediğiniz gibi yazılmasını ve dataların proje bitene kadar XML’de saklanmasını sağlayabilirsiniz. Anlat anlat bitmez bu işlemler, örneğe geçelim isterseniz.

Örnek

Bu kısımları internetten çok beğendiğim bir kaynaktan direk yapıştırıyorum, gerçi tüm örnekler aynı internette.

//IUnitOfWork.cs
public interface IUnitOfWork : IDisposable
{
    IProductRepository ProductRepository { get; }
    IOrderRepository OrderRepository { get; }
    void Save();
    // Gerekiyorsa buraya RollBack eklenebilir...
}

//UnitOfWork.cs
public class UnitOfWork : IUnitOfWork
{
    private readonly MyDataContext _context; // En önemli yer burası!!!
    private IProductRepository productRepository;
    private IOrderRepository orderRepository;

    public UnitOfWork()
    {
        this._context = new MyDataContext();
    }

    public IProductRepository ProductRepository
    {
        get { return this.productRepository ?? (this.productRepository = new ProductRepository(_context)); }
    }

    public IOrderRepository OrderRepository
    {
        get { return this.orderRepository ?? (this.orderRepository = new OrderRepository(_context)); }
    }

    public void Save()
    {
        _context.SaveChanges();
    }

    private bool disposed = false;
    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                _context.Dispose();
            }
        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

Bu arada service katmanında kullanımına gelirsek;

IUnitOfWork _uow = new UnitOfWork();
public void SaveProduct(Product _product)
{
    _uow.ProductRepository.Add(_product);
    _uow.Save();
}

Sonuç

Bu pattern’in kullanılması bu kadar basit, daha sonrasında ister Generic Repository kullanın, ister kendi “repository” nesnenizi içeren barklı bir bağlantı türünüzü kullanın fark etmeyecektir. En önemli noktanız her zaman MyDataContext kısmı olduğunu da aklınızdan çıkarmayın. Bir ara Generic Repository Pattern ile bu Unit of Work’ü nasıl genişleteceğinizi de anlatacağım. Boş vaktinizi iyi değerlendirmeniz dileğiyle. Ha bu arada tabii bir de Generic Unit of Work Pattern diye bir şey de var…


  1. Patterns of Enterprise Application Architecture (Martin Fowler) 

Doğru bil(me)diklerimiz neler?

Dediğim gibi bir sürü boş vaktim olmasa da bir sürü boş işe harcadığım vaktim olduğu için bir çok gereksiz konuda yazı yazabiliyorum. Aynen bir sürü gereksiz yazılım yazmak gibi ama biraz daha farklı. Bus efer ki konu, esasta doğru bildiğimiz yanlışlar ile alakalı. Bildiğiniz gibi, yazılım üzerine çalışınca, yazılım hakkında bir çok diyaloğun da içerisinde oluyorsunuz. Bu yazının ortaya çıkmasında sebep aynı böyle bir tartışmaydı; **“Object Oriented Programming kullanmıyorsunuz!” lafından çıktı hepsi, beni suçlamayın onu suçlayın.

Ne Bil(mi)iyoruz?

Pek tabii ki yazılımcılar olarak biz her şeyi biliyoruz! Aksi ispat edilemez, edilecekse gelsin çıksın karşıma. Biz bu meslekte dirsek çürüttük, her şeyini biliyoruz tabii ki. Ne biliyoruz peki? OOP biliyoruz, Pattern biliyoruz, Nesne biliyoruz, Polimorfizm biliyoruz, her bir şeyi biliyoruz. Açıkcası bir kaç güne kadar ben de böyle diyordum ki, piyasadan bir üstadımız beni yerin yedi kat dibine sokuncaya kadar. Sonrasında kendime geldim, nefes aldım bir oh çektim falan.

Peki gerçekten bu terimlere hakim miyiz?

Konuşmanın biraz daha heyecanlandığı noktada, benim otomatikman muhalefete geçme gibi bir özelliğim olduğundan, konu genelde farklı boyutlara taşınır. Konuşmada arkadaşın yukarıda belirttiği OOP kullanmıyorsunuz, bir nefi bilmiyorsunuz lafı sonrasında, sinirler arttı benim. “OOP Nedir?” dedim arkadaşa, basitçe bana OOP tasarım kalıplarıdır dedi o da. Bir kere öyle değil bu işler. OOP dediğimiz, nesne tabanlı programlamadır. Yani nedir? Nesne olması gerekir, yani senin nesneler yaratman, basitçe bu nesneleri yönetecek katmanları yazman ve buna bağlı programlama yapmanı anlatır. Peki ben hiç tasarım kalıbı ya da güzel adıyla Design Pattern kullanmamışsam? O zaman ben hiç OOP kullanmamış mı olurum? Ekmeğe, şeklini verirken franzile şekil vermediysem ortaya çıkan ürün ekmek değil midir? Aynı mantıkta yanıtlanabilecek bir cümle.

Eğer sen nesnelerini oluşturup, katmanlarını koyduysan, SOLID mantığını biraz da olsun yakaladıysan o zaman zaten OOP yapmışsın ne mutlu sana. Pattern kullanmadıysan OOP yapmadın diye bir algı yok, olmamalıdırda. Pattern kullanmadım diyorsunuz da peki o konuda da emin misiniz?

Pattern olayı

Ya şimdi bir gerçek var, Design Patterns popüler olduğundan beri, herkes bu terimi kullanır oldu hayatında. Adı üzerinde, tasarım kalıbı bu, yani kalıplaşmış kod yapısı. Hiç kullanamadan adam akıllı kod yazmanız için çömez olmanız lazım, kullanıp adını bilmezseniz normal developersınızdır. Fakat insanlar sizden ismini ve cismini bilmenizi bekler. Yeni dünya diye bir meyva var, ismini tam olarak bilmem. Alırım, yerim. Tutup da sen bana bunu yerken, “hiç yeni dünya yememişsin, çok süper meyva” dersen, yemiş olsam bile yemedim psikolojisi oluşur üzerimde.

Kod açısından örnek verirsek, yıllarca data fonksiyonlarını yazdıktan sonra, datayı ele alan DAL yani Data Access Layer’ı yazarken nesnelere uygun tekil sınıflar yazdım. Yani bir tablo varsa, o tabloya data girişini sağlayan. DataTablosuBase.Save() ya da DataTablosuBase.Insert(DataTablosu _dataTablosu) kodlarını içeren sınıfı yazdım ve datalarımı öyle kaydettim. Şimdi yıllar sonra öğreniyorum ki bu yöntem Repository Pattern olarak ele alınıyormuş. Şimdi aynı konuşmada, arkadaş bana onu da dedi “Hiç pattern kullanmadan OOP yazılmaz”. Bu arkadaşı ilk arayan 20 kişiye postayla göndermeye karar verdim. Bildiğin bas baya kullanmışım işte.

Bu pattern’in üç temel prensibi var; Data erişiminde tek noktanın olması, Tablolarınızla alakalı tek bir sorumlu yer olması, Olası altyapı değişimlerinde sistemin minimum değişimle işlemesi. E ben bunu gayet yerine getirmişim, sadece “DataTablosuBase” yerine “DataTablosuRepository” dememişim. Ha bir de EF kullanmamışım ama o kontaya girersem çok olaylar çıkar.

Sonuç

Demem odur ki, asla bir insanla beraber adam akıllı kod yazmadan ona şunu yapmamışsın, bunu yapmamışsın demeyin. Yapmıştır, illa yapmıştır da bilmiyordur. Yapmıştırsın da bilmiyorsundur diyin. Bu sayede siz de o insandan biraz kod öğrenebilir, o insanla aranızı bozmazsınız. Dünya daha güzel bir yere gelir. Fakat konunun başında da dediğim gibi biz yazılımcılar her şeyi bildiğimiz için bu konuda burnu havada insanlarız. Arada bir kendinizden daha iyi olan insanlar tarafından alaşağı edilin de, kendinize gelin vallaha.

Layer Supertype Pattern

Süperli müperli şeyler görünce heyecanlanmıyor değilim.

Nedir?

Martin Fowler’ın1 kim olduğunu bilmiyor olabilirsiniz, fakat ismini kesin bir yerlerde duymuşsunuzdur. Kendisi, şu an için pek hakim olamadığımız “Patterns of Enterprise Application Architecture”(İleri Seviye Yazılım Mimarisi Kalıpları) kitabının yazarı, bir nevi ortamların ağalarından bir tanesidir. Kendisini araştırın derim.

Martin Fowler’ın PoEAA2 kitabında bahsettiği kalıplardan bir tanesi olan Layer Supertype’a bakalım istedim bugün. Güzel bir kalıp ve çok da işe yarıyor, şahsen büyük bir programda kullanma fırsatım olmadı ama sizin imkanınız olabilir, ben de ekleyeceğim ilk fırsatta kendi programlarıma.

Fowler der ki; Kendi katmanında bulunan tüm tipler için bir süpertip oluşturan tip.

Kısaca açıklama çalışırsam; Bir katmanda birden fazla tip – diğer adıyla Entity – kullanıyorsanız ve bu entitylerde ortak olan noktalar var ise, tüm bu entitylerin türeyeceği bir tip yaratın ve bu ortak noktaları oraya yerleştirin.

Bir daha yazayım; Kendi katmanında! Ayrıca bir katmanda birden fazla Supertype olması gayet doğal, rahat olun agalar.

Hangi Durumlarda Kullanılır?

Yukarıda açıklamaya çalıştığım gibi birden çok Entity içerisinde kontrol etmeniz gereken bir durum var ise bunun için bir BaseEntity oluşturup, tüm Enity’leri buradan oluşturursanız, kontrol fonksiyonlarını tek bir süpertip’e vermiş olursunuz.

Örnek verecek olursa; ID alanının boş geçilmemesi her Entity için olabilecek bir şeydir. Genelde de zaten bu örneği verirler ya kıl olurum. Neyse, ID’nin boş geçmemesi için bir ID kontrol’ü yapan Supertype oluşturabilirsiniz.

Aslında anlatılmak istenen durum, bu ID alanının boş olmaması için gerekli küçük Framework’ün yaratılması için gerekli altyapının hazırlanmasıdır. Filozof gibi adam bu Fowler, zira PoEAA’da bu konuda pek bir şey de yazmamış, “kolay ya, ben hep yabıyom” demiş.

Uygulama

Hiç bir zaman şu kod örneklerini, diğer insanlar gibi vermemek gibi bir huyum olduğu için ben ID değil de, kendi kullandığım, Datanın Silinmemesi3 ilkesine göre bir örnek kod oluşturacağım. Bu arada bu kod kopyala yapıştır ile çalışmayabilir, zira direk düz metin olarak yazıyorum pseudo gibi algılayabilirsiniz.

Diyelim ki bir proje geliştiriyoruz, bu proje ne olursa olsun ben her Entity objem için DB’de IsActive, CreatedBy, CreationDate alanlarını tutarım. Bu alanlarım her Entity için var ise, neden bir Supertype yapmayayım ki?

namespace MyProject.Model
{
    public abstract class SuperEntity
    {
        private DateTime _createdDate; // Kontrol edilecek alan
        private IList<string> _errors = new List<string>(); // Hata içerikleri
        private bool _dateEntered = false; // Data girildi mi ki?

        public SuperEntity()
        { }

        public DateTime CreatedDate
        {
            get { return _createdDate; }
            set {
                if (_dateEntered)
                    BanaTarihHatasiVer();

                _createdDate = value;
                _dateEntered = true;
        }

        private void BanaTarihHatasiVer()
        {
            throw new ApplicationException("Yaratılma tarihi bir kere atandıktan sonra değiştirilemez!");
        }

        public bool IsValid()
        {
            ClearBusinessErrors();
            CheckErrors();
            return _errors.Count() == 0;
        }

        private void ClearBusinessErrors()
        {
            _errors.Clear();
        }

        protected abstract void CheckErrors();

        public IEnumerable<string> GetBusinessErrors()
        {
            return _errors;
        }

        protected void AddError(string error)
        {
            _errors.Add(error);
        }
    }
}

Buradan bir SuperEntity oluşturduk, şidmi diğer Entitylerde uygulamasına bakalım bunun;

namespace MyProject.Model
{
    public class News : SuperEntity
    {
        public News() { }

        public string Yazar { get; set; }

        protected override void CheckErrors()
        {
            if(String.IsNullOrEmpty(Yazar))
                base.AddError("Yazar olmadan haber mi olur?");
        }
    }
}

Kullanımını yapabilirsiniz.

Şimdi biz ne yaptık?

1- news.CreatedDate alanı için bir kere değer girildi mi, bir defa daha girilmesini elgelledik.
2- Hata kontrol sistemi entegre ettik. Yani news.Yazar alanı eğer boş geçilmişse, news.IsValid()bize o entity için boş geçilmiş, doldurulması zorunlu alanları verdi.
3- Ayrıca ortak olan fieldleri de bir supertype içine koyarak, mapping işlemleri için kolaylık sağladık.
4- Entity objemiz böyle sade bir entity oldu, içinde tekrar eden fieldler ve bunlar için kod olmadı, okunabilir oldu.

Aynı işlemi daha da genişletebiliriz, IsActive ve CretedBy alanlarını ekleyebilir. Tüm üç alanı, Error kontrolüne sokabilirdik.

İşte bu da bir yazılım kalıbı arkadaşlar, kullanıp kullanmamak tabii ki elinizde, fakat ben ilk gördüğümde gözlerim fal taşı gibi açılmadı diyemem. Darısı sizin başınıza.


  1. Martin Fowler Wikipedia 
  2. Patterns of Enterprise Application Architecture 
  3. Daha sonra detaylıca anlatacağım! 

Anti-Pattern: Smart UI

“Anti-pattern” kavramı hakkında pek fazla bilgiye sahip olmayabilirsiniz. Açıkcası benim için de çok yeni bir kavramdı, sağolsun Nedir TV’nin bir etkinliğinde Burak Selim Şenyurt‘un verdiği bir eğitimde varlığından haberdar olmuştum. Hatta dediğine göre, ülkemizde bazı üniversitelerde ders olarak bile gösteriliyormuş. Bu konu üzerine daha çok araştırma yapınca ben de paylaşım yapmaya özen göstereceğim.

Şimdilik bu konulardan sadece bir tanesi olan Smart UI adındaki anti-pattern’i size anlatmak istiyorum, hem basit bir anti-pattern hem de sık sık yaptığımız bir şey.


Anti-Pattern Nedir?

Çoğumuzun bildiği – ya da bildiğini sandığı – Design Pattern konusu vardır ya hani, yazılım yazmayı kolay hale getiren bazı kalıpları kullanarak hem kolay hem de stabil yazılımlar yazmamız amaçlanır – genelde elimize yüzümüze bulaştırırız. İşte DP1 gibi anti-pattern dediğimiz kavramlar da bize kalıplar sunar, fakat bu kalıplar kod yazarken yaptığımız hataları kapsamaktadır. DP’nin aksine AP2 direk kod içerisinde yapılan saçma hataları ele almaktadır ve tüm yazılımı hedef almaktadır. Öyle ki AP içerisinde proje yönetiminden, user interface’e kadar geniş bir aktegori yelpazesi bulunmaktadır.

O yüzden bir anti-pattern gördüğünüzde, bu direk yapmamanız gereken bir şeyi betimlemektedir! Bu tanım sanırım olabilecek en güzel tanım.

Smart UI

Bir anti-pattern olarak Smart UI, “User Interface”(kullanıcı arabirimi) kategorisine girmektedir. Esasında daha önce bir kaç yerde araştırmama rağmen, resmi AP listelemelerinde karşılaşamadım kendisi ile. Daha çok okuduğum kitaplarda geçen bir AP. Benim gibi Asp.Net üzerine uzmanlaşmış ya da uzmanlaşan birisi iseniz bu Smart UI kesinlikle yazılım hayatınızın bir parçası oluyor, bu yüzden de buna özellikle dikkat etmemiz gerekmekte.

Tanımı

Bir asp.net projesi açtığımızda – hangi tipte olursa olsun – yaptığımız ilk şey genelde UI’ı tasarlamak oluyor. Genelde UI tarafına girmeseniz de fark etmez, sonuçta UI tarafına illa giriyorsunuz ve bu kısımı hemen bitirip diğer işlerinize geçmek istiyorsunuz. Benim gibi işviçre çakısı gibi bir yazılımcı iseniz, sınırlı vakitte maksimum kazanç sağlamak için şirket zaten size dağ kadar iş vermiş ve hemen projenin bitmesini beklemekte sizden. Siz de vakit kaybetmemek için hemen projenin içine sayfayı açıp, gerek sürükle bırak yöntemi, gerek hemen buton altına kod yazma ile fonksiyonları tek sayfanın altında yaratıyorsunuz. Sonuçta proje çalışıyor mu? – Evet çalışıyor. O zaman sorun olmaması gerek. İşte bu Smart UI anti-pattern’i.

  • Proje hızlıca bitsin site tüm fonksiyonların ilgili sayfada toplanması,
  • Fonksiyonları katmanlamak yerine tek bir yerde toplayarak başka yerlerde kullanımlarda aynı fonksiyonların yazılması ya da static değişkeni tanımlayarak projenin bütünlüğünü bozmak

Etkileri

Yukarıdaki işlem bir anti-pattern’i tanımlar. Yani projeniz çalışsa da bir hata yaptığınızı tanımlar. Bu hatanın sonucunda;

  • Kodun bakımı, sistem karmaşıklaştıkça zorlaşır,
  • Geliştirme yapacağınız zaman, unutulan sayfalarda, işe yarar kodlar kalır,
  • Katmanlı mimariye geçilme aşamasınsa vakit kaybı yaratır,

Sonuçta hızla halledeyim dediğinizde, aslında geleceğe yönelik büyük bir hata yaptığınızın farkına varırsınız. Zaten anti-patternler de bu sorunu ortadan kaldırmak için vardır.

Çözüm

Çözüm için belirli bir yol yok. Aslında çözüme geçmeden önce cevap vermeniz gereken bir tane soru bulunmakta. Bu soru;

Bu ekran ya da projenin, ilerleyen zamanlarda geliştirmesi devam edecek mi?

Eğer cevabınız “Evet” ise, çözüm bulmanız gerekmekte. Fakat cevabınız “Hayır” ise, bir çözüm uygulamanıza pek de bir gerek yok. Zira zaten gelişimi devam etmeyecek bir proje ve başka yere de bağlanmayacak, o zaman neden çözesiniz ki, sonuçta amacınız projenin çalışması. Fakat daha sonradan pişman olup da tekrar sayfayı tasarlarken bulursanız kendinizi şaşırmayın.

“Evet” diyenler için çözüm belli, “Separation of concerns3 uygulamasınız, yani “Endişelerin dağıtılması”. Bunun manası da bir design pattern ya da dizayn mimarisi kullanmanızdan geçer. Dizayn mimarileri ile ilgili daha detaylı bir makale anlatacağım, fakat örnek vermek gerekirse MVC ve MVVC birer dizayn patterndir.

İlla ki direk MVC uygulamanıza gerek yok, sonuçta kodunuzun ne kadar gelişeceği burada merak unsuru. Sonuçta sizin projeniz ve istediğiniz şekilde çözümleyebilirsiniz. Bu durumda size tavsiyem, UI katmanı içerisinde fazla fonksiyonlara yer vermemeniz ve Business ile ilgili kodları ayrı sınıflara toplamanızdır. En azından genel bir mantık kurana kadar sizi idare edecektir.

Anti-Pattern konusunda devam yazılarım olacak, şimdiden iyi boş zaman geçirmeler…


  1. Design Patterns’in tarafımdan verilen kısaltması. 
  2. Anti-Pattern’in tarafımdan verilen kısaltması. 
  3. Separation of concerns