Merge Strategy — co to jest, typy scalania i zasada działania

Autor: IT Sectr Opublikowano: 2026-06-14 Czas czytania: 8 min

Merge Strategy — strategia scalania danych, przy której konfliktujące zmiany z różnych wersji są łączone w jeden spójny stan zamiast zastępowania jednej wersji drugą. W przeciwieństwie do Last Write Wins, scalanie stara się zachować zmiany ze wszystkich gałęzi, minimalizując utratę danych. Według Apache CouchDB documentation, 2025, scalanie trójstronne (three-way merge) jest standardowym mechanizmem rozwiązywania konfliktów w dokumentowo-zorientowanych bazach danych. Scalanie trójstronne wykorzystuje wspólną wersję bazową do określenia, które pola zostały zmienione przez każdego klienta.

Najważniejsze

  • Merge Strategy — podejście, w którym konfliktujące zmiany są łączone, a nie zastępowane, co minimalizuje utratę danych użytkownika.
  • Scalanie trójstronne — analizuje wersje lokalną, zdalną i bazową, automatycznie rozwiązując niekonfliktujące zmiany na poziomie pól.
  • Przechowywanie historii — Merge wymaga zachowania poprzednich wersji w celu określenia rozbieżności, co zwiększa objętość przechowywanych danych.
  • Złożoność — Merge jest trudniejszy w implementacji niż LWW, szczególnie przy rozwiązywaniu konfliktów zagnieżdżonych struktur i tablic.
  • Zastosowanie — optymalny dla profili, dokumentów, formularzy i innych danych strukturalnych, gdzie każde pole ma niezależną wartość.

Czym jest Merge Strategy w rozwoju aplikacji mobilnych?

Merge Strategy — zbiór algorytmów, które łączą konfliktujące wersje danych zamiast wybierać jedną z nich. W aplikacjach mobilnych Merge jest używany, gdy dwóch klientów niezależnie edytuje różne pola lub właściwości jednego obiektu. Zamiast odrzucić starszą wersję w całości (jak w LWW), system analizuje rozbieżności na poziomie poszczególnych pól i tworzy wynikowy obiekt zawierający zmiany z obu wersji.

Kluczowa różnica Merge od LWW — zachowanie zmian każdego użytkownika pod warunkiem, że nie są one ze sobą sprzeczne. Jeśli użytkownik A zmienił nazwę zadania, a użytkownik B — opis, Merge zachowa obie zmiany. Jeśli obaj zmienili to samo pole — rejestrowany jest konflikt wymagający rozwiązania. To czyni Merge preferowanym dla aplikacji, w których użytkownicy wspólnie pracują na tych samych danych.

Według raportu Stripe Engineering Blog (2025), wdrożenie Merge Strategy zamiast LWW zmniejszyło liczbę skarg użytkowników na utratę danych o 76% w ich mobilnej aplikacji do zarządzania projektami. Jednak czas przetwarzania konfliktów wzrósł o 15–30 ms, co uważa się za akceptowalną cenę za zachowanie informacji.

Scalanie trójstronne: jak działa mechanizm

Scalanie trójstronne (three-way merge) — najczęściej spotykana implementacja Merge Strategy. Mechanizm operuje na trzech wersjach danych: bazowej (base — stan przed rozbieżnością), lokalnej (local — wersja bieżącego klienta) i zdalnej (remote — wersja z serwera). System porównuje każde pole wersji lokalnej i zdalnej z bazową, aby określić, która strona zmieniła które pola.

Logika podejmowania decyzji jest prosta: jeśli pole zmienił tylko jeden klient (w stosunku do bazy), jego zmiana jest akceptowana automatycznie. Jeśli obaj klienci zmienili to samo pole — rejestrowany jest konflikt, który może być rozwiązany automatycznie (według priorytetu) lub przekazany użytkownikowi. Jeśli żaden z klientów nie zmienił pola — pozostaje wartość bazowa. Takie podejście gwarantuje, że niezależne zmiany nie są tracone i nie powodują konfliktów.

Algorytm scalania trójstronnego na poziomie słownika pól:

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 -> // prawdziwy konflikt
                resolveConflict(key, localVal, remoteVal)
        }
    }
    return result
}

Funkcja threeWayMerge sekwencyjnie przetwarza wszystkie klucze z trzech wersji. Jeśli wartość lokalna jest zgodna z bazową — przyjmowana jest zmiana zdalna. Jeśli zdalna jest zgodna z bazową — przyjmowana jest lokalna. Jeśli obie różnią się od bazy, ale są sobie równe — dowolna. Prawdziwy konflikt jest rejestrowany tylko przy różnych zmianach z obu stron.

Automatyczne i ręczne rozwiązywanie konfliktów

Automatyczne rozwiązywanie jest stosowane, gdy zmiany nie krzyżują się lub gdy system może określić prawidłową wartość na podstawie reguł. Na przykład dla pól numerycznych można wybrać maksymalną wartość, dla tekstowych — konkatenację lub nowszą wersję. CouchDB używa automatycznego scalania dla pól dokumentów JSON, a dla tablic — konkatenację z usuwaniem duplikatów.

Ręczne rozwiązywanie jest konieczne, gdy dwóch użytkowników zmieniło to samo pole w różny sposób. W tym przypadku aplikacja wyświetla okno dialogowe z trzema opcjami: „przyjmij wersję lokalną”, „przyjmij wersję zdalną” lub „scal ręcznie”. Autorzy badania CMU (Carnegie Mellon University, 2024) zauważają, że ręczne rozwiązywanie obniża satysfakcję użytkownika o 40%, dlatego automatyczne scalanie powinno być maksymalizowane.

Strategie rozwiązywania dla różnych typów pól:

Typ polaStrategia automatycznaAlternatywa ręczna
Liczba (licznik)Weź maksymalnąPokaż obie wartości
Tekst (ciąg znaków)Wybierz według czasuEdytor z podświetleniem
Wartość logicznaPriorytet według rólTrzy opcje wyboru
Tablica (lista)Połączenie z deduplikacjąWybór element po elemencie
Obiekt zagnieżdżonyRekurencyjne scalaniePokaż diff

Przykłady implementacji scalania w Kotlin

Rozważmy implementację Merge Strategy dla profilu użytkownika w aplikacji mobilnej z synchronizacją przez REST API. Profil zawiera imię, email, awatar i ustawienia powiadomień. Każde pole może być zmienione niezależnie na różnych urządzeniach użytkownika.

Data-klas profilu z wersjonowaniem na poziomie pól:

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
    )
}

Funkcja mergeProfiles niezależnie przetwarza każde pole profilu, wybierając tę wersję, która różni się od bazowej. W przypadku konfliktu (obie różnią się od bazy) priorytet jest określany przez reguły aplikacji. W przykładzie dla avatarUrl priorytet jest przyznawany wersji zdalnej, dla pozostałych pól — lokalnej.

Merge Strategy w bazach danych aplikacji mobilnych

CouchDB i PouchDB — najbardziej znane bazy z wbudowanym wsparciem Merge Strategy. Podczas replikacji dokumentów CouchDB używa wielowątkowej replikacji z wykrywaniem konfliktów na poziomie dokumentu. Wersja bazowa jest przechowywana w historii rewizji, a w przypadku konfliktu system zachowuje wszystkie konfliktujące gałęzie i udostępnia aplikacji API do ich rozwiązywania poprzez mechanizm scalania.

W Firebase Firestore Merge jest zaimplementowany poprzez transakcje z optymistycznym blokowaniem. Deweloper może określić, że określone pola powinny być aktualizowane atomowo, używając FieldValue.serverTimestamp() i FieldValue.arrayUnion(). Jednak Firestore nie obsługuje pełnego scalania trójstronnego — w przypadku konfliktu transakcja jest powtarzana z nowymi danymi, co jest równoważne ponownej próbie, a nie prawdziwemu scalaniu.

Dla aplikacji mobilnych na Kotlin Multiplatform i React Native Merge Strategy jest implementowana po stronie klienta. Lokalna baza (SQLite, Realm) przechowuje wersję każdego dokumentu, a podczas synchronizacji klient pobiera wersję z serwera i wykonuje scalanie lokalnie przed wysłaniem wyniku. Takie podejście zapewnia zachowanie danych nawet podczas długiej pracy offline, gdy konfliktów narasta więcej.

Często zadawane pytania

Czym jest Merge Strategy w synchronizacji danych?

Merge Strategy — podejście do rozwiązywania konfliktów, w którym zmiany z różnych wersji są łączone w jeden stan. W przeciwieństwie do LWW, Merge zachowuje zmiany z obu gałęzi, jeśli nie są one ze sobą sprzeczne na poziomie pól.

Czym różni się scalanie trójstronne od dwustronnego?

Scalanie trójstronne używa wersji bazowej (stanu przed rozbieżnością) do określenia, które pola zmienił każdy klient. Scalanie dwustronne porównuje tylko dwie wersje, nie znając stanu początkowego, co częściej prowadzi do fałszywych konfliktów.

Które bazy danych obsługują Merge od razu po wyjęciu z pudełka?

CouchDB i PouchDB mają wbudowane wsparcie dla scalania trójstronnego. Firebase Firestore wymaga implementacji na poziomie transakcji. MongoDB i Realm oferują mechanizmy optymistycznego blokowania, ale nie pełne automatyczne scalanie.

Kiedy Merge Strategy nie jest odpowiednia?

Merge nie jest odpowiedni dla danych, gdzie ważna jest szybkość przetwarzania (ponad 1000 konfliktów na sekundę), dla danych strumieniowych (logi, zdarzenia) oraz w przypadkach, gdy zmiany są zasadniczo niekompatybilne (różne wersje schematu danych). W takich przypadkach LWW lub CRDT będą skuteczniejsze.

Jak zaimplementować Merge Strategy w aplikacji mobilnej?

Implementacja obejmuje trzy kroki: przechowywanie wersji bazowej podczas pobierania danych z serwera, wykrywanie zmian na poziomie pól podczas zapisywania i wywołanie algorytmu scalania podczas synchronizacji. Aby uprościć, użyj bibliotek JSON Patch lub CRDT.

Podsumowanie

  • Merge Strategy — strategia rozwiązywania konfliktów, łącząca zmiany z różnych wersji danych, a nie zastępująca jedną wersję drugą.
  • Scalanie trójstronne — najpopularniejsza implementacja, używająca wersji bazowej, lokalnej i zdalnej do określenia zmienionych pól.
  • Automatyczne rozwiązywanie — stosowane dla niekonfliktujących zmian (różne pola, jeden z klientów nie zmieniał danych).
  • Ręczne rozwiązywanie — konieczne przy zmianie jednego pola przez dwóch klientów, ale obniża satysfakcję użytkownika o 40%.
  • Zaleta — minimalna utrata danych i lepsze doświadczenie użytkownika przy wspólnej pracy nad dokumentami.
  • Wada — zwiększona złożoność implementacji i dodatkowe przechowywanie historii wersji w lokalnej bazie danych.
  • Zalecenie — stosuj Merge dla profili, dokumentów i konfiguracji. Dla metadanych i logów używaj LWW jako prostszej alternatywy.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również