Yazılımın ilk 250 günü - Part 7

31 dk okuma

61. Gün

Bugün sizin bize yorumlamamız için gönderdiğiniz javascript kodlarını hayranlıkla okudum. O kadar iyi düşünülmüş ki ben 5 gün düşünsem yine de yapamazdım gibi geldi. 2 ayda okur yazarlık edinildi fakat iyi bir yazar,edebiyatçı,şair olmak için çok uzun bir yol var bugün yine anladım. İngilizce için söylenen “anlıyorum ama konuşamıyorum” ifadesini çok iyi hissettim bugün. Evet yazılan kodun amacını, kullanılan terimlerin anlamını biliyorum ya da kısa bir araştırmayla hemen bulabiliyorum ama iş yapmaya gelince kıvrak ve zeki bir yaklaşımı hâlâ sergileyemiyorum. Biraz da tecrübe ile gelişir diye umuyorum. Çok inanıyorum olacağına, çünkü çok seviyorum. Çok fazla umut, inanç,sevgi gibi pozitif içerikli kelimeler kullandım sanırım. Sebebi ise mesai bitiminde DOM ve event handlers konusuna tekrar bakarken dinlediğim Daft Punk şarkısı sanırım.

Günü o şarkı sözü ile bitirmek istiyorum:

“Work it harder, make it better
Do it faster, makes us stronger
More than ever, hour after hour
Work is never over”

62. Gün

Günün başlangıcında satranç oyununun OOP yöntemi ile nasıl yazılacağı üstüne bir kaynak buldum. Java kullanarak yazılmış kodu PHP’ye döndürüp, sonrasında HTML ve CSS kullanarak bunu bir web sayfasında göstermek istedim. OOP için pratik olur diye düşündüm fakat uzun sürecek gibiydi ve boş durmamak için onunla uğraştım. Sonrasında sizin gönderdiğiniz kodu inceledim. Kullanılan yapıları anlamaya çalıştım. Neden ve nerede kullanılabileceği üstünde çok düşündüm. Aklıma çok bir şey gelmedi amacı konusunda ama en azından kodu okudum. Yorumlamaya çalıştım. Tüm gün bununla geçti diyebilirim. ArrayObject yapısı ile ilk kez karşılaştım(karşılaşmışım daha önce ama onun ne demek olduğunu bilmiyormuşum) ve direkt dokümandan anlamaya çalıştım. Bu kodu anlamak ya da anlamaya çalışmak zorladı. Ve zorlanmadan da gelişim olmayacağı için çabaladım elimden geldiğince. Bugünlük bu kadardı.

63. Gün

Dün sadece inheritance, abstract class , ve interface konularını tekrar ettim. Oturmayan yerler kaldıysa oturtmaya çalıştım. Teorik olarak oturmayan bir yer keşfedemedim, üstüne bir şeyler katmaya çalıştım. Bol bol okumalar yaptım üstüne. Interface, senin ürettiğin sistemde başka developer’lar çalışacağı zaman üretecekleri class’larda bulundurmaları zorunlu metotları tanımlamak için var. Abstract class ise senin sisteminde çalışacak developer’lara birtakım abstract method’ları kullandırtmak ve childs class’larını üretirlerken bazı base method’ları onlara sağlamak için kullanılır, kullanılmalıdır. İkisinin de artıları ve eksileri bulunmaktadır. Nasıl bir yapı kurulacağına göre tercih edilme sebepleri de değişkenlik gösterecektir. Kesinlikle interface ya da kesinlikle abstract kullanmalısın gibi bir durum söz konusu değil. Projeye, systemin gerekliliklerine göre değişebilir. Bildiğimiz gibi interface’I implement edecek her class, interface’de bulunan her method’u kullanmak zorundadır. Birden fazla kez class’lar tarafından implement edilebilirler. Tamamen farklı ve alakasız sınıflar tarafından da kullanılabilirler. Inheritance bu işin neresinde peki denilirse cevap şu olabilir: Interface yapısı sadece fonksiyonel bir inheritance sağlar.
Inheritance konusunda çokça duyduğum bir bakış açısı var:
Abstract class bir “is a” ilişkisini concrete class’lar ile kurar. Bu sadece abstract class için değil aynı zamanda herhangi bir “base class-child class” ilişkisi için de geçerlidir. Interface ise “has a” capability’sini(yeteneğini) class’lar için sağlar.
Interface kısaca bir contract, bir sözleşmedir. Interface’I yazan kişi der ki, “Dostum, ben şey’leri bu şekilde kabul ederim”. Kullanan kişi de der ki, “Tamamdır, yazacağım class’lar bu şekilde olacak size temin ederim”. Yani arayüz boş bir kabuk gibidir. Sadece method’ların ne olacağını belirtir. İçi dolu değildir. Kendi başlarına bir şey yapamazlar. Onlar sadece bir pattern’dir. Interface’ler çok az CPU tüketirler. Çünkü onlar bir class değildir. Bunun önem kazandığı noktada, gömülü yazılım gibi konularda dikkate alınabilirler bu açıdan.
Abstract class’lar ise interface’in aksine bir class’tır. Interface lere benzemektedirler elbette ama birkaç fark bulunmaktadır. Örneğin Onlara bir davranış tanımlayabilirsin. Yani method’ların içi dolu olabilir ya da içinde değişken-property tanımlaman mümkün. Abstract class’ta daha çok “Bu class’lar şu şekilde görünmeli, ve onların ortak yanları da olabilir. Ayrıca aynı yöntemi farklı şekilde kullanabilirler. Ben sana kullanacakları yöntemi söyleyeyim. Onu sen istediğin şekilde doldur.” düşüncesi hâkimdir.

64. Gün

Bugün tekrar niteliğindeydi. Daha önce görmüş olduğumuz konulara tekrar baktım. Nesneler arası ilişkileri tekrar ettim. Abstaction kavramını, polymorphism’I, inheritance’I ve OOP ile alakalı diğer bir birçok konuyu. OOP tarafında bugün baktığım konularda eksik olduğum noktaları size ve google’a sordum. Aklımda kalan sorulara cevap bulabildim. Daha ayrıntılı olarak ne anladığımı yarın genel manada yazacağım. Gün içinde anladığım ve anlamadığım birçok ayrıntıyı not aldım. Yarın design patterns konularına kaldığım yerden devam edeceğim.

65. Gün

Bugün ve dün aldığım notların bir kısmını bugün raporuma eklemek istiyorum. Özet niteliğinde yazmak istediklerim:
  • OOP’yi kullanma amaçlarından bazıları: Karmaşıklığı azalt, bakım maliyetini düşür, modülariteyi arttır, nesneler arası hiyerarşiyi kur.
  • OOP dört temel ilke üzerine kurulu: Encapsulation, abstraction, inheritance, polymorphism.
  • Nesneler arası ilişkiler: Inheritance, implementation, association, dependency, composition, aggregation. Bu yapıların basitçe kodlanması:
    • Inheritance: is+a (A is a B),
    • Implementation: should + do (A should do B),
    • Dependency: references (A references B),
    • Composition: has + a, wholepart, ownership,
    • Aggregation: has + a, wholepart.
  • Dependency
Bir sınıfın tanımında yapılan değişiklikler, başka bir sınıfta değişiklilklere neden oluyorsa iki sınıf arasında bir bağımlılık vardır. SOLID’ de buna dependency injection konusunda yer verilir.
  • Hem aggregation hem de composition için bir örnek
Bir üniversite çeşitli departmanlara sahiptir. Her departmanda farklı profesörler bulunur. Eğer üniversite kapanırsa departmanlarda kapanır. Ama profesörler varolmaya devam ederler. Bu yüzden, üniversite, departmanların composition’I olarak görülebilir. Oysa ki departmanlar, profesörlerin aggregation’ına sahiptir. Ek olarak, professor birden fazla departmanda çalışabilir. Ama departman birden fazla üniversitenin parçası olamaz.
  • Bu konuda son bir örnek
    • Association: Bir obje ile ikişkim var. “Foo uses Bar”.
    • Composition: Bir objeye sahibim ve onun lifetime’I ile yükümlüyüm. “When Foo dies, so does Bar”.
    • Aggregation: Başka birinden ödünç aldığım bir objeye sahibim. “When Foo dies, Bar may live on”.
  • Farklı bir konuda aldığım farklı bir örnek. Abstraction’a dair
Hash function’I nasıl kullanırız? Bir input veririz fonksiyona, o da kendi gerekli hesaplamarını yaptıktan sonra bize çok farklı bir output üretir. Hash yöntemini bilmemize gerek yoktur. Kullanıcı sadece input ve output’u bilse yeterlidir. İşlemlerin olduğu kısımdan soyutlanmamız abstraction’a genel bir örnektir. Abstract class ile tek ortak yanı, abstract kelimesinin ikisinde de geçmesidir. Başka bir ortaklıkları yoktur. İkisi bambaşka konseptler.
  • SOLID
Yazılım geliştirirken sürüdürülebilir kod yazmamızı sağlayan bir prensipler bütünüdür.
  • Single Responsibility Principle
    Her sınıf, method, fonksiyon tek bir sorumluluğa sahip olmalıdır. Eğer sen bir sınıfa birden fazla sorumluluk verirsen, ilerleyen süreçte kodda bir değişikliğe gitmen dahilinde sorunlar çıkacaktır. Bu da maliyeti arttıracaktır. Clean code’da şöyle denir: “There should never be more than one reason for a class to change”.
  • Open Closed Principle
Yapılarımız(sınıf, metod, fonksiyon) gelişime açık, değişime kapalı olmalıdır. Yeni bir davranış ya da özellik eklemek istediğimiz durumda; yapmak istediğimiz değişikliği mevcut koda dokunmadan, değişimi sadece yeni kodlar üzerinden sağlamaktır. Bertrand Meyer şöyle ifade eder:
“Software entities should be open for extension, but closed for modification”.
Yani kullanıcılara mevcut kodu değiştirmeksizin yeni fonksiyoneliteler eklemeyi sağlamalısın.
  • Liskov Substitute Principle
Alt sınıflardan oluşan nesnelerin, üst sınıfın nesneleri ile yer değiştirdiklerinde aynı davranışı sergilemesi gerekmektedir.
Alt sınıflar, üst sınıflardan türediği için onların davranışlarını devralırlar. Eğer üst sınıflara ait davranışları gerçekleştirmiyorlarsa davranışı yapan metodu muhtemelen boş bırakır ya da bir hata fırlatırız. Fakat bu işlemler kod kirliliğine ve geçersiz kod kalabalığına neden olmaktadır. Bunların yanı sıra projeye daha sonradan dahil olacak geliştiriciler için de sorun oluşturmaktadır. Geliştirici systemin sağlıklı yürüdüğünü düşünerek gerçekleştirilmeyen bir davranışı kullanmaya çalışabilir.
  • Interface Segregation Principle
Sınıflar, kullanmadığı metodları içeren arayüzleri uygulamaya zorlanmamalıdır.
Bir sınıf, birden fazla arayüzü uygulaması özelliğiyle de birlikte bu prensip, bu tür durumlarda arayüzlerin ayrılmasını ve ihtiyaç hâlinde olanların kullanmasını söylemektedir.
“Clients should not be forced to depend upon interfaces that they do not use”.
  • Dependency Inversion Principle
Yüksek seviye sınıflar, düşük seviye sınıflara bağlı olmamalıdır. Her ikisi de soyutlamalara bağlı olmalıdır. Soyutlamalar, detaylara bağlı olmamalıdır. Detaylar, soyutlamara bağlı olmalıdır.

Design Patterns

“Her desen, çevremizde tekrar tekrar ortaya çıkan bir sorunu açıklar ve daha sonra bu soruna çözümün uygulanmasını, bu çözümü iki kez aynı şekilde yapmadan milyonlarca kez kullanabileceğiniz şekilde tanımlar.” - Christopher Alexander

“Design patterns are solutions to recurring problems; guidelines on how to tackle certain problems”.

“Aklında tut! Design pattern’ler problemlere çözümdür. Problem bulmaya yarayan bir çözüm değildir. Eğer doğru yerde doğru şekilde kullanırsan onlar birer kurtarıcıdır, aksi hâlde kodunda korkunç sonuçlara neden olabilir.”

Creational Design Patterns

Bir nesnenin ya da bir grubun esnek ve tekrar kullanılabilir biçimde nasıl oluşturulacağı ile ilgilenir. Çeşitleri: Singleton, Simple factory, factory method, abstract factory, builder, prototype.
  • Singleton
Bir sınıfın sadece bir örneği olmalıdır ve bu örneğe global bir erişim noktası sağlanmalıdır.
Sistem boyunca aksiyonları koordine etmek için sadece ama sadece bir tane object isteniyorsa kullanılması faydalıdır.
Conctructor private olmalıdır. Bunun amacı, nesne oluşumunu tek bir yerden sağlamak; istemcinin, “new” anahtar kelimesini kullanmasını engellemektir. Statik bir değişken olmalıdır, referansı tutmak için. Tutulan referansa erişmek için bir metod olmalıdır, getInstance().
Multithread uygulamalarda aynı anda birden fazla thread nesne oluşturabilir farklı farklı. O an bulunan dilde bunu önleyen yapılar var (lock, synchronized gibi).
  • Singleton’ın dezavantajları
    • En büyük dezavantajı, varoluş sebeplerinden biri: global olması. Ayrıca anti-pattern davranış sergilemesi. Global instance olarak kullanılması neden kötü peki? Uygulamanın dependency’lerini bir interface ile göstermek yerine kodunda saklarsın. Bir şeyi global yapmak code smell’e sebep olur. (Code smell’I henüz çok araştırmadım).
    • Single responsibility prensibine tersitr. Çünkü kendi oluşturduklarını ve yaşam döngülerini control ederler.
    • Kodu kalıtımsal olarak sıkıca bağlı yaparlar (tightly coupled).
    • Tightly coupling’e çözüm olarak interface kullanılabileceği, test sorunlarında ise singleton class’ının yapısının değiştirilip kullanılabileceği kimi örneklerde söylenmiş. Bu şekilde kullanımla singleton’ın sorun çıkarabilecek kısımları çözülebilmektedir. Ama kullanırken(eğer doğru yerde doğru şekilde kullanmayı çok iyi bilmiyorsan) çok dikkatli olmak gerekiyor.
    • Uygulamanın lifetime’I boyunca statelerini korurlar. Bu da yine unit test için kötü bir şeydir. Çünkü her test diğerinden bağımsız olmalıdır. Yani application’ın davranışına etki edemeyecek şekilde kullanılmalıdır.

Bu konudaki özlü söz:

“When you think you need a global, you’re probably making a terrible design misktake”.

Creational Design patterns’lara devam ederken kısa bir ara: Prefer composition over inheritance. Neden composition’I inheritance’a tercih etmeliyiz fırsat buldukça?
  • Runtime sürecinde superclass’lardan miras alınan implementation’I değiştiremezsin (Çünkü inheritance compiled time’da tanımlanır).
  • Inheritance, sublass’ın parent class’ın implementation’ını detaylandırmasını ortaya çıkarır. Bu yüzden inheritance’ın encapsulation’I kırdığı belirtilir.
  • Inheritance tarafından sağlanan tight coupling, subclass’ın implementation’ını parent’ın implementation’ına sıkı sıkıya bağlar. Yani parent’ın implementation’ındaki her değişim subclass’I değişime itecek, zorlayacaktır.
  • Subclass’ın aşırı kullanımı, kalıtım yığınını çok derin ve kafa karıştırıcı yapabilir.
  • Diğer yandan, object’ler diğer object’lere referans kazandırırken, object composition’I runtime’da tanımlanır. Bu durumda bu objeler, diğer object’lerin protected data’sına ulaşamayacak (no encapsulation break) ve her birinin interface’ine saygı duyacaktır.
Kısaca deniliyor ki, inheritance’I kullanmak için aşağıdaki 3 koşulun sağlanıyor olmasına bak. Eğer bunlar yoksa composition’I tercih etmen senin için daha yararlı:
  • A Bar is a Foo ( Inheritance “is +a” ilişkisini kuruyorsa ve “has + a” ile alakası yoksa),
  • Bar, Foo’nun yapabildiği her şeyi yapabilir ( Base class’lardaki kodu tekrar kullanabiliyorsan),
  • Base class’I değiştirerek türetilen class’larda global değişiklik yapmak istiyorsan.
Bu kısmın özeti: Subclassing daha fazla karmaşa ve bağlantılılık ifade eder. Hata yapmadan değiştirmesi, bakımı, ölçeklendirmesi zordur. O yüzden bu kısmı eklemeyi de gerekli gördüm ve tekrar design pattern’lere devam edebiliriz.
  1. Simple Factory
  2. Factory Method
  3. Abstract Factory
  4. Builder
Bu kısımlara bugün çalıştım fakat saat geç olduğu için yarın kaldığım yerden aldığım notları burada yazmaya devam edeceğim. Yarın sabah creational design patterns’ları bir kez daha tekrar edip ikinci kısma geçeceğim.

66. Gün

  • Simple Factory
Birbiri ile ilişili nesneleri oluşturmak için bir arayüz sağlar ve alt sınıfların hangi sınıfın örneğini oluşturacağına olanak sağlar. Örneğin kapı yapacaksın diyelim. Marangoz kıyafeti, tahtalar, yapıştırıcı gibi birçok malzeme ile uğraşıp yapabilirsin. Ya da sadece marangozu arayıp, yani factory’yi arayıp sana teslim etmelerini isteyip bu karışıklıktan kurtulursun.

In plain words:

“Simple factory simply generates an instance for client without exposing any instantiation logic to the client”.

Kısaca başka object’leri yaratmak için kullanılan bir object’dir.
Ne zaman kullanılır? Object oluşturmak birkaç basit işlemle olmuyorsa ve biraz mantık içeriyorsa oluşturma aşamasında, her yerde kodu tekrar etmek yerine bir “dedicated factory” yazmak mantıklı olur.
  • Factory Method
İşe alma müdürünü düşünelim. Her pozisyon için bir görüşmeye girmesi imkansıza yakındır. Oluşturulan iş ilanına göre görüşmeye girecek kişilere karar verir ve temsilci atar. Bu factory method için verilebilecek en basit örneklerden biridir. Child class’lara instantiation logic’i verir. Superclass’lar da object yaratmak için bir arayüz sağlar. Ama yaratılacak olan nesnenin tipini değiştirmek için sublass’lara izin verir.
Örneğin logistic app’imiz var diyelim. Bu app ile sadece kara lojistiğini destekliyoruz. Eğer biz deniz taşımacılığını app’imize dahil etmek istersek bir sorun var! Kodumuzda varolan class’lar birbirleriyle tightly coupled vaziyette. Böyle bir durumu çözmek için ne yapabilirsin? Factory method burada kullanılıyor ve çözüm sağlayabiliyor.
Ne zaman kullanılmalıdır? Kodun çalışması için boject’lerin dependency’lerini ve exact type’larını önceden bilmiyorsan kullanabilirsin. Library ve framework’ümüzün dahili component’lerini extend edecek bir yol ile kullanıcılara sağlamak için de kullanılabilir. Varolan object2leri her zaman tekrar inşa etmek yerine onları tekrar kullanarak sistem kaynaklarını korumak için de kullanılabilir.
Ek olarak, factory method ürün üretimi ile ürünün asıl kullanıldığı yeri ayırır. Bu da ürün üretimi tarafını kodun diğer kalan yerlerinden bağımsız olarak genişletebilmemizi sağlar. Örneğin app’ine yeni bir ürün eklemek için, sadece yeni bir creator subclass’ı yaratıp factory method’u override etmen yeterli.
Artıları: Creator ve concrete product’lar arasındaki tight coupling önlenir. SRP ve OCP’ye tamamen uymaktadır doğru yazıldığı takdirde.
Bu konuya bir örnek daha verelim. Diyelim ki sitemize giriş yapmak ya da üye olmak için sosyal medya hesaplarını kullanarak oluşturmak/girmek isteyen kullanıcı Facebook ile giriş yapabiliyor. Bizim sistemimiz buna tamamen uyumlu olsun. Ama eğer kullanıcılar artık linkedin hesabı ile de girmek isterse ve gelecekte başka eklemeler yapmak istersek burada factory method ile bu imkanı sağlarız. Kodumuzu daha flexible hale getiririz.

