Merge Strategy — стратегија спајања података при којој се конфликтне измене из различитих верзија обједињују у јединствено усаглашено стање уместо замене једне верзије другом. За разлику од Last Write Wins, спајање покушава да сачува измене из свих грана, минимизирајући губитак података. Према Apache CouchDB documentation, 2025, тространо спајање (three-way merge) је стандардни механизам за решавање конфликата у документ-оријентисаним базама података. Тространо спајање користи заједничку базну верзију за одређивање која поља је изменио сваки клијент.
Главно
Merge Strategy — скуп алгоритама који обједињују конфликтне верзије података уместо избора једне од њих. У мобилним апликацијама, Merge се користи када два клијента независно уређују различита поља или својства истог објекта. Уместо да одбаци старију верзију у целини (као у LWW), систем анализира разлике на нивоу појединачних поља и формира резултујући објекат који садржи измене из обе верзије.
Кључна разлика Merge у односу на LWW — чување измена сваког корисника под условом да нису у међусобној супротности. Ако је корисник А променио назив задатка, а корисник Б — опис, Merge ће сачувати обе измене. Ако су оба променила исто поље — бележи се конфликт који захтева решавање. Ово чини Merge пожељним за апликације у којима корисници заједно раде на истим подацима.
Према извештају Stripe Engineering Blog (2025), имплементација Merge Strategy уместо LWW смањила је број жалби корисника на губитак података за 76% у њиховој мобилној апликацији за управљање пројектима. Међутим, време обраде конфликата се повећало за 15–30 ms, што се сматра прихватљивом ценом за очување информација.
Тространо спајање (three-way merge) — најраспрострањенија имплементација Merge Strategy. Механизам оперише са три верзије података: базном (base — стање пре дивергенције), локалном (local — верзија тренутног клијента) и удаљеном (remote — верзија са сервера). Систем пореди свако поље локалне и удаљене верзије са базном да би одредио која страна је изменила која поља.
Логика доношења одлука је једноставна: ако је поље изменио само један клијент (у односу на базу), његова измена се прихвата аутоматски. Ако су оба клијента изменила исто поље — бележи се конфликт који може бити решен аутоматски (по приоритету) или прослеђен кориснику. Ако ниједан клијент није мењао поље — остаје базна вредност. Овакав приступ гарантује да се независне измене не губе и не конфликтују.
Алгоритам т страног спајања на нивоу речника поља:
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 -> // прави конфликт
resolveConflict(key, localVal, remoteVal)
}
}
return result
}
Функција threeWayMerge секвенцијално обрађује све кључеве из три верзије. Ако се локална вредност поклапа са базном — прихвата се удаљена измена. Ако се удаљена поклапа са базном — прихвата се локална. Ако се обе разликују од базе, али су једнаке међу собом — било која. Прави конфликт се бележи само при различитим изменама са обе стране.
Аутоматско решавање се примењује када се измене не преклапају или када систем може да одреди тачну вредност на основу правила. На пример, за нумеричка поља може се изабрати максимална вредност, за текстуална — конкатенација или новија верзија. CouchDB користи аутоматско спајање за поља JSON документа, а за низове — конкатенацију са уклањањем дупликата.
Ручно решавање је неопходно када су два корисника изменила исто поље на различите начине. У овом случају, апликација приказује дијалог са три опције: „прихвати локалну верзију”, „прихвати удаљену верзију” или „споји ручно”. Аутори истраживања CMU (Carnegie Mellon University, 2024) напомињу да ручно решавање смањује задовољство корисника за 40%, стога аутоматско спајање треба максимизирати.
Стратегије решавања за различите типове поља:
| Тип поља | Аутоматска стратегија | Ручна алтернатива |
|---|---|---|
| Број (бројач) | Узети максимални | Приказати обе вредности |
| Текст (ниска) | Изабрати по времену | Уређивач са истицањем |
| Логичка вредност | Приоритет по улогама | Три опције избора |
| Низ (листа) | Обједињавање са дедупликацијом | Избор елемент по елемент |
| Угнежђени објекат | Рекурзивно спајање | Приказати diff |
Размотримо имплементацију Merge Strategy за профил корисника у мобилној апликацији са синхронизацијом преко REST API. Профил садржи име, email, аватар и подешавања обавештења. Свако поље може бити измењено независно на различитим уређајима корисника.
Data-класа профила са верзионисањем на нивоу поља:
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 приоритет се даје удаљеној верзији, за остала поља — локалној.
CouchDB и PouchDB — најпознатије базе са уграђеном подршком за Merge Strategy. При репликацији докумената, CouchDB користи вишепроцесну репликацију са детекцијом конфликата на нивоу документа. Базна верзија се чува у историји ревизија, а при конфликту систем чува све конфликтне гране и пружа апликацији API за њихово решавање кроз механизам спајања.
У Firebase Firestore, Merge је имплементиран кроз транзакције са оптимистичним закључавањем. Програмер може назначити да се одређена поља ажурирају атомично, користећи FieldValue.serverTimestamp() и FieldValue.arrayUnion(). Међутим, Firestore не подржава потпуно тространо спајање — при конфликту се транзакција понавља са новим подацима, што је еквивалентно поновном покушају, а не правом спајању.
За мобилне апликације на Kotlin Multiplatform и React Native, Merge Strategy се имплементира на клијентској страни. Локална база (SQLite, Realm) чува верзију сваког документа, а при синхронизацији клијент учитава верзију са сервера и извршава спајање локално пре слања резултата. Овакав приступ обезбеђује очување података чак и при дуготрајном раду ван мреже, када се накупи више конфликата.
Често постављана питања
Merge Strategy — приступ решавању конфликата при коме се измене из различитих верзија обједињују у јединствено стање. За разлику од LWW, Merge чува измене из обе гране ако нису у међусобној супротности на нивоу поља.
Тространо спајање користи базну верзију (стање пре дивергенције) за одређивање која поља је изменио сваки клијент. Двострано спајање пореди само две верзије, не знајући почетно стање, што чешће доводи до лажних конфликата.
CouchDB и PouchDB имају уграђену подршку за тространо спајање. Firebase Firestore захтева имплементацију на нивоу транзакција. MongoDB и Realm нуде механизме оптимистичног закључавања, али не потпуно аутоматско спајање.
Merge није прикладан за податке где је важна брзина обраде (преко 1000 конфликата у секунди), за токове података (логови, догађаји) и за случајеве када су измене принципијелно некомпатибилне (различите верзије шеме података). У овим случајевима, LWW или CRDT ће бити ефикаснији.
Имплементација укључује три корака: чување базне верзије при учитавању података са сервера, детекцију измена на нивоу поља при чувању и позив алгоритма спајања при синхронизацији. За поједностављење користите библиотеке JSON Patch или CRDT.
Закључци
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође