SOLİD PRINCIPLES
Last updated
Was this helpful?
Last updated
Was this helpful?
SOLID yazılım prensipleri; geliştirilen yazılımın esnek, yeniden kullanılabilir, sürdürülebilir ve anlaşılır olmasını sağlayan, kod tekrarını önleyen ve 2000'li yılların başında Robert C. Martin tarafından öne sürülen prensipler bütünüdür
Geliştirdiğimiz yazılımın gelecekte gereksinimlere kolayca adapte olması,
Yeni özellikleri kodda bir değişikliğe gerek kalmadan kolayca ekleyebileceğimiz
Yeni gereksinimlere karşın kodun üzerinde en az değişimi sağlaması,
Kod üzerinde sürekli düzeltme hatta yeniden yazma gibi sorunların yol açtığı zaman kaybını da minimuma indirmektir.
S— Single-responsibility "Her sınıfın veya metodun tek bir sorumluluğu olmalı "
O — Open-closed principle "Sınıflar değişikliğe kapalı ancak gelişime açık olmalıdır"
L — Liskov substitution principle "Liskov prensibi "
I — Interface segregation principle " Ara yüzlerin ayrılması prensibi"
D — Dependency Inversion Principle " Katmanlı mimarilerde üst seviye modüller alt seviyedeki modüllere doğruda bağımlı olmamalıdır "
Karşılaştığımız sorunları çözerken aklımızdan çıkarmamamız gereken ve programcılıkta hayat felsefi haline getirmemiz gereken şey şudur; nası ki Friedrich Nietzsche hayatının her anında üst insana (ubermensch) ulaşmaya çalışıyorsa bizde programcılığımızın her anında en temiz ve en bağımsız koda ulaşmalıyız. Bu şekilde yazdığımızın kodun devamlılığı sağlanabilir. İşte SOLİD prenciplerinin tam olarak ulaşmaya çalıştığı nokta budur.
Bu ilke "bir sınıfın değişmesi için yalnız bir nedeninin olması gerektiğini savunur" yani bir sınıfın az ve öz sorumluluğu olmalı karmaşık yapılardan her zaman kaçınılmalıdır. Bir class oluşturulurken sürekli " bu sorumluluğu buraya vermeli miyim ?" sorusu sorulmalıdır. Böylece kodlarda sonradan yapılacak bakım veya değişikliklerin maliyeti azalacaktır. Burada maliyetten kasıt iş yükü ve zamandır. Uygulamanızda katmanlı mimari kullanarak ve ata sınıflarınızda daha küçük sınıflara veye modüllere yani iş parçacıklarına ayırmanız gerekmektedir.
Varlıklar(Entities) genişlemeye açık olmalı ancak değişikliğe kapalı olmalıdır. Zaten OOP genişlemeyi prensip edinilerek desteklenmiştir. Lakin bu değişikm esnasında yaratılan sınıflarda modifikasyona gerek kalmayacak şekilde mimariyi kurmamız gerekir. Bir sınıfın davraşınını değiştirmeden geliştirmemiz gerekir.
Bizden sınıflara yeni bir yetenek kazandırılmamız istenildiğinde, ilgili özellik için gövdesiz bir method yazılır ve tüm varlıklarda bu method implement edilir. Ve iplement edildiği yerde iş yüklenir. en masrafsız şekilde değişikliği yapmış olduk. Eğer ilerleyen süreçte yeni bir varlık eklenmek istenirse yine var olan yetenekler implemente edilerek kazandırılır. Ve böylece var olan classlarımızda herhangir bir değişiklik yapmamış olurum.
Alt sınıflar miras aldığı üst sınıfın bütün özelliklerini kullanmalı, alt sınıflarda oluşturulan nesneler üst sınıfların nesneleriyle yer değiştirdiklerinde aynı davranışı göstermeli ve herhangi bir kullanılmayan özellik olmamalıdır. Bu ilkeye göre "türetilmiş veya alt sınıflar, temel veya ebeveyn sınıflarının yerine geçebilir." Bu ilke ana sınıfın alt sınıfı olan herhangi bir sınıfın, beklenmedik davranışları olmaksızın ata sınıf yerine kullanılmasını sağlar.
Bir çiftçinin oğlu çiftçilik özelliklerini babasından alması ve gerektiğinde babasının yerine geçmesi bu duruma örnektir. Ama oğul boksör olmak istiyorsa aynı aile hiyerarşisine dahil olmasına rağmen babasının yerini almayacaktır.
Bu prensip SOLİD'deki sınıflar yerine arayüzler interfaceler için gerçerli olan ilk prensiptir ve SRP-LSP prensiplerine benzemektedir. Bu ilke özet olarak şunu söyler "Hiçbir concrete sınıf kendisi ile ilgisi olmayan bir özelliği içeren arayüzden implemente edilmemelidir ". Burada asıl amacımız interfacelerin şişirilmesinden kaçınmamız olmasıdır. Tek bir interface yerine optimum özellikli birçok arayüz tercih edilmelidir.
Bu ilkede yüksek seviyeli sınıflar düşük seviyeli modüllere bağlı olmamalıdır. Modül ve sınıflar soyutlamalara bağlı olmalıdır. Soyutlamalar detaylara bağlı olmamalıdır. Detaylar soyutlara bağlı olmalıdır. Bu detaydan kasıt sınıflara yüklenen görevlerdir. Bu ilkenin en can alıcı noktası bir sınıfın eylem yürütmek için kullandığı araçlar ile birleştirilmemesi gerektiğidir. ancak arayüzün teknik özelliklerini karşılaması gerekir. Yani methodlar aldığı parametleri karşılaması gerekir. Somut sınıflar soyut sınıflara, soctyut sınıflarda UI katmanına bağlı olmalıdır böylece bağımlılık en az seviye indirilir ve bu bağlar oluşturulurken inject yöntemleri kullanılır.
Yukarıdaki satırlara basitçe değinmek gerekirse yüksek seviyeli bir modülün veya sınıfın düşük seviyeli modüllere veya sınıflara daha fazla bağımlı olması durumunda ilgili sınıfların yani child-parent sınıfların birbirlerine sıkı sıkıya bağlı olduğu durumda bir sınıfta bir değişiklik yapıldığında yada yapmaya çalışıldığında bundan kaç sınıf etkilendiği yani kaç sınıfta değişikliği yerine getirmektiğini belirtir. Bu bağlamda alt sınıfları soyut ata sınıflara bağlamalıyız.
Somut bir örnek vermek gerekirse bir televizyon kumandası düşünelim, uzaktan kumandanın pile ihtiyacı vardır, ancak pil markasına bağımlı değildir. İstediğimiz herhangi bir pil markasını kullanabiliriz ve bu bağlamda TV uzaktan kumandasının marka adıyla gevşek bağlı bir şekilde eşleştiğini söyleyebiliriz.
Dependency Injection, S.O.L.I.D prensiplerinin 5'inci özelliği olan “Dependency Inversion” prensibinin uygulanış biçimidir denilebilir.
Nesneye yönelik programlama dillerinde bir nesne oluşturulur ve bu nesne görevini yaparken diğer nesnelerle iletişim halindedir. Classlar birbiri içlerinde new operatörüyle oluşturulup kullanılabilir. Bu yöntem katı bir bağımlılık oluşturmaktadır. Özet olarak; Dependency Injection tekniğinde bağımlılık oluşturacak parçalarının ayrılıp, bunların sisteme dışarıdan verilmesi (enjekte edilmesi) ile bağımlılığın en aza indirilmesiyle meydana gelir.
3 temel Dipendency Injection yöntemi vardır;
Constructor Injection;
Property Injection
Method Injection