Factory method içeriklerinin çalışma prensipleri:

  1. Creator class’ımız factory method’u tanımlar ve ürün class’ının objesini döner. Creator’ın subclass’ları genelde bu metodun uygulanmasını sağlar.
  2. Creator isterse factory methodun default implementation’ını da sağlayabilir.
  3. Creator’ın asıl yükümlülüğü product yaratmak değildir. Method İle geri dönen product objesi ile alakalı temel business logic’ini içermektedir. Subclass’lar dolaylı olarak method üstüne overriding yaparak business logic’i değiştirebilir ve başka bir product tipini döndürür.
  4. Concrete creator’lar product tipini değiştirmek için factory method’un üzerine yazarlar.
  5. Product interface’leri tüm concrete product’ların uyması gereken operasyonları tanımlar.
  6. Concrete product’lar, product interface’inin implementation’larını sağlar.
  7. Tüm bu yazdıklarım sonradan okuyunca çok manasız görünüyor çünkü örnek bir kod olmadan bir anlam taşımıyor gibi. O yüzden bu kadar detaylı kısımları atlayacağım. Fakat abstract factory ve factory method şu üç günde en zorlandığım kısımlar olduğu için biraz fazla not aldım. O yüzden önemli görülen yerleri buraya yazmaya çalışacağım.
  • Abstract Factory
Birbirleri ile ilişkili ürün ailelerini oluşturmak için bir arayüz sağlar. Factory tasarım deseninde bir ürünün oluşturulması soyutlanmışken , abstract factory deseninde birbirleri ile ilişkili ürün ailelerinin oluşturulması soyutlanmıştır. Factory üreten factory deseni olarak da düşünülebilir.
Birden fazla ürün ailesi ile çalışmak zorunda kaldığımız durumlarda, istemciyi bu yapılardan soyutlamak amacıyla Abstract Factory doğru bir yaklaşım olacaktır.
Simple factory’deki kapı örneğimize dönelim. İhtiyacına göre marangozdan tahta, demirciden demir kapı, plastikçiden PVC kapı alırsın. Ayrıca bunların her biri için de ayrı ayrı takacak usta bulman lazım. Çünkü hepsinin ustası farklı. Bir tahta kapı oluşturmak için tahta ve ustası gerekir. Diğerleri için de aynı şekilde geçerlidir. Kapısı oluşturmak için iki farklı objeyi aynı noktada buluşturuken Abstract Factory’den yararlanırız.
Ne zaman kullanırız? İlgili ürünün farklı aileleri ile kodun çalışmaya ihtiyaç duyarsa, ama bu product’ların concrete class’larına bağlı olmasını istemezsen (Öncesinde bilinmeyebilirler ve future extensibility’ye izin vermek istersin) kullanabilirsin.
Farklı bir örnek verelim: Bir web sayfasının farklı elementleri için değişik tipte templates’lerin yaratılması için bir altyapı sağlayabilirsin. Bir web uygulaması aynı anda farklı rendering engines’leri destekleyebilir ancak onun class’ları rendering engine’in concrete class’larından bağımsızsa. Bu yüzden, app’in object’leri ile yalnızca onların abstract interface’lerini kullanarak iletişim kurmak zorundasın. Senin kodun direkt template object’lerini yaratmamalı, ama onların yaratılması için özel factory object’leri atamalıdır. Son olarak, kodun factory object’lerine bağımlı olmamalıdır, ama yerine abstract factory interface aracılığı ile onlarla çalışmalıdır. Sonuç olarak , app’e, rendering engines’lerden birine denk gelen factory object’sini sağlayabileceksin. App’te yaratılan her template, factory tarafından yaratılacak ve ve onların tipi factory’nin tipiyle eşleşecek. Eğer sen rendering engine’I değiştirmek istersen, mevcut kodu bozmadan client koduna yeni bir factory geçebileceksiniz.
Farklı kaynaklardan ek olarak şunlar söylenebilir:
Particular dependency yaratmak için runtime değerlerine ihtiyaç duyduğun her yerde Abstract factory’yi kullanabilirsin.

“ The abstract factory pattern provides a way to encapsulate a group of indivual factories that have a common theme without specifying their concrete classes.” - Wikipedia

Abstract factory’nin gerçek hayat örneklerini araştırdıkça Dependency Injection konularında sıkça kullanıldığını gördüm. Esasında kullanılan yerlerden bazılarına örnek olarak:
  1. You need to supply one or more parameters only known at runtime before you can resolve a dependency,
  2. The lifetime of the dependency is conceptually shorter than the lifetime of the consumer.
Kısaca Abstract factory Dependency Injection için gayet merkezi bir design pattern olarak yer alır.
Factory method ve Abstract Method arasındaki farklar:
Abstract factory, yaratılması gereken object’ler için abstract method’ları içeren base class’ları yaratır. Base class’tan türeyen her factory class, her object tipinin implementation’ını kendi yaratabilir.
Factory method, bir class’ta object’ler yaratmak için kullanılan basit bir method’dur.
Özetle; Factory method’u içeren class’ın asıl amacı obje yaratmak değildir. Abstract Factory ise sadece object yaratmak için kullanılmalıdır. Diğer bir fark ise; abstract factory composition ile implement edilir, ama factory method inheritance ile. Kavranması gereken en önemli nokta abstract factory client’a enjekte edilir. Bu yüzden composition var deriz.
Not: Nesneleri yaratırken LSP’ye ters bir şey yapmak kolay olduğu için factory method’ları kullanırken dikkatli olmalısın.
  • Builder
