SRP (Single Responsibility Principle) — први принцип SOLID-а који одређује: свака класа или модул треба да има тачно један разлог за промену. Овај принцип је формулисао Роберт Мартин у књизи Clean Architecture (2017) и постао је темељ модуларног пројектовања. Према подацима из ове књиге, примена SRP директно смањује повезаност компоненти и елиминише каскадне промене при допуни функционалности.
Главно
SRP (Single Responsibility Principle) — принцип јединствене одговорности који каже: свака класа или модул треба да има тачно један разлог за промену. То не значи да класа треба да обавља тачно једну операцију. Реч је о групи повезаних радњи, обједињених једном одговорношћу према једном актору.
Роберт Мартин је преформулисао SRP у терминима актора: класа треба да се мења само на захтев једне заинтересоване особе или једне групе људи. Ако два различита актора захтевају промену исте класе — одговорност је подељена неправилно.
На пример, класа Employee, која истовремено израчунава плату (захтев рачуноводства) и генерише извештај (захтев менаџмента), крши SRP. Промена правила обрачуна може утицати на генерисање извештаја и обрнуто.
Модул треба да има један и само један разлог за промену. Разлог промене одређује актор — особа или систем који покреће захтев. Ако захтеви од различитих актора доводе до промене истог модула — модул крши SRP.
Концепт актора чини SRP практичним алатом за архитектонску анализу, а не апстрактном препоруком. При пројектовању система довољно је поставити питање: „Ко ће тражити промену овог кода?“ — ако одговор садржи више од једне заинтересоване особе, одговорност треба поделити.
Јединствена одговорност се реализује кроз груписање метода које се мењају из једног разлога. Класа постаје „тачка прикупљања“ повезане логике, а не „швајцарски нож“ за све прилике. То поједностављује разумевање кода: програмер види класу и одмах разуме њену намену.
Механизам рада SRP заснива се на правилу једне осе промене. Ако се функционалност може мењати из независних разлога — треба је извући у засебне класе. Везе између ових класа граде се кроз композицију или делегирање.
Кршење SRP се манифестује у „класама-боговима“ (God Objects), које садрже десетине метода које раде са различитим подацима. Такву класу је тешко тестирати — тест једне методе захтева подешавање окружења за све остале. Промена једне одговорности може покварити другу, што чини код крхким.
У пракси, SRP помаже програмерима да одговоре на питање „где се налази овај код?“. Ако је свака одговорност издвојена у своју класу, проналажење потребног фајла траје секунде. У Android пројекту са MVVM архитектуром то значи да UserViewModel одговара само за стање екрана корисника, а UserRepository — за преузимање података. Програмер који тражи логику кеширања иде у UserCacheRepository, а не у ViewModel. Таква организација кода убрзава укључивање нових чланова тима и смањује број грешака при рефакторисању.
Мобилни развој поставља посебне захтеве за модуларност кода. Android Fragment или iOS ViewController често постају „тачке привлачења“ логике: обрада кликова, позив API-ја, парсирање одговора, ажурирање UI — све у једној класи. SRP захтева раздвајање ових одговорности.
У Android архитектури, SRP је уграђен у Google-ове препоруке за Jetpack: ViewModel одговара за стање екрана, Repository — за податке, UseCase — за пословну логику. Свака компонента има један разлог за промену. У iOS развоју образац MVVM и Coordinator следе исту логику.
Поштовање SRP у мобилним пројектима даје мерљиве предности: смањење величине класа за 40-60%, скраћење времена за код-преглед и смањење броја регресивних грешака при додавању нове функционалности. Изоловани модули се лакше покривају unit-тестовима и поново користе у другим екранима.
Unit-тестирање класа које поштују SRP захтева мање mock-објеката и подешавања. Ако класа има једну одговорност, њене зависности су ограничене. Тест проверава једно понашање, а не комбинацију више неповезаних сценарија.
Према извештају Google Testing Blog (2023), класе са јединственом одговорношћу показују 35% већу покривеност тестовима у поређењу са класама-агрегаторима. Програмери радо пишу тестове за мале, разумљиве модуле.
Размотримо типичну Android класу која крши SRP — и учитава податке, и парсира одговор, и ажурира UI. Након рефакторисања, свака одговорност је издвојена у посебну компоненту.
// Кршење SRP: једна класа ради све
class BadUserProfileActivity {
fun loadUser(userId: Int) {
// HTTP захтев
// Парсирање JSON
// Ажурирање UI
// Чување у бази
}
}
// Након примене SRP
class UserRepository {
fun getUser(userId: Int): User
}
class UserViewModel {
private val repo: UserRepository
fun loadUser(userId: Int) { }
}
class UserProfileFragment {
fun render(user: User) { }
}
Аналогичан пример на iOS Swift са раздвајањем мрежног слоја и слоја приказа:
// Кршење SRP: ViewController управља подацима и UI
class BadProfileViewController: UIViewController {
func viewDidLoad() {
// URLSession захтев
// Декодирање JSON
// Ажурирање label
}
}
// Након примене 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) { }
}
Рефакторисање SRP не компликује архитектуру — прерасподељује одговорност. Количина кода се чак може смањити елиминацијом дуплирања. Свака нова класа има јасну намену и може се развијати независно.
Композиција помаже у поштовању SRP тамо где наслеђивање ствара непотребне повезаности. Уместо суперкласе са десетинама метода, подкласа добија скуп специјализованих објеката кроз конструктор. Сваки објекат одговара за своју функционалност.
У Android развоју, образац Decorator омогућава додавање одговорности без промене оригиналне класе. У iOS-у, ланац Middleware у мрежном слоју раздваја логирање, кеширање и аутентификацију на засебне модуле.
Најчешће кршење — „God Class“: класа која управља базом података, шаље обавештења, генерише извештаје и обрађује кориснички унос. Таква класа постаје уско грло пројекта: свака промена захтева потпуно регресивно тестирање.
У мобилном развоју, кршење SRP доводи до мешања пословне логике и UI логике у Activity, Fragment или ViewController. Када onClickListener метод истовремено валидира податке, позива API и ажурира видљивост дугмади — то је директно кршење принципа јединствене одговорности.
Последице кршења SRP укључују: отежано паралелно програмирање (конфликти у истом фајлу), отежано unit-тестирање, високу цену измена и смањену читљивост кода. Пројекти са систематским кршењем SRP захтевају 2-3 пута више времена за додавање нове функционалности.
Кршење SRP може се одредити по посредним знацима: класа садржи више од 200 линија, увози модуле из различитих слојева апликације (UI + network + database), има више од 5 јавних метода са различитом тематиком. Метрика повезаности (cohesion) — статистички показатељ: ниска повезаност метода унутар класе указује на кршење SRP.
За откривање SRP кршења корисно је користити алате статичке анализе: за Android — Detekt са правилом TooManyFunctions, за iOS — SwiftLint са правилом file_length. Ови алати истичу класе које прелазе граничне вредности величине и сложености.
Рефакторисање класа које крше SRP врши се кроз Extract Class или Extract Delegate: група повезаних метода се извлачи у засебну класу, а оригинална класа им делегира позиве. Постепена примена таквих рефакторисања претвара „God Class“ у скуп слабо повезаних модула, сваки са једном одговорношћу. Такав приступ омогућава побољшање архитектуре без заустављања развоја — рефакторисање се изводи итеративно, по један модул истовремено.
Често постављана питања
Не. SRP није о броју метода, већ о броју разлога за промену. Класа може имати десет метода ако све оне опслужују једну одговорност према једном актору. Једна метода — друга је крајност која води ка претераном уситњавању кода.
То је исти принцип. Single Responsibility Principle се преводи и као „јединствена одговорност“ и као „јединствена обавеза“. Термин „одговорност“ тачније одражава суштину: реч је о одговорности према актору, а не о техничкој функцији.
Repository — директни резултат примене SRP на слој података. Уместо развлачења логике приступа подацима по ViewModel или UseCase, Repository преузима јединствену одговорност: обезбеђивање података са апстракцијом извора. То је класична имплементација SRP у мобилној архитектури.
Да, SRP не забрањује зависности. Класа са једном одговорношћу може делегирати део посла другим класама кроз композицију. Важно је да ти делегирани задаци буду део исте одговорности, а не самостални разлог за промену.
Поставите питање: „Који актори могу захтевати промену ове класе?“ Ако одговор садржи више од једног актора — SRP је прекршен. Додатно: покушајте да опишете намену класе једном реченицом без везника „и“. Ако не успевате — класа ради превише.
Завршни преглед
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође