Aikido

Sınıflar neden tek sorumluluk ilkesine uymalıdır?

Okunabilirlik

Kural
Sınıflar şöyle olmalıdır tek sorumluluğu olmalıdır.
Sınıflar birden fazla birden fazla konuları ihlal
şunu Tek Tek ilkesini ihlal eder.

Desteklenen diller: JS, TS, PY, JAVA, C/C++,
C#, Swift/Objective C, Ruby. PHP, Kotlin, 
Scala, Rust, Haskell, Groovy, Dart. Julia,
Elixit, Klojure, OCaml, Delphi

Giriş

Fazla iş yapan sınıflar darboğazlara dönüşür. Kimlik doğrulama, e-postalar ve geçerlilik denetimini yürüten bir sınıf, herhangi bir konu değiştiğinde değişiklik gerektirir ve bu da alakasız işlevlerde arızalara yol açma riskini doğurur. Test sırasında, tek bir yönü test ediliyor olsa bile sınıfın tamamının simülasyonu gerekir. Tek Sorumluluk İlkesi, bir sınıfın değişmesi için yalnızca tek bir neden olması gerektiğini belirtir.

Neden önemli?

Kodun bakım kolaylığı: Birden fazla sorumluluğa sahip sınıflar daha sık değişir; çünkü herhangi bir sorumluluğun gelişimi sınıfın tamamını etkiler.

Test karmaşıklığı: Birden fazla sorumluluğa sahip sınıfları test etmek, tek bir özelliği test etmek için bile olsa tüm bağımlılıkların simüle edilmesini gerektirir.

Yeniden Kullanılabilirlik: Tüm bağımlılıkları da beraberinde getirmeden tek bir sorumluluğu ayıramazsınız. Geliştiriciler, birden fazla sorumluluğa sahip sınıfları birbirinden ayırmak yerine kodu tekrarlamayı tercih ederler.

Ekip koordinasyonu: Aynı sınıf üzerinde farklı özellikler için çalışan birden fazla geliştirici, sık sık birleştirme çakışmalarına yol açar. Tek sorumluluklu sınıflar, çakışma olmadan paralel geliştirmeye olanak tanır.

Kod örnekleri

❌ Uygun değil:

class UserManager {
    async createUser(userData) {
        const user = await db.users.insert(userData);
        await this.sendWelcomeEmail(user.email);
        await this.logEvent('user_created', user.id);
        await cache.set(`user:${user.id}`, user);
        return user;
    }

    async sendWelcomeEmail(email) {
        const template = this.loadEmailTemplate('welcome');
        await emailService.send(email, template);
    }

    async logEvent(event, userId) {
        await analytics.track(event, { userId, timestamp: Date.now() });
    }
}

Neden yanlış: Bu sınıf, veritabanı işlemlerini, e-posta gönderimini, günlük kaydı ve önbelleklemeyi yönetir. E-posta şablonlarında, günlük kayıt biçimlerinde veya önbellek stratejisinde yapılacak her türlü değişiklik, bu sınıfın değiştirilmesini gerektirir. Kullanıcı oluşturma işlemini test etmek, e-posta hizmetlerini, analiz sistemlerini ve önbelleği simüle etmek anlamına gelir; bu da testlerin yavaşlamasına ve kırılgan hale gelmesine neden olur.

✅ Uygunluk:

class UserRepository {
    async create(userData) {
        return await db.users.insert(userData);
    }
}

class EmailNotificationService {
    async sendWelcomeEmail(email) {
        const template = await this.templateLoader.load('welcome');
        return await this.emailSender.send(email, template);
    }
}

class UserEventLogger {
    async logCreation(userId) {
        return await this.analytics.track('user_created', {
            userId,
            timestamp: Date.now()
        });
    }
}

class UserService {
    constructor(repository, emailService, eventLogger, cache) {
        this.repository = repository;
        this.emailService = emailService;
        this.eventLogger = eventLogger;
        this.cache = cache;
    }

    async createUser(userData) {
        const user = await this.repository.create(userData);
        await Promise.all([
            this.emailService.sendWelcomeEmail(user.email),
            this.eventLogger.logCreation(user.id),
            this.cache.set(`user:${user.id}`, user)
        ]);
        return user;
    }
}

Bunun önemi: Her sınıfın tek bir net sorumluluğu vardır: veri kalıcılığı, e-posta gönderimi, olay günlüğü kaydı veya koordinasyon. E-posta şablonlarında yapılan değişiklikler yalnızca E-posta Bildirim Hizmeti. Kullanıcı oluşturma işlevinin test edilmesinde, bağımlılıklar için basit yedek kodlar kullanılabilir. Sınıflar, farklı özellikler arasında bağımsız olarak yeniden kullanılabilir.

Sonuç

