DEV Community

Nuh Mehmet Demirkol
Nuh Mehmet Demirkol

Posted on Originally published at nmdemirkol.com

iOS ve Android'de Clean Architecture: Ölçeklenebilir ve Test Edilebilir Katmanlı Mimari Rehberi

iOS ve Android'de Clean Architecture: Ölçeklenebilir ve Test Edilebilir Katmanlı Mimari Rehberi

Büyüyen mobil projelerde karşılaşılan en büyük problem, iş mantığı (business logic), ağ çağrıları ve kullanıcı arayüzünün (UI) birbirine sıkı sıkıya bağlanmasıdır (tight coupling). Sonuç: Bir API kontratı değiştiğinde 15 farklı UI dosyasının kırılması, yazılamayan birim testler ve bakım maliyetinin katlanarak artması.

Bu makalede; iOS (Swift) ve çok platformlu (Flutter/Dart) projelerde üretim seviyesinde (production-ready) Clean Architecture prensiplerinin nasıl kurgulanacağını, katman sınırlarını ve bağımlılıkların tersine çevrilmesini (Dependency Inversion Principle) somut kod bloklarıyla inceliyoruz.


1. Clean Architecture Temel Diyagramı ve Katman Kuralları

Robert C. Martin'in (Uncle Bob) ortaya koyduğu mimarinin mobil ekosistemdeki altın kuralı şudur: İç katmanlar dış katmanları bilmez. Bağımlılık akışı her zaman dıştan içe doğrudur.

text
+-------------------------------------------------------------+
| PRESENTATION LAYER |
| [UI (Widgets/Views)] <---> [State Holders (Bloc/VM)] |
+-------------------------------------------------------------+
| (Kullanır)
v
+-------------------------------------------------------------+
| DOMAIN LAYER |
| [Use Cases / Interactors] <---> [Entities] |
| [Repository Contracts (Interfaces)] |
+-------------------------------------------------------------+
^ (İmplemente Eder)
|
+-------------------------------------------------------------+
| DATA LAYER |
| [Repository Impls] <---> [Data Sources (Remote/Local)] |
| [DTOs / Serialization / Mappers] |
+-------------------------------------------------------------+

  1. Domain Katmanı: Saf (pure) iş mantığı. Hiçbir UI çerçevesine (Flutter Material, UIKit, SwiftUI) veya harici kütüphaneye (Dio, Alamofire) bağımlı değildir.
  2. Data Katmanı: Verinin nereden geldiğiyle ilgilenir (REST API, GraphQL, SQLite, Hive, CoreData). Domain katmanının tanımladığı arayüzleri uygular.
  3. Presentation Katmanı: Kullanıcıya veriyi gösterir ve kullanıcı girdilerini yakalar (BLoC, Riverpod, MVVM).

2. Domain Katmanı: Saf İş Mantığı ve Kontratlar

Domain katmanı uygulamanın kalbidir. Bir e-ticaret uygulamasında sepetten ürün silme akışını ele alalım.

Entity Tanımı (Dart)

dart
// domain/entities/cart_item.dart
class CartItem {
final String id;
final String title;
final double price;
final int quantity;

const CartItem({
required this.id,
required this.title,
required this.price,
required this.quantity,
});

double get subtotal => price * quantity;
}

Repository Arayüzü (Contract)

dart
// domain/repositories/cart_repository.dart
abstract interface class CartRepository {
Future, CartFailure>> getCartItems();
Future> removeItem(String itemId);
}

Use Case / Interactor

Her kullanım senaryosu tek bir sorumluluğa (Single Responsibility Principle) sahip olmalıdır:

dart
// domain/usecases/remove_cart_item_usecase.dart
class RemoveCartItemUseCase {
final CartRepository _repository;

const RemoveCartItemUseCase(this._repository);

Future> call(String itemId) async {
if (itemId.isEmpty) {
return Result.failure(CartFailure.invalidId());
}
return await _repository.removeItem(itemId);
}
}


3. Data Katmanı: DTO, Mapper ve Veri Kaynakları

API'den gelen JSON verisi doğrudan Domain Entity'sine çevrilmemelidir. Bunun yerine Data Transfer Object (DTO) kullanılır ve bir Mapper aracılığıyla Entity'ye dönüştürülür.

dart
// data/models/cart_item_model.dart
class CartItemModel {
final String productId;
final String productName;
final int unitPriceCents;
final int count;

CartItemModel.fromJson(Map json)
: productId = json['product_id'] as String,
productName = json['product_name'] as String,
unitPriceCents = json['unit_price_cents'] as int,
count = json['count'] as int;

// Entity Dönüştürücü (Mapper)
CartItem toEntity() {
return CartItem(
id: productId,
title: productName,
price: unitPriceCents / 100.0,
quantity: count,
);
}
}

Repository İmplementasyonu

dart
// data/repositories/cart_repository_impl.dart
class CartRepositoryImpl implements CartRepository {
final CartRemoteDataSource _remoteDataSource;

CartRepositoryImpl(this._remoteDataSource);

@override
Future> removeItem(String itemId) async {
try {
await remoteDataSource.deleteItem(itemId);
return const Result.success(null);
} on NetworkException catch (e) {
return Result.failure(CartFailure.network(e.message));
} catch (
) {
return Result.failure(CartFailure.unexpected());
}
}
}


4. Bağımlılıkların Çözülmesi (Dependency Injection)

Katmanların birbirini doğrudan başlatmaması (instantiate etmemesi) gerekir. Servis bulucu veya DI container (Service Locator / Injector) yapısı kurarak mock'lama süreçlerini kolaylaştırıyoruz:

dart
// core/di/injection_container.dart
import 'package:get_it/get_it.dart';

final sl = GetIt.instance;

Future initDependencies() async {
// Data Sources
sl.registerLazySingleton(() => CartRemoteDataSourceImpl(sl()));

// Repositories
sl.registerLazySingleton(() => CartRepositoryImpl(sl()));

// Use Cases
sl.registerLazySingleton(() => RemoveCartItemUseCase(sl()));

// Presentation (BLoC / Cubit / ViewModel)
sl.registerFactory(() => CartBloc(removeCartItemUseCase: sl()));
}


5. Clean Architecture Kullanmanın CTO ve Mühendislik Kazanımları

  1. Paralel Çalışma Esnekliği: Backend ekibi API kontratını netleştirdiği an, mobil mimar Use Case ve Repository Interface'lerini yazar. UI ekibi ve Data ekibi birbirini beklemeden sahte (mock) verilerle çalışabilir.
  2. Platform ve Kütüphane Bağımsızlığı: UI tarafında Flutter'dan SwiftUI'a geçiş yapılsa ya da ağ katmanında Dio yerine Ktor Client tercih edilse dahi Domain mantığı %100 korunur.
  3. Yüksek Test Kapsamı (Test Coverage): Use Case'ler UI veya Network emülatörlerine ihtiyaç duyulmadan saf unit test ortamında saniyeler içinde test edilir.

Sonuç ve İletişim

Clean Architecture, küçük projelerde başlangıç maliyeti gibi görünse de orta ve büyük ölçekli kurumsal mobil projelerde bakım süresini %60 oranında azaltır ve kod tabanınızı geleceğe hazırlar.

Kurumsal mobil projelerinizde doğru mimariyi inşa etmek, mevcut teknik borcu temizlemek veya 1 yıl bakım garantili anahtar teslim native / cross-platform mobil uygulama çözümleri için benimle iletişime geçebilirsiniz.

Nuh Mehmet Demirkol

Bilgisayar Mühendisi | Mobil Yazılım Mimarı & Danışman

📍 Ofis: Ankara, Türkiye

🌐 Web & Portföy: https://nmdemirkol.com

💬 WhatsApp Direkt İletişim: +90 507 823 68 11

Top comments (0)