Karmaşık yapıdaki nesnelerin oluşturulmasında istemcinin sadece nesne tipini belirterek üretimi gerçekleştirmesini sağlamak için kullanılan bir desendir. Bu desende istemcinin kullanmak istediği gerçek ürünün birden fazla sunumunun olduğu durumlarda kullanılır.
Burger King'e gittik diyelim. İkili menu istedik ve onlarda getirdi. Bu basitçe simple factory’ye benzetilebilir. Ama creation logic’inin daha fazla adım içerme ihtimali de vardır. Mesela “Burger’ın nasıl olsun? Et az pişmiş mi? Hangi sosları eklememizi istersiniz? İçinde turşu ister misiniz? “ gibi. İşte burada builder pattern bizi kurtarmaya gelir.

In plain words:

Constructor pollution’ından kaçınarak bir object’nin farklı niteliklerini yaratmaya izin verir.

“It’s a design pattern with the intentions of finding a solution to the telescoping constructor anti-pattern”. - Wikipedia

Constructor’ımızın için birçok parametre varsa bunu karışma ihtimali çok fazladır. Parametre sayısı daha da artarsa içeriğini düzenlemek daha da zorlaşır. Bu durum telescoping constructor anti-pattern diye geçer literatürde. Buna tek alternatif ise builder pattern’i uygulamaktır.
Factory pattern ile arasındaki ana farklılık: “üretim tek adımlı bir işlemden geçiyorsa factory pattern, üretim birçok aşamadan oluşuyorsa builder method kullanılır.”.

“The builder pattern is a good choice when designing classes whose constructors or static factories would have more than a handful of parameters”. - Joschua Bloch

Eğer telescoping constructor pattern’ine karşı olarak; instance’ı cilent’ta oluşturup her method’u tek tek çağırırsan,birkaç çağrı üzerine object yaratıldığı için concstruction’ın herhangi bir anında inconsistent (tutarsız) bir durum oluşabilir. Bu da thread safety’yi sağlamak için ekstra çabaya neden olabilir. Bu yüzden en iyi alternatif builder pattern’dir.

Faydaları:

  1. Parametre değerlerinin hepsi tek bir lokasyonda bulunur.
  2. Kodun daha kolay yazılıp, okunmasını, ve anlaşılmasını sağlar.
  3. Parametreleri control etmek için build method modifiye edilebilir ve eğer geçersiz bir parametre değeri verildiyse “IllegalStateException” hatası throw edilebilir.
  4. Flexible’dır. Gelecekte parametre eklemek çok daha kolaydır.
  • Prototype
Dolly’yi hatırladın mı? Klonlanmıştı. Buradaki tek konu klonlama. Varolan object’yi klonlayarak yeni bir object yaratmak.
PHP’de klonlama işlemi direkt “__clone” magic method’u ile yapılabilir. Ya da direkt “clone” ile de yapabilirsin.
Ne zaman kullanmalı? Varolan bir objenin bir benzeri gerekliyse veya cloning’e kıyasla creation daha masraflı ise kullanabilirsin. Maliyetleri üretimi olan nesneleri az maliyetle üretmek için (Maliyetten kasıt parametreli constructor vb. olabilir). Shallow copy ve deep copy olarak iki türü var. Shallow copy ile nesnelerin bellekteki adresleri kopyalanır. Yüzeysel bir işlem olduğu için yeni bir nesne üretilmez. Deep copy ise bizim istediğimiz şekildedir. Birebir kopyalayıp, bu kopya ile asıl nesne farklı referanslar ile işaretlenebilmektedir.

Amaç: “intends to do is reduce the creation time of an object”.

Structural Design Patterns

Nesnelerin birbirleriylse nasıl birleşecekleri üzerinde durur.
  • Adapter
Bir sınıfın arayüzünü istemicinin beklediği arayüze çevirmeye yarar. Ya da uyumsuz bir yapıyı, istemcinin beklediği bir yapıya getirir diyebiliriz.

In plain words:

“Adapter pattern allows the interface of an existing class to be used as another interface. Often used to make existing classes work with others without modifying their source code”.

Bir örnek verelim gerçek hayattan: Şimdi bir sistemde external DVR’lar ile ilgili bir arayüze ihtiyaç duyulduğunu düşünelim. Her DVR üreticisi aletlerinin bizim tarafımızdan kontrol edilebilmesi için kod yazmamıza izin veren bir kütüphane sağlar. Bu kütüphaneye SDK diyelim. Her SDK, DVR’ların en temel fonskiyonalitilerini sağlayan arayüzlere sahip olsa da onların hepsi aynı benzerlikte değildir. Yani SDK’dan SDK’ya fark gösterebilmektedir. Bizim yazacağımız yazılım ise tüm DVR’lar ile etkileşimde olamlı. Her farklı SDK için ayrı bir switch case durumu açmak yerine, ortak bir arayüz yaratıp, tüm sistem kodumuzu bu arayüz vasıtası ile geliştirebiliriz. Her farklı SDK için farklı bir adapter yazılıp bizim interface’imizi implement eder. Bu şekilde kodumuzu daha basit yapabiliriz, Adapter pattern sayesinde.
Daha basitçe anlaşılacak örnek ise: JSON işlemleri için sistemimiz JsonSerializer arayüzünü kullanıyor. Ama sonrasındaki süreçte 3. Parti bir şey ekleyip farklı bir arayüz kullanmak istiyoruz diyelim. Bizim sistemimiz JsonSerializer üstünden yürüdüğü için adapter pattern’I kullanarak JsonSerializer gibi görünerek 3. Parti yazılımının çalışmasını sağlıyoruz.
  • Bridge
Abstract yapıpı, implementasyonundan ayırmaya, bağımsız olarak geliştirilebilir iki yapı elde etmemize yarar.
Örnek: Farklı sayfaları olan bir websitemiz olduğunu düşünelim. Kullanıcıların sayfaların theme’ini (dark mode gibi) değiştirebildiğini düşünelim. Ne yapardın? Her sayfanın tek tek kopyasını oluşturup hepsi için theme yaratmak mı? Ya da sadece kullanıcının tercihine göre yüklenecek ayrı bir theme yaratmak mı? Bridge pattern 2.’yi yapmamıza izin verir.

In plain words:

“Bridge pattern, ‘prefer composition over inheritance üzerinedir. Implementation detayları,ana hiyerarşiden uzaklaştırılıp başka bir objenin ayrı bir hiyerarşisine itilir”.

“Decouple an abstraction from its implementation so that the two can vary independently”. - Wikipedia

“Adapter makes things work after they’re designed; Bridge makes them work before they are”. - GOF (page 219)

Saat geç olduğu için yarın kaldığım yerden devam edeceğim. Direkt defterden yazığım için bazı yerler haddinden fazla uzamış ve karışık olmuş olabilir. Yazarken farkındaydım. Ama şu ana kadar en oturmayan ya da karşıma çıksa zorlanacağım dediğim yer Abstract Factory oldu. Şimdiye kadar zorlandığım birçok yer sonradan tekrar ve tekrar üstüne gidince oturmuştu. Onun da oturacağına inanıyorum.

67. Gün

  • Composite
Nesneleri ağaç yapısına göre düzenleyerek ağaç yapısındaki alt üst ilişkisini kurmaya yarayan bir desendir.

In plain words:

"Composite patttern, client'ın aynı tavırla bireysel nesnelere davranmasına izin verir."
"Farklı nesneleri gruplayıp, bir nesnenin tek bir instance'ı şeklinde davranılmasını tanımlar." - Wikipedia

Amaç: Part-whole hiyerarşini temsil etmek için nesneleri ağaç yapısına "compose" eder. Composite pattern'i uygulamak client'ın indivual nesnelere ve compositon'lara homojen şekilde davranmasına izin verir.

Örneklendirelim: Her organizasyon, her şirket çalışanlara sahiptir. Çalışanların her biri aynı özelliklere sahiptir. Maaşa sahiptirler. Sorumlulukları vardır. Birine rapor vermeleri gerekebilir yada gerekmeyebilir. Astları bulunabilir ya da bulunmayabilir. Bunları aynı collection'a alıp istersek maaşlarını toplayabilir ya da hepsi için başka method'larda uygulayabiliriz.

"Use the composite pattern when You want to represent represent part-whole relationship; You want clients to be able to ignore th difference between compositions of objects and indivual objects. Clients will treat all objects in the composite structure uniformly." - GOF

  • Decorator
Nesnelere dinamik olarak yeni sorumluluklar atamamızı sağlayan tasarım desenidir. Object'lerin class'ını subclassing ile tüm object'lerin türetildiği class'a işlevsellik eklemek kolaydır. Ama tek bir nesneyi bu şekilde extend etmek imkansızdır.Decorator pattern ile, tek bir nesneye işlevsellik ekleyebilir
"Aynı class'tan türeyen diğer objelerin davranışını etkilemeden, statik veya dinamik olarak, bir tek nesneye davranış eklemeye izin verir. Single responsibility principle'a bağlı kalmak için kullanışlıdır." - Wikipedia
  • Facade
Bilgisayarı nasıl açarım? Bir güç düğmesine basarak. Bu aslında senin inandığın şey çünkü bilgisayarın dışarıda sağladığı basit bir arayüzü kullanırsın. Dahili olarak bilgisayar bu işlemleri yaparken çok daha karmaşık bir ilişkiler bütünü vardır. Kompleks alt sisteme verilen basit arayüz Facede olarak adlandırılır.

In plain words:

"Facade pattern provides a simplified interface to a complex system".

Design Pattern tekrar eden bir problemi çözmenin ortak bir yolunu sağlar. Design Pattern'lerdeki class'lar sadece normal birer class'tır. Önemli olan onların nasıl yapısal olarak kurulduğu ve bir problemi çözmek için en iyi şekilde nasıl beraber çalıştıklarıdır.
Facade design patterns karmaşık bir sistemin arayüzünü basitleştirir. Complex bir sistemin subsystemlerini oluşturan class'ların tümünden oluşur. Facade, kullanıcıyı sistemin karışık detaylarından korur ve kullanımı kolay basitleştirilmiş bir görünüm sağlar. Ayrıca sistemi kullanan kodu alt sistemlerin ayrıntılarından ayırarak sistemi daha sonra değiştirmeyi kolaylaştırır.
Daha önce de yazmıştım ama tekrar etmekte kendim için fayda var. Tasarım kalıplarını öğrenirken önemli olan, verilen problemimize hangi kalıbın uyduğunu fark edebilmek ve sonra onu uygun şekilde kullanabilmektir. Bir pattern'i yanlış biçimde kullanmak veya bir pattern'i bildiğin için problemini sadece onunla çözmeyi denemek büyük bir sorundur. Bu tuzaklara düşmeden design pattern'ları öğrenmekte fayda var.
Facade için özetle şunu diyebiliriz: amaç sistemi yeni bir altyapıya sokmak değil, alt sınıflardaki karmaşıklığı soyutlayarak pratiklik sunmaktır.
  • Flyweight
Askerlik sırasında kahvaltı için yemekhaneye gidldiğinde birçok bardak çayla doludur ve sırasıyla her gelen er çayını ve yemeğini alıp yerine oturur. Birçok çay bardağı birden doldurulur sebebi ise kaynaklardan tasarruf etmek olabilir. Burada kaynak, zaman insan işgücü, hız, çayın az ve eşit oranda doldurulup çaydan tasarruf yapmak da düşünülebilir. Kısaca Flyweight pattern tamamen paylaşmak hakkındadır. Sık kullanılan nesnelerin bellek yönetimini kontrol etmek için kullanılır.

In plain words:

"It is used to minimize memory usage or computational expenses by sharing as much as possible with similar objects."

"Flyweight, diğer benzer object'ler ile mümkün olduğu kadar veri paylaşarak hafıza kullanımını minimize etmeye çalışan bir object'dir. Basit bir tekrarlanan temsilin kabul edilemez miktarda bellek kullanması durumunda, nesneleri çok sayıda kullanmanın bir yoludur." - Wikipedia
Gereksiz nesne initialize etmeyi bırakıp hafızada daha az yer kaplamak amaçtır dediğimiz üzere. GoF'ta bir object'nin iki durumundan bahsedilir:
"Esas Durum(Intrinsic State): Flyweight'te depolanır. Flyweight içeriğinden bağımsız bilgilerden oluşur. Bu da onu paylaşılabilir kılar.
Eğreti Durum(Extrinic State): Flyweight'in içeriği ile değişebilir ve ona bağlıdır. Bu yüzden paylaşılabilir değildir. Client object'leri ihtiyaç olduğu durumda eğreti durumu flyweight'e geçirmekle yükümlüdür." ??Bu cümleyi pek anlamadım.??
  • Proxy
