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}

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

Yorumlar

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

Dönüşüm: Refactoring ve Düşük CRS

Bu bileşeni, her bir sorumluluğu ayrı bir modüle veya daha küçük bir bileşene delege ederek refactor edebiliriz. Amacımız, ProductDetailPage bileşeninin sadece ana düzeni ve alt bileşenleri bir araya getirme sorumluluğunu üstlenmesini sağlamaktır. İşte nasıl refactor edebileceğimize dair bir örnek:

  1. ProductDisplay: Ürün bilgilerini, varyantları ve görsel galerisini gösterme.
  2. AddToCartButton: Sepete ekleme mantığı.
  3. FavoriteButton: Favorilere ekleme mantığı.
  4. ProductCommentsSection: Yorumları çekme, gösterme ve yeni yorum ekleme.
  5. RelatedProductsList: İlgili ürünleri çekme ve gösterme.
  6. useProductData: Ürün, yorum ve ilgili ürün verilerini çeken özel bir hook (mantık delege edildi).

Refactor Sonrası ProductDetailPage Sorumlulukları:

  • Alt bileşenleri bir araya getirme ve düzenleme - 1 puan
  • Veri alma özel hook'unu çağırma ve veriyi alt bileşenlere iletme - 1 puan
  • Yükleme ve hata durumlarını yönetme (hook'tan gelen durumu kullanarak) - 1 puan

Refactor Sonrası CRS: 3. Bu, önemli bir iyileşmedir ve bileşenin artık çok daha odaklı olduğunu gösterir. Diğer bileşenlerin CRS değeri de genellikle 1-3 arasında olacaktır. Örneğin, AddToCartButton'ın CRS değeri 1 (sepete ekleme mantığı), ProductCommentsSection'ın CRS değeri 3 (yorum çekme, gösterme, gönderme) olabilir.


// useProductData.js (Özel Hook)
import { useState, useEffect } from 'react';
import axios from 'axios';

function useProductData(productId) {
    const [product, setProduct] = useState(null);
    const [comments, setComments] = useState([]);
    const [relatedProducts, setRelatedProducts] = useState([]);
    const [isLoading, setIsLoading] = useState(true);
    const [error, setError] = useState(null);

    useEffect(() => {
        const fetchData = async () => {
            setIsLoading(true);
            try {
                const [productRes, commentsRes, relatedRes] = await Promise.all([
                    axios.get(/api/products/${productId}),
                    axios.get(/api/products/${productId}/comments),
                    axios.get(/api/products/${productId}/related)
                ]);
                setProduct(productRes.data);
                setComments(commentsRes.data);
                setRelatedProducts(relatedRes.data);
            } catch (err) {
                setError(err);
            } finally {
                setIsLoading(false);
            }
        };
        fetchData();
    }, [productId]);

    return { product, comments, relatedProducts, isLoading, error, setComments };
}

export default useProductData;

// ProductDisplay.js
import React from 'react';

function ProductDisplay({ product, variants, selectedVariant, onVariantChange }) {
    return (
        

{product.name}

Fiyat: {product.price}

{variants && variants.length > 0 && ( )}
); } export default ProductDisplay; // AddToCartButton.js import React from 'react'; function AddToCartButton({ product, selectedVariant }) { const handleAddToCart = () => { console.log(Ürün ${product.name}, varyant ${selectedVariant.name} sepete eklendi.); // API çağrısı }; return ; } export default AddToCartButton; // ProductCommentsSection.js import React, { useState } from 'react'; import axios from 'axios'; function ProductCommentsSection({ productId, comments, setComments }) { const [newCommentText, setNewCommentText] = useState(''); 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); } }; return (

Yorumlar

{comments.map(comment => (
{comment.text}
))}
); } export default ProductCommentsSection; // RelatedProductsList.js import React from 'react'; function RelatedProductsList({ products }) { return (

İlgili Ürünler

{products.map(rp => (
{rp.name}
))}
); } export default RelatedProductsList; // ProductDetailPage.js (Refactor edilmiş hali) import React, { useState } from 'react'; import useProductData from './useProductData'; import ProductDisplay from './ProductDisplay'; import AddToCartButton from './AddToCartButton'; import FavoriteButton from './FavoriteButton'; // Yeni oluşturulacak import ProductCommentsSection from './ProductCommentsSection'; import RelatedProductsList from './RelatedProductsList'; function ProductDetailPage({ productId }) { const { product, comments, relatedProducts, isLoading, error, setComments } = useProductData(productId); const [selectedVariant, setSelectedVariant] = useState(null); if (isLoading) return
Yükleniyor...
; if (error) return
Hata: {error.message}
; if (!product) return null; // selectedVariant'ı product.variants üzerinden yönet useState(() => { if (product && product.variants && product.variants.length > 0) { setSelectedVariant(product.variants[0]); } }, [product]); return (
setSelectedVariant(product.variants.find(v => v.id === variantId))} /> {/* Sorumluluğu kendine ait olacak */}
); } export default ProductDetailPage;

Bu dönüşüm sayesinde, ProductDetailPage bileşeni artık sadece alt bileşenleri düzenlemekle ve veri hook'undan gelen bilgileri dağıtmakla sorumlu. Her bir alt bileşen kendi özel işini yapıyor. Bu, hem kodun okunabilirliğini artırıyor hem de her bir parçanın ayrı ayrı test edilmesini ve yeniden kullanılmasını sağlıyor.

CRS'i Düşürmek İçin Hangi Teknikleri Kullanabiliriz?

CRS değerini düşürmek ve daha modüler, sürdürülebilir bileşenler oluşturmak için birçok yazılım mühendisliği prensibi ve tasarım deseni kullanılabilir. İşte bu tekniklerden bazıları:

  1. Tek Sorumluluk Prensibi (SRP - Single Responsibility Principle): SOLID prensiplerinin ilk harfi olan SRP, her modülün, sınıfın veya bileşenin yalnızca tek bir değişiklik nedenine sahip olması gerektiğini belirtir. Bu, CRS'yi düşürmek için en temel ve en etkili yaklaşımdır. Eğer bir bileşenin birden fazla sorumluluğu varsa, bu sorumlulukları ayrı bileşenlere veya modüllere ayırarak SRP'ye uygun hale getirebiliriz. Örneğin, veri çekme mantığını ayrı bir servise veya özel bir hook'a, UI gösterme mantığını ayrı bir görsel bileşene ayırmak gibi.
  2. Kompozisyon (Composition) Kullanımı: Kalıtım (Inheritance) yerine kompozisyonu tercih etmek, daha esnek ve daha az bağımlı yapılar oluşturmamızı sağlar. Küçük, bağımsız bileşenleri bir araya getirerek daha büyük ve karmaşık işlevler oluşturmak, her bir alt bileşenin CRS'sini düşük tutarken, ana bileşenin de sadece bu alt bileşenleri düzenleme sorumluluğunu üstlenmesini sağlar. Bu sayede, "Tanrı Bileşen" oluşumunu engelleriz.
  3. Bağımlılık Enjeksiyonu (Dependency Injection - DI): Bileşenlerin ihtiyaç duydukları bağımlılıkları (servisler, yardımcı fonksiyonlar vb.) kendilerinin oluşturması yerine dışarıdan almasını sağlamak, bileşenlerin daha az bilgi sahibi olmasını ve dolayısıyla daha az sorumluluk üstlenmesini sağlar. DI, test edilebilirliği artırır ve bileşenlerin belirli bir uygulama bağlamına sıkıca bağlanmasını engeller. Özellikle Angular gibi framework'lerde bu doğal bir yaklaşımdır.
  4. Soyutlama ve Arayüzler (Abstraction and Interfaces): Belirli bir işlevselliğin nasıl uygulandığına dair detayları gizleyerek, bileşenlerin sadece soyut bir arayüzle etkileşime girmesini sağlamak. Bu, bileşenin sadece "ne" yapıldığını bilmesini, "nasıl" yapıldığını bilmemesini sağlar. Örneğin, bir API servisi için bir arayüz tanımlayarak, bu servisin farklı implementasyonları bileşeni etkilemeden değiştirilebilir.
  5. Delegasyon (Delegation): Bir bileşenin, yapması gereken bir işi başka bir bileşene veya modüle devretmesi. Örneğin, bir ana bileşen, bir listenin filtrelenmesi sorumluluğunu ayrı bir filtreleme bileşenine delege edebilir. Bu, ana bileşenin sadece filtreleme bileşeninin sonucunu kullanmasını sağlar ve CRS'sini düşürür.
  6. Özel Hook'lar veya Servisler (Custom Hooks/Services): Özellikle React ekosisteminde özel hook'lar (useProductData örneğimizdeki gibi) veya diğer framework'lerde servis katmanları, durum yönetimi, veri çekme, doğrulama gibi mantıksal sorumlulukları UI bileşenlerinden ayırmak için mükemmel araçlardır. Bu, bileşenlerin sadece görsel sunumla ilgili sorumluluklara odaklanmasını sağlar.
  7. Kapsayıcı (Container) ve Sunumsal (Presentational) Bileşenler: Bu desen, bileşenleri iki kategoriye ayırır: Kapsayıcı bileşenler (akıllı bileşenler) veriyi yönetir ve mantığı içerir; Sunumsal bileşenler (aptal bileşenler) ise sadece veriyi alır ve görüntüler, kendi içlerinde neredeyse hiç mantık barındırmazlar. Bu ayrım, sorumlulukları net bir şekilde bölmeye yardımcı olur ve her bir bileşenin CRS'sini düşük tutar.
