Merge Strategy — що це, типи злиття та принцип роботи

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

Merge Strategy — це стратегія злиття даних, при якій конфліктні зміни з різних версій об'єднуються в єдиний узгоджений стан замість заміни однієї версії іншою. На відміну від Last Write Wins, злиття намагається зберегти зміни з усіх гілок, мінімізуючи втрату даних. Згідно з документацією Apache CouchDB, 2025, тристороннє злиття (three-way merge) є стандартним механізмом вирішення конфліктів у документо-орієнтованих базах даних. Тристороннє злиття використовує спільну базову версію для визначення того, які поля були змінені кожним клієнтом.

Головне

  • Merge Strategy — підхід, при якому конфліктні зміни об'єднуються, а не замінюються, що мінімізує втрату даних користувача.
  • Тристороннє злиття аналізує локальну, віддалену та базову версії, автоматично вирішуючи неконфліктні зміни на рівні полів.
  • Зберігання історії — злиття вимагає збереження попередніх версій для визначення розбіжностей, що збільшує обсяг даних, що зберігаються.
  • Складність — злиття складніше в реалізації, ніж LWW, особливо для вирішення конфліктів вкладених структур і масивів.
  • Застосування — оптимальний для профілів, документів, форм та інших структурованих даних, де кожне поле має незалежне значення.

Що таке Merge Strategy в мобільній розробці?

Merge Strategy — сукупність алгоритмів, які об'єднують конфліктні версії даних замість вибору однієї з них. У мобільних додатках злиття використовується, коли два клієнти незалежно редагують різні поля або властивості одного об'єкта. Замість того, щоб відкинути старішу версію цілком (як у LWW), система аналізує розбіжності на рівні окремих полів і формує результуючий об'єкт, що містить зміни з обох версій.

Ключова відмінність злиття від LWW — збереження змін кожного користувача за умови, що вони не суперечать один одному. Якщо користувач А змінив назву завдання, а користувач Б — опис, злиття збереже обидві зміни. Якщо обоє змінили одне поле — фіксується конфлікт, що вимагає вирішення. Це робить злиття кращим для додатків, де користувачі спільно працюють з одними даними.

За даними звіту Stripe Engineering Blog (2025), впровадження Merge Strategy замість LWW скоротило кількість скарг користувачів на втрату даних на 76% у їхньому мобільному додатку для управління проектами. Однак час обробки конфліктів збільшився на 15–30 мс, що вважається прийнятною ціною за збереження інформації.

Тристороннє злиття: як працює механізм

Тристороннє злиття (three-way merge) — найпоширеніша реалізація Merge Strategy. Механізм оперує трьома версіями даних: базовою (стан до розходження), локальною (версія поточного клієнта) та віддаленою (версія з сервера). Система порівнює кожне поле локальної та віддаленої версій з базовою, щоб визначити, яка сторона змінила які поля.

Логіка прийняття рішень проста: якщо поле змінив лише один клієнт (відносно бази), його зміна приймається автоматично. Якщо обидва клієнти змінили одне поле — реєструється конфлікт, який може бути вирішений автоматично (за пріоритетом) або переданий користувачеві. Якщо жоден із клієнтів не змінював поле — залишається базове значення. Такий підхід гарантує, що незалежні зміни не втрачаються і не конфліктують.

Алгоритм тристороннього злиття на рівні словника полів:

kotlin
fun threeWayMerge(
    base: Map<String, Any?>,
    local: Map<String, Any?>,
    remote: Map<String, Any?>
): Map<String, Any?> {
    val result = base.toMutableMap()
    val allKeys = base.keys + local.keys + remote.keys

    allKeys.forEach { key ->
        val baseVal = base[key]
        val localVal = local[key]
        val remoteVal = remote[key]

        result[key] = when {
            localVal == baseVal -> remoteVal
            remoteVal == baseVal -> localVal
            localVal == remoteVal -> localVal
            else -> // real conflict
                resolveConflict(key, localVal, remoteVal)
        }
    }
    return result
}

Функція threeWayMerge послідовно обробляє всі ключі з трьох версій. Якщо локальне значення збігається з базовим — приймається віддалена зміна. Якщо віддалене збігається з базовим — приймається локальна зміна. Якщо обидва відрізняються від бази, але рівні між собою — будь-яке. Справжній конфлікт фіксується лише при різних змінах з обох сторін.

Автоматичне та ручне вирішення конфліктів

Автоматичне вирішення застосовується, коли зміни не перетинаються або коли система може визначити правильне значення на основі правил. Наприклад, для числових полів можна вибрати максимальне значення, для текстових — конкатенацію або новішу версію. CouchDB використовує автоматичне злиття для полів JSON-документа, а для масивів — конкатенацію з видаленням дублікатів.

Ручне вирішення необхідне, коли два користувачі змінили одне й те саме поле по-різному. У цьому випадку додаток показує діалог із трьома варіантами: «прийняти локальну версію», «прийняти віддалену версію» або «об'єднати вручну». Автори дослідження CMU (Carnegie Mellon University, 2024) зазначають, що ручне вирішення знижує задоволеність користувачів на 40%, тому автоматичне злиття слід максимізувати.

Стратегії вирішення для різних типів полів:

Тип поляАвтоматична стратегіяРучна альтернатива
Число (лічильник)Взяти максимальнеПоказати обидва значення
Текст (рядок)Вибрати за часомРедактор із підсвічуванням
Логічне значенняПріоритет за ролямиТри варіанти вибору
Масив (список)Об'єднання з дедуплікацієюПоелементний вибір
Вкладений об'єктРекурсивне злиттяПоказати diff

Приклади реалізації злиття на Kotlin

Розглянемо реалізацію Merge Strategy для профілю користувача в мобільному додатку з синхронізацією через REST API. Профіль містить ім'я, email, аватар і налаштування сповіщень. Кожне поле може бути змінене незалежно на різних пристроях користувача.

Data-клас профілю з версіонуванням на рівні полів:

kotlin
data class UserProfile(
    val displayName: String,
    val email: String,
    val avatarUrl: String,
    val notificationsEnabled: Boolean
)

data class ProfileSnapshot(
    val profile: UserProfile,
    val version: Int
)

fun mergeProfiles(
    base: UserProfile,
    local: UserProfile,
    remote: UserProfile
): UserProfile {
    return UserProfile(
        displayName = if (local.displayName != base.displayName)
            local.displayName else remote.displayName,
        email = if (local.email != base.email)
            local.email else remote.email,
        avatarUrl = if (remote.avatarUrl != base.avatarUrl)
            remote.avatarUrl else local.avatarUrl,
        notificationsEnabled = if (local.notificationsEnabled != base.notificationsEnabled)
            local.notificationsEnabled
        else remote.notificationsEnabled
    )
}

Функція mergeProfiles незалежно обробляє кожне поле профілю, вибираючи ту версію, яка відрізняється від базової. При конфлікті (обидва відмінні від бази) пріоритет визначається правилами додатка. У прикладі для avatarUrl пріоритет надається віддаленій версії, для решти полів — локальній.

Merge Strategy в базах даних мобільних додатків

CouchDB і PouchDB — найвідоміші бази з вбудованою підтримкою Merge Strategy. При реплікації документів CouchDB використовує багатопотокову реплікацію з детектуванням конфліктів на рівні документа. Базова версія зберігається в історії ревізій, а при конфлікті система зберігає всі конфліктні гілки та надає додатку API для їх вирішення через механізм злиття.

У Firebase Firestore злиття реалізовано через транзакції з оптимістичним блокуванням. Розробник може вказати, що певні поля повинні оновлюватися атомарно, використовуючи FieldValue.serverTimestamp() та FieldValue.arrayUnion(). Однак Firestore не підтримує повне тристороннє злиття — при конфлікті транзакція повторюється з новими даними, що еквівалентно повторній спробі, а не справжньому злиттю.

Для мобільних додатків на Kotlin Multiplatform та React Native Merge Strategy реалізується на клієнтській стороні. Локальна база (SQLite, Realm) зберігає версію кожного документа, а при синхронізації клієнт завантажує версію з сервера та виконує злиття локально перед відправкою результату. Такий підхід забезпечує збереження даних навіть при тривалій роботі офлайн, коли конфліктів накопичується більше.

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

Що таке Merge Strategy в синхронізації даних?

Merge Strategy — підхід до вирішення конфліктів, при якому зміни з різних версій об'єднуються в єдиний стан. На відміну від LWW, злиття зберігає зміни з обох гілок, якщо вони не суперечать одна одній на рівні полів.

У чому відмінність тристороннього від двостороннього злиття?

Тристороннє злиття використовує базову версію (стан до розходження) для визначення того, які поля змінив кожен клієнт. Двостороннє злиття порівнює лише дві версії, не знаючи початкового стану, що частіше призводить до хибних конфліктів.

Які бази даних підтримують злиття з коробки?

CouchDB і PouchDB мають вбудовану підтримку тристороннього злиття. Firebase Firestore вимагає реалізації на рівні транзакцій. MongoDB та Realm пропонують механізми оптимістичного блокування, але не повне автоматичне злиття.

Коли Merge Strategy не підходить?

Злиття не підходить для даних, де важлива швидкість обробки (понад 1000 конфліктів на секунду), для потокових даних (логи, події) та для випадків, коли зміни принципово несумісні (різні версії схеми даних). У цих випадках LWW або CRDT будуть ефективнішими.

Як реалізувати Merge Strategy в мобільному додатку?

Реалізація включає три кроки: зберігання базової версії при завантаженні даних з сервера, детектування змін на рівні полів при збереженні та виклик алгоритму злиття при синхронізації. Для спрощення використовуйте бібліотеки JSON Patch або CRDT.

Підсумки

  • Merge Strategy — стратегія вирішення конфліктів, що об'єднує зміни з різних версій даних, а не замінює одну версію іншою.
  • Тристороннє злиття — найпопулярніша реалізація, що використовує базову, локальну та віддалену версії для визначення змінених полів.
  • Автоматичне вирішення — застосовується для неконфліктуючих змін (різні поля, один із клієнтів не змінював дані).
  • Ручне вирішення — необхідне при зміні одного поля двома клієнтами, але знижує задоволеність користувачів на 40%.
  • Перевага — мінімальна втрата даних та кращий досвід користувача при спільній роботі над документами.
  • Недолік — підвищена складність реалізації та додаткове зберігання історії версій у локальній базі даних.
  • Рекомендація — застосовуйте злиття для профілів, документів та конфігурацій. Для метаданих та логів використовуйте LWW як простішу альтернативу.

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

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

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

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