SRP (Single Responsibility Principle) — první princip SOLID, který stanovuje: každá třída nebo modul by měl mít přesně jeden důvod ke změně. Tento princip byl formulován Robertem Martinem v knize Clean Architecture (2017) a stal se základem modulárního návrhu. Podle této knihy aplikace SRP přímo snižuje provázanost komponent a eliminuje kaskádové změny při vylepšování funkcionality.
Hlavní body
SRP (Single Responsibility Principle) — princip jedné odpovědnosti, který říká: každá třída nebo modul by měl mít přesně jeden důvod ke změně. To neznamená, že by třída měla provádět přesně jednu operaci. Jde o skupinu souvisejících akcí spojených jednou odpovědností vůči jednomu aktérovi.
Robert Martin přeformuloval SRP z hlediska aktérů: třída by se měla měnit pouze na žádost jedné zainteresované osoby nebo jedné skupiny lidí. Pokud dva různí aktéři požadují změnu stejné třídy — odpovědnost je rozdělena nesprávně.
Například třída Employee, která současně vypočítává mzdu (požadavek účetnictví) a vytváří zprávu (požadavek vedení), porušuje SRP. Změna pravidel výpočtu může ovlivnit vytváření zprávy a naopak.
Modul by měl mít jeden a pouze jeden důvod ke změně. Důvod změny je určen aktérem — osobou nebo systémem, který iniciuje požadavek. Pokud požadavky od různých aktérů vedou ke změně jednoho modulu — modul porušuje SRP.
Koncept aktéra činí SRP praktickým nástrojem architektonické analýzy, nikoli abstraktním doporučením. Při navrhování systému stačí položit otázku: „Kdo bude žádat o změnu tohoto kódu?“ — pokud odpověď obsahuje více než jednu zainteresovanou osobu, odpovědnost by měla být rozdělena.
Jedna odpovědnost je realizována seskupením metod, které se mění z jednoho důvodu. Třída se stává „místem shromažďování“ související logiky, nikoli „švýcarským nožem“ pro všechny příležitosti. To zjednodušuje pochopení kódu: vývojář vidí třídu a okamžitě chápe její účel.
Mechanismus fungování SRP je založen na pravidlu jedné osy změny. Pokud se funkcionalita může měnit z nezávislých důvodů — měla by být převedena do samostatných tříd. Vazby mezi těmito třídami se budují prostřednictvím kompozice nebo delegování.
Porušení SRP se projevuje v „božských třídách“ (God Objects), které obsahují desítky metod pracujících s různými daty. Takovou třídu je obtížné testovat — test jedné metody vyžaduje nastavení prostředí pro všechny ostatní. Změna jedné odpovědnosti může narušit jinou, což činí kód křehkým.
V praxi SRP pomáhá vývojářům odpovědět na otázku „kde je tento kód?“. Pokud je každá odpovědnost vyčleněna do své vlastní třídy, nalezení potřebného souboru trvá sekundy. V projektu Android s architekturou MVVM to znamená, že UserViewModel odpovídá pouze za stav uživatelské obrazovky a UserRepository za získávání dat. Vývojář hledající logiku cache jde do UserCacheRepository, nikoli do ViewModel. Takto organizovaný kód urychluje zapracování nových členů týmu a snižuje počet chyb při refaktorizaci.
Vývoj mobilních aplikací klade zvláštní požadavky na modularitu kódu. Android Fragment nebo iOS ViewController se často stávají „místy přitažlivosti“ logiky: zpracování kliknutí, volání API, parsování odpovědi, aktualizace UI — vše v jedné třídě. SRP vyžaduje oddělení těchto odpovědností.
V architektuře Android je SRP zakotveno v doporučeních Google pro Jetpack: ViewModel odpovídá za stav obrazovky, Repository za data, UseCase za obchodní logiku. Každá komponenta má jeden důvod ke změně. Ve vývoji iOS následují vzor MVVM a Coordinator stejnou logiku.
Dodržování SRP v mobilních projektech přináší měřitelné výhody: snížení velikosti tříd o 40-60%, zkrácení doby code review a snížení počtu regresních chyb při přidávání nové funkcionality. Izolované moduly se snadněji pokrývají unit testy a znovu používají v jiných obrazovkách.
Unit testy tříd dodržujících SRP vyžadují méně mock objektů a konfigurací. Pokud má třída jednu odpovědnost, její závislosti jsou omezené. Test kontroluje jedno chování, nikoli kombinaci několika nesouvisejících scénářů.
Podle zprávy Google Testing Blog (2023) vykazují třídy s jedinou odpovědností o 35% větší pokrytí testy ve srovnání s agregačními třídami. Vývojáři ochotněji píší testy pro malé, srozumitelné moduly.
Podívejme se na typickou třídu Android, která porušuje SRP — načítá data, parsuje odpověď a aktualizuje UI. Po refaktorizaci je každá odpovědnost vyčleněna do samostatné komponenty.
// Porušení SRP: jedna třída dělá vše
class BadUserProfileActivity {
fun loadUser(userId: Int) {
// HTTP požadavek
// Parsování JSON
// Aktualizace UI
// Uložení do DB
}
}
// Po aplikaci SRP
class UserRepository {
fun getUser(userId: Int): User
}
class UserViewModel {
private val repo: UserRepository
fun loadUser(userId: Int) { }
}
class UserProfileFragment {
fun render(user: User) { }
}
Obdobný příklad na iOS Swift s oddělením síťové vrstvy a prezentační vrstvy:
// Porušení SRP: ViewController spravuje data a UI
class BadProfileViewController: UIViewController {
func viewDidLoad() {
// Požadavek URLSession
// Dekódování JSON
// Aktualizace label
}
}
// Po aplikaci SRP
protocol UserServiceProtocol {
func fetchUser(id: Int) async throws -> User
}
class ProfileViewModel {
private let service: UserServiceProtocol
func loadProfile(id: Int) { }
}
class ProfileViewController: UIViewController {
func display(user: User) { }
}
Refaktorizace SRP nekomplikuje architekturu — přerozděluje odpovědnost. Množství kódu se může dokonce snížit odstraněním duplicit. Každá nová třída má jasný účel a může být vyvíjena nezávisle.
Kompozice pomáhá dodržovat SRP tam, kde dědičnost vytváří zbytečné provázání. Místo supertřídy s desítkami metod dostává podtřída sadu specializovaných objektů prostřednictvím konstruktoru. Každý objekt odpovídá za svou funkcionalitu.
Ve vývoji Android umožňuje vzor Decorator přidávat odpovědnosti bez změny původní třídy. V iOS řetězec Middleware v síťové vrstvě rozděluje logování, cache a autentizaci do samostatných modulů.
Nejčastější porušení — „God Class“: třída, která spravuje databázi, odesílá oznámení, generuje zprávy a zpracovává vstup uživatele. Taková třída se stává úzkým hrdlem projektu: každá změna vyžaduje úplné regresní testování.
Ve vývoji mobilních aplikací vede k porušení SRP míchání obchodní logiky a logiky UI v Activity, Fragment nebo ViewController. Když metoda onClickListener současně validuje data, volá API a aktualizuje viditelnost tlačítek — to je přímé porušení principu jedné odpovědnosti.
Důsledky porušení SRP zahrnují: obtížnost paralelního vývoje (konflikty v jednom souboru), ztížené unit testování, vysoké náklady na změny a snížení čitelnosti kódu. Projekty se systematickým porušením SRP vyžadují 2-3krát více času na přidání nové funkcionality.
Porušení SRP lze určit podle nepřímých znaků: třída obsahuje více než 200 řádků, importuje moduly z různých vrstev aplikace (UI + network + database), má více než 5 veřejných metod s různou tematikou. Metrika soudržnosti (cohesion) — statistický ukazatel: nízká soudržnost metod uvnitř třídy naznačuje porušení SRP.
Pro odhalování porušení SRP je užitečné používat nástroje statické analýzy: pro Android — Detekt s pravidlem TooManyFunctions, pro iOS — SwiftLint s pravidlem file_length. Tyto nástroje zvýrazňují třídy překračující prahové hodnoty velikosti a složitosti.
Refaktorizace tříd porušujících SRP se provádí pomocí Extract Class nebo Extract Delegate: skupina souvisejících metod je převedena do samostatné třídy a původní třída jim deleguje volání. Postupná aplikace takových refaktorizací přeměňuje „God Class“ na sadu volně provázaných modulů, každý s jednou odpovědností. Takový přístup umožňuje zlepšovat architekturu bez zastavení vývoje — refaktorizace se provádí iterativně, jeden modul po druhém.
Často kladené otázky
Ne. SRP není o počtu metod, ale o počtu důvodů ke změně. Třída může mít deset metod, pokud všechny slouží jedné odpovědnosti vůči jednomu aktérovi. Jedna metoda — je druhý extrém, který vede k nadměrné fragmentaci kódu.
Je to stejný princip. Single Responsibility Principle se překládá jak jako „jedna odpovědnost“, tak jako „jedna povinnost“. Termín „odpovědnost“ přesněji odráží podstatu: jde o odpovědnost vůči aktérovi, nikoli o technickou funkci.
Repository — přímý výsledek aplikace SRP na datovou vrstvu. Místo rozmazávání logiky přístupu k datům přes ViewModel nebo UseCase přebírá Repository jedinou odpovědnost: poskytování dat s abstrakcí zdroje. To je klasická implementace SRP v mobilní architektuře.
Ano, SRP nezakazuje závislosti. Třída s jednou odpovědností může delegovat část práce na jiné třídy prostřednictvím kompozice. Důležité je, aby tyto delegované úkoly byly součástí stejné odpovědnosti, nikoli nezávislým důvodem ke změně.
Položte otázku: „Jací aktéři by mohli požadovat změnu této třídy?“ Pokud odpověď obsahuje více než jednoho aktéra — SRP je porušeno. Dodatečně: zkuste popsat účel třídy jednou větou bez spojky „a“. Pokud se to nedaří — třída dělá příliš mnoho.
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é