Arda Çetinkaya Yazılım ve arada kendim ile ilgili karaladıklarım…

Şu sıralar .NET dünyasının en popüler konularından biri .NET Compiler Platform(a.k.a Roslyn). .NET Compiler’ın API’i olarak dışarı açılan servisleri ile bayaa taklalar atmak mümkün. Bir önceki yazımda küçük bir giriş yapmıştım hatırlarsanız. .NET Compiler Platform‘u olgunlaşana kadar, biraz da temelleri daha iyi anlamak için “Expression Tree” kavramından, çok derinlere inmeden bahsetmeye çalışacağım. Açıkcası biraz merak uyandırmak, arkalarda işler nasıl oluyor bunları araştırmaya teşvik etmek için bu yazıda çok fazla derinlere girmek istemiyorum. İlerleyen yazılarda zaten kaybolup gideceğiz, baştan söyliyim.Neyse…

Expression Tree, bir çok compiler’ın çalışma mantığında geçerli olan bir kavram aslında. Kodun, ağaç gibi dallar(node) ile temsil edildiği bir veri yapısı diyebiliriz Expression Tree için. Zaten adından da anlaşılıyor. Bu dallar, koddaki her bir parçayı temsil eder. Değişken, metod çağrısı, if-then-else bloğu gibi gibi…

Temel olarak kodların çalışması da, bu ağaç yapısının derlenmesinden sonra oluyor. .NET tarafındaki Expression sınıfı da, bu ağaç yapısının oluşturulmasında ve derlenmesinde kullanılması için bize sunulan bir sınıf. Lambda kavramının .NET tarafında oluşturulması, LINQ ve dinamik runtime(DLR) aslında bu “Expression Tree” yaklaşımı sayesinde, yani Expression sınıfı ile oluyor. Yani basitçe de olsa, çalışan kodda dinamik değişiklikler yapmak, dinamik ifadeler oluşturmak .NET’de zaten mümkündü.

Kod görmeden, ben anlamam diyorsanız aşağıdaki kod örneğine bir göz atalım.

Expression<Func<string, bool>> lambdaExpression = name => name == "Arda";
Func<string, bool> quessMyName = lambdaExpression.Compile();

bool result = quessMyName("Arda");

Console.WriteLine("Sonuç: {0}", result.ToString());

Yukarıdaki kod ile run-time sırasında bir metod oluşturuyoruz ve bu metodu çağırıp, sonucunu konsola yazdırıyoruz. Burada önemki olan generic olan, Expression tipindeki obje. Lambda ifadesi ile name değerinin “Arda”‘ya eşitliliği tanımlanıyor. Bu ifadeyi daha sonra Compile() metodu ile derliyor olduğumuzu düşünebiliriz. Ve artık elimizde quessMyName() adında bir metodumuz olmuş oluyor. Oluşturulduğu context’den dolayı, normal bir metod gibi düşünmek çok doğru olmaz tabi ki.

Expression sınıfı, oldukça geniş bir metod yelpazesine sahip. Kodu yazarken kullanabileceğiniz Expression’ları kolaylıkla ifade edebileceğiniz tüm metodlar var. if-then-else bloğu, döngü oluşturmak için loop bloğu, aritmetik operasyonlar, büyük-küçük ifadeleri gibi Expression sınıfı ile oluşturabilirsiniz. Hepsini tek tek anlatmam mümkün değil açıkcası. Ama biraz daha anlaşılır olması için yine aşağıdaki koda göz atabiliriz.

ParameterExpression value = Expression.Parameter(typeof(int), "value");

LabelTarget returnValue = Expression.Label(typeof(bool));

BlockExpression methodBody = Expression.Block(

Expression.IfThenElse(
Expression.Equal(Expression.Modulo(value, Expression.Constant(2)), Expression.Constant(0)),
Expression.Return(returnValue, Expression.Constant(true)),
Expression.Return(returnValue, Expression.Constant(false))),
Expression.Label(returnValue, Expression.Constant(false))
);

Func<int, bool> IsEven = Expression.Lambda<Func<int, bool>>(methodBody, value).Compile();

var result = IsEven(6);

Console.WriteLine("Sonuç: {0}", result.ToString());

Yukarıda, run-time’da yine bir metod oluşturuyoruz. Bu metod ile bir sayının çift mi ya da tek mi olduğunu kontrol ediyoruz. Basit bir aritmetik işlem aslında. { } ifadelerine denk gelen, Block() metodu içinde, teker teker Expression’larımızı oluşturuyoruz. Önce IfThenElse() ile parametre olarak alacağımız sayının %(Module) mod’unu alıp, bunun 0 şeklinde bir sabit değişkenle eşitliğini kontrol ediyoruz. Eğer eşitlik doğru ise, Return() ifadesi ile true dönüyoruz, eğer eşitlik doğru değil ise yine Return() ifadesi ile false dönüyoruz.

Daha sonra IsEven olarak bir değişken belirleyip bu ifadeyi, Compile() metodu ile derliyoruz(!!! yani sayılır). Bu kod bloğunu yazdığımız içerikte artık IsEven() şeklinde bir metodumuz, -ki aslında bir delege, kullanıma hazır oluyor.

Bu kodu çalıştırdığımızda methodBody‘yi Debug yaparak kontrol ettimizde, DebugView özelliğinde aşağıdaki gibi biraz daha tanıdık bir ifade görüyor olacağız.

ExpressionBlockResult

Fark etmiş olduğunuz gibi, Expression sınıfı ile yazdığımız ifadeler, biraz daha aşina olduğumuz bir syntax ile karşımızda.

Expression Tree’leri, .NET Framework’ünü genişletmek amacıyla, dinamik olarak kodda değişiklikler ve eklemeler yapmak için kullanabiliriz. Açıkcası ilk başlarda çok zorlanabilirsiniz. Hem Expression’ları oluşturmak, hem de nasıl çalıştıklarını anlamak ilk başlarda oldukça zorlayacaktır. Ancak kavradıktan ve asıl önemlisi tüm Expression metodlarına hakim olduktan sonra bir çok problemi kolaylıkla çözebilecek duruma geleceksiniz.

Şimdilik bu kadar…Bir ara biraz daha derinlere ineriz.

2011’in sonlarına doğru Microsoft, Roslyn ’nin ilk versiyonu çıkardığında anlamak konusunda biraz zorlanmıştım açıkcası. Neden böyle bir şeye ihtiyaç olabileceği, ya da .NET compiler’ın servis olarak açılmasının neler getireceğini o zamanlar bayaa anlamak için çalışmıştım. Preview ve CTP versiyonları olmasının getirdiği net olmayan kavramların da olması işleri pek kolaylaştırmıyordu açıkcası.

Hala son halini tam olarak almamış olmasına rağmen oldukça olgunlaşmış olduğunu söyleyebilirim. Hatta bu senenin içinde RTM haberini de duyarız gibime geliyor.

Rosyln kısaca, .NET için olan bir compiler platformu. Hatta resmi adı da zaten .NET Compiler Platform. .NET Runtime’ında çalışan kodları derleyen, compiler’ın servis olarak, API’lar üzerinden dışarı açılması olarak tanımlayabiliriz. Bu API’lar, lexical analiz, semantic analiz gibi compiler’ların olmazsa olmaz bileşenlerine müdahele etmeyi, genişletmeyi sağlayan parçalar olarak karşımıza çıkıyor. Ve tabi ki derleme aşamasına da aynı şekilde müdahale edebiliyoruz.

Yani?

Biraz daha içerlere girersek, her programlama dilinin bir grammer’i vardır; normal konuşma dillerinde olduğu gibi. Bu grammer, o dilin kurallarını oluşturur. if’den sonra () içerisinde true/false bir ifade kontrolü ile { } içerisinde ki kodların çalıştırılması gibi. Buradaki keyword ya da diğer ifadeler de dilin syntax’ını yani alfabesini oluşturur. Yazdığımız ifadeler, syntax’ın parse edilip, dilin kuralları ile yorumlanması ve derlenmesi ile de çalışır hale gelirler. Basitçe anlatmaya çalıştığım bütün bu adımlara, Rosyln ile artık çeşitli noktalarda müdahele etme şansımız ortaya çıkıyor.

Eee Yani?

Yani Rosyln sayesinde, kendi keyword’lerinizi tanımlayıp, kodların derlendiğinde farklı ifadeler üretmesi, lexical analiz ve syntax analiz adımlarında kendi kurallarınızı uygulamanız artık mümkün olabilecek. Biraz daha gerçek ve anlaşılır olması adına, mesela kendi scripting dilinizi Rosyln sayesinde geliştirebileceksiniz.

İlerleyen zamanlarda biraz daha derinlere girerek farklı şeyleri paylaşmayı umuyorum. Ama şimdilik biraz daha başlamayı teşvik edebilecek kolay bir örnek ile ısınma hareketleri kıvamında bir konuya değinmeye çalışacağım.

