https://www.buraksenyurt.com/Burak Selim Şenyurt - Tasarım Prensipleri(Design Principles)2016-08-08T07:25:43+00:00Matematik Mühendisi Bir Bilgisayar Programcısının NotlarıBurak Selim SenyurtBlogEngine.Net Syndication Generatorhttps://www.buraksenyurt.com/opml.axdBurak Selim SenyurtMatematik Mühendisi Bir Bilgisayar Programcısının Notlarıtr-TRBurak Selim Şenyurt0.0000000.000000https://www.buraksenyurt.com/post/Biyutiful-Kod-Ninject-ile-Bir-Dependency-Injection-MacerasiBiyütıful Kod - Ninject ile Bir Dependency Injection Macerası2015-01-04T20:00:00+00:00bsenyurt<p><a href="https://www.buraksenyurt.com/pics/legoninjas.jpg"><img style="background-image: none; float: right; padding-top: 0px; padding-left: 0px; margin: 4px 0px; display: inline; padding-right: 0px; border-width: 0px;" title="OLYMPUS DIGITAL CAMERA " src="/pics/legoninjas_thumb.jpg" alt="OLYMPUS DIGITAL CAMERA " width="280" height="180" align="right" border="0" /></a>Merhaba Arkadaşlar,</p>
<p>Her yazılım geliştirici özellikle büyük bir projeye girdiğinde kodlarının kaliteli olması için uğraşır. Bu yönde adımlar atar. Çoğu zaman bu bir sanata dahi dönüşebilir. Okunabilir kodlar oluşturmanın dışında, mimari açıdan büyüleyici olan, yeniden kullanılabilirliğin üst seviyede olduğu, fazla uğraşılmadan genişleyebilen ürünler ortaya çıkartmak en büyük gayelerden birisi haline gelir. Martin Fowler' ın ilkeleri sıkı sıkıya takip edilir. Kurumsal çözüm içerisinde Fluent API' ler kullanılmaya, <strong>"Dependency Injection Container"</strong> gibi kavramlar konuşulmaya başlanır. Ne kadar başarılabilir bilinmez ama amaçlardan birisi de Biyütıful Kodu ortaya çıkartmaktır.</p>
<h1>Dependency Injection Container Hakkında</h1>
<p>Nesne yönelimli programlama<em>(Object Oriented Programming)</em> dünyasından bakıldığında <strong>Dependency Injection</strong>, yazılımların<em>(Software)</em> harici bileşenlere<em>(External Components)</em> olan bağımlılıklarının kontrol altın alınmasında önem arz eden bir prensiptir. Amaç, yazılımların kullandıkları bileşenler ile<em>(veya sınıfların birbirleri ile)</em> gevşek bağlar<em>(loose coupling) </em>kurabilmesini sağlamaktır. Söz konusu prensibin kolayca uygulanabilmesi de önemlidir. Öyle ki, gevşek bağlanan bileşenler arasında kolayca ve zahmetsizce geçişler yapılabilmeli ya da sorumluluk zincirine yeni bağımlılıklar zahmetsizce eklenebilmelidir. Üstelik bu değişiklikler koda minimum seviyede dokunarak ve sadece gerekli olanlar yeniden <strong>Build </strong>edilerek yapılabilmelidir.</p>
<blockquote>
<p>Kısaca Dependency Injection, bileşenler arasındaki hard-coded bağımlılıkların, tasarım zamanı<em>(design time)</em> yerine çalışma zamanında<em>(run time)</em> enjekte edilmesidir.</p>
</blockquote>
<p>Bu esenkliğin pek çok noktada faydası vardır. Örneğin;</p>
<ul>
<li>Test güdümlü geliştirilen<em>(Test Driven Development)</em> uygulamalarda, o an için ihtiyaç duyulmayan bileşenlerin sahteleri ile kolayca değiştirilerek birim testlerin<em>(Unit Test)</em> çalıştırılmasında,</li>
<li>Miras olarak kalmış kod parçalarının<em>(Legacy Codes)</em> yazılım tarafında fazla kod davranışı değiştirmeden kullanılabilmesinde,</li>
<li>Asıl uygulamaların yeniden derlenmeye gerek kalmadan kolayca bileşen değiştirebilmesinde,</li>
<li>Mikro servis mimarisinde,</li>
<li>Log' lama gibi Cross Cutting bileşenlerinin dış bağımlılıklarının esnek bir şekilde değiştirilebilmesinde,</li>
<li>İzole edilmiş 3ncü parti bileşenler arasında geçişler yapılabilmesinde,</li>
<li>Belli bir bağımlılığın n sayıda bileşene enjekte edilmesi gerektiği durumlarda<em>(Özellikle DAO-Data Access Object' ler de sıklıkla görebiliriz)</em>,</li>
<li>Bir bileşenin farklı örneklerinin diğer bileşenlere farklı konfigurasyonlar ile bağlanması gerektiği durumlarda vb...</li>
</ul>
<blockquote>
<p><strong>Depedency Injection</strong> ile ilişkili olarak akla gelen en büyük soru aslında ne zaman kullanılması gerektiğidir. Bu noktada <a href="http://blog.ploeh.dk/2012/11/06/WhentouseaDIContainer/" target="_blank">şu adresteki</a> makaleyi takip etmenizi şiddetle öneririm.</p>
</blockquote>
<p>Yukarıda bahsettiğimiz vakalar göz önüne alındığında <strong>Dependency Injetcion</strong>' ın basitçe uygulanmasının da önemli olduğunu ifade edebiliriz. Bunun için geliştirilmiş pek çok <strong>Container </strong>kütüphanesi mevcuttur. En popülerleri <strong>Castle Windsor</strong>, <strong>Spring.Net</strong>, <strong>Unity </strong>ve <strong>Ninject' </strong>tir. Elbette kendimiz de bir Dependency Injection Container bileşeni yazabiliriz. Ancak kurumsal çaptaki uygulamalarda çoğunlukla hazır kütüphanelerden faydalanıldığını da unutmamalıyız<em>(Reinventing the Square Wheel gibi bir anti-pattern oluşmaması için. Tabi sıfırdan öğrenmek istiyorsak istisnai bir durum mümkündür)</em></p>
<h1>Başlangıç</h1>
<p>İşte bu yazımızdaki amacımız temel anlamda bu tip Container' ların nasıl kullanılabildiğini anlamaktır. Neredeyse tüm <strong>Conatiner </strong>araçları aynı temeller üzerine oturmaktadır. <strong>Ninject </strong>kütüphanesini göz önüne alarak ilerlemeye çalışalım. Konuyu basitçe değerlendirmek için ele alacağımız <strong>Console </strong>uygulamasına <strong>Ninject </strong>kütüphanesini <strong>NuGet </strong>paket yönetim aracı ile yükleyerek devam edebiliriz.</p>
<p><a href="https://www.buraksenyurt.com/pics/htn_1.png"><img style="margin: 4px 0px; display: inline;" title="htn_1" src="/pics/htn_1_thumb.png" alt="htn_1" width="420" height="236" /></a></p>
<blockquote>
<p>Ninject açık kaynak kodlu bir projedir. <a href="https://github.com/ninject/ninject" target="_blank">GitHub</a> üzerinden bakılabilir.</p>
</blockquote>
<h1>İlk Kodlar</h1>
<p><strong>Ninject</strong> ile bağımlılıkları enjekte etmeden önce aşağıdaki gibi bir kod içeriğine sahip olduğumuzu düşünelim.</p>
<p><a href="https://www.buraksenyurt.com/pics/htn_2.png"><img style="margin: 4px 0px; display: inline;" title="htn_2" src="/pics/htn_2_thumb.png" alt="htn_2" width="521" height="425" /></a></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">namespace HowTo_UsingNinject
{
class Program
{
static void Main(string[] args)
{
IEncryptor dv = new DaVinciEncryptor();
MessageProvider provider = new MessageProvider(dv);
string encryptedMessage=provider.EncryptMessage("Bir not");
string decryptedMessage = provider.DecryptMessage(encryptedMessage);
}
}
class MessageProvider
{
private IEncryptor _encryptor;
public MessageProvider(IEncryptor Encryptor)
{
_encryptor = Encryptor;
}
public string EncryptMessage(string Message)
{
return _encryptor.Encrypt(Message);
}
public string DecryptMessage(string Message)
{
return _encryptor.Decrypt(Message);
}
}
interface IEncryptor
{
string Encrypt(string Message);
string Decrypt(string Message);
}
class MichalengeloEncryptor
: IEncryptor
{
public string Decrypt(string Message)
{
// Bir takım işlemler yapıldığını düşünelim
return Message;
}
public string Encrypt(string Message)
{
// Bir takım işlemler yapıldığını düşünelim
return Message;
}
}
class DaVinciEncryptor
: IEncryptor
{
public string Decrypt(string Message)
{
// Bir takım işlemler yapıldığını düşünelim
return Message;
}
public string Encrypt(string Message)
{
// Bir takım işlemler yapıldığını düşünelim
return Message;
}
}
}</pre>
<h1>İlk Kod Parçasında Ne Yaptık?</h1>
<p>Örnek senaryoda bir mesajlaşma sisteminde hareket eden içeriklerin şifrelenme ile ilgili işlemlerin ele alındığını ifade edebiliriz. <strong>IEncryptor </strong>isimli arayüz<em>(Interface) </em>bilginin şifrelenmesi veya şifrelenmiş bilginin çözülmesi için gerekli iki temel fonkisyonellik sunmaktadır. Asıl şifreleme işini ise <strong>DaVinciEncryptor </strong>ve <strong>MichalengeloEncryptor </strong>isimli sınıflar üstlenmektedir. Elbette yeni şifreleme teknikleri bu arayüz sözleşmesinden yararlanılarak sisteme kolayca entegre edilebilir ve MessageProvider tarafında ele alınabilir. Bir nevi şifreleme sözleşmesi<em>(Contract) </em>tanımladığımızı ve iki basit uyarlamasını hazırladığımızı düşünebiliriz.</p>
<p><strong>MessageProvider </strong>sınıfı ise aslında manuel olarak bir <strong>Dependency Injection </strong>uygulamaktadır. Dikkat edileceği üzere yapıcı metod<em>(constructor)</em> <strong>IEncryptor </strong>arayüzü tipinden bir parametre almakta ve <strong>private </strong>tanımlanmış <strong>_encrpytor</strong> değişkeninin set edilmesinde kullanılmaktadır. Bu değişkenin alabileceği çalışma zamanı nesne örnekleri, <strong>IEncryptor </strong>sözleşmesini uygulayan sınıflardan olabilir. İçerdiği <strong>EncryptMessage </strong>ve <strong>DecryptMessage </strong>metodları ise, çalışma zamanında atanacak şifreleme tipini kullanmaktadır.</p>
<p>Önemli olan nokta ise; <strong>IEncryptor</strong> arayüzünün taşıyacağı gerçek nesne örneğinin ne olacağına <strong>MessageEncryptor</strong> sınıfı içinde değil, <strong>MessageEncryptor</strong>' ı çağıran yerde<em>(senaryoda Console uygulamasının kendisidir)</em> karar verilmesidir.</p>
<h1>Ninject ile Bağımlılıkların Enjekte Edilmesi</h1>
<p>Peki bu manuel olarak bağımlılıkları enjekte etme yöntemi yerine <strong>Ninject </strong>aracını kullanmak istesek nasıl bir yol izleriz? Dahası Ninject bize bu bağımlılıkların enjekte edilmesi noktasında nasıl bir avantaj sağlamaktadır? Kod içeriğini aşağıdaki şekilde değiştirerek devam edelim bu soruların cevabını bulmaya çalışalım.</p>
<p><a href="https://www.buraksenyurt.com/pics/htn_3.png"><img style="margin: 4px 0px; display: inline;" title="htn_3" src="/pics/htn_3_thumb.png" alt="htn_3" width="215" height="144" /></a></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Reflection;
using Ninject;
using Ninject.Modules;
namespace HowTo_UsingNinject
{
class Program
{
static void Main(string[] args)
{
#region Ninject Kullanarak
IKernel kernel = new StandardKernel();
kernel.Load(new MessageBindingModule());
IEncryptor dv = kernel.Get<IEncryptor>();
MessageProvider provider = new MessageProvider(dv);
string encryptedMessage = provider.EncryptMessage("Bir not");
string decryptedMessage = provider.DecryptMessage(encryptedMessage);
#endregion
}
}
class MessageBindingModule
:NinjectModule
{
public override void Load()
{
Bind<IEncryptor>().To<DaVinciEncryptor>();
}
}
// Diğer kodlar
}</pre>
<p>İlk dikkat edilmesi gereken nokta var olan sınıflarda ve arayüz de herhangibir kod değişikliği <span style="text-decoration: underline;">yapılmamış</span> olmasıdır. Bağımlılıkların tanımlanması tamamen yeni bir sınıf içerisinde gerçekleştirilmektedir. <strong>MessageBindingModule </strong>sınıfının ve <strong>Main </strong>metodundaki enjekte etme adımlarının farklı bir <strong>assembly</strong>' da olabileceğini düşünürsek özellikle var olan bileşen yapılarını da bozmadan ilerlenebileceğini ifade edebiliriz.</p>
<p><strong>MessageBindingModule</strong>, <strong>NinjectModule</strong> sınıfından türemiştir ve <strong>Load</strong> metodu ezilmiştir. Bu modül tahmin edileceği üzere bağımlılıkların tanımlandığı yerdir. Koda göre <strong>IEncryptor </strong>arayüzünün <strong>DaVinciEncryptor</strong>' a bağlanması söz konusudur ki bu çalışma zamanında icra edilecek bir operasyondur.</p>
<blockquote>
<p>Modül kullanımı bu tip bağımlılıkların tanımlanması için bir zorunluluk değildir. Farklı Injection Pattern teknikleri de bulunmaktadır. Diğer yandan çoklu bağımlılık tanımlamalarında(Multi Injection) modül yaklaşımı tercih edilmelidir.</p>
</blockquote>
<p><strong>Main</strong> metodu içerisinde ise dikkat çekici işlemler vardır. <strong>IKernel</strong> referansı bir <strong>StandartKernel</strong> nesne örneği olarak alındıktan sonra bağımlılıkların <strong>Load</strong> metodu içerisine verilen <strong>MessageBindingModule</strong> üzerinden yapılması gerektiği ifade edilmektedir. <strong>kernel.Get<T></strong> metoduna verilen arayüz adı, modül içerisindeki <strong>Load </strong>metodunca otomatik olarak bulunacak ve geriye <strong>DaVinciEncryptor</strong> örneği döndürülecektir. Kodun geri kalan kısmında yapılanlar ise aynıdır.</p>
<h1>Nasıl Bir Avantaj?</h1>
<p>Aslında <strong>Ninject</strong> ile bağımlılıkları enjekte ettiğimiz yukarıdaki örnekte çok da fazla avantaj yok gibi görünmektedir. Hatta manuel yazdığımız örnektekine göre daha fazla kod satırı oluştuğunu düşünebiliriz. <strong>Ninject</strong>' in veya benzer bir <strong>Container</strong>' ın hangi noktada avatantaj sağladığını görmek için, bileşenler arası bağımlılıkların sayısının arttığını düşünmemiz yerinde olacaktır. Nitekim bir gerçek hayat projesinde bileşenler arasındaki bağımlılıkların proje büyüdükçe arttığı gözlemlenir. Bu artış sonrası bağımlılık zincirlerinin tesit edilmesi, component’ ler in değiştirilmesi giderek zorlaşır. İşte böyle bir durumda bağımlılıkları otomatik olarak algılayabilecek ve kod eforunu aza indirgeyecek <strong>Container'</strong> ların kullanılması önemlidir.</p>
<p>Bu anlamda senaryoya şöyle bir ek yaptığımızı düşünelim.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">interface IAlgorithmProcessor
{
string Calculate(string Info);
}
class IntelligenceProcessor
: IAlgorithmProcessor
{
public string Calculate(string Info)
{
// Bir algoritma kullanılıyor
return Info;
}
}
class MichalengeloEncryptor
: IEncryptor
{
private IAlgorithmProcessor _processor;
public MichalengeloEncryptor(IAlgorithmProcessor Processor)
{
_processor = Processor;
}
public string Decrypt(string Message)
{
// Bir takım işlemler yapıldığını düşünelim
return _processor.Calculate(Message);
}
public string Encrypt(string Message)
{
// Bir takım işlemler yapıldığını düşünelim
return _processor.Calculate(Message);
}
}</pre>
<p><strong>MichalengeloEncryptor</strong> içerisinde <strong>IAlgorithmProcessor</strong> arayüzünü uygulayan sınıflar için bir bağımlılık daha söz konusudur. Çok doğal olarak <strong>MessageProvider</strong> sınıfı da bu bağımlılık üzerinden <strong>IAlgorithmProcessor'</strong> a bağlanmıştır. Bu yeni bağımlılığın sisteme enjekte edilmesi için <strong>Ninject </strong>modülü içerisinde aşağıdaki kodlamayı yapmak yeterli olacaktır.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">class MessageBindingModule
:NinjectModule
{
public override void Load()
{
Bind<IEncryptor>().To<MichalengeloEncryptor>();
Bind<IAlgorithmProcessor>().To<IntelligenceProcessor>();
}
}</pre>
<p>Dolayısıyla bir <strong>Dependency Injection Container</strong> bileşeni, uygulamada kullanılan sınıflar arası bağımlılıklar arttıkça etkisini gösterecektir. <strong>Ninject Container </strong>aracını kullanmak görüldüğü üzere son derece kolaydır. Diğer yandan aracın çok daha farklı yetenekleri bulunmaktadır. Ninject popüler olanlarından sadece birisidir. Diğerleri de benzer ilkeler ile çalışmakta ve temel olarak <strong>IoC<em>(Inversion of Control)</em></strong> prensibini baz almaktadır.</p>
<p>Bu yazımızda <strong>Ninject </strong>aracının çok basit seviyede bağımlılıkları enjekte etme notkasında nasıl kullanılabileceği ele alınmıştır. <a href="http://www.ninject.org/learn.html" target="_blank">Detaylı bilgi için Dojo' ya</a> uğramanız gerekmektedir. İlerleyen günlerde Ninject ile bağımlılıkların farklı seviyelerde nasıl oluşturulabileceğini de incelemeye çalışacağız. Yani yapıcı metod haricindeki metodlarda veya özellik<em>(Property) </em>seviyesinde bu bağımlılıkları nasıl tanımlayabileceğimize bakacağız. Böylece geldik bir makalemizin daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>2015-01-04T20:00:00+00:00dependency injectionninjectdesign principlessoftware design principlesc#.netinversion of controldependency injection containerbsenyurtHer yazılım geliştirici özellikle büyük bir projeye girdiğinde kodlarının kaliteli olması için uğraşır. Bu yönde adımlar atar. Çoğu zaman bu bir sanata dahi dönüşebilir. Okunabilir kodlar oluşturmanın dışında, mimari açıdan büyüleyici olan, yeniden kullanılabilirliğin üst seviyede olduğu, fazla uğraşılmadan genişleyebilen ürünler ortaya çıkartmak en büyük gayelerden birisi haline gelir. Martin Fowler' ın ilkeleri sıkı sıkıya takip edilir. Kurumsal çözüm içerisinde Fluent API' ler kullanılmaya, "Dependency Injection Container" gibi kavramlar konuşulmaya başlanır. Ne kadar başarılabilir bilinmez ama amaçlardan birisi de Biyütıful Kodu ortaya çıkartmaktır.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=fefcf076-07e1-4dba-820b-9eea55cdf73d3https://www.buraksenyurt.com/trackback.axd?id=fefcf076-07e1-4dba-820b-9eea55cdf73dhttps://www.buraksenyurt.com/post/Biyutiful-Kod-Ninject-ile-Bir-Dependency-Injection-Macerasi#commenthttps://www.buraksenyurt.com/syndication.axd?post=fefcf076-07e1-4dba-820b-9eea55cdf73dhttps://www.buraksenyurt.com/post/Entity-Framework-Generic-Repository-ve-Unit-of-Work-UyarlamasiEntity Framework - Generic Repository ve Unit of Work Uyarlaması2014-12-14T03:00:00+00:00bsenyurt<p><a href="https://www.buraksenyurt.com/pics/thinking.jpg"><img style="background-image: none; float: right; padding-top: 0px; padding-left: 0px; margin: 4px 0px; display: inline; padding-right: 0px; border: 0px;" title="thinking" src="/pics/thinking_thumb.jpg" alt="thinking" width="240" height="232" align="right" border="0" /></a>Merhaba Arkadaşlar,</p>
<p>Yazılım dünyasında var olan mimari prensipler veya tasarım kalıpları tek başlarına belirli sorunları çözseler de, bazı kurumsal projelerde mutlak suretle bir arada düşünülmeleri gerekir. Söz gelimi <strong>Repository</strong> ve <strong>Unit of Work</strong> kalıpları, özellikle <strong>Domain Driven Design</strong> odaklı yapılarda bir arada değerlendirilmesi gerekenlerdendir.</p>
<p><strong>DDD </strong>denilince aklımıza daha çok veri odaklı uygulamalar gelir ve bu tip ürünlerde <strong>RDBMS<em>(Relational Database Management System) </em></strong>lerin yeri hatırı sayılır ölçüde fazladır<em>(Her ne kadar son yıllarda NoSQL cephesinde önemli gelişmeler ve kullanımda ciddi artışlar olsa da…) </em></p>
<p>Hal böyle olunca <strong>O/RM<em>(Object Relational Mapping)</em></strong> araçlarının kullanımı da önem kazanmaktadır. Yıllardır hayatımızda olan bu araçlar modellerin nesnel olarak inşasında da önemli bir yere sahiptirler. Lakin <strong>Object Oriented </strong>dünyasının kuralları içerisinde yaşarlar ve bu yüzden bazı kurumsal prensipleri uygulamaları gerekmektedir.</p>
<p>Benim gibi <strong>.Net</strong> üzerinde geliştirme yapanlar için O/RM araçları da az çok bellidir. <strong>Entity Framework</strong> bunlardan birisidir. Ancak <strong>Entity Framework</strong>’ ün uygulamalardaki kullanımında genellikle hatalar yapılır. <strong>Enterprise</strong> bir çözüm söz konusu olduğunda varsayılan olarak <strong>Data Access</strong> ve <strong>Business Logic</strong> katmanlarının olması izolasyon açısından önemlidir. İşte bu noktada <strong>DAL</strong> ve <strong>BLL</strong> arasındaki kullanımlarda <strong>EF</strong>’in çoğu zaman bir O/RM aracı olarak soyutlanamadığı görülür. Hal böyle olunca sistemin farklı bir kaynağı kullanarak yaşamaya devam etmesi de zorlaşır. <a href="http://martinfowler.com/eaaCatalog/repository.html" target="_blank">Repository</a> ve <a href="http://martinfowler.com/eaaCatalog/unitOfWork.html" target="_blank">Unit of Work</a> özellikle bu vakalara çözüm niteliğindeki iki değerli desendir.</p>
<blockquote>
<p>Hiç kimse bu deseneleri Martin Fowler kadar iyi açıklayamaz. Bu yüzden makalenin amacı ilgili desenelerin Entity Framework için örnek bir kullanımının anlatımından ibarettir.</p>
</blockquote>
<h1>İşin Gerçeği</h1>
<p>Gerçek hayatta <strong>Entity Framework</strong> veya başka bir <strong>O/RM</strong> aracının kullanıldığı hallerde aşağıdaki grafikteki iki durumdan birisi söz konusu olur<em>(Genellikle de en soldaki)</em>. Klasik olarak <strong>DbContext</strong> doğrudan iş katmanında değerlendirilir. Ancak <strong>Test Driven Development </strong>veya <strong>Domain Driven Design</strong> gibi yaklaşımların kullanıldığı geliştirme süreçlerinde, <strong>Repository</strong> ve <strong>Unit of Work</strong> desenelerinin icra edilmesi önemlidir. Nitekim bu sayede uygulamanın iş mantığının tutulduğu katman ile veri erişim katmanının izole edilmesi kolaylaşır. t anında farklı bir <strong>Repository</strong> ile çalışılabilmesi veya yenilerinin yazılarak sisteme dahil edilmesinin yolu açılır. Aynı kolaylık <strong>Unit of Work</strong> yapıları için de geçerlidir.</p>
<p><a href="https://www.buraksenyurt.com/pics/ruof_1.png"><img style="margin: 4px 0px; display: inline;" title="ruof_1" src="/pics/ruof_1_thumb.png" alt="ruof_1" width="600" height="368" /></a></p>
<p>İlk senaryoya göre iş mantığı, veri erişimi ve EF arasında kuvvetli bağlar oluşur. Bu sebepten, üründe kullanılan veri tabanını değiştirmek<em>(farklı bir Repository’ yi tercih etmek)</em> ve özellikle <strong>Unit Test </strong>gibi yapılarda <strong>Mock</strong> nesneleri değerledirmek zorlaşır. Bir <strong>Unit Test </strong>metodu içerisindeki işlemler bütününde her zaman <strong>CRUD<em>(CreateReadUpdateDelete)</em></strong> operasyonları icra edilmek istenmeyebilir. Nitekim iş bütününün <strong>Repository</strong> odaklı olmayan kısımlarının test edilmesi de söz konusudur.</p>
<p><strong>Unit Test’</strong> lerin çalıştığı geliştirme ortamının hiç bir şekilde bir veri kaynağına gidemediği hallerde geri kalan kısmın test edilme ihtiyacı bu tip bir gereksinimdir. Ayrıca aynı veri kaynağı ile çalışılacak diye bir kural yoktur. <strong>Domain</strong> içerisindeki <strong>Entity</strong> modelleri sabit kalabilir ve iş kuralları çok az değişiklik gösterebilir. Ama verilerin yazıldığı ortamlar duruma göre farklılık gösterebilir, açılıp kapatılmak istenebilir. Bu sebeple soyutlama(abstraction) yapmak ve uygun sözleşme tanımlamalarını<em>(Interface bildirimleri diyebiliriz) </em>işin içerisine katmak önemlidir.</p>
<p>Gelin konuyu basit ve pek de işe yaramayacak örnek bir senaryo üzerinden ele alalım. Amacımız içinde iki <strong>Entity</strong> barındıran bir <strong>DbContext</strong> türevini, <strong>Repository</strong> ve <strong>Unit of Work</strong> desenleri çerçevesinde nasıl ele alabileceğimizi incelemektir.</p>
<h1>Code First ile Entity Modelin İnşası</h1>
<p>Örnek uygulama her zaman ki gibi gösterişsiz bir <strong>Console</strong> projesidir. Amaç ilgili desenlerin sade bir uyarlamasını görebilmektir. Ama öncesinde <strong>NuGet</strong> üzerinden güncel <strong>Entity</strong> <strong>Framework’</strong> ün son sürümü projeye indirilerek işe başlanabilir.</p>
<p><a href="https://www.buraksenyurt.com/pics/rpuow_1.png"><img style="margin: 4px 0px; display: inline;" title="rpuow_1" src="/pics/rpuow_1_thumb.png" alt="rpuow_1" width="640" height="360" /></a></p>
<p>Ardından kobay olarak aşağıdaki <strong>Entity</strong> sınıfları ve <strong>DbContext</strong> türevini yazabiliriz.</p>
<p><a href="https://www.buraksenyurt.com/pics/ruof_2.png"><img style="margin: 4px 0px; display: inline;" title="ruof_2" src="/pics/ruof_2_thumb.png" alt="ruof_2" width="306" height="482" /></a></p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.Collections.Generic;
using System.Data.Entity;
namespace RPandUOW.EntityModel
{
public class ShopContext
: DbContext
{
public DbSet<Category> Categories { get; set; }
public DbSet<Product> Products { get; set; }
}
public class Category
{
public int CategoryID { get; set; }
public string Title { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
public int ProductID { get; set; }
public string Title { get; set; }
public decimal UnitPrice { get; set; }
public int Quantity { get; set; }
public int CategoryID { get; set; }
public virtual Category Category { get; set; }
}
}</pre>
<p>Tipik olarak <strong>one-to-many</strong> ilişki içerisinde sayabileceğimiz iki <strong>POCO</strong> tipi bulunmaktadır. Bir kategori ve bu kategoriye bağlı olan ürünler. Gelelim Repository deseninin uygulanış biçimine.</p>
<h1>Repository Yapısının İnşası</h1>
<p>Öyle bir yapı kurgulamalıyız ki, hem bir <strong>Repository</strong> için gerekli minimum fonksiyonelliklerin bir sözleşmesi hem de <strong>Context</strong> içerisinde yer alan her <strong>T</strong> tipi için çalışabilecek generic bir sınıf olsun. Ve pek tabi varsayılan kuralları istediği gibi işleyecek yeni <strong>Repository’</strong> leri yazmanın da yolu açılabilsin. İlk olarak aşağıdaki sınıf diagramında görülen tiplerin tasarlanmasıyla işe başlanabilir.</p>
<p><a href="https://www.buraksenyurt.com/pics/rpuow_2.png"><img style="margin: 4px 0px; display: inline;" title="rpuow_2" src="/pics/rpuow_2_thumb.png" alt="rpuow_2" width="437" height="492" /></a></p>
<p>ve kodlar;</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using RPandUOW.EntityModel;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
namespace RPandUOW.Repositories
{
public interface IGenericRepository<T>
where T:class
{
T FindById(object EntityId);
IEnumerable<T> Select(Expression<Func<T, bool>> Filter = null);
void Insert(T Entity);
void Update(T Entity);
void Delete(object EntityId);
void Delete(T Entity);
}
public class ShopRepository<T>
:IGenericRepository<T>
where T:class
{
private ShopContext _context;
private DbSet<T> _dbSet;
public ShopRepository(ShopContext Context)
{
_context = Context;
_dbSet = _context.Set<T>();
}
public virtual T FindById(object EntityId)
{
return _dbSet.Find(EntityId);
}
public virtual IEnumerable<T> Select(Expression<Func<T, bool>> Filter = null)
{
if (Filter != null)
{
return _dbSet.Where(Filter);
}
return _dbSet;
}
public virtual void Insert(T entity)
{
_dbSet.Add(entity);
}
public virtual void Update(T entityToUpdate)
{
_dbSet.Attach(entityToUpdate);
_context.Entry(entityToUpdate).State = EntityState.Modified;
}
public virtual void Delete(object EntityId)
{
T entityToDelete = _dbSet.Find(EntityId);
Delete(entityToDelete);
}
public virtual void Delete(T Entity)
{
if (_context.Entry(Entity).State == EntityState.Detached) //Concurrency için
{
_dbSet.Attach(Entity);
}
_dbSet.Remove(Entity);
}
}
}</pre>
<p>Burada neler yaptık, ortalığı nasıl karıştırdık incelemeye çalışalım. <strong>IRepository<T></strong> arayüzü içerisinde bir <strong>Repository</strong> için söz konusu olabilecek temel fonksiyonların tanımlandığını görmekteyiz. <strong>CRUD(CreateReadUpdateDelete)</strong> operasyonları olarak adlandırabileceğimiz metodlar ile bir <strong>Repository’</strong> nin minimumda sahip olması gereken sözleşmeyi de tanımlamış oluyoruz.</p>
<p><strong>ShopRepository<T></strong> sınıfı dikkat edileceği üzere <strong>IRepository<T></strong> arayüzünü uygulamakta ve kendi içerisinde <strong>DbContext</strong> sınıfından türetilmiş bir <strong>ShopContext</strong> örneğini kullanmaktadır. Yani <strong>ShopRepository</strong> generic sınıfı, <strong>ShopContext</strong> içinde tanımlı herhangi bir <strong>T </strong>tipini kullanarak <strong>CRUD</strong> operasyonlarını gerçekleştirebilir. Bunun bir diğer anlamıda, farklı kaynakları kullanan veya Mock nesne olabilen <strong>Repository</strong> tiplerinin istenildiği zaman sisteme dahil edilebilmesidir. Tek yapılması gereken ilgili <strong>IRepository<T></strong> sözleşmesinin yeni Repository için uygulanmasından başka bir şey değildir.</p>
<p><strong>Repository</strong>’ nin kullandığı <strong>Context</strong> nesnesinin oluşturulması aslında yapıcı metod içerisinde icra edilmektedir. Burada da generic bir kullanım yolu düşünülebilir. Dikkat çekici noktalardan bir tanese bir <strong>Context</strong> için söz konusu olan <strong>Save</strong> işleminin bu tiplerde her angi bir biçimde ele alınmamış olmasıdır. Aslında bu, <strong>Unit of Work</strong> yapısının inşasında ele alınması gereken bir fonksiyonelliktir. Öyleyse Unit of Work yapısını tesis etmeye başlayabiliriz.</p>
<h1>Unit of Work Yapısının İnşası</h1>
<p><strong>Entity Framework</strong> açısından bir birimlik işi; içerisinde konuya dahil olması gereken <strong>Repository</strong> örneklerinin oluşturulması ve <strong>Save</strong> işleminin icra edilmesi olarak düşünebiliriz<em>(Hatta bu yapı içerisine <strong>Transaction</strong> açılıp kapatılması da dahil edilebilir)</em> Pek tabi Unit of Work yapısınında bir sözleşme üzerinden değerlendirilmesi, farklı Unit of Work’ lerin de değerlendirilebilmesi açısından önemlidir. Bu düşünceler ışığında aşağıdaki yapıyı kurgulayabiliriz.</p>
<p><a href="https://www.buraksenyurt.com/pics/rpuow_3.png"><img style="margin: 4px 0px; display: inline;" title="rpuow_3" src="/pics/rpuow_3_thumb.png" alt="rpuow_3" width="358" height="432" /></a></p>
<p>ve kodlar;</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using RPandUOW.EntityModel;
using RPandUOW.Repositories;
using System;
using System.Transactions;
namespace RPandUOW.UnitOfWorks
{
public interface IUnitOfWork
:IDisposable
{
void Save();
// Başka operasyonlar da tanımlanabilir.
// void OpenTransaction();
// void CloseTransaction();
// gibi
}
public class ShopUnitOfWork
:IUnitOfWork
{
private ShopContext _context = new ShopContext();
private ShopRepository<Category> _categoryRepository;
private ShopRepository<Product> _productRepository;
private bool _disposed = false;
public ShopRepository<Category> CategoryRepository
{
get
{
if (_categoryRepository == null)
_categoryRepository = new ShopRepository<Category>(_context);
return _categoryRepository;
}
}
public ShopRepository<Product> ProductRepository
{
get
{
if (_productRepository == null)
_productRepository = new ShopRepository<Product>(_context);
return _productRepository;
}
}
public void Save()
{
using (TransactionScope tScope = new TransactionScope())
{
_context.SaveChanges();
tScope.Complete();
}
}
protected virtual void Dispose(bool disposing)
{
if (!this._disposed)
{
if (disposing)
{
_context.Dispose();
}
}
this._disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}</pre>
<p>Pek tabi soyutlama amacıyla <strong>IUnitOfWork</strong> isimli bir arayüz tanımlanarak işe başlanmıştır. Arayüz şu an için Save metodunun uygulanması gerektiğini belirtir. Tabi bir de <strong>IDisposable</strong> arayüzü nedeniyle <span style="font-weight: bold;">Dispose</span> metodunun ezilmesi zorunlıdır. Bir birimlik iş için ihtiyaca göre başka genel fonksiyonellikler de sözleşme içerisine dahil edilebilir. Örneğin bir <strong>Transaction</strong> açılması ve kapatılması için gerekli metodlar sözleşme ile zorunlu tutulabilir. Tabi bunu çok da spesifik düşünmemek gerekir. Nitekim kimi <strong>Repository</strong>’ lerin, kullandığı veri kaynakları bir <strong>Transaction</strong> ile çalışmak zorunda olmayabilir. Hatta ortada bir veri kaynağı da bulunmayabilir<em>(Burada Mock nesnelere atıfta bulunmaktayım)</em></p>
<p><strong>ShopContext</strong> için kullanılacak <strong>Unif of Work</strong> kurgusunda ise, işe dahil olacak <strong>Repository’</strong> ler birer <strong>Property</strong> olarak tanımlanmış ve sadece okunabilir şekilde son kullanıcıya sunulmuşlardır. Üretim işlemleri sırasında yapılan <strong>null</strong> kontrolü, <strong>Unit of Work</strong> nesnesinin yaşamı boyunca, tüm <strong>Repository’</strong> lerin aynı <strong>Context</strong> tipini<em>(ki örnekte _context isimli ShopContext örneğidir) </em>kullanması açısında önemlidir. <em>(Bu durumu daha iyi anlamak için debug modda çalışmanızı öneririm)</em></p>
<p>Bir başka deyişle örneğin <strong>Save</strong> işlemi sırasında tüm <strong>Repository</strong> nesnelerinin aynı <strong>DbContext</strong> örneği üzerinden işlemlerini gerçekleştirmesi ve tek bir <strong>Transaction </strong>bütünlüğü içerisinde çalışması sağlanmış olmaktadır. Zaten <strong>Unit of Work</strong> desenin temel amaçlarından birisi de bu işlem bütünlüğünü kurgulamaktr.</p>
<h1>Basit Bir Kullanım</h1>
<p>Yazılan <strong>Unit of Work</strong> uyarlamasının uygulanış biçimi oldukça kolaydır. Normal şartlarda bir <strong>BLL</strong> fonksiyonelliği içerisinde de değerlendirilebilir. Konunun basitçe ele alınması açısından <strong>Main </strong>metodu aşağıdaki kodları içerecek şekilde geliştirilmiştir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using RPandUOW.EntityModel;
using RPandUOW.UnitOfWorks;
using System;
using System.Collections.Generic;
namespace RPandUOW
{
class Program
{
static void Main(string[] args)
{
using (ShopUnitOfWork worker = new ShopUnitOfWork())
{
Category computerBook = new Category { Title = "Computer Books" };
worker.CategoryRepository.Insert(computerBook);
computerBook.Products = new List<Product> {
new Product { Title = "Advanced NoSQL", Quantity = 1, UnitPrice = 34.59M },
new Product { Title = "NHibernate in Action", Quantity = 5, UnitPrice = 29.99M },
new Product { Title = "Unleashed Delphi 2.0", Quantity = 3, UnitPrice = 9.99M }
};
Category cookBook = new Category { Title = "Cook Books" };
worker.CategoryRepository.Insert(cookBook);
cookBook.Products = new List<Product> {
new Product()
{
Title = "Italian Kitchen", Quantity = 20, UnitPrice = 12 }
};
worker.CategoryRepository.Insert(cookBook);
worker.Save();
var books = worker.ProductRepository.Select(p => p.CategoryID == computerBook.CategoryID);
foreach (var book in books)
{
Console.WriteLine("{0} {1} {2}", book.Title, book.UnitPrice, book.Quantity);
}
}
}
}
}</pre>
<p><a href="https://www.buraksenyurt.com/pics/rpuow_4.png"><img style="margin: 4px 0px; display: inline;" title="rpuow_4" src="/pics/rpuow_4_thumb.png" alt="rpuow_4" width="324" height="131" /></a></p>
<p><strong>IDisposable</strong> arayüzü implementasyonu nedeniyle <strong>ShopUnitOfWork</strong> sınıfı <strong>using</strong> bloğun içerisinde kullanılabilir. Zaten <strong>dipose</strong> işlemi sınıfın içerisinde <strong>override</strong> edilmiştir. Blok içerisinde bir dizi örnek işlem icra edilmektedir. Buna göre bir kaç kategorinin ve bu kategorilere bağlı ürünlerin eklenmesi işlemi ele alınmaktadır. <strong>Save</strong> işlemi, <strong>Unit of Work</strong> uyarlamasının bir fonksiyonu olduğundan, dahil edilen tüm <strong>Repository</strong> örnekleri için ortak bir kullanım noktasıdır. Öyle ki, örnekte asıl <strong>Context</strong> nesnesi üzerinden yapılan kaydetme işleminin bir <strong>TransactionScope</strong> içerisinde gerçekleştirilmesi sağlanmaktadır.</p>
<p>Görüldüğü üzere <strong>Repository</strong> ve<strong> Unit of Work</strong> desenelerini <strong>Entity Framework</strong> tarafında uygulamak oldukça kolaydır. Kaynaklarda bu desenlerin daha etkili uygulanış biçimlerini de görebilirsiniz. Örneğin <a href="http://genericunitofworkandrepositories.codeplex.com/" target="_blank">Codeplex’ in şu adresindeki</a> uygulanış tarzı beni etkileyenler arasındadır. Hatta <strong>Unit of Work</strong> uyarlamasının daha <strong>generic</strong> ve <strong>Context’</strong> lere gevşek bağlı<em>(Loosely Coupled)</em> olan bir versiyonu da yazılabilir<em>(İşin içine Dependency Injection da katılıp olay daha bir renkli hale getirilebilir)</em> Bunlara biraz kafa yormakta fayda vardır. </p>
<p>Böylece geldik bir makalemizin daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>2014-12-14T03:00:00+00:00entity frameworkgeneric repositorygenericsunit of workdesign patternssoftware design principlesbsenyurtDDD denilince aklımıza daha çok veri odaklı uygulamalar gelir ve bu tip ürünlerde RDBMS(Relational Database Management System) lerin yeri hatırı sayılır ölçüde fazladır(Her ne kadar son yıllarda NoSQL cephesinde önemli gelişmeler ve kullanımda ciddi artışlar olsa da…) Hal böyle olunca O/RM(Object Relational Mapping) araçlarının kullanımı da önem kazanmaktadır. Yıllardır hayatımızda olan bu araçlar modellerin nesnel olarak inşasında da önemli bir yere sahiptirler. Lakin Object Oriented dünyasının kuralları içerisinde yaşarlar ve bu yüzden bazı kurumsal prensipleri uygulamaları gerekmektedir.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=c323fd11-1192-4395-8cd4-d3fa04a4ee6d23https://www.buraksenyurt.com/trackback.axd?id=c323fd11-1192-4395-8cd4-d3fa04a4ee6dhttps://www.buraksenyurt.com/post/Entity-Framework-Generic-Repository-ve-Unit-of-Work-Uyarlamasi#commenthttps://www.buraksenyurt.com/syndication.axd?post=c323fd11-1192-4395-8cd4-d3fa04a4ee6dhttps://www.buraksenyurt.com/post/SOLIDe28093Adc4b1m-Adc4b1m-Tanc4b1makSOLID–Adım Adım Tanımak2014-03-10T00:00:00+00:00bsenyurt<p>Merhaba Arkadaşlar,</p>
<p>SOLID basit bir kelime gibi görünse de, her harfinin ifade ettiği yazılım prensipleri göz önüne alındığında devasa bir evreni işaret etmekte. <strong>Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation</strong> ve son olarak <strong>Dependency Inversion</strong>. İşte bu görsel dersimizde bu prensipleri çok basit ve yüzeysel bir örnek üzerinden anlamaya çalışıyoruz. Önce ilkeleri ihlal ediyor, sonrasında bunları düzeltme yoluna gidiyoruz.</p>
<p><object width="640" height="360">
<param name="movie" value="//www.youtube.com/v/2AJ_trQ1LWc?hl=en_US&version=3" />
<param name="allowFullScreen" value="true" />
<param name="allowscriptaccess" value="always" /><embed type="application/x-shockwave-flash" width="640" height="360" src="//www.youtube.com/v/2AJ_trQ1LWc?hl=en_US&version=3" allowfullscreen="allowfullscreen" allowscriptaccess="always" />
</object></p>
<p><em>Not : Şu ana kadar anlatmakta en çok zorlandığım görsel dersti. Konunun soyutluğu, örneğin yeteri kadar doyurucu olmayışı, üst kattaki iki kardeşin gecenin o vakti koşuşturması vb nedenlerden ötürü...Dolayısıyla sürçü lisan ettiysem affola.</em></p>2014-03-10T00:00:00+00:00bsenyurtSOLID basit bir kelime gibi görünse de, her harfinin ifade ettiği yazılım prensipleri göz önüne alındığında devasa bir evreni işaret etmekte. Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation ve son olarak Dependency Inversion. İşte bu görsel dersimizde bu prensipleri çok basit ve yüzeysel bir örnek üzerinden anlamaya çalışıyoruz. Önce ilkeleri ihlal ediyor, sonrasında bunları düzeltme yoluna gidiyoruz.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=ee0f7ba6-5f61-4384-8a58-900548000c1914https://www.buraksenyurt.com/trackback.axd?id=ee0f7ba6-5f61-4384-8a58-900548000c19https://www.buraksenyurt.com/post/SOLIDe28093Adc4b1m-Adc4b1m-Tanc4b1mak#commenthttps://www.buraksenyurt.com/syndication.axd?post=ee0f7ba6-5f61-4384-8a58-900548000c19https://www.buraksenyurt.com/post/Fluent-Interface-Prensibi-ile-Daha-Okunabilir-Kod-GelistirmekFluent Interface Prensibi ile Daha Okunabilir Kod Geliştirmek - 1nci Yarı2013-12-23T01:34:00+00:00bsenyurt<p>Merhaba Arkadaşlar,</p>
<p>Keşfedilmesi, anlaşılması ve okunması kolay kod geliştirmek, özellikle dışarıya açık arayüzü bulunan API’ ler için oldukça önemlidir. Bir <strong>Domain Specific Language</strong>’ in olmassa olmazı kodun kolayca keşfedilebilirliğidir. <strong>Ruby</strong> ve <strong>Scala</strong> gibi diller <strong>built-in</strong> olarak bu kolaylığı sunarlar. <strong>LINQ(Language INtegrated Query) </strong>ifadeleri, zincir şeklinde bir birlerine bağlanabilen <strong>Extension</strong> metodlar ile aynı esnekliği vermektedir. Test süreçlerinde kullanılan pek çok <strong>Mock</strong> nesne API’si benzer kabiliyetlere sahiptir. Tüm bunlar aynı prensipten yararlanır. <strong>Fluent Interface</strong>… Bu görsel dersimizde <strong>Martin Fowler</strong> tarafından yıllar önce ortaya konan yaklaşımın uygulanışını incelemeye çalışıyoruz.</p>
<p><iframe src="https://www.youtube.com/embed/lVgz-DeTJhM" width="640" height="360" frameborder="0" allowfullscreen="allowfullscreen"></iframe></p>
<p>Bir başka görsel dersimizde görüşmek üzere.</p>2013-12-23T01:34:00+00:00fluent interfacefluent apimartin fowlerrubyscalamock nesneunit testdomain driven designdomain specific languagedslbsenyurtKeşfedilmesi, anlaşılması ve okunması kolay kod geliştirmek, özellikle dışarıya açık arayüzü bulunan API’ ler için oldukça önemlidir. Bir Domain Specific Language’ in olmassa olmazı kodun kolayca keşfedilebilirliğidir. Ruby ve Scala gibi diller built-in olarak bu kolaylığı sunarlar. LINQ(Language INtegrated Query) ifadeleri, zincir şeklinde bir birlerine bağlanabilen Extension metodlar ile aynı esnekliği vermektedir. Test süreçlerinde kullanılan pek çok Mock nesne API’si benzer kabiliyetlere sahiptir. Tüm bunlar aynı prensipten yararlanır. Fluent Interface… Bu görsel dersimizde Martin Fowler tarafından yıllar önce ortaya konan yaklaşımın uygulanışını incelemeye çalışıyoruz.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=8a442d30-9eb2-4597-a63d-6391ef5eac437https://www.buraksenyurt.com/trackback.axd?id=8a442d30-9eb2-4597-a63d-6391ef5eac43https://www.buraksenyurt.com/post/Fluent-Interface-Prensibi-ile-Daha-Okunabilir-Kod-Gelistirmek#commenthttps://www.buraksenyurt.com/syndication.axd?post=8a442d30-9eb2-4597-a63d-6391ef5eac43https://www.buraksenyurt.com/post/Dependency-Inversion-Principle-KavramakDependency Inversion Principle - Kavramak2013-05-03T00:10:00+00:00bsenyurt<p>Merhaba Arkadaşlar,</p>
<p>Bu görsel dersimizde, SOLID ilkelerinden birisi olup <strong>Yazılım Tasarım Presinpleri<em>(Software Design Principles)</em></strong> içerisinde yer alan <strong>Dependency Inversion</strong>’ ı kavramaya çalışıyoruz. Konuyu irdelerken basit bir senaryoyu göz önüne alıyor, önce <strong>DIP</strong> olmadan ilerliyor ve sorunları teşhis ediyoruz. Sonrasında ise <strong>Dependency Inversion </strong>prensibini baz alarak bağımlılıkları tersine çeviriyor ve problemli kısımları iyileştiriyoruz.</p>
<p><iframe src="https://www.youtube.com/embed/zQvkzzwElXs" width="560" height="315" frameborder="0" allowfullscreen="allowfullscreen"></iframe></p>
<p>Bir başka görsel dersimizde görüşmek dileğiyle <img class="wlEmoticon wlEmoticon-winkingsmile" style="border-style: none;" src="http://www.buraksenyurt.com/pics/wlEmoticon-winkingsmile_202.png" alt="Winking smile" /></p>2013-05-03T00:10:00+00:00software design principlesdipdependency injectioninversion of controlninjectwindsor castleunity frameworksolidbsenyurtBu görsel dersimizde, SOLID ilkelerinden birisi olup Yazılım Tasarım Presinpleri(Software Design Principles) içerisinde yer alan Dependency Inversion’ ı kavramaya çalışıyoruz. Konuyu irdelerken basit bir senaryoyu göz önüne alıyor, önce DIP olmadan ilerliyor ve sorunları teşhis ediyoruz. Sonrasında ise Dependency Inversion prensibini baz alarak bağımlılıkları tersine çeviriyor ve problemli kısımları iyileştiriyoruz.https://www.buraksenyurt.com/pingback.axdhttps://www.buraksenyurt.com/post.aspx?id=cbbe7461-b0c8-4fba-a673-400b010804657https://www.buraksenyurt.com/trackback.axd?id=cbbe7461-b0c8-4fba-a673-400b01080465https://www.buraksenyurt.com/post/Dependency-Inversion-Principle-Kavramak#commenthttps://www.buraksenyurt.com/syndication.axd?post=cbbe7461-b0c8-4fba-a673-400b01080465