İstemcinin orjinal nesneye direkt erişimi yerine bu erişimi nesneyi temsil eden proxy(vekil) sınıflar üzerinden gerçekleştirmesini ve bu proxy sınıfların sunduğu imkanları kullanmasını sağlayan tasarım desenidir.
Çoğu PHP uygulamasında pek kullanılmasa da yine de kullanıldığı bazı alanlar var: caching, logging, access control, delayed initialization gibi. Örneğin downloader da bu konuya örnek verilebilir. Proxy sayesinde caching kullanarak downloader'ın performansı arttırılabilir. Mesela bir dosyayı indirdin diyelim. Sonrasında tekrar indireceksin aynı ürünü. Birinci indirmende bu veriyi caching ile direkt sana vermek hem zamandan hem de trafikten tasarruf sağlar.
Gerçek dünyadan bir örnek olarak da kredi kartı verilebilir. Banka hesabımız için kredi kartı bir proxy'dir. Nakit para yerine kullanılabilir ve gerektiğinde nakit parayı çekmemize yarar. Bu da tam olarak proxy'nin yaptığı şeydir:

"Control and manage access to the object they are protecting".

"En genel haliyle proxy, başka bir şeye arayüz olarak işlev gören bir sınıftır. Proxy, sahne arkasında gerçek hizmet veren nesneye erişmek için istemci tarafından çağrılan bir sarmalayıcı (wrapper) veya aracı (agent) nesnedir. Proxy kullanımı, gerçek nesneye yönlendirme olabilir veya ek mantık sağlayabilir. Proxy'de, örneğin gerçek nesne üzerindeki işlemler kaynak yoğun olduğunda önbelleğe alma veya gerçek nesne üzerindeki işlemler çağrılmadan önce ön koşulların kontrol edilmesi gibi ekstra işlevsellik sağlanabilir." - Wikipedia
Structural design pattern'ları bir sonraki konuya geçmeden önce özetleyelim. Aralarındaki farkları yazalım. Çünkü hepsi birbirine yapısal olarak benzemekte ve kafamızın karışma ihtimali çok fazla. Proxy, decorator, adapter, ve bridge; hepsi bir sınıfı "wrapping" (saramalamak) üstüne varyasyonlardır. Ama kullanımları farklıdır.

Proxy: Bir nesneyi lazy-instantiate etmek istersen, veya remote bir service'i çağırdığını gizlemek için, veya nesneye erişimi kontrol etmek istersen kullanılabilir.


Decorator: "Smart Proxy" olarak adlandırılır. Bir nesnenin türünü genişletmeden, ona yeni bir işlevsellik eklemek istersen kullanılabilir. Bu, runtime'da yapmanızı sağlar.


Adapter: Bir abstract arayüzün olduğunda ve farklı bir arayüze ama çok benzer bir işleve sahip başka bir objenin arayüzü ile eşleştirmek istersen kullanabilirsin.


Bridge: Adapter'a çok benzerdir ama sen hem abstract interface'i hem de temeldeki implementation'ı tanımladığında onu kullanırsın. Örneğin, bazı 3. parti kodlara adapte olmuyorsun ve tüm kodun designer'ı da sahibi de sensin. Ve sadece bazı farklı implementation'ları değiştirmek istiyorsun.


Facade: Bir veya birden fazla sınıfın alt sınıflarına yönelik oluşturulan bir high-level interface'dir. Düşünelim ki birden çok nesnenin oluşmasını gerektiren kompleks bir yapıya sahipsin. Bu nesneler kümesinde değişimler yapmak kafa karıştırıcı olabilir çünkü hangi nesnenin senin çağırmak istediğin metoda sahip olduğunu her zaman bilmeyebilirsin. Nesnelerin koleksiyonuna yapabileceğin kompleks işlemler için high-level methodlara sahip bir facade yazma zamanı gelir!

Behavioral Design Patterns

Nesneler arası ortak haberleşmeyi efektif ve esnek bir yapıya getirmemizi sağlar.
  • Chain of Responsibility
Bir amaca yönelik bir dizi işlemi gerçekleştiren nesnelerin birbirinden bağımsız bir şekilde çalışmasını ve her bir nesnenin sadece kendisiyle tanımlı işleri yapmasını sağlayan bir tasarım desenidir.

In plain words:

"Nesne zinciri üretmeye yardım eder. Uygun handler'ı buluncaya dek istek bir nesneden yerden başlar ve tek tek nesneleri gezerek devam eder."
3 ödeme şeklim var diyelim. Birincisi banka hesabım, ikincisi Paypal hesabım, üçüncüsü de bitcoin olsun diyelim. Bankada 100 liram var, Paypal hesabımda 200 lira var, bitcoin cüzdanımda da 300 liram var toplamda diyelim. Şimdi ben 259 liralık alışveriş yapacağım. Diyorum ki, "sevgili banka hesabım sende bi 259 almam lazım". Ama görüyoruz ki orada o kadar yok. Banka hesabım da diyor ki "Ben seni Paypal hesabına yönlendireyim. Bende o kadar bozukluk yok" dedi. Paypal hesabında da o kadar para olmayınca, bitcoin cüzdanına yönlendirdi ve sonunda orada para olduğu için işlemin tamamlandı. Burada yapılan şey nesnelerin davranışı ile ilgiliydi. Yükümlülük zinciri gibi bir ismi var, ve tabii ki nesneler için. En azından biz OOP üstüne ilerlediğimiz için.
  • Command

In plain words:

"Eylemleri nesnelerde kapsüllememizi (encapsulation) sağlar. Bu kalıbın arkasındaki ana fikir, istemciyi alıcıdan ayırmanın yollarını sağlamaktır."
"Bir eylemi gerçekleştirmek veya sonraki bir zamanda bir olayı tetiklemek için gereken tüm bilgileri kapsüllemek için bir nesnenin kullanıldığı davranışsal bir tasarım kalıbıdır. Bu bilgiler, yöntem adını, yöntemin sahibi olan nesneyi ve yöntem parametreleri için değerleri içerir." - Wikipedia
Örnek verelim. Bir restaurantta sipariş verdiğini düşün. Sen (Client), garsona (Invoker) iskender (Command) getirmesini söylersin. Ve garson senin talebini şefe (Receiver) iletir, ki şef iskenderi nasıl pişirileceğine dair bilgisi olan insandır). Diğer bir örnek ise: Sen (Client), uzaktan kumandayı (Invoker) kullanarak televeziyonu (Receiver) açarsın(Command).
Bugün behavioral design pattern'lara geçiş yaptım. Yarın tamamen bitirip cumartesi günü hepsini tekrar edeceğim.

