SoC (Separation of Concerns) je zkratka principu, podle kterého se softwarový systém dělí na izolované oblasti odpovědnosti. Podle Martina Fowlera je rozdělení odpovědnosti klíčovým prvkem udržovatelného kódu. Princip SoC umožňuje vývojářům měnit jednu vrstvu aplikace, aniž by ovlivnili ostatní, což je obzvláště důležité v týmovém mobilním vývoji.
Hlavní body
SoC znamená Separation of Concerns — „rozdělení odpovědnosti" nebo „oddělení oblastí zájmu". V kontextu programování termín concern označuje jakoukoli oddělitelnou funkcionalitu: zobrazení uživatelského rozhraní, zpracování kliknutí, validaci dat, síťovou komunikaci nebo práci s databází. Princip SoC předepisuje seskupování kódu kolem těchto oblastí tak, aby změny v jedné neovlivnily ostatní.
Zkratka SoC je široce používána v technické literatuře, architektonických diskusích a dokumentaci frameworků. Například v dokumentaci Android Architecture Components je SoC opakovaně zmiňováno jako motivace pro oddělení ViewModel a View. V iOS komunitě se termín používá při diskusi o problému Massive View Controller — přímém důsledku absence SoC.
Je důležité pochopit, že SoC není jednorázová akce, ale kontinuální proces. Jak aplikace roste, objevují se nové oblasti odpovědnosti a architektura musí být přehodnocena. Dobrá kódová základna prochází několika iteracemi rozdělení, než dosáhne stabilního stavu, kde je každý concern izolovaný a řiditelný.
Separation of Concerns a jeho zkratka SoC označují stejný princip. Rozdíl je pouze v kontextu použití: plný název se používá ve formálních dokumentech, vzdělávacích materiálech a při prvním vysvětlování konceptu novým vývojářům. SoC je vhodné v technických diskusích, code review a dokumentaci, kde je důležitá stručnost.
V profesionálním prostředí jsou oba termíny zaměnitelné. Vývojář může říct „zde je SoC porušeno" nebo „to porušuje Separation of Concerns" — význam se nemění. Nicméně v pracovních inzerátech a architektonických požadavcích se častěji objevuje plný název, zatímco v chatech a code review — zkratka. Znalost obou variant je nezbytná pro pohodlný vstup do průmyslu.
Existuje terminologický zmatek: zkratka SoC se také používá v hardwarovém kontextu pro System-on-a-Chip (systém na čipu). V mobilním vývoji je kontext vždy jasný z prostředí — pokud se diskuse týká architektury kódu, jedná se o Separation of Concerns. V tomto článku se SoC všude vztahuje k principu rozdělení odpovědnosti.
Třívrstvá architektura — nejběžnější způsob implementace SoC v mobilních aplikacích. Dělí kód na Presentation (UI), Domain (obchodní logika) a Data (práce se zdroji). Každá vrstva obsahuje přesně definované typy tříd a je od sousedů izolována pomocí rozhraní. Tento přístup je stejně efektivní pro iOS, Android i Flutter projekty.
View a ViewModel tvoří prezentační vrstvu. View je zodpovědné za vykreslování rozhraní a předávání událostí uživatele. ViewModel ukládá stav obrazovky a převádí data z vrstvy Domain do formátu připraveného k zobrazení. ViewModel nemá reference na Activity, Fragment nebo UIViewController — to zajišťuje SoC mezi UI a logikou.
Například v Android Jetpack ViewModel přežije rotaci obrazovky, zatímco UI je znovu vytvořeno. Bez SoC bychom museli ukládat stav v Activity, čímž bychom smíchali správu životního cyklu s daty. ViewModel řeší tento úkol izolovaně a demonstruje čistou implementaci principu rozdělení odpovědnosti.
Use Cases obsahují obchodní pravidla nezávislá na platformě. Tato vrstva neimportuje Android SDK, iOS UIKit ani Flutter framework. Use Case získává data z Repository, aplikuje na ně obchodní logiku a vrací výsledek. Díky SoC lze jeden Use Case znovu použít na různých obrazovkách a platformách.
Klasickým příkladem je ValidateAndSaveUseCase pro registrační formulář. Kontroluje správnost emailu a hesla, volá UserRepository pro uložení a vrací ValidationResult. Ani UI, ani databáze neznají validační pravidla — jsou soustředěna na jednom místě, což usnadňuje jejich změnu.
Repository abstrahuje zdroje dat od zbytku aplikace. ViewModel neví, odkud data pocházejí — z REST API, GraphQL, lokální databáze nebo cache. Repository rozhoduje, který zdroj použít, a skrývá tuto logiku za rozhraním. To je SoC mezi získáváním dat a jejich spotřebou.
DataSource poskytuje ještě hlubší rozdělení: RemoteDataSource je zodpovědný pouze za HTTP požadavky, LocalDataSource — za práci s Room, CoreData nebo SharedPreferences. Repository je kombinuje s aplikováním strategií ukládání do cache. Každý DataSource lze nezávisle vyměnit, což je kritické při migraci mezi servery nebo databázemi.
Takový víceúrovňový systém DataSource implementuje SoC na infrastrukturní úrovni: síťová komunikace, lokální úložiště a cache — samostatné concerns, každý se svou vlastní logikou a životním cyklem. Při výměně HTTP klienta se mění pouze RemoteDataSource, zatímco Repository a vyšší vrstvy zůstávají nedotčeny, což potvrzuje praktickou hodnotu rozdělení odpovědnosti.
MVP (Model-View-Presenter) — jeden z prvních vzorů, který explicitně implementuje SoC v mobilním vývoji. Presenter obsahuje logiku a řídí View prostřednictvím rozhraní. View je pasivní — pouze zobrazuje to, co říká Presenter. Rozdělení zjednodušuje testování: Presenter se testuje bez emulátoru a View zůstává tak jednoduché, že se v něm není co rozbít.
MVVM přidal reaktivní vazbu: View se přihlašuje ke změnám ViewModel pomocí Observable nebo StateFlow. ViewModel neuchovává referenci na View, což eliminuje riziko úniku paměti a ještě silněji odděluje concerns. V Androidu se MVVM stal standardem díky Jetpack ViewModel a LiveData, v iOS — díky Combine a RxSwift.
Clean Architecture Roberta Martina přivádí SoC k radikálnímu rozdělení na kruhy. Vnější kruh (frameworky a ovladače) závisí na vnitřním (entity), ale ne naopak. V praxi mobilní projekty zřídka implementují všechny čtyři kruhy — vrstvy Domain a Data kolem Presentation jsou dostačující. Ale samotný princip závislosti „dovnitř" poskytuje významné výhody při změně frameworků.
// View — pouze zobrazení, bez logiky
final class LoginViewController: UIViewController {
let viewModel: LoginViewModel
func loginTapped() {
viewModel.login(emailField.text, passwordField.text)
}
}
// ViewModel — obsahuje logiku obrazovky, nezná UIKit
final class LoginViewModel {
private let loginUseCase: LoginUseCase
func login(email: String?, password: String?) {
loginUseCase.execute(email, password)
}
}
// Use Case — obchodní logika, nezávislá na platformě
final class LoginUseCase {
private let repo: AuthRepository
func execute(email: String?, password: String?) {
guard let e = email, let p = password else { return }
repo.authenticate(e, p)
}
}
Příklad ukazuje tři úrovně SoC: LoginViewController pouze předává události, LoginViewModel spravuje stav, LoginUseCase obsahuje obchodní pravidla. Každá třída se testuje nezávisle a změna UI frameworku neovlivní Use Case.
Massive View Controller — nejčastější porušení SoC v iOS. Třída, která spravuje UI, zpracovává síťové požadavky, parsuje JSON a ukládá data, porušuje princip na všech úrovních. Řešení — vyčlenit každou odpovědnost do samostatné komponenty: NetworkingService, JSONParser, CoreDataStack, a ViewController ponechat pouze správu View.
V Android je analogický problém — God Activity nebo God Fragment. Jedna aktivita, která načítá data, validuje formuláře, zobrazuje dialogy a aktualizuje UI. Léčí se zavedením ViewModel a Repository, které přebírají správu stavu a dat. ViewModel také chrání proti ztrátě dat při rotaci obrazovky.
Třetí porušení — míchání platformového a obchodního kódu. Například umístění HTTP požadavku přímo do SwiftUI View nebo Android Composable. To činí kód nepřenosným a obtížně testovatelným. Správný přístup — vyčlenit požadavek do Repository, které je voláno přes Use Case, a View se pouze přihlásí k výsledku. Každý prvek systému řeší svůj úkol a nepřekračuje své hranice.
Často kladené otázky
Ne. SoC je obecnější princip rozdělení systému na oblasti odpovědnosti. SOLID je soubor pěti konkrétních pravidel pro objektově orientovaný návrh. První princip SOLID (Single Responsibility) je zvláštním případem SoC na úrovni jedné třídy.
Použijte pravidlo jednoho důvodu ke změně (Single Responsibility). Pokud se třída mění kvůli změně UI, formátu dat a obchodních pravidel — SoC je porušeno. Nástroje jako ArchTest (Android) a StrictConcurrency (iOS) pomáhají taková porušení automaticky odhalovat.
V teorii přidávají další vrstvy nepřímá volání, ale v praxi je dopad na výkon mobilní aplikace zanedbatelný. Kompilátor inline mnohá volání a optimalizace JIT a AOT eliminují režii. Udržovatelnost kódu získává mnohem více, než se ztrácí na abstrakcích.
Začněte extrakcí síťových požadavků z UI do Repository. Poté vyčleňte obchodní logiku do Use Cases. Použijte dependency injection pro propojení vrstev. Provádějte změny iterativně a pokrývejte nový kód testy — to zaručuje, že refaktorování nerozbije stávající funkcionalitu.
V prototypech můžete SoC porušovat kvůli rychlosti. Ale pokud se prototyp přesune do produktového vývoje, náklady na refaktorování mohou převýšit výhodu rychlého startu. Optimální — udržovat minimální rozdělení (UI a data) i v prototypu, abyste nemuseli vše přepisovat od začátku při spuštění.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také