Not: .NET Compiler Platform’u ile sağlıklı çalışabilmek için, Visual Studio 2015 Preview ve Visual Studio 2015 Preview SDK’yı yüklemeniz gerekli olacaktır. Daha sonra Nuget’den Rosyln ile ilgili paketi almanız gerekecektir.
 Install-Package Microsoft.CodeAnalysis –Pre
Yapmaya çalışacağım örnek, VSIX proje şablonları üzerinden Visual Studio’ya extension yazmak olacak. O yüzden bu konulara biraz hakim olmak gerekiyor.

Kodumuzu teşhis edelim…

“Diagnostic” yani teşhiş olarak adlandırabileceğimiz kodu analiz eden ve yazdığımız kuralları kodda uygulayabileceğimiz çözümleyiciler(analyzer), .NET Compiler Platform’un sunduğu en önemli özelliklerden biri. FxCop’u hatırlayanlar için oldukça tanıdık gelecektir. .NET Compiler Platform ile beraber gelen, DiagnosticAnalyzer sınıfını kullanarak kendi statik kod analizimizi yapacağız.

Devam…

Çok fazla kitap okuyabilen biri değilim ne yazık ki. Mesleğim ile ilgili kitapları biraz daha kolay okuyabiliyorum sanırım. Bir ara blog’da ara sıra okuduğum kitapları paylaşıyordum ya da yazı aralarında bahsediyordum. Eskisi kadar yazmadığım için, eskisi kadar kitap da paylaşmadığımı fark ettim. Son okuduğum bir kaç kitap için, “Süper, herkes bunu okumalı” düşüncesi de ortaya çıkınca, ciddi anlamda başarılı ve faydalı olduğunu düşündüğüm iki tane kitabı paylaşmak isterim.

Microsoft .NET – Architecting Applications for the Enterprise (2nd Edition)

applicationsforenterpriseDino Esposito ve Andrea Saltarello‘nun 2014 Eylül çıkışlı bu kitabı, tam bir referans kitabı olmuş. Yazılım mimarisi, yazılım prensipleri ile başlayıp, Domain-driven design’a oradan da CQRS’e kadar uzanan oldukça zengin bir içeriği var. Güzel yanı, oldukça basit ve anlaşılır bir anlatım diline sahip olması. Kapsamı büyük yazılımlar geliştirirken karşılaşılan problem ve onlara sunulabilecek çözüm alternatifleri kitabın önemli noktaları. DDD ve CQRS gibi kavramların, hangi problemlere çözüm olabileceği, uygulanırken ki zorlukları ve zorlukları aşmak için yapılabilecekler bu ikinci versiyonun yeni içerikleri. DDD’yi merak ediyorsanız, ilk giriş ve başlamak için bu kitap oldukça faydalı. Eric Evans’ın ve sonrasında Vaughn Vernon’nun DDD kitapları daha kolay gelecektir diye düşünüyorum.

Agile Project Management with Scrum (Developer Best Practices)

agile-project-management-with-scrumKen Schwaber‘ın Scrum’ın nasıl uygulanabileceğini case-study’ler ile anlattığı güzel bir kitap. Aslında bu kitabı ilk 2007 senesinde alıp, o zaman okumuştum. O zamanlar Agile kavramlara, Scrum’a uzak olduğum için, bazı noktalar havada kalmıştı açıkcası. Zamanla daha fazla içine girdikçe, daha fazla şey öğrendikçe, tekrardan okumanın faydalı olabileceğini düşünüp, yeniden okumak istedim. Bazı konulara hakim olunca, ikinci defa okumakla case-study’lerin daha gerçekçi ve anlamlı geldiğini söyleyebilirim. Özellikle case-study’lerin sonundaki “Lesson Learned” bölümleri şahane. Şirketinizde Agile pratiklerini uygulamak, Scrum yapmak istiyorsanız ve planlıyorsanız, sizi nelerin beklediğini görmek için güzel bir kaynak.

 

 

Erik Meijer‘ın bu seneki Reaktor Dev Day’deki keynote konuşması sabah sabah bayaa şaşırttı beni. Yazılım ile ilgili bir etkinlikte bir keynote konuşması ne kadar ilginç olabilir de şaşırtabilir ki, dimi… Öyle demeyin ama, Erik Meijer olunca ve keynote’u biraz sert olunca, blog yazısı yazacak kadar ilginç bir keynote olabiliyormuş…Öncelikle Erik Meijer’ı bilmeyenler için kısa bir özet; kendisi 2000’lerin başından 2013’e kadar, Microsoft’da yazılım mimarı olarak hatırı sayılır ciddi projeler yaptı. Azure ve .NET tarafında ciddi katkıları olan biri. Bilgisayar bilimi dalında da akademik olarak oldukça başarılı biri diyebilirim. Dolayısıyla yakından takip ettiğim biri…

