Takip et

Taming the “God Component”: A Framework-Agnostic Guide to the Component Responsibility Score (CRS)

Yazılım geliştirmede, özellikle büyük ve karmaşık uygulamalarda, bileşenlerin sorumluluklarını yönetmek bazen içinden çıkılmaz bir hal alabilir. Bu makale, “Tanrı Bileşen” sorununu ve Bileşen Sorumluluk Skoru (CRS) kavramını derinlemesine inceleyerek projelerinizde modülerliği nasıl artırabileceğinizi gösteriyor.

Her geliştiricinin kariyerinde en az bir kez karşılaştığı, uygulamadaki birçok işlevi tek başına üstlenen, aşırı büyük ve karmaşık bir bileşen türü vardır: “Tanrı Bileşen” (God Component). Bu tür bileşenler, adeta bir tanrı gibi her şeyi bilir, her şeye müdahale eder ve uygulamanın en kritik işlevlerini merkezileştirir. Başlangıçta basit bir ihtiyacı karşılamak üzere tasarlanmış olsa da, zamanla yeni özellikler ve gereksinimlerle şişerek devasa bir yapıya dönüşürler. Örneğin, bir kullanıcı arayüzü (UI) bileşeni düşünün; başlangıçta sadece veri göstermekle yükümlüyken, zamanla veri alma, gönderme, durum yönetimi, doğrulama, hatta yetkilendirme gibi onlarca farklı sorumluluğu üzerine alabilir. Bu durum, yazılım geliştirme sürecinde ciddi sorunlara yol açar.

Peki, bir “Tanrı Bileşen”in ortaya çıkardığı sorunlar nelerdir? Öncelikle, bakım kolaylığını derinden etkiler. Tek bir dosyada yüzlerce, hatta binlerce satır kodun bir araya gelmesi, herhangi bir hatayı bulmayı veya yeni bir özellik eklemeyi kabusa çevirir. Kodun hangi kısmının hangi işlevi yerine getirdiğini anlamak bile önemli bir çaba gerektirir. İkinci olarak, test edilebilirlik büyük ölçüde azalır. Çok sayıda sorumluluğu olan bir bileşeni izole bir şekilde test etmek neredeyse imkansızdır. Her test, bileşenin tüm bağımlılıklarını ve işlevlerini dikkate almak zorunda kalır, bu da testlerin yavaşlamasına ve kırılgan hale gelmesine neden olur. Üçüncü olarak, yeniden kullanılabilirlik ortadan kalkar. Bir “Tanrı Bileşen” o kadar çok özel işlevi içerir ki, uygulamanın farklı bir yerinde veya başka bir projede bu bileşeni doğrudan kullanmak genellikle mümkün olmaz. Çünkü ihtiyaç duyulmayan birçok ek işlevselliği de beraberinde getirir. Son olarak, ölçeklenebilirlik ve performans da olumsuz etkilenir. Gereksiz bağımlılıklar ve karmaşık mantık, uygulamanın yavaşlamasına ve hatta bellek sorunlarına yol açabilir. Bu yüzden, yazılım mimarisi açısından sağlıklı bir yapı kurmak ve sürdürülebilir bir geliştirme süreci sağlamak için bu tür bileşenlerden kaçınmak kritik öneme sahiptir. Bu sorunun üstesinden gelmek için sistemli bir yaklaşıma ihtiyacımız var ve burada devreye Bileşen Sorumluluk Skoru (CRS) giriyor.

Bileşen Sorumluluk Skoru (CRS) Nedir ve Neden Önemlidir?

Bileşen Sorumluluk Skoru (CRS), bir bileşenin ne kadar fazla sorumluluğa sahip olduğunu niceliksel olarak ölçmek için geliştirilmiş framework-agnostik bir ölçüttür. Basitçe ifade etmek gerekirse, bir bileşenin sahip olduğu farklı işlevsel veya mantıksal sorumlulukların sayısının bir göstergesidir. Amacımız, CRS değerini mümkün olduğunca düşük tutmaktır; çünkü düşük bir CRS, bileşenin daha odaklı, daha anlaşılır, daha test edilebilir ve dolayısıyla daha sürdürülebilir olduğu anlamına gelir. Bu skor, “Tek Sorumluluk Prensibi” (Single Responsibility Principle – SRP) gibi SOLID prensiplerinin somut bir uygulamasını sunar ve yazılım kalitesini artırmak için pratik bir yol haritası çizer.

