SoC у мобільній розробці: що це, принципи та розподіл відповідальності

Автор: IT Sectr Опубліковано: 2026-05-13 Час читання: 8 хв

SoC (Separation of Concerns) — це абревіатура принципу, за яким програмна система ділиться на ізольовані області відповідальності. За даними Martin Fowler, розподіл відповідальності — ключовий елемент ремонтопридатного коду. Принцип SoC дозволяє розробникам змінювати один шар додатку, не зачіпаючи інші, що особливо важливо в командній мобільній розробці.

Головне

  • SoC — скорочення від Separation of Concerns, що означає розподіл коду за областями відповідальності
  • Абревіатура використовується в архітектурних дискусіях для позначення принципу незалежності шарів
  • MVP, MVVM і Clean Architecture — патерни, які реалізують SoC в iOS та Android проектах
  • Ізоляція шарів спрощує Unit-тестування та розпаралелювання роботи між розробниками
  • Порушення SoC призводить до появи класів на тисячі рядків, які важко підтримувати

Що означає абревіатура SoC

SoC розшифровується як Separation of Concerns — «розподіл відповідальності» або «розподіл областей інтересу». У контексті розробки термін concern позначає будь-яку відокремлювану функціональність: відображення користувацького інтерфейсу, обробка натискань, валідація даних, мережева взаємодія або робота з базою даних. Принцип SoC наказує групувати код навколо цих областей так, щоб зміни в одній не зачіпали інші.

Абревіатура SoC широко використовується в технічній літературі, архітектурних обговореннях та документації фреймворків. Наприклад, у документації Android Architecture Components багаторазово згадується SoC як мотивація для розподілу ViewModel та View. В iOS-спільноті термін використовується при обговоренні проблеми Massive View Controller — прямого наслідку відсутності SoC.

Важливо розуміти, що SoC — це не одноразова дія, а безперервний процес. Зі зростанням додатку з'являються нові області відповідальності, і архітектуру доводиться переглядати. Хороша кодова база проходить кілька ітерацій розподілу, перш ніж досягає стабільного стану, де кожен concern ізольований та керований.

SoC vs Separation of Concerns

Separation of Concerns та його абревіатура SoC позначають один і той самий принцип. Різниця лише в контексті використання: повна назва застосовується у формальних документах, навчальних матеріалах і при першому поясненні концепції новим розробникам. SoC зручний у технічних дискусіях, код-рев'ю та документації, де важлива стислість.

У професійному середовищі обидва терміни взаємозамінні. Розробник може сказати «тут порушено SoC» або «це порушує Separation of Concerns» — сенс не змінюється. Однак у вакансіях та вимогах до архітектури частіше зустрічається повна назва, тоді як у чатах та код-рев'ю — абревіатура. Знання обох варіантів необхідне для комфортного входження в індустрію.

Існує термінологічна плутанина: абревіатура SoC також використовується в апаратному контексті для System-on-a-Chip (система на кристалі). У мобільній розробці контекст завжди зрозумілий з оточення — якщо обговорення стосується архітектури коду, йдеться про Separation of Concerns. У цій статті SoC скрізь відноситься до принципу розподілу відповідальності.

Як SoC застосовується в мобільній архітектурі

Тришарова архітектура — найпоширеніший спосіб реалізації SoC у мобільних додатках. Вона ділить код на Presentation (UI), Domain (бізнес-логіка) та Data (робота з джерелами даних). Кожен шар містить строго визначені типи класів та ізольований від сусідів через інтерфейси. Цей підхід однаково ефективний для iOS, Android та Flutter проектів.

Presentation шар і ViewModel

View та ViewModel утворюють presentation-шар. View відповідає за відмальовування інтерфейсу та передачу подій користувача. ViewModel зберігає стан екрану та перетворює дані з Domain-шару у формат, готовий для відображення. ViewModel не має посилань на Activity, Fragment або UIViewController — це забезпечує SoC між UI та логікою.

Наприклад, у Android Jetpack ViewModel переживає поворот екрану, а UI перестворюється. Без SoC довелося б зберігати стан в Activity, змішуючи управління життєвим циклом з даними. ViewModel вирішує це завдання ізольовано, демонструючи чисту реалізацію принципу розподілу відповідальності.

Domain шар і Use Cases

Use Cases містять бізнес-правила, що не залежать від платформи. Цей шар не імпортує Android SDK, iOS UIKit або Flutter framework. Use Case отримує дані з Repository, застосовує до них бізнес-логіку та повертає результат. Завдяки SoC один Use Case можна перевикористовувати на різних екранах і платформах.

Класичний приклад — ValidateAndSaveUseCase для форми реєстрації. Він перевіряє коректність email та пароля, викликає UserRepository для збереження та повертає ValidationResult. Ні UI, ні база даних не знають про правила валідації — вони зосереджені в одному місці, що спрощує їх зміну.

Data шар і Repository

Repository абстрагує джерела даних від решти додатку. ViewModel не знає, звідки беруться дані — з REST API, GraphQL, локальної бази даних чи кеша. Repository вирішує, яке джерело використовувати, і приховує цю логіку за інтерфейсом. Це SoC між отриманням даних та їх споживанням.

DataSource забезпечує ще більш глибокий розподіл: RemoteDataSource відповідає лише за HTTP-запити, LocalDataSource — за роботу з Room, CoreData або SharedPreferences. Repository комбінує їх, застосовуючи стратегії кешування. Кожен DataSource можна замінювати незалежно, що критично важливо при міграції між серверами або базами даних.