Uzman İpucu: Kodunuzda "callback hell" veya iç içe API çağrıları görmeye başladığınızda, bu genellikle yeni bir sorumluluğun ortaya çıktığının veya mevcut bir sorumluluğun aşırı büyüdüğünün işaretidir. Bu tür durumları tespit ettiğinizde hemen CRS analizi yapın.

Farklı Çerçevelerde CRS Uygulamaları: React, Angular, Vue ve Ötesi

Bileşen Sorumluluk Skoru'nun (CRS) en güzel yanlarından biri, onun tamamen framework-agnostik olmasıdır. Yani, ister React, ister Angular, ister Vue, ister Svelte, isterse de backend'de bir Node.js modülü ile çalışıyor olun, CRS prensipleri aynı şekilde uygulanabilir. Temelde yatan yazılım mühendisliği prensipleri, dil veya çerçeve seçiminden bağımsız olarak geçerliliğini korur. Ancak, her çerçeve, bu prensipleri uygulamak için farklı araçlar ve yaklaşımlar sunar. Bu bölümde, popüler ön yüz çerçevelerinde CRS'i nasıl düşürebileceğimize dair genel yaklaşımlara değineceğiz.

React Eko-sisteminde CRS

React'te "Tanrı Bileşen"ler genellikle çok fazla useState, useEffect hook'u içeren, karmaşık render mantığına sahip bileşenler olarak karşımıza çıkar. CRS'i düşürmek için şu teknikler kullanılabilir:

  • Custom Hook'lar: Veri çekme, durum yönetimi, form doğrulama gibi mantıksal sorumlulukları custom hook'lara taşıyarak bileşenlerin sadece UI sunumuna odaklanmasını sağlayın. Örneğin, useProductData veya useFormValidation gibi hook'lar.
  • Higher-Order Components (HOC) / Render Props: Paylaşılan mantığı bileşenler arasında yeniden kullanmak ve karmaşıklığı dağıtmak için bu desenleri kullanabilirsiniz (ancak modern React'te genellikle custom hook'lar tercih edilir).
  • Kompozisyon: Küçük, odaklanmış bileşenler oluşturup bunları ana bileşen içinde bir araya getirin. ProductDisplay, AddToCartButton gibi alt bileşenler buna iyi bir örnektir.

Angular Eko-sisteminde CRS