Keynote’unda Agile ile ilgili söyledikleri oldukça dikkatimi çekti. Ki aslında çoğunlukla Agile ve Agile yöntemler ile ilgili konuştu. Gerçi pek konuştu demek doğru değil, bildiğin giydirdi… “Agile” yaklaşımları yerden yere vurup, duvardan duvara atıyor. Agile ile ilgili söylediklerine kesinlikle katılmasam da, yazılımın, kod yazmanın çok ama çok önemli olduğunun altını çizmesi ve kod yazmaya daha da fazla önem verilmesi gerekliliğini bağıra bağıra söylemesi oldukça hoşuma gitti.

Bu arada videoyu mutlaka izleyin…45 dakika ama oldukça sürükleyici bir gerilim dizisi kıvamında.

“Agile is a cancer that we have to eliminate from the industry”

Agile yani çevik yaklaşımların, yazılım üretkenliğine ve kalitesine, değişen dünya ve ihtiyaçlarına çözüm üretebilmek için çok fazla fayda sağladığına inanıyorum. Yani ortaya çıkan ürünlere, oluşumlara bakıldığında zaten bu gerçekten çok kaçmanın bir anlamı yok. Yazılımın soyut yanının, Agile yaklaşımlar ile somutlaşarak, iletişim kanalları ile anlamlı hale geldiğini düşünüyorum. Agile yaklaşımların en büyük faydası, getirisi “iletişim”. Yazılımcı ya da IT sektörü insanı genellikle asosyal olarak betimlenir. Üretkenlikleri kendi içlerinde oldukça yüksek olmasına rağmen, geleneksel yazılım geliştirme yöntemlerinden dolayı, dış dünyaya fayda sağlama konusunda oldukça yetersiz olduğumuzu söyleyebilirim. Eminim kod yazan herkesin, bilgisayarında bir yerde, yazdığı küçük projeler hala duruyordur. Belki bir çok problemi çözecek, bir sürü işi kolaylaştıracak projeler, kodlar…

