- Kod kokusu nedir, hata ile farkı ne?
- En sık karşılaşılan kokular ve ne söyledikleri
- Kokuyu fark etmek: kod incelemesinde nelere bakılır?
- Güvenli refactoring süreci: önce test, sonra küçük adımlar
- Örnek: uzun bir fonksiyonu adım adım dönüştürmek
- Hangi kokuya hangi dönüşüm uygulanır?
- Kod kokularında ve refactoring'de sık yapılan hatalar
- Bu beceriyi Mindset programlarında nerede geliştirirsiniz?
- Sık sorulan sorular
Kod Kokuları ve Refactoring: Belirtiden Güvenli Dönüşüme
Sık görülen kod kokuları, kokuya göre refactoring dönüşümleri, testle güvenli ilerleme ve uzun bir fonksiyonun adım adım dönüştürülmesi.
Kod kokusu nedir, hata ile farkı ne?
Kod kokusu (code smell), kodun çalıştığı ama yapısında daha derin bir sorun olabileceğini düşündüren belirtidir. Hata değildir: program doğru sonuç üretir, testler geçer. Ancak kokan kodu okumak, değiştirmek ve test etmek zordur; bu zorluk zamanla yeni hataların kapısını açar. Koku bir kesinlik değil, bir ipucudur. Bazen uzun bir fonksiyon gerçekten gereklidir; önemli olan bunun bilinçli bir karar olup olmadığıdır.
Refactoring ise kodun dış davranışını değiştirmeden iç yapısını iyileştirme işidir. Yeni özellik eklemez, hata düzeltmez; aynı işi yapan kodu daha anlaşılır ve değiştirmesi kolay hale getirir. Bu ayrım önemlidir: aynı değişiklikte hem davranışı değiştirip hem yapıyı toparlamak, bir şey bozulduğunda nedenini bulmayı güçleştirir.
Kokuları fark etmek bir kuraldan çok bir alışkanlıktır. Kod incelemesinde "bunu okurken nerede takıldım?" sorusunu sormak, çoğu kokunun ilk habercisidir. Takıldığınız yer, genellikle isim, uzunluk ya da sorumluluk sorunu taşır.
En sık karşılaşılan kokular ve ne söyledikleri
Kokuları belirtiyle tanımak, çözümü bulmayı kolaylaştırır: • Uzun fonksiyon: Bir fonksiyon birden çok iş yapıyorsa ve her bölümünün yanına yorum yazma ihtiyacı doğuyorsa bölünmeye adaydır. • Büyük sınıf: Çok fazla alan ve metot taşıyan, birden çok sebeple değişen sınıf sorumluluğunu aşmıştır. • Uzun parametre listesi: Birlikte dolaşan parametreler ayrı bir nesneye ait olabilir. • Yinelenen kod: Aynı mantığın farklı yerlerde kopyalanması, değişiklikte bir kopyanın unutulmasına yol açar. • Özellik imrenmesi (feature envy): Bir metot kendi sınıfından çok başka bir sınıfın verisiyle uğraşıyorsa yanlış yerdedir. • İlkel tür saplantısı: Para, telefon, e-posta gibi kavramları düz metin ve sayıyla taşımak, doğrulama ve davranışı dağıtır. • Ardışık değişiklik (shotgun surgery): Tek bir değişiklik için çok sayıda dosyaya dokunmak gerekiyorsa sorumluluk parçalanmıştır. • Switch zincirleri: Aynı koşul kontrolünün birden çok yerde tekrarlanması, davranışın bir nesneye taşınması gerektiğini gösterir. • Ölü kod ve yorum satırına alınmış kod: Sürüm kontrolü zaten geçmişi saklar. • Sihirli sayılar ve belirsiz isimler: Anlamı belli olmayan değerler kodu okunaksız kılar.
Bu listenin tamamını ezberlemek gerekmez; kod tabanınızda en çok tekrar eden birkaç kokuyu ekip olarak tanımlamak yeterlidir.
Kokuyu fark etmek: kod incelemesinde nelere bakılır?
Bir fonksiyonu okurken şu sorular sizi kokuya yönlendirir: Bu fonksiyonun adı yaptığı işi tam anlatıyor mu? Bir cümleyle özetleyebiliyor muyum, yoksa "ve" ile birleştirmek zorunda mı kalıyorum? İçindeki girinti seviyeleri çok derinleşti mi? Parametrelerden biri bayrak (true/false) olarak davranışı değiştiriyor mu? Aynı bloğu başka yerde gördüm mü?
Sınıf ya da modül düzeyinde sorular farklıdır: Bu sınıf kaç farklı nedenle değişebilir? Başka bir sınıfın iç yapısını çok mu biliyor? Test yazmak neden zor; çok fazla bağımlılığı mı var? Test yazmanın zorluğu, tasarım kokusunun en güvenilir belirtilerinden biridir.
Statik analiz araçları da yardımcı olur: karmaşıklık ölçümü, yinelenen kod tespiti, kullanılmayan kod taraması. Ancak araç yalnız belirtiyi gösterir; hangi kokunun gerçekten sorun olduğu ve ne zaman düzeltilmesi gerektiği insan kararıdır. Ekip, araç eşiklerini kendi bağlamına göre ayarlamalı ve eşiklerin aşılması otomatik olarak yeniden yapılandırma anlamına gelmemelidir.
Güvenli refactoring süreci: önce test, sonra küçük adımlar
Refactoring'in temel kuralı, davranışın korunduğunu doğrulayabilmektir. Bu nedenle ilk adım, ilgili kodu çevreleyen testleri kontrol etmektir. Test yoksa önce karakterizasyon testi yazın: kodun bugün ne yaptığını, doğru ya da yanlış, olduğu gibi kayda geçiren testler. Böylece refactoring sırasında davranışı değiştirip değiştirmediğinizi görürsünüz.
Süreç şu döngüyle ilerler. Küçük bir dönüşüm seçin (örneğin bir bloğu fonksiyona çıkarmak), uygulayın, testleri çalıştırın, yeşilse kaydedin (commit), sonra sıradaki dönüşüme geçin. Büyük ve tek parça bir yeniden yazım yerine, her biri kendi başına geri alınabilen küçük adımlar riski düşürür. IDE'nin otomatik refactoring araçları (yeniden adlandırma, fonksiyon çıkarma) mümkünse elle düzenlemeye tercih edilir; çünkü referansları tutarlı biçimde günceller.
Refactoring ile özellik geliştirme aynı işte karışmamalıdır. Önce yapıyı yeni özelliğin kolayca ekleneceği hale getirin, sonra özelliği ekleyin; bu adımları ayrı commit'lere bölmek incelemeyi ve geri almayı kolaylaştırır.
Örnek: uzun bir fonksiyonu adım adım dönüştürmek
Örneğin bir sipariş toplamını hesaplayan şu fonksiyonu düşünelim:
def calculate_price(order, customer_type, coupon, vat_rate): total = sum(k.price * k.quantity for k in order.items) if customer_type == "corporate": total = total * corporate_multiplier elif customer_type == "individual": total = total * individual_multiplier if coupon is not None: total = total - coupon.amount return total + total * vat_rate
Koku: fonksiyon kalem toplamını, müşteri indirimini, kuponu ve vergiyi bir arada yapıyor; çok sayıda parametre taşıyor ve müşteri tipi koşulu yeni tip eklendikçe büyüyecek.
Dönüşüm adımları: önce mevcut davranışı kilitleyen testler yazılır. Sonra her sorumluluk fonksiyona çıkarılır: items_total, apply_customer_multiplier, apply_coupon, add_vat. Koşul zinciri, tip adından katsayıya giden bir sözlüğe ya da stratejiye dönüştürülür. Sonuçta ana fonksiyon yalnızca adımları sırayla çağırır ve her adım ayrı test edilebilir.
def calculate_price(order, customer, coupon, vat_rate): total = items_total(order) total = apply_customer_multiplier(total, customer) total = apply_coupon(total, coupon) return add_vat(total, vat_rate)
Dış davranış aynıdır, ama yeni bir müşteri tipi eklemek artık yalnız bir fonksiyona dokunmayı gerektirir.
Hangi kokuya hangi dönüşüm uygulanır?
Dönüşüm seçimi, kokunun nedenine bağlıdır. Bazı eşleşmeler sık kullanılır: • Uzun fonksiyon: fonksiyon çıkarma; geçici değişkenleri sorguya çevirme • Yinelenen kod: ortak fonksiyona çıkarma; ortak üst sınıf ya da bileşim • Uzun parametre listesi: parametre nesnesi oluşturma; nesnenin kendisini geçirme • Switch zincirleri ve tür koşulları: polimorfizm; strateji kalıbı • Özellik imrenmesi: metodu verinin bulunduğu sınıfa taşıma • İlkel tür saplantısı: değer nesnesi (örneğin Para, Telefon) oluşturma • Sihirli sayılar: adlandırılmış sabit • İç içe koşullar: koruma ifadeleri (guard clause) ile erken dönüş • Büyük sınıf: sorumluluğa göre sınıf çıkarma
Her dönüşümün bir maliyeti vardır. Fazla soyutlama, basit kodu gereksiz karmaşıklaştırabilir. Kural olarak, gerçek bir tekrar ya da değişim ihtiyacı görmeden soyutlama eklemeyin. Kodun hangi bölgesinin sık değiştiğini sürüm geçmişinden bakarak belirleyin: sık değişen ve kokan yer, refactoring yatırımının en çok karşılığını bulduğu yerdir.
Kod kokularında ve refactoring'de sık yapılan hatalar
Birincisi, testsiz refactoring yapmaktır; davranışın bozulup bozulmadığını bilemezsiniz. İkincisi, büyük bir yeniden yazım planlamaktır. Büyük yeniden yazımlar çoğu zaman bitmez ya da yeni hatalar getirir; küçük adımlarla ilerlemek daha güvenlidir.
Üçüncüsü, refactoring'i teslim tarihine bağlı ayrı bir proje olarak görmektir. Etkili ekipler küçük iyileştirmeleri günlük işe yayar: bir dosyaya dokunduğunuzda onu bulduğunuzdan biraz daha temiz bırakmak gibi. Dördüncüsü, her kokuyu hemen düzeltmeye çalışmaktır; hiç değişmeyen, risk taşımayan bir eski kod parçasında yatırım yapmak çoğu zaman değmez.
Beşincisi, ekip standardı olmadan kişisel zevkle refactoring yapmaktır. Bir kişinin "temiz"liği başkasının karmaşıklığı olabilir; kodlama standardı, isimlendirme kuralları ve inceleme listesi bu nedenle gereklidir. Son olarak, refactoring ile davranış değişikliğini aynı değişiklikte yapmak, hatayı bulmayı güçleştirir.
Bu beceriyi Mindset programlarında nerede geliştirirsiniz?
Yazılım geliştiriciler, takım liderleri ve kod incelemesi yapan mühendisler için Temiz Kod (Clean Code) Prensipleri programı okunabilirlik ve isimlendirme, fonksiyon tasarımı, hata yönetimi ve test edilebilirliği işler; programın son modülü kod kokuları ve ekip standardına ayrılmıştır.
Clean Coding Uzmanlığı Eğitimi ise refactoring ve performans optimizasyonunu ayrı bir modül olarak ele alır ve uygulamalı proje ile kod incelemesiyle sonlanır. Kurumsal ekipler kendi kod tabanlarından seçilmiş, gizlilik sorunu olmayan parçalar üzerinde ortak refactoring atölyesi yapabilir.
İlgili Mindset programı
Temiz Kod (Clean Code) Prensipleri
Sık sorulan sorular
Kod kokusu ile hata (bug) arasındaki fark nedir?
Hata, yanlış sonuç üreten davranıştır. Kod kokusu ise doğru çalışan kodun yapısında bir sorun olabileceğini gösteren belirtidir. Koku şimdiki davranışı bozmaz ama değişikliği zorlaştırır ve gelecekte hata üretme riskini artırır.
Refactoring ne zaman yapılmalı?
Yeni özelliği eklemeden hemen önce, hata düzeltirken ve kod incelemesinde anlaşılması zor bir yerle karşılaşıldığında yapılır. Sık değişen ve kokan bölgeler önceliklidir. Davranışı kilitleyen testler yoksa önce test yazılır; sonra küçük adımlarla ilerlenir.
Birden fazla kod kokusu varsa hangisinden başlanmalı?
Sık değişen, hata geçmişi olan ya da yeni özelliği engelleyen bölgedeki kokudan başlayın. Küçük adımla giderilebilen kokular, örneğin uzun bir fonksiyondan parça çıkarmak, hızlı kazanım sağlar ve sonraki dönüşümleri kolaylaştırır. Her dönüşümü ayrı ve küçük bir değişiklik olarak yapıp testlerle doğrulayın.
Her kod kokusu düzeltilmeli mi?
Hayır. Hiç değişmeyen ve risk taşımayan eski bir parçada yatırım çoğu zaman karşılığını vermez. Koku sık değişen, hata üreten ya da yeni özelliği engelleyen bölgedeyse düzeltmek mantıklıdır. Karar etkiye ve maliyete göre verilir.
Statik analiz araçları kod kokularını bulmaya yeter mi?
Araçlar karmaşıklık, yinelenen kod ve kullanılmayan kod gibi belirtileri gösterir ama hangisinin gerçek sorun olduğuna karar veremez. Tasarım kokuları, örneğin yanlış sorumluluk dağılımı, insan incelemesi ve ekip tartışması gerektirir; araç çıktısı bu tartışmanın başlangıç noktasıdır.
İlgili rehberler
İlgili eğitimler
Kategori: Yazılım Geliştirme