Yazılım Tasarım İlkeleri (Software Design Principles)
Yazılım tasarım ilkeleri, erişilebilir, okunaklı, sürdürülebilir, esnek, test edilebilir ve yeniden kullanılabilir yazılım geliştirmek için kullanılan rehber ilkelerdir. Bu ilkeler yazılımı anlaşılır, düzenli, organize ve ölçeklenebilir hale getirir.
Ayrıca, yazılımın uzun ömürlü olmasını ve bütünsel olarak tasarlanmasını sağlar. Yazılım tasarım ilkeleri arasında SOLID prensipleri, DRY, KISS, YAGNI, SoC ve diğerleri bulunur.
Bu yazıda SOLID harici diğer prensipler incelenecektir. SOLID Prensipleri ile ilgili derinlemesine bilgiye buradan ulaşabilirsiniz:
DRY Prensibi
Don’t repeat yourself.
Bir kod yazılırken birbirini tekrar eden ifadeler varsa bunlar metotlaştırılarak reusable bir hale getirilmeli, birbirini tekrar eden bloklardan kaçınılmalıdır.
KISS Prensibi
Keep it simple, stupid.
Basitlik ve sadelik prensibi. Kolay bir yol ile çözülebilecek bir problemi gereksiz ifadelerle karmaşık hale getirmemek gerektiğini söyler. Gerçekten ihtiyaca yönelik özellikleri öne çıkarmanın da altını çizer.
YAGNI Prensibi
You ain’t gonna need it.
İhtiyaç olmayan şeyleri ileride lazım olur düşüncesiyle sisteme dahil etmemek gerekir. Talep olmadan geliştirilen özellikler extra test eforu, dökümantasyon ve bakım zorluklarını da beraberinde getirir.
SoC Prensibi
Seperation of Concerns.
Aspect Oriented Programming’in önemli prensiblerindendir. Farklı işlevlere sahip parçaların birbirinden ayrı tutularak yönetilmesi gibi tanımlanabilir. Archtirectural bir design pattern olan mvc aslında bu prensibi açıklamanın en iyi örneklerinden biridir. Veri ve gösterimin soyutlandığı bu yapı, farklı işlevlere sahip olduğundan birbirinden ayrıştırılmıştır.
Bu yapı sayesinde bir geliştirme yapılacağında, diğer yapıları etkilemeden geliştirme yapılabilir ve yönetilebilir.
Composition Over Inheritance Prensibi
Bir nesne tasarlanırken, o nesnenin davranışlarını/kapasitelerini başka sınıflardan miras almaktansa, mümkünse bu sınıfları birbirleriyle birleştirip birleştirilmiş yeni bir nesne elde etmek üzere kullanmak felsefesi ve yaklaşımıdır.
Bu yaklaşım, özellikle büyük proje/mikro servis yapıları ve ölçeklenebilir uygulamalar gibi karmaşık uygulama geliştirme senaryolarında oldukça kullanışlıdır.
C# örneği üzerinden açıklamak gerekirse, bir araba sınıfı ve bir motor sınıfı olduğunu varsayalım. Geleneksel kalıtım yaklaşımına göre, araba sınıfını motor sınıfına kalıtıp bir araba motoru ortaya çıkarabilirdik. Ancak bu durumda, daha sonra bir farklı motor tipi eklemeye çalıştığımızda sınıf hiyerarşisinde kargaşa oluşabilir. Bu yüzden Composition Over Inheritance yaklaşımını kullanarak, araba sınıfı yerine bir motorsuz araba sınıfı oluşturur ve bunu bir motor nesnesiyle birleştiririz. Böylece daha sonra ihtiyaca göre farklı motor türleri ekleyebiliriz. Aşağıdaki örnek kod parçası bu yaklaşımı uygular:
public class Engine
{
public void Run()
{
// run engine
}
public void Stop()
{
// stop engine
}
}
public class Car
{
private readonly Engine _engine;
public Car(Engine engine)
{
_engine= engine;
}
public void Run()
{
_engine.Run();
}
public void Stop()
{
_engine.Stop();
}
}
Bu örnekte, Araba sınıfı Motor nesnesiyle birleştiriliyor ve Araba sınıfının Calistir() ve Durdur() yöntemleri, Motor sınıfındaki benzer yöntemleri çağırıyor. Böylece Araba sınıfı farklı Motor türlerine sahip olabilir ve Motor sınıfına yapılan değişiklikler Araba sınıfını etkilemez.
Encapsulate What Varies Principle
Bu prensibe göre, değişken özelliklerin bir araya getirilerek ayrı bir sınıf oluşturulması ve bu özelliklerin bir arada ele alınması gerektiği unutulmamalıdır. Bu prensip, bir programlama projesinde parçaların ayrılmasını, modülerliği ve tekrar kullanılabilirliği artırmak için kullanılır.
C# dilinde EWV prensibine örnek olarak, bir özelliğin değişebilirliği gösterilebilir. Bir özellik, örnek bir sınıfın özelliği olarak tanımlanırsa, esnekliği sağlamak ve yeni gereksinimlere adapte olmak için özelliği bir araya getiren başka bir sınıf oluşturulabilir. Bu sınıf, özellikleri bir arada tutarak onları verimli bir şekilde yönetebilir ve programlamacıların kodu yönetmesini kolaylaştırır.
Kodun belirli bir kısmında yol açabilecek değişiklikleri minimuma indirmek için kullanılır. Bu prensip, kodun bakımını kolaylaştırır ve değişiklikler gerektiğinde sadece ilgili alanları etkiler.
Örneğin, bir e-ticaret web sitesinde, müşterilerin farklı ülkelerdeki gönderim adresleri için farklı gönderim ücretleri olabilir. Klasik bir yaklaşım, gönderim ücretlerinin hesaplanması için bütün adrese göre ayrı ayrı döngüler oluşturulmasıdır. Ancak bu yaklaşım, ücretlerde yapılan değişikliklerin tüm kodu etkilemesine neden olabilir. EWV prensibini kullanarak, kodun değişkenliğini isolasyonlandırmak mümkündür. Bu durumda, gönderim ücretlerinin hesaplanmasında farklı bir sınıf kullanabiliriz. Bu sınıf, belirli bir adrese göre gönderim ücretlerini hesaplama görevini alır. Bu sınıfın yapısı, gönderim ücretlerinde yapılacak değişiklikleri minimuma indirir.
public interface IShipmentCalculator
{
decimal CalculateShippingFee(Address address);
}
public class DomesticShipmentCalculator : IShipmentCalculator
{
public decimal CalculateShippingFee(Address address)
{
// Domestic shipment fee calculation logic
}
}
public class InternationalShipmentCalculator : IShipmentCalculator
{
public decimal CalculateShippingFee(Address address)
{
// International shipment fee calculation logic
}
}
public class Address
{
public string Country { get; set; }
// Other properties
}
public class Order
{
private readonly IShipmentCalculator _shipmentCalculator;
public Order(IShipmentCalculator shipmentCalculator)
{
_shipmentCalculator = shipmentCalculator;
}
public decimal CalculateOrderTotal(Address address)
{
decimal subtotal = 0; // Calculate order subtotal
decimal shippingFee = _shipmentCalculator.CalculateShippingFee(address);
decimal total = subtotal + shippingFee;
return total;
}
}
Bu örnekte, IShipmentCalculator arayüzü, gönderim ücretlerini hesaplamak için bir standart oluşturur. DomesticShipmentCalculator ve InternationalShipmentCalculator sınıfları, her bir adrese göre gönderim ücretlerini hesaplamak için ayrı ayrı oluşturulur. Adres bilgisine göre, ilgili hesaplama sınıfı Order sınıfına enjekte edilir. Bu sayede, gönderim ücretleri değiştiğinde sadece ilgili hesaplama sınıfı değiştirilir ve Order sınıfında yapılacak değişiklik minimuma indirgenir.
Bu konuda bahsedeceklerim bu kadar. Bana ulaşmak ve open-source projelerimi incelemek için :
LinkedIn : https://www.linkedin.com/in/yigittanyel/
GitHub: https://github.com/yigittanyel