Tüm Yazılar
KategoriArchitecture
Okuma Süresi
23 dk okuma
Yayın Tarihi
...
Kelime Sayısı
1.683kelime

Kahveni hazırla - bu içerikli bir makale!

Microservices yaklaşımını mobil dünyaya taşıyın: feature modules, dynamic frameworks, dependency injection ve inter-module communication ile ölçeklenebilir iOS uygulamaları.

Mobile Microservices Architecture: Modüler ve Ölçeklenebilir iOS

# Mobile Microservices Architecture: Modüler ve Ölçeklenebilir iOS

Büyük iOS projeleri zamanla monolit canavarlara dönüşür: derleme süreleri dakikalar alır, bir dosyadaki değişiklik beklenmedik yerleri kırar, ve yeni geliştiriciler projeye adapte olamaz. Microservices mimarisi backend dünyasını dönüştürdü — aynı prensipler mobil dünyada da devrim yaratabilir. Bu rehberde, iOS uygulamanızı bağımsız, test edilebilir ve ölçeklenebilir modüllere ayırmayı öğreneceksiniz.

Not: Mobile microservices, backend microservices ile birebir aynı değildir. Burada "micro" kelimesi, bağımsız feature modülleri anlamında kullanılmaktadır.

İçindekiler


1. Monolit vs Modüler Mimari

Karşılaştırma

Kriter
Monolit
Modüler
Micro-Feature
**Derleme süresi**
Uzun (tümü)
Orta (değişen modül)
Kısa (tek modül)
**Ekip ölçeği**
1-5 geliştirici
5-15 geliştirici
15+ geliştirici
**Code ownership**
Herkes her yer
Modül bazlı
Feature team
**Test izolasyonu**
Zor
Kolay
Mükemmel
**Bağımlılık yönetimi**
İmplicit
Explicit
Strict boundaries
**Reusability**
Düşük
Orta
Yüksek
**Onboarding**
Tüm projeyi anla
Modülü anla
Feature'ı anla
**Merge conflict**
Sık
Nadir
Çok nadir
**Release bağımsızlığı**
Yok
Kısıtlı
Feature flag ile

2. Module Boundaries Tasarımı

Doğru sınırları belirlemek, modüler mimarinin en kritik adımıdır.

Katman Yapısı

swift
1// MARK: - Module Hierarchy
2 
3// TIER 1: Core Modules (sifir bagimlilik)
4// - CoreFoundation: Extensions, utilities, protocols
5// - CoreNetworking: HTTP client, request/response models
6// - CoreStorage: Local storage abstractions
7// - CoreUI: Design system, shared components
8 
9// TIER 2: Domain Modules (Core'a bagimli)
10// - AuthDomain: Authentication models, protocols
11// - PaymentDomain: Payment models, protocols
12// - UserDomain: User models, protocols
13 
14// TIER 3: Feature Modules (Domain + Core'a bagimli)
15// - AuthFeature: Login, register, forgot password UI
16// - HomeFeature: Home screen, feed
17// - ProfileFeature: User profile, settings
18// - PaymentFeature: Checkout, payment history
19 
20// TIER 4: App Module (hepsini birlestirir)
21// - MyApp: Composition root, dependency injection, navigation

Bağımlılık Kuralı

swift
1// Package.swift - Module bagimliliklari
2// swift-tools-version: 5.9
3import PackageDescription
4 
5let package = Package(
6 name: "AppModules",
7 platforms: [.iOS(.v17)],
8 products: [
9 // Core
10 .library(name: "CoreFoundation", targets: ["CoreFoundation"]),
11 .library(name: "CoreNetworking", targets: ["CoreNetworking"]),
12 .library(name: "CoreUI", targets: ["CoreUI"]),
13 // Domain
14 .library(name: "AuthDomain", targets: ["AuthDomain"]),
15 .library(name: "UserDomain", targets: ["UserDomain"]),
16 // Feature
17 .library(name: "AuthFeature", targets: ["AuthFeature"]),
18 .library(name: "HomeFeature", targets: ["HomeFeature"]),
19 .library(name: "ProfileFeature", targets: ["ProfileFeature"]),
20 ],
21 targets: [
22 // TIER 1: Core - sifir internal bagimlilik
23 .target(name: "CoreFoundation"),
24 .target(name: "CoreNetworking", dependencies: ["CoreFoundation"]),
25 .target(name: "CoreUI", dependencies: ["CoreFoundation"]),
26 
27 // TIER 2: Domain - sadece Core'a bagimli
28 .target(name: "AuthDomain", dependencies: ["CoreFoundation"]),
29 .target(name: "UserDomain", dependencies: ["CoreFoundation"]),
30 
31 // TIER 3: Feature - Domain + Core'a bagimli
32 .target(name: "AuthFeature", dependencies: [
33 "AuthDomain", "CoreNetworking", "CoreUI"
34 ]),
35 .target(name: "HomeFeature", dependencies: [
36 "UserDomain", "CoreNetworking", "CoreUI"
37 ]),
38 .target(name: "ProfileFeature", dependencies: [
39 "UserDomain", "CoreNetworking", "CoreUI"
40 ]),
41 
42 // Tests
43 .testTarget(name: "AuthFeatureTests", dependencies: ["AuthFeature"]),
44 .testTarget(name: "HomeFeatureTests", dependencies: ["HomeFeature"]),
45 ]
46)

3. Inter-Module Communication

Feature modüller birbirini doğrudan import edemez. İletişim, protocol-based routing ile sağlanır.

swift
1// MARK: - Module Router Protocol (CoreFoundation'da)
2protocol ModuleRouter {
3 func route(to destination: RouteDestination) -> AnyView
4}
5 
6enum RouteDestination: Hashable {
7 case profile(userId: String)
8 case settings
9 case payment(productId: String)
10 case auth(mode: AuthMode)
11}
12 
13enum AuthMode: Hashable {
14 case login
15 case register
16}
17 
18// MARK: - Feature Module Route Handler
19// Her feature kendi route'larini handle eder
20protocol FeatureRouteHandler {
21 var handledRoutes: Set<String> { get }
22 func handle(_ destination: RouteDestination) -> AnyView?
23}
24 
25// ProfileFeature icinde:
26struct ProfileRouteHandler: FeatureRouteHandler {
27 var handledRoutes: Set<String> { ["profile", "settings"] }
28 
29 func handle(_ destination: RouteDestination) -> AnyView? {
30 switch destination {
31 case .profile(let userId):
32 return AnyView(ProfileView(userId: userId))
33 case .settings:
34 return AnyView(SettingsView())
35 default:
36 return nil
37 }
38 }
39}
40 
41// MARK: - Central Router (App Module'de)
42final class AppRouter: ModuleRouter {
43 private var handlers: [FeatureRouteHandler] = []
44 
45 func register(_ handler: FeatureRouteHandler) {
46 handlers.append(handler)
47 }
48 
49 func route(to destination: RouteDestination) -> AnyView {
50 for handler in handlers {
51 if let view = handler.handle(destination) {
52 return view
53 }
54 }
55 return AnyView(NotFoundView())
56 }
57}

Easter Egg

Gizli bir bilgi buldun!

Bu bölümde gizli bir bilgi var. Keşfetmek ister misin?


4. Dependency Injection Container

swift
1// MARK: - DI Container
2final class DIContainer {
3 static let shared = DIContainer()
4 
5 private var factories: [String: () -> Any] = [:]
6 private var singletons: [String: Any] = [:]
7 private let lock = NSRecursiveLock()
8 
9 func register<T>(
10 _ type: T.Type,
11 scope: Scope = .transient,
12 factory: @escaping() -> T
13 ) {
14 let key = String(describing: type)
15 lock.lock()
16 defer { lock.unlock() }
17 
18 switch scope {
19 case .transient:
20 factories[key] = factory
21 case .singleton:
22 factories[key] = { [weak self] in
23 guard let self else { return factory() }
24 if let existing = self.singletons[key] as? T {
25 return existing
26 }
27 let instance = factory()
28 self.singletons[key] = instance
29 return instance
30 }
31 }
32 }
33 
34 func resolve<T>(_ type: T.Type) -> T {
35 let key = String(describing: type)
36 lock.lock()
37 defer { lock.unlock() }
38 
39 guard let factory = factories[key] else {
40 fatalError("\(key) kayitli degil! register() ile kaydedin.")
41 }
42 guard let instance = factory() as? T else {
43 fatalError("\(key) icin factory yanlis tip dondu")
44 }
45 return instance
46 }
47 
48 enum Scope {
49 case transient // Her resolve'da yeni instance
50 case singleton // Tek instance
51 }
52}
53 
54// MARK: - Module Registration
55// Her feature module kendi dependency'lerini kaydeder
56protocol ModuleRegistrar {
57 static func registerDependencies(in container: DIContainer)
58}
59 
60// AuthFeature/AuthModule.swift
61struct AuthModuleRegistrar: ModuleRegistrar {
62 static func registerDependencies(in container: DIContainer) {
63 container.register(AuthServiceProtocol.self, scope: .singleton) {
64 AuthService(
65 networkClient: container.resolve(NetworkClientProtocol.self),
66 tokenStore: container.resolve(TokenStoreProtocol.self)
67 )
68 }
69 container.register(LoginViewModel.self) {
70 LoginViewModel(authService: container.resolve(AuthServiceProtocol.self))
71 }
72 }
73}

5. Feature Module Anatomisi

swift
1// MARK: - Ideal Feature Module Yapisi
2//
3// Sources/ProfileFeature/
4// Public/
5// ProfileFeatureAPI.swift (Public interface)
6// ProfileRouteHandler.swift (Route handling)
7// Internal/
8// Views/
9// ProfileView.swift
10// EditProfileView.swift
11// ViewModels/
12// ProfileViewModel.swift
13// Models/
14// ProfileState.swift
15// Services/
16// ProfileService.swift
17//
18// Tests/ProfileFeatureTests/
19// ProfileViewModelTests.swift
20// ProfileServiceTests.swift
21// Mocks/
22// MockProfileService.swift
23 
24// Public API - sadece bu dosya public
25public struct ProfileFeatureAPI {
26 public static func makeProfileView(userId: String) -> some View {
27 let vm = DIContainer.shared.resolve(ProfileViewModel.self)
28 return ProfileView(viewModel: vm, userId: userId)
29 }
30 
31 public static func routeHandler() -> FeatureRouteHandler {
32 ProfileRouteHandler()
33 }
34}

6. Build Performance

Modüler mimarinin en büyük avantajlarından biri derleme süresidir.

Build Süresi Karşılaştırması

Senaryo
Monolit
Modüler (SPM)
Kazanım
**Clean build**
180 sn
160 sn
%11
**Incremental (1 dosya)**
45 sn
8 sn
%82
**Incremental (1 modül)**
45 sn
15 sn
%67
**Test (1 modül)**
120 sn
12 sn
%90
**CI full build**
300 sn
200 sn
%33

Build Optimizasyonları

swift
1// Xcode build settings per module
2// SWIFT_COMPILATION_MODE = wholemodule (Release)
3// BUILD_LIBRARY_FOR_DISTRIBUTION = YES (binary framework)
4// EAGER_LINKING = YES (Xcode 15+)
5 
6// Pre-compiled binary cache
7// CI'da her commit'te modulleri pre-build edin
8// swift build --product CoreNetworking
9// Artifact'i cache'leyin (GitHub Actions cache, Tuist warmup vb.)

swift
1// MARK: - CI icin Dependency Graph Validator (Swift Script)
2import Foundation
3 
4struct ModuleDependency: Codable {
5 let name: String
6 let tier: Int
7 let dependencies: [String]
8}
9 
10func validateDependencyGraph(_ modules: [ModuleDependency]) -> [String] {
11 var violations: [String] = []
12 
13 for module in modules {
14 for dep in module.dependencies {
15 guard let depModule = modules.first(where: { $0.name == dep }) else {
16 violations.append("HATA: '\(module.name)' bilinmeyen modulu import ediyor: '\(dep)'")
17 continue
18 }
19 // Kural: Ust tier, alt veya esit tier'a bagimli olamaz
20 if depModule.tier >= module.tier && module.tier > 1 {
21 violations.append("IHLAL: Tier\(module.tier) '\(module.name)' -> Tier\(depModule.tier) '\(dep)'")
22 }
23 }
24 }
25 
26 // Dongusel bagimlilik kontrolu (DFS)
27 // ... topological sort ile cycle detection
28 return violations
29}
30 
31// CI'da: swift validate-deps.swift || exit 1

ALTIN İPUCU

Bu yazının en değerli bilgisi

Bu ipucu, yazının en önemli çıkarımını içeriyor.

Okuyucu Ödülü

Tebrikler! Bu yazıyı sonuna kadar okuduğun için sana özel bir hediyem var:

Sonuç ve Öneriler

Mobile microservices mimarisi, büyük ekiplerin büyük uygulamalar geliştirmesi için vazgeçilmezdir. Doğru module boundary'leri çizin, bağımlılıkları strict tutun, inter-module communication'ı protocol-based yapın ve DI container ile composition root oluşturun. Derleme süreleri düşecek, test coverage artacak ve yeni geliştiriciler çok daha hızlı adapte olacak.

Etiketler

#Microservices#Architecture#Modular#SPM#Dependency Injection#iOS
Muhittin Çamdalı

Muhittin Çamdalı

Senior iOS Developer

12+ yıllık deneyime sahip iOS Developer. Swift, SwiftUI ve modern iOS mimarileri konusunda uzman. Apple platformlarında performanslı ve kullanıcı dostu uygulamalar geliştiriyorum.

iOS Geliştirme Haberleri

Haftalık Swift tips, SwiftUI tricks ve iOS best practices. Spam yok, sadece değerli içerik.

Gizliliğinize saygı duyuyoruz. İstediğiniz zaman abonelikten çıkabilirsiniz.

Paylaş

Bunu da begenebilirsiniz