C# ile Clean Code Prensipleri
C# ile clean code prensiplerini öğrenin. Okunabilir, sürdürülebilir ve bakımı kolay kod yazma teknikleri örneklerle anlatılıyor.
Clean Code (Temiz Kod), sadece çalışan değil, aynı zamanda okunabilir, sürdürülebilir ve genişletilebilir kod yazma felsefesidir. “Kod bir kere yazılır ama binlerce kez okunur.” prensibinden hareketle, temiz kodun amacı yalnızca hatasız bir program üretmek değil, gelecekte o kodu okuyacak kişilerin (hatta kendimizin) onu kolayca anlayabilmesini sağlamaktır. Bu makalede C# dilinde temiz kod yazmanın temel prensiplerini ve pratik uygulama örneklerini ele alıyoruz.
1. Anlamlı İsimlendirme (Meaningful Naming)
Değişken, metot ve sınıf isimleri kodun okunabilirliğini doğrudan etkiler. Kısa ama anlamsız isimler yerine açık, amaca yönelik isimler kullanın.
// Kötü Örnek
int x = 5;
var lst = new List<string>();
void DoIt() { ... }
// İyi Örnek
int retryCount = 5;
List<string> customerNames = new();
void ProcessOrder() { ... }
- Değişkenler: Neyi temsil ettiğini net belirtin (
count,totalPricevb.). - Metotlar: Eylem (fiil) odaklı isimler verin (
SaveFile(),CalculateTax()). - Sınıflar: Bir kavramı veya sorumluluğu tanımlasın (
UserRepository,PaymentService).
2. Tek Sorumluluk Prensibi (Single Responsibility Principle)
Her sınıf veya metodun yalnızca tek bir amacı olmalıdır. Bir metot hem veritabanına yazıyor hem e-posta gönderiyorsa, muhtemelen iki farklı işi aynı anda yapıyordur.
// Kötü Örnek: Birden fazla iş
public class OrderService
{
public void CompleteOrder(Order order)
{
SaveToDatabase(order);
SendEmail(order);
}
}
// İyi Örnek: Ayrılmış sorumluluklar
public class OrderRepository
{
public void Save(Order order) { ... }
}
public class EmailService
{
public void SendOrderConfirmation(Order order) { ... }
}
Her sınıf tek bir sebep yüzünden değişmeli. Bu hem bakımı kolaylaştırır hem test edilebilirliği artırır.
3. Kısa ve Odaklı Metotlar
Uzun metotlar, anlam karmaşası ve hata olasılığını artırır. Her metot, yalnızca tek bir işi yapan birkaç satırlık birim olmalıdır.
// Kötü Örnek
public void Process()
{
// 100 satırdan fazla iş mantığı...
}
// İyi Örnek
public void Process()
{
Validate();
CalculateTotal();
SaveChanges();
NotifyCustomer();
}
Metotlar küçük ve açıklayıcı olduğunda, test etmek, yeniden kullanmak ve hata ayıklamak kolaylaşır.
4. Kod Tekrarından Kaçının (DRY – Don’t Repeat Yourself)
Aynı kodu tekrar tekrar yazmak, bakımı zorlaştırır ve hataya açık hale getirir. Ortak işlemleri metot, yardımcı sınıf veya extension olarak ayırın.
// Kötü Örnek
if (age >= 18) Console.WriteLine("Reşit");
if (age >= 18) SendMail();
// İyi Örnek
bool IsAdult(int age) => age >= 18;
if (IsAdult(age)) { Console.WriteLine("Reşit"); SendMail(); }
Kod tekrarı azaldıkça değişikliklerin etkisi küçülür ve hata riski düşer.
5. Yorum Satırlarını Azaltın, Kodun Kendisi Açıklayıcı Olsun
Gereksiz yorumlar kodun güncelliğini kaybettirir. Kod zaten ne yaptığını anlatabilmelidir.
// Kötü Örnek
// Kullanıcının adını yazdır
Console.WriteLine(user.Name);
// İyi Örnek
Console.WriteLine(user.FullName);
Yorumlar sadece “neden” yapıldığını anlatmalı, “ne yaptığını” değil.
6. Sabitler ve Magic Number Kullanımı
Kod içinde doğrudan sayı veya string değerleri kullanmak (“magic number”) okunabilirliği bozar. Bunları sabit değişkenlerle tanımlayın.
// Kötü Örnek
if (speed > 120) Console.WriteLine("Aşırı hız!");
// İyi Örnek
const int MaxSpeed = 120;
if (speed > MaxSpeed) Console.WriteLine("Aşırı hız!");
7. Guard Clauses (Koruma Kontrolleri) Kullanın
İç içe if blokları yerine, erken çıkış yaparak kodun okunabilirliğini artırın.
// Kötü Örnek
if (user != null)
{
if (user.IsActive)
{
Process(user);
}
}
// İyi Örnek
if (user is null) return;
if (!user.IsActive) return;
Process(user);
Guard clause yapısı, “erken döndürme” (early return) ile kod akışını sadeleştirir.
8. Bağımlılıkları Enjekte Edin (Dependency Injection)
Kod içinde doğrudan nesne oluşturmaktan kaçının. Bunun yerine bağımlılıkları dışarıdan alın; bu test edilebilirliği ve esnekliği artırır.
// Kötü Örnek
public class NotificationService
{
private EmailSender sender = new EmailSender();
public void Notify() => sender.Send();
}
// İyi Örnek
public class NotificationService
{
private readonly IEmailSender _sender;
public NotificationService(IEmailSender sender) => _sender = sender;
public void Notify() => _sender.Send();
}
Bu yaklaşım, Inversion of Control (IoC) ve Dependency Injection (DI) prensiplerinin temelidir.
9. Exception Yönetimi
Exception yakalamak zorunda değilseniz yakalamayın; yakalıyorsanız anlamlı şekilde yönetin.
// Kötü Örnek
try
{
Save();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
// İyi Örnek
try
{
Save();
}
catch (SqlException ex)
{
_logger.LogError(ex, "Veritabanı hatası oluştu.");
throw; // Üst katmana fırlat
}
Geniş kapsamlı catch (Exception) blokları hata yönetimini zorlaştırır.
10. SOLID Prensipleri ile Uyum
Temiz kod, SOLID prensipleriyle paralel yürür:
- S – Single Responsibility: Her sınıf tek bir iş yapsın.
- O – Open/Closed: Yeni davranışlar için açık, mevcut kod için kapalı olsun.
- L – Liskov Substitution: Türev sınıflar temel sınıfların yerine geçebilmeli.
- I – Interface Segregation: Gereksiz metotları içermeyen küçük arayüzler.
- D – Dependency Inversion: Somut sınıfa değil, soyuta bağımlı olun.
Bu prensipler, temiz kodun yapı taşlarını oluşturur.
11. Gereksiz Karmaşıklıktan Kaçının (KISS & YAGNI)
- KISS (Keep It Simple, Stupid): Gereksiz soyutlama veya optimizasyon yapmayın.
- YAGNI (You Ain’t Gonna Need It): Şu anda ihtiyaç olmayan özellikleri yazmayın.
// Kötü Örnek
public interface IAnimal { void Bark(); void Fly(); void Swim(); }
// İyi Örnek
public interface IDog { void Bark(); }
public interface IFish { void Swim(); }
Kod basit, amaca yönelik ve gereğinden fazla genelleştirilmemiş olmalıdır.
12. Formatlama ve Tutarlılık
- Kod satır uzunluklarını makul tutun (maks. 120 karakter).
- Gereksiz boşluk, satır veya tab kullanmayın.
- Auto-format (Ctrl + K + D) veya EditorConfig ile standart belirleyin.
// .editorconfig örneği
[*.cs]
indent_size = 4
trim_trailing_whitespace = true
insert_final_newline = true
Örnek: Sipariş Servisinin Temizlenmesi
Aşağıdaki örnekte karmaşık ve bakımı zor bir kod parçası, temiz kod prensipleriyle yeniden düzenlenmiştir.
// Kötü Örnek
public class OrderManager
{
public void Process(Order order)
{
if (order.Total <= 0) throw new Exception("Tutar hatalı");
Console.WriteLine("Sipariş işlendi: " + order.Id);
File.AppendAllText("log.txt", DateTime.Now + " - " + order.Id);
}
}
// İyi Örnek
public interface ILogger { void Log(string msg); }
public class FileLogger : ILogger
{
public void Log(string msg) => File.AppendAllText("log.txt", $"{DateTime.Now} - {msg}\n");
}
public class OrderValidator
{
public void Validate(Order order)
{
if (order.Total <= 0) throw new ArgumentException("Tutar 0'dan büyük olmalı");
}
}
public class OrderService
{
private readonly ILogger _logger;
private readonly OrderValidator _validator;
public OrderService(ILogger logger, OrderValidator validator)
{
_logger = logger;
_validator = validator;
}
public void Process(Order order)
{
_validator.Validate(order);
Console.WriteLine($"Sipariş işlendi: {order.Id}");
_logger.Log($"Order {order.Id} işlendi.");
}
}
Artık her sınıfın sorumluluğu net, test edilebilir ve okunabilir hale gelmiştir.
TL;DR
- Temiz kod, okunabilirlik ve sürdürülebilirlik demektir.
- Anlamlı isimler, kısa metotlar, tek sorumluluk ve tekrarsız yapı anahtardır.
- Yorum yerine iyi isimlendirme, guard clauses ve DI tercih edin.
- Karmaşıklığı azaltın (KISS, YAGNI) ve SOLID prensiplerine uyun.
- Kodunuzu hem insanlar hem makineler için yazın.
İlişkili Makaleler
C# FluentValidation Kullanımı
C#’ta FluentValidation kullanarak veri doğrulama kurallarını öğrenin. Temiz ve sürdürülebilir validation senaryoları.
C# ile SOLID Prensipleri
C# örnekleriyle SOLID prensiplerinin uygulanışı: daha esnek, sürdürülebilir ve test edilebilir kod tasarımları.
C# Katmanlı Mimari ve Clean Architecture
C#’ta katmanlı mimari ve Clean Architecture yaklaşımını öğrenin. Bağımlılık yönetimi ve sürdürülebilir proje yapıları anlatılıyor.
C# Metotlar ve Parametre Kullanımı
C#’ta metot tanımlama ve parametre kullanımını öğrenin. Değer ve referans parametreleri, varsayılan parametreler ve örneklerle.
C# Unit Test Yazımı (xUnit, NUnit, MSTest)
C#’ta unit test yazmayı öğrenin. xUnit, NUnit ve MSTest ile test senaryoları oluşturarak güvenilir yazılım geliştirin.