Yazılım dünyasında, kodumuzu düzenli ve anlaşılır tutmak çok önemlidir. Özellikle Nesne Yönelimli Programlama (OOP) kullanırken, sınıflarımızı nasıl tasarladığımız kodun gelecekteki bakımını ve geliştirilmesini doğrudan etkiler. İşte bu noktada SOLID prensipleri bize yol gösterir. SOLID’in ilk harfi olan ‘S’, Tek Sorumluluk Prensibi (Single Responsibility Principle — SRP) anlamına gelir.

Bu prensip, kulağa geldiği kadar basittir ama uygulaması yazılım kalitesi açısından büyük fark yaratır. Temelde, her sınıfın veya modülün sadece tek bir işi olması gerektiğini söyler.

Bu rehberde, SRP’nin ne demek olduğunu, neden önemli olduğunu ve Python’da nasıl uygulandığını basit ve anlaşılır bir dille açıklamaya çalışacağız.

Bölüm 1: Tek Sorumluluk Prensibi (SRP) Ne Demek?
Temel Kural
Bir sınıfın değişmesi için sadece tek bir nedeni olmalıdır.

Yani, bir sınıfı yazdığınızda veya değiştirdiğinizde kendinize şu soruyu sorun: “Bu sınıfı ileride hangi sebeplerle değiştirmem gerekebilir?” Eğer bu soruya birden fazla bağımsız cevap veriyorsanız (örneğin, “veritabanı değişirse DEĞİŞİR” ve “rapor formatı değişirse DEĞİŞİR”), o sınıf muhtemelen birden fazla sorumluluğa sahiptir ve SRP’yi ihlal ediyordur.

Daha basit bir ifadeyle:

Bir sınıf sadece tek bir iş yapmalı ve o işi iyi yapmalıdır.

“Sorumluluk” Ne Anlama Geliyor?

Buradaki sorumluluk, sınıfın yaptığı ana görev veya ilgilendiği ana konudur. Örneğin:

Kullanıcı bilgilerini yönetmek.
Veritabanına veri kaydetmek.
Bir raporu belirli bir formatta oluşturmak.
E-posta göndermek.
Matematiksel bir hesaplama yapmak.
SRP, bu farklı sorumlulukların farklı sınıflara veya modüllere ayrılmasını önerir.

Analoji: Mutfaktaki Araçlar

Mutfağınızı düşünün. Bir bıçağınız vardır (kesmek için), bir tencereniz vardır (pişirmek için), bir de süzgeciniz (süzmek için). Her aracın belirli, tek bir görevi vardır. Eğer tek bir aracınız olsaydı ve bu araç hem kesip, hem pişirip, hem de süzseydi, kullanımı çok karmaşık olurdu ve herhangi bir parçasını değiştirmek veya onarmak zorlaşırdı. SRP de sınıflarımızın böyle özel amaçlı araçlar gibi olmasını ister; her biri kendi işine odaklansın.

Bölüm 2: SRP Neden Önemli? Faydaları Neler?
Bir sınıfın tek bir işe odaklanması neden bu kadar önemli? Çünkü birçok faydası var:

Anlaşılırlık Artar: Tek iş yapan bir sınıfı anlamak, birçok farklı işi karışık şekilde yapan bir sınıfı anlamaktan çok daha kolaydır. Kod daha okunaklı hale gelir.
Bakım Kolaylaşır: Bir işleyişte değişiklik yapmanız gerektiğinde, sadece o işten sorumlu olan sınıfı değiştirirsiniz. Bu, diğer kısımları bozma riskinizi azaltır ve değişikliği daha hızlı yapmanızı sağlar. Örneğin, e-posta gönderme yönteminiz değişirse, sadece e-posta ile ilgili sınıfı güncellersiniz.
Test Etmek Basitleşir: Küçük ve tek bir işe odaklanmış sınıfları test etmek daha kolaydır. Sadece o sınıfın sorumluluğunu test edersiniz, birçok farklı şeyi aynı anda test etmeye çalışmazsınız.
Tekrar Kullanılabilirlik Artar: Belirli bir işi yapan küçük bir sınıfı, başka projelerde veya aynı projenin farklı yerlerinde kullanma olasılığınız daha yüksektir. Her işi yapan dev bir sınıfı başka yerde kullanmak zordur.
Daha Az Hata Riski: Bir sınıfı değiştirdiğinizde, sadece tek bir sorumluluğu etkilediğiniz için, beklenmedik yan etkilerle karşılaşma ve başka yerleri bozma ihtimaliniz azalır.
Takım Çalışması Kolaylaşır: Farklı geliştiriciler, farklı sorumluluklara sahip farklı sınıflar üzerinde daha rahat çalışabilirler, birbirlerinin kodunu bozma riski azalır.
Kısacası, SRP kodunuzu daha temiz, daha düzenli ve zamanla yönetmesi daha kolay hale getirir.

Bölüm 3: SRP İhlalini Nasıl Anlarız?
Bir sınıfın SRP’yi ihlal edip etmediğini anlamanıza yardımcı olabilecek bazı işaretler:

Sınıf Çok Büyükse: Bir sınıf dosyası yüzlerce veya binlerce satır kod içeriyorsa, muhtemelen çok fazla iş yapıyordur.
Sınıfa İsim Vermek Zorsa: Sınıfa yaptığı işi anlatan tek ve net bir isim bulamıyorsanız (örn: KullaniciVeriVeRaporlamaYonetimi), birden fazla iş yapıyor olabilir.
Çok Fazla import: Sınıfınız, birbiriyle alakasız görünen birçok farklı kütüphaneyi (örn: hem veritabanı, hem e-posta, hem de grafik kütüphanesi) import ediyorsa dikkatli olun.
“Tanrı Sınıfı” (God Class): Neredeyse her şeyi bilen ve her şeyi yapan bir sınıf varsa, bu klasik bir SRP ihlalidir.
Değişiklik Sebepleri Çoksa: Yukarıda bahsettiğimiz gibi, sınıfı değiştirmek için birden fazla farklı sebep (farklı iş kuralları, farklı teknolojiler, farklı kullanıcı istekleri) aklınıza geliyorsa SRP ihlal ediliyor olabilir.
Açıklamak Gerekirse: Sınıfın ne yaptığını anlatırken “hem bunu yapar, hem de şunu yapar…” gibi ifadeler kullanıyorsanız, sorumlulukları ayırmayı düşünmelisiniz.
Bölüm 4: Python’da SRP Uygulama Örneği
Şimdi basit bir örnek üzerinden SRP ihlalini görelim ve sonra düzeltelim.

4.1. SRP İhlali Yapan Örnek
Diyelim ki bir Kitap sınıfımız var ve bu sınıf hem kitabın bilgilerini tutuyor hem de kitabın bilgilerini bir dosyaya kaydediyor.

--- SRP İHLALİ ---

class Kitap:
def init(self, ad, yazar, icerik):
self.ad = ad
self.yazar = yazar
self.icerik = icerik
def bilgileri_goster(self):
print(f"Ad: {self.ad}")
print(f"Yazar: {self.yazar}")
# İçeriği göstermek de ayrı bir sorumluluk olabilir ama şimdilik kalsın.
# print(f"İçerik: {self.icerik[:50]}...")
# BU KISIM SRP İHLALİ YARATIYOR!
# Kitap sınıfının sorumluluğu kitabın bilgilerini tutmaktır,
# dosyaya nasıl kaydedileceğini bilmek DEĞİLDİR.
def dosyaya_kaydet(self, dosya_adi):
"""Kitap içeriğini bir dosyaya kaydeder."""
try:
with open(dosya_adi, 'w', encoding='utf-8') as f:
f.write(f"--- {self.ad} ---\n")
f.write(f"Yazar: {self.yazar}\n")
f.write("---\n")
f.write(self.icerik)
print(f"'{self.ad}' kitabı '{dosya_adi}' dosyasına kaydedildi.")
except IOError as e:
print(f"Dosya kaydetme hatası: {e}")

Kullanım

kitap1 = Kitap("Denemeler", "Montaigne", "İlk deneme içeriği...")
kitap1.bilgileri_goster()
kitap1.dosyaya_kaydet("denemeler.txt") # Kitap nesnesi kaydetme işini de yapıyor!
Neden İhlal Var?

Kitap sınıfının değişmesi için iki neden var:
Kitabın temel bilgileri (ad, yazar) değişirse.
Kitabı dosyaya kaydetme şekli (formatı, hata yönetimi vb.) değişirse.
Kitabın bilgilerini tutmak (veri modeli olmak) ile veriyi bir yere kaydetmek (kalıcılık sağlamak) farklı sorumluluklardır.
4.2. SRP’ye Uygun Çözüm
Çözüm, sorumlulukları ayırmaktır. Kitap sınıfı sadece kitap bilgilerini tutmalı, kaydetme işlemi için ayrı bir sınıf (veya fonksiyon) olmalıdır.

--- SRP UYUMLU ÇÖZÜM ---

Sorumluluk 1: Kitap verilerini tutmak

class Kitap:
def init(self, ad, yazar, icerik):
self.ad = ad
self.yazar = yazar
self.icerik = icerik
def bilgileri_goster(self):
print(f"Ad: {self.ad}")
print(f"Yazar: {self.yazar}")

Sorumluluk 2: Kitabı bir yere kaydetmek (Kalıcılık)

class KitapKaydedici:
def dosyaya_kaydet(self, kitap: Kitap, dosya_adi: str): # Kitap nesnesini parametre olarak alır
"""Verilen Kitap nesnesini dosyaya kaydeder."""
if not isinstance(kitap, Kitap):
print("Hata: Sadece Kitap nesneleri kaydedilebilir.")
return
try:
with open(dosya_adi, 'w', encoding='utf-8') as f:
f.write(f"--- {kitap.ad} ---\n")
f.write(f"Yazar: {kitap.yazar}\n")
f.write("---\n")
f.write(kitap.icerik)
print(f"'{kitap.ad}' kitabı '{dosya_adi}' dosyasına kaydedildi.")
except IOError as e:
print(f"Dosya kaydetme hatası: {e}")
# İleride başka kaydetme metotları eklenebilir (örn: veritabanına_kaydet)
# def veritabanina_kaydet(self, kitap: Kitap, db_baglantisi):
# pass

