iOS Development

TCA vs Clean Architecture: Refleksje z przepisywania produkcyjnej aplikacji

4 min readRafał Dubiel
#iOS#TCA#Clean Architecture

Wprowadzenie

Po ponad 8 latach programowania w iOS nauczyłem się doceniać architekturę, która służy zespołowi i projektowi, a nie odwrotnie. Jakiś czas temu dołączyłem do projektu, gdzie aplikacja była napisana w The Composable Architecture (TCA). Po kilku miesiącach zmagań podjęliśmy decyzję o przepisaniu jej do Clean Architecture. Chcę podzielić się tym, czego nas to nauczyło.

Wyzwania, z którymi się zmierzyliśmy

  1. Akumulacja problemów technicznych

    Aplikacja borykała się z problemami związanymi z zarządzaniem stanem: race conditions przy współbieżnych akcjach, nieoczekiwane mutacje stanu, problemy z czasem zycia subskrypcji. TCA obiecuje przewidywalność przez strict unidirectional data flow. W praktyce jednak:

    • Każda akcja może wywołać effect,
    • Effects mogą emitować kolejne akcje,
    • Reducery modyfikują współdzielony stan,
    • Wszystko dzieje się w asynchronicznym środowisku.

    Dla zespołu, który nie miał 100% komfortu z każdym aspektem biblioteki, stało się to źródłem frustracji i błędów.

  2. Debugowanie wymagało detektywistycznej pracy

    Przykład: użytkownik zgłosił problem z wyświetlaniem danych po ponownym zalogowaniu. W tradycyjnej architekturze sprawdzilibyśmy przepływ: Repository → Use Case → ViewModel. W TCA musieliśmy przejść przez kilka warstw reducerów, effects, zarządzania współdzielonym stanem i environment dependencies. Znalezienie źródła zajęło znacznie więcej czasu niż zwykle.

    Problem? Jeden z reducerów nie czyścił poprawnie stanu przy wylogowaniu - rzecz, którą w prostszej architekturze zauważylibyśmy w kilka minut.

  3. Game-changer: wsparcie cross-platformowe

    Ten punkt przeważył w naszej decyzji. Aplikacja na Androida była napisana w Clean Architecture. W pewnym momencie nacisk na dostarczanie features stał się tak duży, że zarząd przesunął kilku developerów z Android team do pracy nad iOS.

    I tutaj ujawnił się prawdziwy problem. Ci developerzy - doświadczeni seniorzy znający Kotlina, Jetpack Compose i Clean Architecture stanęli przed ścianą TCA. Swift i SwiftUI opanowali szybko. Ale specyfika TCA (Reducers, Actions, Effects, Store) była dla nich obca i wymagała tygodni nauki.

    Co więcej, różnice architektoniczne przełożyły się na rozbieżności w logice biznesowej. Android team operował na jasno zdefiniowanych Use Case'ach, my na Actions i State mutations. Obie aplikacje, mimo korzystania z tego samego API, czasami prezentowały dane w odmienny sposób.

    Po przepisaniu do Clean Architecture sytuacja wyglądała zupełnie inaczej. Gdy ponownie potrzebowaliśmy wsparcia od Android team, otrzymywaliśmy je prktycznie natychmiastowo:

    • Rozumieli Use Cases - dokładnie ten sam pattern,
    • Rozumieli Repository pattern - identyczny jak w ich kodzie,
    • Rozumieli SOLID principles - te same zasady stosowali codziennie,

    Jeden z kolegów powiedział mi wtedy: "To jest dokładnie to samo co piszemy u nas, tylko w Swift."

Dlaczego zdecydowaliśmy się na refactor?

Decyzja nie była pochopna. Rozważaliśmy ją przez kilka tygodni. Przeważyły trzy czynniki:

  • Synchronizacja z Android team - wspólny język architektoniczny eliminował rozbieżności w logice biznesowej,
  • Redukcja friction - prostszy debugging, szybszy development, krótszy onboarding,
  • Długoterminowa perspektywa - Clean Architecture i SOLID to standardy branżowe, które przetrwają dekadę. TCA, choć świetnie rozwijany przez Point-Free, pozostaje biblioteką jednego vendora.

Efekty

Refactor zajął 3 miesiące. Rezultaty:

  • Liczba bugów związanych ze stanem spadła o ~60%,
  • Onboarding nowych developerów: z 3-4 tygodni zmniejszył się do kilku dni,
  • Czas debugowania typowych problemów skrócił się o połowę,
  • Rotacja między zespołami iOS i Android stała się bezproblemowa.

Podsumowanie

Czy TCA to zły wybór? Nie. To dobrze przemyślany framework, który sprawdza się w wielu kontekstach - szczególnie w mniejszych zespołach, gdzie wszyscy są w niego wdrożeni. Ale w naszym przypadku - duży, długoterminowy projekt, wymóg synchronizacji między platformami, rotacja developerów, jak najszybsze dowożenie nowych funckjonalności - niezależność od konkretnej biblioteki przeważyła nad korzyściami płynącymi z TCA.

Kluczowa lekcja: nie ma złych architektur, są tylko niewłaściwe wybory dla danego kontekstu. Wybieraj świadomie, uwzględniając:

  • Rozmiar i doświadczenie zespołu,
  • Przewidywaną długość życia projektu,
  • Koordynację z innymi platformami,
  • Dostępność deweloperów na rynku.

Architektura powinna służyć projektowi i zespołowi. Nie odwrotnie.

Rafał Dubiel

Rafał Dubiel

Senior iOS Developer z ponad 8-letnim doświadczeniem w tworzeniu aplikacji mobilnych. Pasjonat czystej architektury, Swift i dzielenia się wiedzą ze społecznością.

Udostępnij artykuł:

TCA vs Clean Architecture: Refleksje z przepisywania produkcyjnej aplikacji | FractalDev Blog