Tek Sorumluluk İlkesi, sınıfları olabildiğince küçük hale getirmekle ilgili değildir; her sınıfın değişmesi için tek ve net bir neden olmasını sağlamaktır. Bir sınıf birden fazla konuyu ele almaya başladığında, her bir sorumluluğu odaklanmış bir arayüze sahip kendi sınıfına ayırarak yeniden yapılandırın. Bu, alakasız işlevler arasında zincirleme değişikliklere yol açmadan kodun test edilmesini, bakımının yapılmasını ve geliştirilmesini kolaylaştırır.

Sık Sorulan Sorular

Sorularınız mı var?

Bir sınıfın çok fazla sorumluluğu olduğunu nasıl anlarım?

Değişiklik gerektiren birçok nedeni olan sınıfları arayın. E-posta mantığını, günlük kaydı biçimini ve veritabanı şemasını değiştirmek için hepsinde aynı sınıfın değiştirilmesi gerekiyorsa, bu sınıfın sorumlulukları çok fazladır. Yöntem adlarını kontrol edin: Aynı sınıfta sendEmail(), logEvent() ve validateData() gibi birbiriyle ilgisiz fiilleri kapsıyorlarsa, bu bir uyarı işaretidir. 300-400 satırdan fazla olan sınıflar genellikle çoklu sorumluluklara işaret eder, ancak boyut tek başına kesin bir gösterge değildir.

Sınıfları bölmek, daha fazla dosya ve karmaşıklığa yol açmaz mı?

Dosya sayısının fazla olması, karmaşıklığın da fazla olduğu anlamına gelmez. Her biri 50 satırdan oluşan ve belirli bir amaca odaklanmış on sınıf, her şeyi tek başına üstlenen 500 satırlık bir sınıftan daha kolay anlaşılır. Önemli olan, her sınıfın basit olması ve net bir amaca sahip olmasıdır. Modern IDE’lerdeki gezinme özellikleri sayesinde dosya sayısı önemsiz hale gelir. Karmaşıklığın azalması, konuyla ilgisi olmayan unsurları dikkate almadan her sınıfı bağımsız olarak değerlendirebilme imkânından kaynaklanır.

Peki ya doğal olarak birden fazla işlemi koordine etmesi gereken sınıflar ne olacak?

Koordinasyon başlı başına bir sorumluluktur. Bir UserService sınıfı, UserRepository, EmailService ve EventLogger’a yapılan çağrıları, bu işlevleri kendisi uygulamadan koordine edebilir. Buna “orkestratör” veya “fasad” kalıbı denir. Aradaki fark, orkestratörün birden fazla işlevi doğrudan uygulamak yerine, bu işlevleri uzmanlaşmış sınıflara devretmesidir. Bu, iş mantığı değil, ince bir bağlayıcı koddur.

Bu ilke, statik yöntemlere sahip yardımcı sınıflara nasıl uygulanır?

Yardımcı sınıflar, tek sorumluluk ilkesini ihlal etmeye özellikle yatkındır; çünkü bunlara alakasız statik yöntemler eklemeye devam etmek kolaydır. Bir StringUtils sınıfı, başlangıçta biçimlendirme yardımcı yöntemleriyle başlayıp zamanla doğrulama, ayrıştırma, şifreleme ve kodlama işlevlerini de içerecek şekilde büyüyebilir. Bunları StringFormatter, StringValidator ve StringEncoder gibi odaklanmış yardımcı sınıflara ayırın. Her birinin birbiriyle ilişkili ve tutarlı bir işlem kümesi vardır.

Bu ilkeyi ihlal eden mevcut sınıfları nasıl yeniden düzenleyebilirim?

Öncelikle sınıf içindeki farklı sorumlulukları belirleyin. En kolay olanı ilk olarak yeni bir sınıfa ayırın, testleri güncelleyin ve her şeyin çalıştığını doğrulayın. Büyük bir yeniden yapılandırma girişiminde bulunmak yerine, bu işlemi yinelemeli olarak tekrarlayın. “Strangler Fig” desenini kullanın: yeni, tek sorumluluklu sınıflar oluşturun ve kodu eski sınıftan kademeli olarak bu sınıflara taşıyın. Eski sınıf boşaldığında veya asgari düzeye indiğinde, onu kullanımdan kaldırın. Her adım, çalışan ve test edilebilir bir artış olmalıdır.

Tek sorumluluk, tek yöntem anlamına mı gelir?

Hayır. Bir sınıf, tüm yöntemler aynı sorumlulukla ilişkili olduğu sürece birden fazla yönteme sahip olabilir. Bir UserRepository sınıfı, create(), update(), delete() ve findById() yöntemlerine sahip olabilir; çünkü bu yöntemlerin tümü, kullanıcı verilerinin kalıcılığı gibi tek bir sorumluluğu yerine getirir. Bu yöntemler, aynı konunun birbiriyle uyumlu varyasyonlarıdır; ayrı konuların bir araya getirilmiş hali değildir.

Şimdi güvenliğinizi sağlayın

Kodunuzu, bulutunuzu ve çalışma zamanınızı tek bir merkezi sistemde güvenceye alın.
Güvenlik açıklarını otomatik olarak hızla bulun ve düzeltin.

Kredi kartı gerekmez | Tarama sonuçları 32 saniyede.