Kullanım

kitap2 = Kitap("Yabancı", "Albert Camus", "Bugün annem öldü...")
kaydedici = KitapKaydedici() # Kaydetme işini yapacak ayrı bir nesne
kitap2.bilgileri_goster()

Kaydetme işlemi için Kitap nesnesini ve dosya adını kaydediciye veriyoruz

kaydedici.dosyaya_kaydet(kitap2, "yabanci.txt")

Şimdi Kitap sınıfı sadece kitapla ilgili, KitapKaydedici ise sadece kaydetmeyle ilgili.

Eğer kaydetme formatı değişirse, sadece KitapKaydedici sınıfını değiştiririz.

Eğer kitaba yeni bir özellik (örn: sayfa sayısı) eklenirse, sadece Kitap sınıfını değiştiririz.

Bu ayrım sayesinde kod daha modüler, anlaşılır ve bakımı daha kolay hale gelir.

Bölüm 5: SRP ve Diğer Prensiplerle İlişkisi
SRP, diğer SOLID prensipleriyle ve genel OOP kavramlarıyla yakından ilişkilidir:

Açık/Kapalı Prensibi (OCP): SRP’ye uymak genellikle OCP’yi uygulamayı kolaylaştırır. Tek sorumluluğu olan bir sınıfın, yeni özellikler için değiştirilmesi yerine genişletilmesi (örneğin kalıtım veya kompozisyon ile) daha olasıdır.
İçsel Uyum (Cohesion): SRP, yüksek içsel uyumu teşvik eder. Bir sınıfın tüm üyeleri tek bir amaca hizmet ettiği için birbirleriyle daha ilişkili olurlar.
Bağlantı (Coupling): SRP dolaylı olarak bağlantıyı azaltmaya yardımcı olur. Daha küçük, odaklanmış sınıflar genellikle daha az şeye bağımlı olurlar ve daha az sınıf onlara bağımlı olur.
Kapsülleme: Kapsülleme, veri ve davranışları bir araya getirirken, SRP bu bir araya getirmenin ne kadar odaklı olması gerektiğini söyler.
Bölüm 6: Potansiyel Tuzaklar ve Dikkat Edilmesi Gerekenler
Aşırıya Kaçmak: SRP’yi çok katı yorumlayıp her küçük işlev için ayrı bir sınıf oluşturmak, gereksiz sayıda sınıfa ve karmaşık ilişkilere yol açabilir (“Class Explosion”). Doğru dengeyi bulmak önemlidir. Birbiriyle çok yakından ilişkili ve her zaman birlikte değişen birkaç küçük görev bazen tek bir sınıfta kalabilir.
“Sorumluluk” Görecelidir: Daha önce de belirtildiği gibi, neyin “tek bir sorumluluk” olduğu projenin bağlamına ve bakış açısına göre değişebilir. Önemli olan, “değişme nedenlerini” analiz etmektir.
Erken Optimizasyon Gibi Görünebilir: Çok basit bir uygulama için sorumlulukları en baştan ayırmak gereksiz gibi gelebilir. Ancak uygulamanın büyüme potansiyeli varsa, SRP’yi baştan düşünmek uzun vadede faydalı olacaktır.
Bölüm 7: Sonuç: Odaklanmış Sınıfların Gücü
Tek Sorumluluk Prensibi (SRP), SOLID prensiplerinin ilk ve belki de anlaşılması en kolay olanıdır, ancak etkisi derindir. Temelde bize şunu hatırlatır: Sınıflarınızı odaklı tutun. Her sınıfın net, tek bir amacı olsun.

Bu basit kurala uymak, kodumuzun kalitesini önemli ölçüde artırır:

Daha okunabilir ve anlaşılır kod.
Daha kolay test edilebilir birimler.
Daha az hata riskiyle yapılabilen değişiklikler ve bakımlar.
Daha yüksek yeniden kullanılabilirlik potansiyeli.
Daha iyi organize edilmiş ve modüler bir yapı.
Python’da SRP’yi uygulamak, sınıflarımızı dikkatlice tasarlamayı, farklı sorumlulukları fark etmeyi ve gerektiğinde bu sorumlulukları ayrı sınıflara veya fonksiyonlara/modüllere ayırmayı gerektirir. Bu, başlangıçta biraz daha fazla çaba gerektirse de, projenin yaşam döngüsü boyunca katlanarak geri dönen bir yatırımdır. Odaklanmış sınıflar, daha sağlam ve sürdürülebilir yazılımların temelini oluşturur.

Abdulkadir Güngör - Kişisel WebSite
Abdulkadir Güngör - Kişisel WebSite
Abdulkadir Güngör - Özgeçmiş
Github
Github
Linkedin