Ana Sayfa / Blog / Combine’dan async/await’e geçiş: 6 hafta sonrası kod karşılaştırması

Combine’dan async/await’e geçiş: 6 hafta sonrası kod karşılaştırması

Combine ile kurduğum bir iOS app'i async/await'e geçirdim. Neler kazandım, neler kaybettim, gerçek kod karşılaştırması.

Combine iOS 13’te (2019) geldi. Reactive programming için Apple’ın cevabı. 4-5 yıl boyunca benim de iOS projelerimde standart aracımdı.

2024’te yeni bir projede async/await ile başladım. Eski projede de mevcut Combine kodunu yavaş yavaş migrate ettim. 6 hafta sonra dönüp baktığımda kod tabanı ciddi anlamda daha okunur ve bakımı daha kolay hale geldi. Ama her yer için mantıklı değil.

Async/await’in kazandığı yerler

1. Network call’ları. En büyük kazanım. Combine’da tek bir network call için Publisher, map, tryMap, subscribe, sink, AnyCancellable store zinciri gerekiyordu. Async/await’te 3 satır kod.

Combine versiyonu: URLSession’un dataTaskPublisher’ı, decode için bir tryMap, error handling için catch, main thread’e aktarmak için receive(on:), subscribe için sink ve returned cancellable’ı store’da tutmak.

Async/await versiyonu: let (data, _) = try await URLSession.shared.data(from: url), sonra decoder. Hepsi bu.

2. Sequential operations. 3 API call’u sırayla yapmak gerekiyorsa, Combine’da flatMap chain’i gereksiz karışık. Async/await’te normal await satırları gibi yazıyorsun.

3. Error handling. Combine’da her operator’ün kendi error type’ı, bunları tryMap ile wrap etmek gerekiyor. Async/await’te Swift’in native throw/catch mekanizması çalışıyor.

4. Debug edilebilirlik. Stack trace’ler düzgün görünüyor. Combine’da bir error’un kaynağını bulmak için 5-6 operator arasında gezinmek gerekiyordu.

Combine’ın hâlâ kazandığı yerler

Evet, async/await her şeyi çözmedi. Şu durumlarda Combine hâlâ daha iyi:

1. Event stream’leri. Kullanıcı text field’a yazıyor, 500ms sonra search tetikliyorsun. Combine’da debounce, throttle, removeDuplicates operator’leriyle 5 satır. Async/await’te Task cancellation ve Task.sleep ile kendin kurmalısın.

2. Multiple data sources combining. Publishers.CombineLatest ile 3 farklı publisher’ı birleştirip en son değerlerini alıyorsun. Async/await’te TaskGroup ile mümkün ama daha verbose.

3. SwiftUI olmayan reactive UI. UIKit projelerde Combine hâlâ standart. @Published property’ler ve binding’ler için.

4. RxSwift geçmişi olan ekipler. Combine RxSwift’le kavramsal olarak yakın. Eğer ekibin Combine’da rahat ise zorlayıp async’e geçirmek productivity düşürür.

Migration stratejim

6 haftalık migration’da şu sırayla ilerledim:

Hafta 1-2: Yeni kod async/await ile. Eski Combine kodu korundu. İki world coexist ediyor.

Hafta 3-4: Network layer migrate edildi. URLSession.dataTaskPublisher yerine URLSession.data kullanıldı. ViewModel’ler async function’lar expose etmeye başladı.

Hafta 5-6: ViewModel’ler @Published property’lerini @Observable macro (iOS 17+) veya normal property ile değiştirdi. Task’lar kullanıcı aksiyonlarıyla başladı.

Geride kalan Combine kullanımları: Search debounce ve keyboard events. Bunları kasıtlı olarak Combine’da bıraktım çünkü async/await’te yazmak daha çirkin olurdu.

Kod büyüklüğü karşılaştırması

6 hafta sonunda kod tabanında:
– Combine import’ları: 24’ten 4’e düştü
– AnyCancellable array’leri: 18’den 2’ye düştü
– Toplam LOC: yaklaşık %12 azaldı (aynı functionality)
– Yeni geliştiriciyi onboarding süresi: 40% azaldı (ölçtüğüm kadarıyla)

Ama en büyük kazanç ölçülemez bir şey: kod okurken “ne oluyor” sorusunu 2 saniyede cevaplıyorsun, eskiden 30 saniye sürebiliyordu.

Hangi projeye uygun?

Yeni iOS projesi başlatıyorsan, iOS 15+ target’ta async/await default olsun. Combine sadece gerçek reactive stream’ler için.

Mevcut bir Combine-heavy project’te sen varsan, aggressive migration yerine kademeli yaklaş:
1. Yeni kod async/await
2. Network layer’ı migrate et
3. ViewModel’lerin expose ettiği API’lar async’e dönsün
4. UI reactive binding’leri (search, keyboard vs) son migrate et, veya hiç etme

6 hafta 3000 LOC’lik bir proje için yeterli oldu. Daha büyük projelerde 3-6 aylık iş.

Yanıltıcı bir popüler görüş

Twitter’da sıkça “Combine öldü, async/await geldi” diye yazılıyor. Kısmen doğru ama yanıltıcı. Apple Combine’ı kaldırmıyor, değişmiyor, sadece yeni framework’lere koymuyor. Mevcut kod tabanlarınız çalışmaya devam edecek, yeni kod için daha iyi alternatif var.

Takımına agnostik kalıp duruma göre seç. Blog hype’ları için kod migrate etme, kendi ekibinin productivity’si için et.

Bu konuda bir projeniz mi var?

Kısa bir özet bırakın, 24 saat içinde size dönüş yapayım.

İletişime Geç