Code Smell, bir uygulamanın tasarımında veya mimarisinde potansiyel bir soruna işaret eden yüzeysel bir kod göstergesidir. Terim Kent Beck tarafından ortaya atılmış ve Martin Fowler tarafından “Refactoring: Improving the Design of Existing Code” kitabında popüler hale getirilmiştir. Martin Fowler'a göre, kod kokusu mutlaka bir hata anlamına gelmez, ancak bakımı iyileştirmek için neredeyse her zaman yeniden düzenleme gerektiğini gösterir.
Önemli Noktalar
Code Smell, yüksek olasılıkla daha derin sorunlara işaret eden kaynak koddaki semptomlar için bir metafordur. Terimin kendisinin resmi bir tanımı yoktur — geliştiricilerin deneyimine dayanan bir buluşsal yöntemdir. Martin Fowler ve Kent Beck, 1999 yılında “Refactoring” kitabında ilk kez 22 kokuyu sistematize etti ve çoğu on yıllar sonra hala geçerliliğini koruyor.
Code Smell ve hata arasındaki farkı anlamak önemlidir. Koku bir hata değildir: kod derlenir, çalışır ve doğru sonuçlar üretir. Sorun, bu tür kodun okunması, değiştirilmesi ve test edilmesinin zor olmasıdır. Zamanla, her değişikliğin maliyeti artar ve yeniden düzenlemenin doğruluğuna olan güven azalır. Statik analiz araçları (SonarQube, Detekt, SwiftLint) birçok kokuyu otomatik olarak tespit eder.
Code Smell'in buluşsal doğası, her uzun metodun bölünmesi gerekmediği ve her büyük sınıfın yeniden düzenlenmesi gerekmediği anlamına gelir. Karar, geliştirici tarafından bağlamı değerlendirerek verilir: değişiklik sıklığı, modülün kritikliği, geliştirme planları. Deneyimli mühendisler bir kokuyu sezgisel olarak hisseder — tüm resmi kurallar takip edilse bile kod “kötü kokar”.
Fowler, birkaç kategoriye ayrılmış 22 koku belirlemiştir. Mobil geliştirme için en alakalı olanlar yapısal kokular, nesne yönelimli tasarım kokuları ve platform kısıtlamalarıyla ilgili spesifik sorunlardır. Her grubu gerçek dünya örnekleriyle inceleyelim.
Long Method mobil uygulamalarda en yaygın kokudur. Bir kayıt formu ekranı genellikle tüm View'ları oluşturan, kısıtlamaları ayarlayan, olaylara abone olan ve hataları işleyen 200+ satırlık tek bir setupUI metodu içerir. Çözüm: mantıksal bloklara göre metotlara bölün — configureEmailField, configurePasswordField, setupConstraints, bindViewModel.
Large Class — görüntüleme, gezinme, iş mantığı ve ağ etkileşimlerinin hepsinden sorumlu bir Activity veya ViewController. Böyle bir sınıf, Tek Sorumluluk İlkesini ihlal eder ve düzinelerce alan ve metot içerir. Android'de bu genellikle farklı ekranların mantığını içeren 1000+ satırlık bir Fragment'tir. Çözüm: bir presenter/ViewModel çıkarın, ağ kodunu bir depoya ve gezinmeyi bir koordinatöre taşıyın.
Duplicate Code — uygulamanın farklı bölümlerinde aynı blokları kopyalamak. Tipik bir örnek: iki ekran bir ürün kartı gösteriyor — katalogda ve favorilerde. Görüntüleme mantığı kopyalanmışsa, bir yerdeki hatayı düzeltmek diğer yerde düzeltmez. Çözüm: ortak mantığı yeniden kullanılabilir bir bileşene veya uzantıya çıkarın.
Feature Envy — bir sınıfın metodu başka bir sınıfın verilerini yoğun şekilde kullanır. Android'de bu, bir ViewModel'in modelin metodunu çağırmak yerine doğrudan bir User modelinin alanlarına erişmesiyle ortaya çıkar. İşaret: bir metot, verilerini kullandığı sınıfa taşınabiliyorsa — taşıyın. Switch Statements (koşul zincirleri) — nesne türünü kontrol eden bir switch yapısı veya if-else zinciri. Bunun yerine, çok biçimlilik veya strateji deseni kullanın.
Data Class — yalnızca veri depolayan ancak davranış içermeyen sınıf. Kotlin'deki data class'lar veya Swift'teki yapılar kendi başlarına bir koku değildir. Sorun, bu verilerle çalışan iş mantığının kapsüllenmek yerine kod tabanına dağılmasıyla ortaya çıkar. Refused Bequest — bir alt sınıf, ebeveynin metotlarının çoğunu kullanmaz ve bunları boş saplamalarla geçersiz kılar. Yanlış kalıtım işareti: kalıtımı kompozisyonla değiştirin.
God Activity / God Fragment — yaşam döngüsü, veri, gezinme, izinler, DI hakkında her şeyi bilen bir Activity veya Fragment. Bir uygulamada bakımı en pahalı sınıftır. Çözüm: MVVM, MVI veya Clean Architecture gibi mimari desenler sorumlulukları ayırır. Giant ViewController — iOS'taki karşılığı, bir UIViewController'ın ekranın tüm mantığını içerdiği ve genellikle 500 satırı aştığı durumdur.
Hardcoded Resources — dizeler, renkler, boyutlar, API URL'leri doğrudan koda gömülü. Android'de bu, R kaynak sistemini ihlal eder; iOS'ta NSLocalizedString ve Asset Catalog'u ihlal eder. Düzeltme: tüm dizeleri strings.xml veya Localizable.strings'e, URL'leri bir yapılandırma dosyasına, boyutları dimens'e taşıyın. Leaking Context — bir Activity veya ViewController referansını bileşenin kendi ömründen daha uzun süre tutmak. Bellek sızıntılarına ve çökmelere yol açar. Çözüm: zayıf referanslar, Jetpack Lifecycle, RxSwift DisposeBag.
| Koku | Nerede Görülür | Çözüm |
|---|---|---|
| Long Method | Android/iOS | Extract Method, bölme |
| Large Class | Activity, ViewController | MVVM, VIPER, Clean Arch |
| Duplicate Code | Herhangi bir ekran | Paylaşılan Bileşen, DRY |
| Feature Envy | ViewModel, Presenter | Move Method |
| Leaking Context | Android | Lifecycle-aware bileşenler |
Kod incelemesi kokuları tespit etmenin en güvenilir yoludur. İnsan gözü, otomatik analizörlerin gözden kaçırdığı doğal olmayan yapıları fark eder. Ekip tipik kokuların bir kontrol listesini kullandığında kod inceleme etkinliği artar. Oturum başına 200–400 satırdan fazla kod incelenmemesi önerilir — bu eşikten sonra dikkat azalır ve kokular gözden kaçmaya başlar.
Statik analiz yapısal kokuların aranmasını otomatikleştirir. Android için standart araçlar Detekt (Kotlin) ve Android Lint'tir; iOS için SwiftLint ve SonarQube. Bu araçlar uzun metotlar, büyük sınıflar, yinelenen kod ve diğer birçok sorunu bulur. Kuralları projeye göre ayarlamak önemlidir — varsayılan yapılandırmalar genellikle çok katıdır veya tam tersine kritik kokuları gözden kaçırır.
Kod metrikleri nesnel kriterler sağlar: Döngüsel Karmaşıklık (eşik >10 dikkat gerektirir), Metot Başına Kod Satırı (eşik >30), Kalıtım Derinliği (>3 — düşünme nedeni). CodeMetrics (Xcode) ve Gradle Metrics Plugin gibi araçlar, metriklerin zaman içindeki değişiminin grafiklerini oluşturur. Son commit'ten sonra bir metodun karmaşıklığı 5'ten 15'e yükseldiyse — bu yeniden düzenleme sinyalidir.
// Örnek: Döngüsel Karmaşıklık = 7 olan metot (eşik 5'in üzerinde)
fun processOrder(order: Order) {
if (order.status == Status.NEW) { /* 10 satır */ }
else if (order.status == Status.PAID) { /* 15 satır */ }
else if (order.status == Status.SHIPPED) { /* 20 satır */ }
else if (order.status == Status.DELIVERED) { /* 8 satır */ }
else if (order.status == Status.CANCELLED) { /* 5 satır */ }
else { throw IllegalStateException() }
}
// Düzeltme: switch yerine çok biçimlilik
interface OrderHandler {
fun handle(order: Order)
}
Otomatik koku tespiti kod incelemesinin yerini almaz: statik analizörler yalnızca yapısal sorunları bulur ancak anlamsal kokuları (Feature Envy, Inappropriate Intimacy) yakalayamaz. Otomatik araçlar ve insan incelemesinin kombinasyonu en iyi sonuçları verir. CI/CD hattınızı, karmaşıklık veya metot uzunluğu eşikleri aşıldığında derlemelerin başarısız olacağı şekilde yapılandırın.
Yeniden düzenleme kod kokularını ortadan kaldırmanın birincil yöntemidir. Fowler, her biri belirli bir kokuya uygulanabilen düzinelerce yeniden düzenleme tekniğini açıklar. Extract Method — uzun metotlar için, Extract Class — büyük sınıflar için, Move Method — Feature Envy için. Her değişiklikten sonra kodu çalışır durumda tutarak küçük adımlarla yeniden düzenleme yapmak önemlidir.
Yeniden düzenlemeden önce testler zorunludur. Kod birim testlerle kapsanmıyorsa, yeniden düzenleme bilinmeyen sonuçlarla yeniden yazmaya dönüşür. Testleri olmayan eski kod için Karakterizasyon Testleri kullanın — mevcut davranışı yakalayan testler yazın, sonra yeniden düzenleyin. Testler, yeniden düzenlemeden sonra iş mantığının bozulmadığına dair güven verir.
Aşamalılık mobil geliştirmede kokuları başarıyla düzeltmenin anahtarıdır. Bir God Activity'yi tamamen yeniden yazmaya çalışmayın. Önce gezinme katmanını, sonra veri katmanını, sonra görüntüleme mantığını çıkarın. Her adıma bir commit ve test çalıştırması eşlik etmelidir. Kullanıcıların bir alt kümesi için yeniden düzenlemeyi etkinleştirmek ve sorun çıkarsa geri almak için özellik geçişleri kullanın.
IDE araçları birçok yeniden düzenleme tekniğini otomatikleştirir. Android Studio ve IntelliJ IDEA, yerleşik yeniden düzenlemeler sunar: Extract Method, Extract Interface, Pull Members Up, Encapsulate Fields. Xcode (sürüm 14'ten itibaren) Swift için yeniden düzenleme desteğini geliştirmiştir. Otomatik yeniden düzenlemelerin kullanılması, manuel kod kopyalamaya kıyasla hata riskini azaltır.
Mobil geliştirme, platform kısıtlamalarıyla ilgili kendine özgü kokular ekler. Android'de bu, Context sızıntıları, kapatılmamış imleçler ve Lifecycle'ın yanlış kullanımını içerir. iOS'ta, closure'lar aracılığıyla tutma döngüleri, Auto Layout'un yanlış işlenmesi ve dev ViewController'lar. Bu kokular yalnızca bakımı zorlaştırmakla kalmaz, aynı zamanda uygulamanın performansını ve kararlılığını doğrudan etkiler.
Callback Hell, eşzamansız işlemlerle çalışan kod için karakteristik bir kokudur. İç içe geçmiş geri çağırmalar kodu okunamaz ve hata ayıklaması zor hale getirir. Çözüm: coroutine'ler (Kotlin), async/await (Swift 5.5+), RxJava/RxSwift veya Combine. Google I/O 2023'e göre, geri çağırma stilinden coroutine'lere geçen projeler hata sayısını %30 azalttı ve yeni özelliklerin eklenmesini hızlandırdı.
Platform Coupling — iş mantığının platform bileşenlerine sıkı bağlanması. Bu tür mantığı test etmek bir öykünücü başlatmayı gerektirir, bu da geri bildirim döngüsünü yavaşlatır. Düzeltme: Clean Architecture, kodu Domain (platform bağımlılığı olmayan saf Kotlin/Swift) ve Data/UI (platform bağımlılıkları olan) katmanlarına ayırır. İş mantığı, öykünücü olmadan JVM'de test edilir.
Sıkça Sorulan Sorular
Hayır — Code Smell bir hata değildir. Kokulu kod doğru çalışır, ancak bakımı, değiştirilmesi ve test edilmesi zordur. Hata yanlış davranıştır; koku ise olası gelecek sorunlar hakkında bir uyarıdır.
22 koku “Refactoring” (2019) ikinci baskısında. Bunlar arasında Long Method, Large Class, Primitive Obsession, Data Clumps, Switch Statements, Speculative Generality ve diğerleri bulunur. Topluluk, modern paradigmalar ve platformlar için düzinelerce yeni koku eklemiştir.
Bir kombinasyon en iyi sonucu verir: otomatik analiz için Detekt (Android/Kotlin), SwiftLint (iOS), SonarQube (her ikisi) ve anlamsal kokular için kod incelemesi. Hiçbir tek araç sorunların %100'ünü bulamaz — insan deneyimi belirleyici olmaya devam eder.
Evet, kod nadiren değişiyorsa veya yakında tamamen yeniden yazılacaksa. Ancak, kokuların birikmesi teknik borca dönüşür: her yeni değişiklik daha da zorlaşır ve düzeltme maliyeti katlanarak artar.
Evet — bildirimsel çerçeveler yeni kokular ortaya çıkarmıştır: dev @State blokları, tekrarlanan işlemelerin yanlış işlenmesi, aşırı yeniden oluşturma ve ayrı View'lara çıkarma eksikliği. SwiftUI için tipik bir koku, düzinelerce @State değişkenine sahip Massive View'dır.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun