Separation of Concerns, her modülün veya uygulama katmanının bir sorumluluk alanından sorumlu olduğu bir ilkedir. Wikipedia'ya göre, terim 1974 yılında Edsger Dijkstra tarafından tanıtılmış ve o zamandan beri yazılım mimarisinin temeli haline gelmiştir. Sorumlulukların ayrılması, geliştiricilerin diğerlerini etkilemeden kodun bir katmanını değiştirmesine olanak tanır; bu, uzun destek döngülerine sahip mobil projelerde kritik öneme sahiptir.
Anahtar Noktalar
Separation of Concerns, bir yazılım sistemini her biri bir görevi çözen bağımsız parçalara ayırma ilkesidir. Concern (sorumluluk alanı) terimi, işlevselliğin ayrılabilir herhangi bir parçasını belirtir: ekran görüntüleme, dokunma işleme, veri doğrulama veya ağ iletişimi. İlke, bir alandaki değişikliklerin diğer alanlarda değişiklik gerektirmemesi için kodun gruplandırılmasını emreder.
Mobil geliştirmede, SoC birkaç seviyede kendini gösterir: uygulamayı ekranlara bölmekten tek bir sınıf içinde kod düzenlemeye kadar. Aynı anda ağdan veri yükleyen, JSON ayrıştıran ve UI oluşturan bir Activity veya ViewController, Separation of Concerns'i ihlal eder — bu tür kod bakımı, test edilmesi ve genişletilmesi zordur. Alternatif, her sorumluluğu ayrı bir bileşene çıkarmaktır.
İlke, soyutlama kavramıyla yakından ilişkilidir: her katman kesin olarak tanımlanmış bir arayüz sağlar ve uygulama ayrıntılarını gizler. Bu sayede bir geliştirici, UI mantığını yeniden yazmadan bir ağ kütüphanesini veya veritabanını değiştirebilir. Bu, gereksinimlerin ve teknolojilerin zamanla değiştiği uzun ömürlü projelerde özellikle değerlidir.
Edsger Dijkstra, Separation of Concerns fikrini ilk kez 1974 tarihli «On the Role of Scientific Thought» makalesinde formüle etti. Yazılım sistemlerinin karmaşıklığının, sistemleri izole olarak analiz edilen parçalara bölerek kontrol edilebileceğini savundu. Bu yaklaşım, kodun hesaplama, giriş-çıkış ve kullanıcı arayüzünü karıştırdığı dönemin monolitik programlarının tam tersiydi.
1980'lerde, fikir yapısal programlama savunucuları ve daha sonra nesne yönelimli yaklaşım tarafından geliştirildi. Smalltalk ve C++ gibi diller, SoC'yi pratik bir araç haline getiren kapsülleme ve modülerlik mekanizmaları sağladı. Modern mimari desenler — MVC, MVP, MVVM ve Clean Architecture — Separation of Concerns ilkesinin doğrudan somutlaşmış halleridir.
Mobil geliştirme dünyasında, Apple iOS için MVC'yi standart olarak tanıttı; burada Model-View-Controller verileri, görüntülemeyi ve kontrol mantığını ayırır. Google, Android için ViewModel ve Repository'ye dayalı mimari yönergeler önerdi — her bileşen kendi sınırlı görevini çözer. SoC olmadan, mobil uygulamalar Massive View Controller — binlerce satırlık sınıflar — haline gelir ve herhangi bir değişiklik tüm işlevselliği bozma riski taşır.
Dört ana katman, Separation of Concerns'i uygulayan tipik bir mobil uygulama mimarisi oluşturur. Her katman yalnızca kendi alanından sorumludur ve arayüzler aracılığıyla komşularıyla etkileşime girer.
View, yalnızca verileri görüntülemekten ve kullanıcı olaylarını işlemekten sorumludur. iOS'ta bu UIViewController ve UIView, Android'de — Fragment veya Activity'dir. ViewModel, ekran durumunu ve verileri görüntülemeye hazır bir biçime dönüştürme mantığını içerir. Ayırma, UIKit'in SwiftUI ile değiştirilmesinin veya bir ekranın Jetpack Compose ile yeniden yazılmasının iş mantığını etkilememesini sağlar.
ViewModel'i test etmek için bir emülatör veya simülatör çalıştırmak gerekmez — veri dönüşümünü ve kullanıcı eylemlerine yanıtı doğrulayan birim testler yeterlidir. Bu, Separation of Concerns'in doğrudan bir sonucudur: UI iş kurallarıyla karışmaz ve her bileşen izole olarak test edilir.
Use Case (veya Interactor), uygulamanın iş kurallarını içerir — hesaplamalar, doğrulamalar, veri çağrılarının orkestrasyonu. Bu katman, UI'nın veya platform çerçevelerinin varlığını bilmez. Use Case, Repository'den veri alır, mantığı uygular ve hazır sonucu ViewModel'e döndürür. Ayırma, aynı Use Case'in farklı ekranlarda yeniden kullanılmasına olanak tanır.
Örneğin, LoginUseCase e-posta geçerliliğini kontrol eder, kimlik doğrulama için AuthRepository'i çağırır ve sonucu döndürür. Giriş ekranının nasıl göründüğüne bağlı değildir — SwiftUI, UIKit veya Compose. İş kuralları değişirse, UI'ya veya veritabanına dokunmadan bir Use Case'i değiştirmek yeterlidir.
Repository, veri kaynaklarını soyutlar: uzak API, yerel veritabanı veya bellek önbelleği. ViewModel ve Use Case, verilerin tam olarak nereden geldiğini bilmez — Repository, ağdan mı yoksa önbellekten mi yükleneceğine karar verir. Bu ayırma, iş mantığını veya UI'yı etkilemeden depolama uygulamasının değiştirilmesine olanak tanır.
DataSource daha düşük seviyeli bir ayırmadır: NetworkDataSource yalnızca HTTP isteklerinden sorumludur, LocalDataSource — Room veya CoreData ile çalışmaktan. Repository, farklı DataSources'lara yapılan çağrıları tek bir tutarlı arayüzde birleştirir. Her DataSource, mock veya sahte sunucular kullanılarak bağımsız olarak test edilir.
DataSource katmanının doğru uygulanması, veritabanı şemasını değiştirmenin veya REST API'yi GraphQL ile değiştirmenin yalnızca bir DataSource'u etkilemesini, ancak Repository'yi veya tüketicilerini etkilememesini sağlar. Bu, altyapı düzeyinde Separation of Concerns'in doğrudan bir sonucudur: her teknik endişe izole edilir ve basamaklı değişiklikler olmadan değiştirilebilir.
MVVM (Model-View-ViewModel), mobil geliştirme için en popüler desendir ve Separation of Concerns'i doğrudan uygular. Model, verileri ve iş mantığını içerir, View görüntülemeden sorumludur ve ViewModel, reaktif mekanizmalar aracılığıyla bunları birbirine bağlar. Flutter'da BLoC, olaylar, durumlar ve iş mantığına ayırma ile benzer bir rol oynar.
Robert Martin'in (Uncle Bob) Clean Architecture'ı SoC'yi maksimuma çıkarır: sistem bağımsız halkalara bölünür — varlıklar, kullanım durumları, bağdaştırıcılar ve çerçeveler. İç halkalar (varlıklar) dış halkalara (çerçeveler) bağlı değildir. Bu, uygulamanın temel mantığını yeniden yazmadan veritabanını, UI çerçevesini ve hatta platformu değiştirmeye olanak tanır.
Pratikte, mobil projeler nadiren tam Clean Architecture'ı uygular — çoğu uygulama için üç katmanlı bir mimari yeterlidir: UI, Alan ve Veri. Alan katmanı, Use Case'ler ve iş modelleri içerir ve Android SDK veya iOS SDK'dan tamamen izole edilmiştir. Böyle bir ayırma, %20 çabayla %80 fayda sağlar.
// Data layer — yalnızca veri almaktan sorumlu
class UserRepository(private val api: UserApi) {
suspend fun getUser(id: String): User = api.fetchUser(id)
}
// Domain layer — iş mantığı, API veya veritabanını bilmez
class GetUserNameUseCase(
private val repo: UserRepository
) {
suspend fun invoke(id: String): String {
val user = repo.getUser(id)
return "${user.firstName} ${user.lastName}"
}
}
// UI layer — yalnızca görüntüleme
class UserViewModel(
private val getUserName: GetUserNameUseCase
) {
fun onUserLoaded(id: String) {
viewModelScope.launch {
_name.value = getUserName.invoke(id)
}
}
}
Yukarıdaki kod saf ayırmayı gösterir: UserRepository yalnızca API ile çalışır, GetUserNameUseCase ad biçimlendirmenin iş mantığını içerir ve UserViewModel UI durumunu yönetir. Her sınıfın değişmesi için bir nedeni vardır, bu da Separation of Concerns'in özüdür.
SoC'nin ana avantajı bakım kolaylığıdır. Bağımsız katmanlara bölünmüş kodun analiz edilmesi daha kolaydır: geliştirici yalnızca hatanın oluştuğu katmana bakar ve diğerleri tarafından dikkati dağılmaz. Uzun vadeli projelerde bu, monolitik koda kıyasla hata bulma ve düzeltme süresini %30–50 oranında azaltır.
İkinci önemli avantaj test edilebilirliktir. İş mantığı UI ve çerçevelerden izole edildiğinde, emülatör çalıştırmadan birim testlerle kapsanır. Yüksek birim test kapsamına sahip Android ve iOS projeleri, yeni özellikler eklerken önemli ölçüde daha az gerilemeye sahiptir.
Ana sınırlama artan karmaşıklıktır. Mikro katmanlara ve soyutlamalara aşırı parçalama, basit bir düğme eklemek için geliştiricinin beş dosyayı düzenlemesi gerektiği anlamına gelir. Separation of Concerns ilkesi makul bir denge gerektirir: yalnızca gerçekten bağımsız olarak değişen alanları ayırın. Küçük projeler için, ek soyutlamalar olmadan UI, mantık ve veriye temel bir ayırma yeterlidir.
Sıkça Sorulan Sorular
SoC sorumluluk alanlarına göre ayırma ilkesidir, modülerlik ise kodu fiziksel modüller halinde organize etmenin bir yoludur. SoC, tek bir modül içinde katmanlar veya sınıflar aracılığıyla uygulanabilirken, modülerlik bağımsız yapılara bölünmeyi gerektirir.
SoC, SOLID ilkelerinin üzerinde bir üst yapıdır. Tek Sorumluluk İlkesi (S), tek bir sınıf düzeyinde SoC'dir. Bağımlılığı Tersine Çevirme İlkesi (D), arayüzler ve bağımlılık enjeksiyonu yoluyla katmanlar arasında SoC uygulanmasına yardımcı olur.
Evet, ancak ılımlı bir derecede. Basit bir uygulama için UI ve iş mantığını ayırmak yeterlidir. Aşırı sayıda katman, pratik bir fayda sağlamadan kodu karmaşıklaştıracaktır. Proje büyüdükçe katman sayısı kademeli olarak artırılır.
Performans üzerinde doğrudan bir etkisi yoktur — SoC kod mimarisiyle ilgilidir, yürütmeyle değil. Ancak, katmanlara ayırma, katmanlar arasındaki ek çağrılar nedeniyle dolaylı bir yük ekleyebilir. Pratikte bu etki, bakım kolaylığının faydalarına kıyasla ihmal edilebilir düzeydedir.
Bağımlılık enjeksiyonu (Hilt, Koin, Swinject) katmanlar arasındaki sınırları açıkça yönetir. Detekt (Android) ve SwiftLint (iOS) içindeki mimari lint kuralları, izin verilmeyen katmanlardan içe aktarmaları yasaklar. Git kancaları, iş katmanının UI kütüphanelerini içe aktarmadığını kontrol edebilir.
Ö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