Agile kavramı ve Agile metodlar, bu kodların dış dünya ile iletişime geçmesini ve fayda sağlayabilecek şekilde üretkenliklerinin artmasını sağlayan yaklaşımlar. Open Source kod depoları, Scrum, XP ve Kanban gibi anahtar kelimeler bu yaklaşımda iletişim kapılarını açan anahtarlar. Çok haddime olmasada Erik Meijer’ın bu açıdan bakmayı atladığını ve Agile’ı bir “araç” olarak yorumladığını düşünüyorum. Agile’ı bir araç olarak görmek yerine, bir kültür olarak yorumlamak, daha anlamlı kodlar yazmayı sağlayacaktır. Daha anlamlı kodlar da, zaten daha fazla çözüm üretmek için daha fazla kod yazmamızı gerektirecek…Yani umarım… (:

 

 

Uzun bir aradan sonra, şu günlerde sıkça uğraştığım Entity Framework‘ün yeni versiyonuyla gelen bir özellik ile ihmal ettiğim blog’u biraz hareketlendirmek istedim… Uzun süre yazmayınca, insan nasıl giriş yapacağını da bilemiyor. Neyse…Fazla uzatmadan konumuza gelelim.

Entity Framework’ün yeni versiyonu dedim ama 6.x çıkalı sanırım oldu bayaa. Hatta geçen hafta, en son 6.1.2 versiyonu yayınlandı. Entity Framework ilk çıktığında, genişletilebilirliği ve yaratılan sorgulara müdahale edilebilirliği çok konuşulmuştu. 4.x versiyonu ile beraber, çeşitli wrapper’lar ile belli noktalara müdahale etmek mümkün hale geliyordu. Resmi olarak EF ekibi tarafından geliştirilmiş olmasa da, eski o ekipde çalışan kişilerin geliştirdiği ve yayınladığı Provider Wrapper’lar kısmen de olsa çok hayat kurtarmıştı. Kısaca EF kullanan kişilerin, bazı noktalarda ciddi şekilde aralara girip müdahale etme ihtiyacı oluyordu.

Entity Framework 6.x ile built-in gelen “Interception” yaklaşımı bu ihtiyacı gerektiren durumlarda güzel bir çözüm olarak bizlere sunuldu. Interception yaklaşımı ile artık Entity Framework’ün veritabanına gittiği son noktalarda araya girmek ve müdahale etmek mümkün olabiliyor.

IDbCommandInterceptor interface’inden oluşturacağımız sınıfın ilgili metodlarını yazdığımız zaman, tüm “Execution” noktalarında müdahale etmek oldukça kolay.

Neden böyle bir şeye ihtiyacımız olsun ki?

Biraz daha gerçek dünya örneği vermek sanırım netleşmesi adına daha doğru olacaktır. Mesela EF ile yaptığınız sorguları kendi formatınızda istediğiniz yere log’lamak isteyebilirsiniz ya da en çok hangi parametreler ile veritabanına gidildiğini log’layıp, veritabanı tarafında buna göre INDEX çalışması yapabilirsiniz. Ya da sorgulanmaması gereken tablolar var ise bunlara çeşitli kontroller yaparak kısıtlamalar getirebilirsiniz.

Biraz daha net olması için, EF ile uğraşan herkesin ve hatta özellikle SQL Admin’lerin rahatsız olduğu alias ile ilgili bir örnek vermek isterim. Aşağıdaki sorgunun çıktısını eminim herkes tahmin edebilir.

    var result = context.Students.Where(s => s.FirstName== "Arda").FirstOrDefault();

EF sorguları oluştururken, tablolara [Extendx] şeklinde bir alias verip bunlara göre sorguları oluşturmakta bildiğiniz üzere. Mesela [Extendx]’i bu Interception yaklaşımı sayesinde kaldırıp, istediğimiz değer ile değiştirmemiz mümkün.

internal class DatabaseAccessInterceptor : IDbCommandInterceptor
{

        public void NonQueryExecuted(System.Data.Common.DbCommand command,
                                     DbCommandInterceptionContext<int> interceptionContext)
        {

        }

        public void NonQueryExecuting(System.Data.Common.DbCommand command,
                                      DbCommandInterceptionContext<int> interceptionContext)
        {

        }

        public void ReaderExecuted(System.Data.Common.DbCommand command,
                                   DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
        {

        }

        public void ReaderExecuting(System.Data.Common.DbCommand command,
                                    DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
        {
            var alias = new Dictionary<string, string>();
            var commantText = command.CommandText;

            var pattern = @"\[dbo\]\.\[([\w\d]*)\] AS \[(Extent\d*)\]";

            var matches = Regex.Matches(commantText, pattern);

            foreach (Match match in matches)
            {

                if (match.Groups.Count == 3)
                {
                    alias.Add(match.Groups[2].Value, match.Groups[1].Value);
                }
            }

            foreach (var pair in alias)
            {
                command.CommandText = command.CommandText.Replace(String.Format("[{0}]", pair.Key),
                                                                  String.Format("[{0}]", pair.Value));
            }
        }

        public void ScalarExecuted(System.Data.Common.DbCommand command,
                                   DbCommandInterceptionContext<object> interceptionContext)
        {

        }

        public void ScalarExecuting(System.Data.Common.DbCommand command,
                                    DbCommandInterceptionContext<object> interceptionContext)
        {

        }
}
Not: Yukarıdaki kod, tüm extend ifadelerini değiştirmez. Sadece örnek olması adına basitçe yazmak istedim. Genişletip kullanmak ödev olsun…

Yukarıdaki kodda dikkat ederseniz Scalar,Reader,NonQuery gibi ADO.NET’den tanıdık gelen ifadeler var. Bunlar Entity Framework’ün oluşturduğu sorgulara göre araya girebileceğimiz metodları temsil ediyor. Bunların içerisinde istediğimiz işlemleri yapabiliyoruz.

Peki bu yarattığımız sınıfları, EF Context’inde nasıl tanımlıyoruz? Bunun için EF 6.x ile beraber yine oldukça gelişen konfigürasyon özelliklerinden faydalanabiliyoruz. Kod tarafında context sınıfımız içerisinde aşağıdaki gibi bir tanımla, yazmış olduğumuz “Interception”nın kullanılacağını belirtebiliyoruz.

        public SchoolContext(): base("SchoolContext")
        {
            DbInterception.Add(new DatabaseAccessInterceptor());
        }

Ya da app.config/web.config içerisinde de aşağıdaki gibi belirtebiliyoruz.

      <entityFramework>
        <interceptors>
          <interceptor type="{namespace.classname}, {assembly}">
            </interceptor>
        </interceptors>
      </entityFramework>

Umarım bu basit ve kolay özellik, EF kullanıyorsanız yeni ve farklı çözümler yaratmanızda faydalı olur. Biraz hızlı oldu farkındayım ama takıldığınız ya da sormak istediğiniz bir şey olursa, yorum yazarak ya da e-mail atarak bana iletebilirsiniz.