Angular, modüler yapıya ve bağımlılık enjeksiyonuna (DI) doğal olarak yatkın bir çerçevedir. Bu, CRS'yi düşük tutmak için harika fırsatlar sunar:

  • Servisler: Veri işleme, API çağrıları, durum yönetimi, iş mantığı gibi tüm görevleri bileşenlerden ayırarak Angular servislerine taşıyın. Bileşenler sadece servisleri enjekte edip kullanmalı, mantığı kendileri uygulamamalıdır.
  • Pipe'lar ve Direktifler: Veri formatlama veya DOM manipülasyonu gibi sunumsal sorumlulukları pipe'lara veya özel direktiflere delege edin.
  • Modüller: Uygulamanızı, her biri belirli bir işlevsel alanı temsil eden daha küçük özellik modüllerine ayırın. Bu, bileşenlerin sorumluluklarını doğal olarak sınırlar.
  • Smart/Dumb Component Pattern: Kapsayıcı bileşenler (Smart) servisleri kullanarak veriyi alır ve mantığı yönetirken, sunumsal bileşenler (Dumb) sadece @Input() ve @Output() ile iletişim kurarak veriyi görüntüler.

Vue.js Eko-sisteminde CRS

Vue.js, esnekliği ile bilinir ve CRS'yi yönetmek için hem Options API hem de Composition API'de çeşitli yöntemler sunar:

  • Composable'lar (Composition API): React'teki custom hook'lara benzer şekilde, mantıksal sorumlulukları yeniden kullanılabilir composable fonksiyonlara taşıyın (örn: useFetchData.js, useFormValidation.js).
  • Mixins (Options API): Paylaşılan işlevselliği farklı bileşenlere enjekte etmek için mixin'leri kullanabilirsiniz, ancak Composition API genellikle daha tercih edilen ve daha temiz bir yaklaşımdır.
  • Props ve Emit Olayları: Bileşenler arasında net bir veri akışı ve iletişim mekanizması kurarak her bileşenin kendi sorumluluk alanında kalmasını sağlayın.
  • Slot'lar: Bileşenlerin içeriğini dinamik olarak enjekte etmek için slot'ları kullanarak, bir bileşenin kendi içeriğinin düzeninden bağımsız olmasını sağlayın ve sunumsal sorumlulukları dışa aktarın.

Aşağıdaki tablo, farklı çerçevelerde CRS'i düşürmek için kullanılabilecek yaygın desenleri özetlemektedir:

Desen / İlke React Karşılığı Angular Karşılığı Vue.js Karşılığı Amacı
Mantık Ayırma Custom Hooks Services Composables Veri çekme, durum yönetimi gibi iş mantığını UI'dan ayırmak.
UI Ayırma Kompozisyon (Küçük Bileşenler) Dumb Components, Pipe'lar, Directifler Kompozisyon, Slot'lar Görsel sunumu ve etkileşimleri daha küçük, yeniden kullanılabilir parçalara bölmek.
Modülerlik Klasör Yapısı, Shared Components Feature Modules Klasör Yapısı, Bileşen Kütüphaneleri Uygulamanın farklı kısımlarını izole edilmiş birimlere ayırmak.

Özetle, çerçeveden bağımsız olarak, ana fikir aynıdır: Sorumlulukları belirleyin, ölçün ve aşırı yüklenmiş bileşenleri daha küçük, daha odaklı parçalara ayırmak için çerçevenizin sunduğu en iyi araçları kullanın. Bu sayede, "Tanrı Bileşen"lerden kurtulacak ve daha temiz, daha sürdürülebilir bir kod tabanı oluşturacaksınız.

Sonuç: Temiz Kod ve Sürdürülebilir Geliştirme İçin CRS

"Tanrı Bileşen"ler, yazılım projelerinin gizli düşmanlarıdır. Başlangıçta masum gibi görünen bu bileşenler, zamanla büyüyerek bakım maliyetlerini artırır, test süreçlerini karmaşıklaştırır ve geliştirme hızını düşürür. Bu makalede ele aldığımız Bileşen Sorumluluk Skoru (CRS), bu görünmez tehlikeyi somut bir metrikle ölçmek ve yönetmek için güçlü, framework-agnostik bir araç sunar.

CRS, bileşenlerinizi değerlendirirken size objektif bir bakış açısı sağlar ve refactoring ihtiyacını net bir şekilde ortaya koyar. Düşük bir CRS değeri, bileşeninizin Tek Sorumluluk Prensibi'ne uygun olduğunu, daha kolay test edilebilir, daha yeniden kullanılabilir ve daha anlaşılır olduğunu gösterir. Vaka analizimizde gördüğümüz gibi, yüksek CRS'e sahip bir "Tanrı Bileşen"i parçalara ayırarak ve her bir parçayı kendi sorumluluk alanına odaklayarak, genel kod kalitesini ve sürdürülebilirliği önemli ölçüde artırabiliriz.

Unutmayın, yazılım geliştirme sürekli bir evrim sürecidir. CRS'yi bir kez hesaplayıp bırakmak yerine, onu geliştirme sürecinizin bir parçası haline getirmek önemlidir. Yeni özellikler eklenirken veya mevcut kodda değişiklik yapılırken bileşenlerin sorumluluklarını gözden geçirmek, "Tanrı Bileşen"lerin yeniden ortaya çıkmasını engellemenin en iyi yoludur. Modüler ve bakımı kolay bir kod tabanı oluşturmak, sadece bugünün sorunlarını çözmekle kalmaz, aynı zamanda gelecekteki geliştirmeler için sağlam bir temel atar. Bu yaklaşım, ekip verimliliğini artırır, yeni üyelerin adaptasyonunu kolaylaştırır ve uzun vadede projenizin başarısına katkıda bulunur.

Sıkça Sorulan Sorular (SSS)

1. CRS'i hangi sıklıkla hesaplamalıyım?

CRS'yi düzenli aralıklarla (örneğin, her sprint sonunda veya büyük bir özellik geliştirmesi tamamlandığında) veya kritik bileşenlerde önemli değişiklikler yapıldığında hesaplamak iyi bir uygulamadır. Ayrıca, yeni bir bileşen oluşturduğunuzda veya mevcut bir bileşenin çok karmaşık hissettirdiğini düşündüğünüzde de hemen kontrol edebilirsiniz. Otomatik araçlarla entegrasyon, bu süreci daha verimli hale getirebilir.

2. İdeal bir CRS değeri nedir?

Genellikle, bir bileşen için ideal CRS değeri 1 ile 3 arasındadır. Yani, bir bileşenin 1 ila 3 arasında farklı sorumluluğa sahip olması beklenir. Ancak bu bir kuraldan çok bir rehberdir; bazı karmaşık domain bileşenleri için bu değer biraz daha yüksek olabilir. Önemli olan, ekibinizin kendi bağlamına göre "kabul edilebilir" bir üst sınır belirlemesi ve bu sınırı aşan bileşenleri refactoring için işaretlemesidir.

3. CRS'i otomatik olarak hesaplayabilir miyim?

Doğrudan CRS'i hesaplayan genel bir otomatik araç bulunmamaktadır çünkü "sorumluluk" kavramı kod metrikleri kadar net değildir ve bazen insan yorumu gerektirir. Ancak, AST (Abstract Syntax Tree) analizi yapan veya belirli kalıpları (örn: çok sayıda useEffect bağımlılığı, çok fazla prop geçme) tespit eden statik analiz araçları, potansiyel "Tanrı Bileşen" adaylarını bulmanıza yardımcı olabilir. Daha sonra bu adayların CRS'ini manuel olarak değerlendirebilirsiniz.

4. CRS sadece ön yüz (frontend) geliştirme için mi geçerlidir?

Kesinlikle hayır. CRS, yazılım mühendisliğinin temel bir prensibi olan "Tek Sorumluluk Prensibi"ne dayanır ve bu prensip ön yüz, arka yüz, mobil veya herhangi bir yazılım mimarisi için geçerlidir. Bir backend servisi, bir veritabanı sınıfı veya bir iş mantığı modülü de birden fazla sorumluluğu üstlenerek "Tanrı Bileşen" haline gelebilir. CRS, bu tür durumları tespit etmek ve düzeltmek için evrensel bir kılavuzdur.

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Gönder

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.
Mobil sürümden çık