CRS’in önemi birkaç ana başlıkta özetlenebilir:

  1. Nesnel Değerlendirme: “Bu bileşen çok mu büyük?” sorusuna “Evet, çünkü CRS değeri 7, hedefimiz 2’nin altında olması!” gibi somut bir cevap vermemizi sağlar. Bu, takım içinde daha net tartışmalar yapılmasına ve refactoring kararlarının daha kolay alınmasına yardımcı olur.
  2. Erken Uyarı Sistemi: Geliştirme sürecinin başlarında bileşenlerin CRS değerlerini düzenli olarak kontrol ederek, “Tanrı Bileşen” oluşumunu henüz başlangıç aşamasında tespit edip önleyebiliriz. Bu, maliyetli ve zaman alıcı refactoring işlemlerinden kaçınmamızı sağlar.
  3. Sürdürülebilirliğin Anahtarı: Düşük CRS’li bileşenler, hata ayıklamayı kolaylaştırır, yeni özellik ekleme sürecini hızlandırır ve genel olarak kod tabanının yaşam döngüsünü uzatır. Her bileşen kendi küçük işini en iyi şekilde yapmaya odaklanır.
  4. Ekip Verimliliği: Bileşenler daha küçük ve anlaşılır olduğunda, farklı ekip üyeleri aynı bileşen üzerinde daha az çakışma ile çalışabilir. Ayrıca, yeni ekip üyelerinin projeye adaptasyon süresi kısalır çünkü kodun karmaşıklığı azalır.
  5. Framework-Agnostik Yaklaşım: CRS, belirli bir programlama diline, kütüphaneye veya framework’e (React, Angular, Vue, Svelte vb.) bağlı değildir. Temel yazılım mühendisliği prensipleri üzerine inşa edildiği için her türlü projede uygulanabilir. Bu evrensellik, onu çok değerli bir araç haline getirir.

CRS, karmaşık yazılım metrikleri olan Döngüsel Karmaşıklık (Cyclomatic Complexity) veya Kaynak Kodu Satır Sayısı (SLOC) gibi değerlere kıyasla daha sezgisel ve doğrudan “sorumluluk” kavramına odaklanır. Bir bileşenin ne kadar iş yaptığını değil, kaç farklı *türde* iş yaptığını ölçmeyi hedefler. Bu sayede, “Tanrı Bileşen” sendromunun yaygın olduğu projelerde, kod kalitesini artırmak ve daha sağlıklı bir mimari oluşturmak için güçlü bir başlangıç noktası sunar. Şimdi CRS’i nasıl hesaplayacağımıza geçelim.

CRS Nasıl Hesaplanır? Adım Adım Yaklaşım

Bileşen Sorumluluk Skoru (CRS) hesaplamak için standart bir “tek doğru formül” yoktur, çünkü sorumlulukların tanımlanması kısmen sübjektif bir süreçtir. Ancak, pratik bir yaklaşım benimseyerek tutarlı ve faydalı bir skor elde edebiliriz. İşte adım adım bir hesaplama yöntemi:

  1. Bileşeninizi Belirleyin: Analiz etmek istediğiniz bileşeni seçin. Bu bir React bileşeni, bir Angular servisi, bir Vue bileşeni veya herhangi bir sınıfla temsil edilen bir modül olabilir.
  2. Tüm Sorumlulukları Listeleyin: Bileşenin gerçekleştirdiği tüm farklı işlevleri, eylemleri ve etkileşimleri belirleyin. Bu aşamada mümkün olduğunca detaylı olmaya çalışın. Bir sorumluluk, genellikle bir “neden değişme” prensibiyle tanımlanır. Yani, “Bu bileşen neden değişmeli?” sorusunun her farklı cevabı, ayrı bir sorumluluk olarak kabul edilebilir.
    • Veri Gösterme (Rendering Data): Bileşenin temel amacı olan veriyi kullanıcıya sunma.
    • Veri Alma (Fetching Data): API çağrıları veya diğer kaynaklardan veri çekme.
    • Veri Gönderme (Submitting Data): Form gönderimi veya diğer kullanıcı eylemleriyle veri kaydetme/güncelleme.
    • Durum Yönetimi (State Management): Bileşenin kendi iç durumunu (örn: bir formun input değerleri, bir menünün açık/kapalı durumu) veya global durumu yönetme.
    • Girdi Doğrulama (Input Validation): Kullanıcı girdilerini kontrol etme.
    • Yetkilendirme/İzin Kontrolü (Authorization/Permission Check): Kullanıcının belirli bir eylemi gerçekleştirme veya veriyi görme iznine sahip olup olmadığını kontrol etme.
    • Olay Yönetimi (Event Handling): Kullanıcı etkileşimlerini (tıklama, yazma vb.) işleme.
    • Görsel Etkileşimler/Animasyonlar (Visual Interactions/Animations): UI animasyonları veya karmaşık görsel efektler.
    • Depolama İşlemleri (Storage Operations): LocalStorage, SessionStorage gibi yerel depolama birimleriyle etkileşim.
    • Routing/Navigasyon (Routing/Navigation): Uygulama içi sayfa yönlendirmeleri.
  3. Sorumlulukları Niteliksel Olarak Değerlendirin: Her bir sorumluluğun karmaşıklığına veya etkisine göre bir ağırlık atayabilirsiniz. Basit bir “Evet/Hayır” değerlendirmesi (her sorumluluk 1 puan) başlangıç için yeterli olsa da, daha gelişmiş bir sistemde bazı sorumluluklar (örn: veri alma/gönderme) daha yüksek puan alabilirken, diğerleri (örn: basit veri gösterme) daha düşük puan alabilir. Ancak genelde, her farklı sorumluluk bir birim olarak sayılır.
  4. Skoru Hesaplayın: Tüm belirlediğiniz sorumlulukların sayısını toplayın. Bu, bileşeninizin CRS değeridir.

Örnek Hesaplama:

Bir UserProfile bileşenimiz olduğunu varsayalım. Bu bileşen hem kullanıcının profil bilgilerini gösteriyor, hem bu bilgileri bir API’den çekiyor, hem de kullanıcının profilini düzenlemesine olanak tanıyan bir formu yönetiyor. Ayrıca, kullanıcının avatarını yükleme ve gösterimini de kendisi hallediyor.

  • Veri Gösterme (Profil bilgileri): 1 puan
  • Veri Alma (API’den profil çekme): 1 puan
  • Veri Gönderme (Profil güncelleme): 1 puan
  • Durum Yönetimi (Form inputları ve yükleme durumu): 1 puan
  • Girdi Doğrulama (Form inputları için): 1 puan
  • Dosya Yükleme (Avatar yükleme): 1 puan
  • Görsel Etkileşimler (Avatar önizlemesi): 1 puan

Bu durumda, UserProfile bileşeninin CRS değeri 7 olacaktır. Bu skor, tek bir bileşen için oldukça yüksektir ve bu bileşenin “Tanrı Bileşen” olma eğiliminde olduğunu gösterir. Ideal olarak, çoğu bileşen için CRS değerinin 1-3 arasında olması hedeflenmelidir. Şimdi bu tür bir bileşeni nasıl dönüştürebileceğimize dair bir vaka analizine göz atalım.

Uzman İpucu: CRS hesaplamasına başlamadan önce, ekibinizle “sorumluluk” tanımı üzerinde anlaşın. Hangi işlevlerin ayrı bir sorumluluk olarak kabul edileceği konusunda ortak bir dil oluşturmak, tutarlı sonuçlar elde etmenin anahtarıdır.

Vaka Analizi: Bir “Tanrı Bileşen”in CRS Değeri ve Dönüşümü

Vaka: E-ticaret sitemizdeki ProductDetailPage (Ürün Detay Sayfası) bileşeni, başlangıçta sadece ürün bilgilerini göstermek için tasarlanmıştı. Ancak zamanla, ürünün varyantlarını seçme, sepete ekleme, yorumları gösterme, yorum ekleme, ürünle ilgili öneriler sunma ve hatta “Favorilere Ekle” gibi birçok farklı işlevi tek başına yöneten bir “Tanrı Bileşen” haline geldi. Ekip, bu bileşende değişiklik yapmaktan çekiniyor, her güncelleme yeni bir hatayı tetikliyor ve performans sorunları yaşanıyordu.

Başlangıç Durumu: Yüksek CRS Değeri

ProductDetailPage bileşeninin mevcut sorumluluklarını listeleyelim:

  1. Ürün bilgilerini gösterme (isim, fiyat, açıklama) – 1 puan
  2. Ürün varyantlarını seçme ve yönetme – 1 puan
  3. Sepete ürün ekleme mantığı – 1 puan
  4. Ürün yorumlarını API’den çekme – 1 puan
  5. Ürün yorumlarını gösterme – 1 puan
  6. Yeni yorum gönderme formu ve mantığı – 1 puan
  7. İlgili ürün önerilerini API’den çekme – 1 puan
  8. İlgili ürün önerilerini gösterme – 1 puan
  9. “Favorilere Ekle” butonu mantığı (API ile etkileşim) – 1 puan
  10. Ürün görsel galerisi yönetimi (büyük/küçük resim geçişleri) – 1 puan
  11. Sayfa yükleme ve hata durumlarını yönetme – 1 puan

Initial CRS: 11. Bu değer, beklendiği gibi oldukça yüksek ve bileşenin adeta bir monolit gibi davrandığını gösteriyor. İşte bu bileşenden basitleştirilmiş bir kod parçası:


// ProductDetailPage.js (Kısaltılmış "Tanrı Bileşen" örneği)
import React, { useState, useEffect } from 'react';
import axios from 'axios';

function ProductDetailPage({ productId }) {
    const [product, setProduct] = useState(null);
    const [variants, setVariants] = useState([]);
    const [selectedVariant, setSelectedVariant] = useState(null);
    const [comments, setComments] = useState([]);
    const [newCommentText, setNewCommentText] = useState('');
    const [relatedProducts, setRelatedProducts] = useState([]);
    const [isLoading, setIsLoading] = useState(true);
    const [error, setError] = useState(null);

    // 1. Ürün verilerini çekme
    // 4. Yorumları çekme
    // 7. İlgili ürünleri çekme
    useEffect(() => {
        const fetchData = async () => {
            setIsLoading(true);
            try {
                const productRes = await axios.get(/api/products/${productId});
                setProduct(productRes.data);
                setVariants(productRes.data.variants);
                setSelectedVariant(productRes.data.variants[0]);

                const commentsRes = await axios.get(/api/products/${productId}/comments);
                setComments(commentsRes.data);

                const relatedRes = await axios.get(/api/products/${productId}/related);
                setRelatedProducts(relatedRes.data);
            } catch (err) {
                setError(err);
            } finally {
                setIsLoading(false);
            }
        };
        fetchData();
    }, [productId]);

    // 3. Sepete Ekle mantığı
    const handleAddToCart = () => {
        // Sepete ekleme API çağrısı ve bildirim mantığı
        console.log(Ürün ${product.name}, varyant ${selectedVariant.name} sepete eklendi.);
    };

    // 6. Yeni yorum gönderme mantığı
    const handleAddComment = async () => {
        if (!newCommentText.trim()) return;
        try {
            const res = await axios.post(/api/products/${productId}/comments, { text: newCommentText });
            setComments([...comments, res.data]);
            setNewCommentText('');
        } catch (err) {
            console.error("Yorum eklenemedi", err);
        }
    };

    // 9. Favorilere Ekle mantığı
    const handleAddToFavorites = () => {
        // Favorilere ekleme API çağrısı
        console.log(${product.name} favorilere eklendi.);
    };

    if (isLoading) return 
Yükleniyor...
; if (error) return
Hata: {error.message}
; if (!product) return null; return (
{/* 1. Ürün bilgilerini gösterme */}

{product.name}

Fiyat: {product.price}

{product.name} {/* 10. Görsel yönetimi */} {/* 2. Varyant seçimi */}

Yorumlar

{/* 5. Yorumları gösterme */} {comments.map(comment => (
{comment.text}
))}

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.