Така багаторівнева система DataSource реалізує SoC на інфраструктурному рівні: мережева взаємодія, локальне зберігання та кешування — окремі concerns, кожен зі своєю логікою та життєвим циклом. При заміні HTTP-клієнта змінюється лише RemoteDataSource, а Repository та вищі шари залишаються недоторканими, що підтверджує практичну цінність розподілу відповідальності.

SoC в архітектурних патернах

MVP (Model-View-Presenter) — один з перших патернів, що явно реалізують SoC у мобільній розробці. Presenter містить логіку та керує View через інтерфейс. View пасивна — вона лише відображає те, що каже Presenter. Розподіл спрощує тестування: Presenter тестується без емулятора, а View залишається настільки простою, що в ній нічому ламатися.

MVVM додав реактивне зв'язування: View підписується на зміни ViewModel через Observable або StateFlow. ViewModel не зберігає посилання на View, що усуває ризик витоку пам'яті та ще сильніше розділяє concerns. В Android MVVM став стандартом завдяки Jetpack ViewModel та LiveData, в iOS — завдяки Combine та RxSwift.

Clean Architecture Роберта Мартіна доводить SoC до радикального розподілу на кільця. Зовнішнє кільце (фреймворки та драйвери) залежить від внутрішнього (сутності), але не навпаки. На практиці мобільні проекти рідко реалізують всі чотири кільця — достатньо Domain та Data шарів навколо Presentation. Але сам принцип залежності «всередину» дає значні переваги при зміні фреймворків.

swift
// View — лише відображення, без логіки
final class LoginViewController: UIViewController {
    let viewModel: LoginViewModel

    func loginTapped() {
        viewModel.login(emailField.text, passwordField.text)
    }
}

// ViewModel — містить логіку екрану, не знає UIKit
final class LoginViewModel {
    private let loginUseCase: LoginUseCase

    func login(email: String?, password: String?) {
        loginUseCase.execute(email, password)
    }
}

// Use Case — бізнес-логіка, не залежить від платформи
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)
    }
}

Приклад показує три рівні SoC: LoginViewController лише передає події, LoginViewModel керує станом, LoginUseCase містить бізнес-правила. Кожен клас тестується незалежно, і заміна UI-фреймворку не зачіпає Use Case.

Типові порушення SoC у мобільних проектах

Massive View Controller — найчастіше порушення SoC в iOS. Клас, який керує UI, обробляє мережеві запити, парсить JSON та зберігає дані, порушує принцип на всіх рівнях. Рішення — винести кожну відповідальність в окремий компонент: NetworkingService, JSONParser, CoreDataStack, залишивши ViewController лише керування View.

В Android аналогічна проблема — God Activity або God Fragment. Одна активність, яка завантажує дані, валідує форми, показує діалоги та оновлює UI. Лікується впровадженням ViewModel та Repository, які забирають на себе керування станом та даними. ViewModel також захищає від втрати даних при повороті екрану.

Третє порушення — змішування платформенного та бізнес-коду. Наприклад, розміщення HTTP-запиту безпосередньо у SwiftUI View або Android Composable. Це робить код непереносимим та складним для тестування. Правильний підхід — винести запит у Repository, який викликається через Use Case, а View лише підписується на результат. Кожен елемент системи вирішує своє завдання та не виходить за його межі.

Поширені запитання

SoC та SOLID — це одне й те саме?

Ні. SoC — більш загальний принцип розподілу системи на області відповідальності. SOLID — набір з п'яти конкретних правил для об'єктно-орієнтованого проектування. Перший принцип SOLID (Single Responsibility) є частковим випадком SoC на рівні одного класу.

Як перевірити, чи дотримується SoC у проекті?

Використовуйте правило однієї причини для зміни (Single Responsibility). Якщо клас змінюється через зміну UI, формату даних та бізнес-правил — SoC порушено. Інструменти на кшталт ArchTest (Android) та StrictConcurrency (iOS) допомагають виявити такі порушення автоматично.

Чи може SoC погіршити продуктивність?

Теоретично додаткові шари додають непрямі виклики, але на практиці вплив на продуктивність мобільного додатку мізерний. Компілятор інлайнить багато викликів, а JIT та AOT оптимізації усувають накладні витрати. Підтримуваність коду виграє набагато більше, ніж втрачається на абстракціях.

Як впровадити SoC у існуючий проект?

Почніть з екстракції мережевих запитів з UI в Repository. Потім винесіть бізнес-логіку в Use Cases. Використовуйте dependency injection для зв'язування шарів. Робіть зміни ітеративно, покриваючи новий код тестами — це гарантує, що рефакторинг не зламає існуючу функціональність.

Чи потрібно дотримуватися SoC у прототипах та MVP?

У прототипах можна порушувати SoC заради швидкості. Але якщо прототип переходить у продуктову розробку, витрати на рефакторинг можуть перевищити вигоду від швидкого старту. Оптимально — дотримуватися мінімального розподілу (UI та дані) навіть у прототипі, щоб не переписувати все з нуля при запуску.

Підсумки

  • SoC — абревіатура Separation of Concerns, принцип розподілу коду на незалежні області відповідальності
  • Тришарова архітектура (Presentation, Domain, Data) — стандартний спосіб реалізації SoC у мобільній розробці
  • MVP та MVVM — архітектурні патерни, в основі яких лежить розподіл UI та бізнес-логіки
  • Clean Architecture розширює SoC на рівень всієї системи, ізолюючи бізнес-сутності від фреймворків
  • Massive View Controller — прямий наслідок порушення SoC, що усувається через екстракцію шарів
  • Dependency injection — ключовий інструмент для дотримання меж між шарами при реалізації SoC
  • Баланс між розподілом та простотою — головне правило застосування SoC на практиці

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також