DRY / KISS / YAGNI – Yazılımın Altın Kuralları konusunu anlatan renkli 3D teknik illüstrasyon

Giriş

Modern yazılım geliştirmede, kodun sürdürülebilir, esnek ve okunabilir olması için üç tasarım ölçütü birlikte değerlendirilir: DRY, KISS ve YAGNI. DRY, KISS ve YAGNI, tasarım kararını ihtiyaca göre tartmaya yardımcı olur. Aşağıdaki C# kesitleri ortaklaştırma, sadelik ve gereksiz özellik maliyetini gösteriyor.

dry-kiss-yagni

1. DRY Prensibi – Don’t Repeat Yourself

Tanım ve Temel Felsefe

DRY, yani “Kendini Tekrar Etme”, yazılımda aynı bilginin, mantığın ya da işin birden fazla yerde bulunmamasını önerir.
Bunun temel sebebi şudur: Bir bilgi birden fazla yerde varsa, onu güncellemek, hataları önlemek ve sistemi yönetmek giderek zorlaşır.

DRY Neden Hayati?

  • Bakım Kolaylığı: Kodun herhangi bir kısmında değişiklik gerektiğinde, tek bir yeri güncellemek yeterli olur.
  • Hata Azaltma: Aynı kodun birden fazla kopyası varsa, biri güncellenmediğinde beklenmeyen hatalar oluşabilir.
  • Kod Kısalığı ve Temizliği: Kod tabanı daha sade, fonksiyonlar ise daha kısa ve amaca uygun olur.

2. DRY – Kapsamlı Açıklama ve C# Kod Örnekleri

Yanlış Kullanım (Kendini Tekrar)

decimal totalPrice = itemPrice + tax + 15;
decimal invoiceTotal = itemPrice + tax + 15;
decimal cartTotal = itemPrice + tax + 15;

Doğru Kullanım (DRY Uygulaması)

const decimal ShippingCost = 15m;

decimal CalculateTotal(decimal itemPrice, decimal tax)
{
    return itemPrice + tax + ShippingCost;
}

decimal totalPrice = CalculateTotal(itemPrice, tax);
decimal invoiceTotal = CalculateTotal(itemPrice, tax);
decimal cartTotal = CalculateTotal(itemPrice, tax);

DRY Prensibinde Dikkat Edilecekler

  • Sabitler için “const”, “static readonly” kullan.
  • Utility/Helper metotlarını ortaklaştır.
  • Kodun farklı yerlerinde aynı ifadeyi, sorguyu veya algoritmayı tekrar tekrar kullanma.
  • DRY aşırıya kaçarsa, bazen soyutlamalar çok karmaşık olabilir. Her tekrar DRY uygulanacak diye zorlamamalı, “mantıksal tekrar” olmasına dikkat edilmeli.

3. DRY ile İlgili Ek Avantajlar ve Sıkça Sorulanlar

Soru: Her tekrar DRY ihlali midir?

Cevap: Hayır. Aynı görünen kod farklı iş kurallarını temsil edebilir. Ortak değişiklik nedeni yoksa tekrar kalıcı olarak da kabul edilebilir; yanlış abstraction bağımsız policy’leri birbirine bağlar.

Avantajlar:

  • Kodun kapsamı büyüdükçe yönetim kolaylaşır.
  • Takımda herkes nerede hangi işin yapıldığını hızlıca bulur.
  • Test yazmak, mocklamak ve hata ayıklamak kolaylaşır.

4. KISS Prensibi – Keep It Simple, Stupid

Tanım ve Temel Felsefe

KISS, “basit tut” anlamına gelir. Karmaşık, gereksiz katmanlar, interface’ler, over-engineering projeyi yavaşlatır. KISS, çözümleri sade ve anlaşılır tutmayı önerir.

Neden Basitlik Önemli?

  • Hızlı Anlaşılabilirlik: Her ekip üyesi kodun mantığını kolayca çözebilir.
  • Daha Az Hata: Karmaşık kodda bug bulmak, debug yapmak daha zordur.
  • Bakım Kolaylığı: Zaman geçtikçe, projeyi ilk yazan kişi bile kodu kolayca okuyup geliştirebilir.

5. KISS – Kapsamlı Açıklama ve C# Kod Örnekleri

Yanlış Kullanım (Aşırı Karmaşıklık)

IMultiplier multiplier = new Multiplier();
Console.WriteLine(multiplier.Multiply(5, 2));

public interface IMultiplier
{
    int Multiply(int num, int factor);
}

public class Multiplier : IMultiplier
{
    public int Multiply(int num, int factor) => num * factor;
}

Doğru Kullanım (KISS Uygulaması)

Console.WriteLine(5 * 2);

KISS Uygulamasında Dikkat Edilecekler

  • Gerekmedikçe soyutlama ve tasarım desenlerinden kaçın.
  • Okunabilirliği, performanstan veya “ileride lazım olur” düşüncesinden önde tut.
  • Her fonksiyonun tek ve net bir amacı olmalı.

6. KISS’in Dezavantajları ve Sık Sorulan Sorular

Soru: Her şeyi basit yazarsak kod büyüdüğünde zorlanmaz mıyız?

Cevap: Basitliği korurken, modülerliği ve tekrar kullanılabilirliği de göz önünde bulundur. Ancak, erken optimize etmek veya gereksiz abstraction çoğu zaman faydadan çok zarar verir.

Avantajlar:

  • Kod tabanı kolay büyür, refactoring gerektiğinde korkulmaz.
  • Yeni başlayanlar, stajyerler veya dış ekipler daha hızlı katkı verir.

7. YAGNI Prensibi – You Aren’t Gonna Need It

Tanım ve Temel Felsefe

YAGNI, “Gereksiz işlev ekleme!” prensibidir. Gelecekte lazım olur diye kodu şişirme, her ihtimali önceden çözmeye çalışma.

YAGNI Neden Gereklidir?

  • Zaman Kazandırır: Gereksiz kod yazmayarak projeni hızlı teslim edersin.
  • Bakım Kolaylığı: Kullanılmayan fonksiyonlar hata riski ve kafa karışıklığı yaratmaz.
  • Kod Kısa ve Sade Kalır: Gerçekten ihtiyaç olduğunda eklemek, baştan gereksiz kod yazmaktan daha iyidir.

8. YAGNI – Kapsamlı Açıklama ve C# Kod Örnekleri

Yanlış Kullanım (Gereksiz Fonksiyonlar)

public class Payment
{
    public void PayCreditCard() { /* ... */
    }

    public void PayBitcoin() { /* ... */
    }

    public void PayWithGold()
    { /* ... */
    } // Kimse sormadı, ihtiyaç yok
}

Doğru Kullanım (YAGNI Uygulaması)

public class Payment
{
    public void PayCreditCard() { /* ... */
    }

    public void PayBitcoin() { /* ... */
    }
    // "Gold" ile ödeme isteği gelirse, o zaman eklenir!
}

YAGNI Uygulamasında Dikkat Edilecekler

  • Proje başlarken yalnızca ihtiyaç olan özellikleri yaz.
  • Fazla generic veya reusable kod yazma hevesine kapılma.
  • Her parametre, method veya class gerçekten kullanılacak mı diye düşün.

9. YAGNI’nin Sınırları ve İstisnalar

Bazen, projenin mimari gereksinimleri için küçük bir öngörü eklemek mantıklı olabilir (örn. loglama altyapısı, exception yönetimi), ancak asla gereksiz detaya kaçılmamalı.

10. Pratik Uygulama ve Kod Refactoring

DRY – Pratik Refactoring

// Ayrı iş kuralları; yalnız benzer aritmetik DRY ihlali değildir.
decimal CalculateNet(decimal price)
{
    return price / 1.18m; // 18% varsayımsal oranla gross -> net
}
decimal CalculateTaxed(decimal price)
{
    return price * 1.18m; // net -> gross
}
// Genel çarpma helper’ı; iki domain kuralının otomatik yerine geçmez.
decimal CalculateWithRate(decimal price, decimal rate)
{
    return price * rate;
}

KISS – Pratik Refactoring

Printer p = new Printer();
p.Print("Merhaba");

// Yanlış (Gereksiz class)
public class Printer
{
    public void Print(string text)
    {
        Console.WriteLine(text);
    }
}
// Doğru (Sade)
Console.WriteLine("Merhaba");

YAGNI – Pratik Refactoring

// Yanlış (Ekstra parametreler ve methodlar)
public void Log(
    string message,
    int level,
    bool useAsync,
    string? context = null
)
{
    // Sadece message loglanacaksa fazlasına gerek yok
}
// Doğru (Kısa ve yeterli)
public void Log(string message)
{
    // ...
}

11. Kod İncelemesinde Dikkat Edilecekler

  • Kodda tekrar var mı? (DRY)
  • Fonksiyonlar gereğinden fazla soyutlanmış mı? (KISS)
  • Kullanılmayan method/class/parametre var mı? (YAGNI)
  • Kod yeni başlayan için anlaşılır mı?
  • Her fonksiyonun amacı açıkça belli mi?

12. En Sık Yapılan Hatalar

  • Farklı modüllerde aynı işin tekrar tekrar yapılması.
  • Her özelliğe ayrı interface, class ve abstraction yazılması.
  • Hiçbir zaman kullanılmayacak kodun projeye dahil edilmesi.
  • “Burası büyür” diye, gereksiz esneklik ve generic yapı kurmak.

13. Sıkça Sorulan Sorular

DRY, KISS ve YAGNI birbiriyle çelişir mi?
Bazen trade-off oluşur: DRY için ortaklaştırma KISS’i zorlaştırabilir; YAGNI gereksiz genişletme noktalarından kaçınmayı önerir. Ortak değişiklik nedeni ve bugünkü ihtiyaca göre karar verin.

Bu prensipler küçük projede de uygulanmalı mı?
Evet. Küçük projede başlamak, büyüyünce işini çok kolaylaştırır.

Fazla sadeleştirmek riskli mi?
Kodun amacını bozmadıkça sadeleştirmek avantaj sağlar.
Her kod satırının bir amacı olmalı.

14. Sonuç ve Pratik İpuçları

  • Bilgi tekrarını incele: Aynı iş kuralını birden fazla yerde güncellemeyi gerektiren tekrarları azalt.
  • Karmaşıklıktan kaç: Sade, açık ve doğrudan çözümleri tercih et.
  • Sadece ihtiyacın olanı kodla: Varsayımsal özellikleri ertele; gerekli güvenlik, test, bakım ve refactoring’i ihmal etme.

15. Kaynaklar

DRY, KISS ve YAGNI açısından invoice ve cart aynı aritmetiği bugün kullanıyor diye aynı policy değildir. Vergi örneğindeki 18% güncel yasal oranı temsil etmez; netten gross’a çarpma ile gross’tan nete bölme farklı işlemlerdir. ShippingCost yalnız gerçek compile-time sabitse const olur; değişen kargo ücreti configuration/policy gerektirir.

Kesitler ayrı alternatiflerdir; aynı adlı Payment tiplerini tek projeye birlikte eklemeyin. itemPrice ve tax çağıran kodun değerleridir. Payment/Log gövdelerindeki yorumlar uygulama yerine geçmez. Multiplier ve Printer tek seferlik kullanımda gereksiz görünebilir; mevcut contract, test veya farklı implementation ihtiyacı varsa sınıf/interface makul olur.

YAGNI güvenlik, gözlem ve otomatik testleri ertelemenin gerekçesi değildir. Fowler’ın kaynaklardaki yazısı refactoring ve testin değişebilir tasarımı mümkün kıldığını anlatır. Sabit/configuration ayrımını Magic String ve Magic Number rehberi ile birlikte değerlendirin.

By tanju.bozok

Senior .NET Engineer | Backend architecture, distributed systems & real-time communication