68. Gün

UML'e Giriş

Giriş

UML yürürken ayaklarına bakmak gibidir. Genellikle bilinçsizce yapabileceğin şeyleri bilinçli ve açık hâle getirir Hepimiz kodları okuruz, yazarız, yorumlarız. Bizim hobimiz, işimiz, ya da mecburi alınan bir programlama dili dersini geçmek gibi sebepleri olabilir. Ve bir yazılım geliştiricisi genelde kodu yorumlamak veya diyagramlarını çizmeye pek eğilimli değildir. Direkt kodun kendisini okumak daha akla yatkın gelir. Ama bazı faydaları vardır ki onu da göz önünde bulundurup kullanmak gerekebilir. Hem forward engineering hem de reverse engineering için kullanılabilir.
UML'i sadece yaptığın bir şey ile alakalı düşünmemek gerekir. Örneğin gece ormandasın ve yağmur yağmaya başladı. Ortalık kapkaranlık. Kendi ayaklarına baksan bile fayda etmeyecek çünkü hiçbir şey göremiyorsun. Ama birisi bir meşale ile yakınında olsaydı onun ışığını ya da ayak izlerini takip edebilirsin. Çamur, karanlık, ağaçlar, dikenli otlar arasında yolunu bulurdun. Bu benzetmeye örnek olarak,bir projeye başlandı şirkette. 5 yıl sonra, bu projeye önceden dahil olan insanlar gittiğinde ne olacak peki? Projeye daha sonra katılan herkes için bazı temel güncel belgelerin mevcut olması inanılmaz derecede yararlıdır. Şöyle bir gerçek de var. Bir projenin her kısmı tamamen method ve parametre isimleri ile dolu dolu açıklanmaya çalışılırsa bunun sürdürülebilirliği ve bakımı zordur. Yine de sistemdeki yapılar arasındaki ilişkilerin temel diyagramlarını göstermek çok değerlidir. Genelde hiç kimse 50 sayfalık herşeyiyle tam oluşturulmuş bir UML diyagramını okumayı istemez. Bu yüzden ölçülü bir şekilde bir sistemin UML diyagramını oluşturmak gerekir. UML'in bir diğer yaralı olduğu nokta da şu: Yazılım departmanında senior olan bi geliştirici bir yapıyı dizayn etmekten sorumlu olup, tasarımın uygulamasını junior geliştiriciye bırakması.
Genel olarak UML'in ne için kullanıldığı, eşsiz olmayan benzetmelerle (based on stack overflow entries) açıklanmaya çalışıldı. Şimdi UML'in ne olduğuna bakalım.

Gelişme

UML bir modelleme dilidir. Temel amacı tasarlanan bir sistemi görselleştirmektir. UML bir programı dili değil, görsel bir dildir aslında. UML nesne yönelimli programlama ile bağlantılıdır ve elementler arası ilişkinin görselleştirilmesini diyagramlar ile sağlar. Bu diyagramlar ikiye ayrılabilir: Behavior (Davranış) diyagramı, Structural (Yapısal) diagram.
Class Diagrams
UML'i herşeyiyle tam olarak anlatmak aşırı uzun ve zaman alacak bir şey olduğu için sözü direkt class diagrams'lara getirelim. Class diyagramları her nesne yönelimli metodun ana "building block"larıdır. Sınıflar arası ilişkileri, arayüz kullanımını, ve diğer sınıflar ile alakalı şeyleri göstermek için kullanılır. Class diyagramları şu yapılardan oluşmaktadır:
  1. Class {name, attribute, method}
  2. Objects
  3. Interface
  4. Relationships {inheritance (generalization), implementation (realization), association, dependency, composition, aggregation}
  5. Associaitons {bidirectional, unidirectional}
Her class dikdörtgen bir kutunun içinde ismi, özellikleri (nitelikleri), ve kullandığı metotları ile oluşturulur.
Metotların ve özelliklerin görünümünü (public, private, protected) belirtebilceğimiz 3 tip "modifier" vardır: "+" public görünürlük sağlar (Herkes için). "#" protected görünürlük sağlar (Kendisinden türetilen sınıflarda da görünebilmesi için). "-" private görünürlük sağlar (Sadece kendisi için).

Sonuç

Bugün aldığım notlar bu şekildeydi. Genel olarak class diagram'daki elementlerin neler olduğunu öğrendim. Nesnelerin-class'ların birbirleri ile olan ilişkilerinin nasıl bir diyagramda gösterildiğini öğrendim.

69. Gün

UML ile class diyagramın nasıl oluşturulduğunu öğrendim. UML ile oluşturulan diyagramı okuyup bir programlama dilinde(PHP) yazmayı öğrendim. Cumartesi günü kısaca bunun üstüne okumalar ve pratik üzerine geçti. Sizin yazdığınız kodu genel olarak anladım oluşturulurken. UML’de bir interface yaratırken biraz ezbere oluşturmuş gibi hissettim. Çünkü siz kodu yazarken ihtiyacı farkettiğinizde kodu ona göre şekillendirmiştiniz. Bense biraz daha düz mantıkla hareket etmiştim. İhtiyaca göre elementler ekleme fikri biraz daha oturdu aslında. Ben de kendim için aynı metodu uygulamak istiyorum.

70. Gün

Bugün veritabanı bağlantısını ve query builder’ı object oriented nasıl yapabileceğim üstüne çalıştım. Query builder’I spesifik bir tablo için yapmak hiç zor değildi. Aslında her tablo için yapmak da çok zor olmamalı fakat çok basit görünen kısımlarda sürekli hata aldım. Neydi bu kısımlar? En kolay görünen array’den string’e dönüştürme, sql sorgusunu doğru yazma gibi şeylerdi. Quotation marks’ların birbiriyle çakışmasını düzeltmeye çalıştım ama başarılı olamadım. Yarın ilk iş, sabahtan hatalarımı tekrar düzeltmeye çalışmak olacak. Query builder için arayüz sağlamak ve factory method kullanmak istememizin sebebini çok net anladım. Sorgunun doğru çalışmasını sağlayabilirsem oraları düzenlemek kolay olacaktır diye düşünüyorum. Kısaca ne yaptığımızın, nasıl yapmamız gerektiğinin farkındayım fakat günün ikinci yarısı hataları düzeltemedim. Yarın zinde bir kafa ile tekrar bakacağım.