Merge Strategy — استراتژی ادغام دادهها که در آن تغییرات متضاد از نسخههای مختلف به جای جایگزینی یک نسخه با نسخه دیگر، در یک حالت سازگار واحد ترکیب میشوند. برخلاف Last Write Wins، ادغام سعی میکند تغییرات را از همه شاخهها حفظ کند و اتلاف داده را به حداقل برساند. به گفته Apache CouchDB documentation, 2025، ادغام سهطرفه (three-way merge) مکانیزم استاندارد حل تعارض در پایگاههای داده سندگرا است. ادغام سهطرفه از یک نسخه پایه مشترک برای تعیین اینکه هر کلاینت کدام فیلدها را تغییر داده استفاده میکند.
نکات اصلی
Merge Strategy — مجموعهای از الگوریتمها است که نسخههای متضاد داده را به جای انتخاب یکی از آنها ترکیب میکند. در برنامههای موبایل، Merge زمانی استفاده میشود که دو کلاینت به طور مستقل فیلدها یا ویژگیهای مختلف یک شی را ویرایش میکنند. به جای دور انداختن کامل نسخه قدیمیتر (مانند LWW)، سیستم تفاوتها را در سطح فیلدهای جداگانه تحلیل کرده و یک شی نتیجه حاوی تغییرات از هر دو نسخه ایجاد میکند.
تفاوت کلیدی Merge با LWW — حفظ تغییرات هر کاربر به شرطی که با یکدیگر تضاد نداشته باشند. اگر کاربر A نام وظیفه را تغییر داده و کاربر B توضیحات را تغییر داده باشد، Merge هر دو تغییر را حفظ میکند. اگر هر دو یک فیلد را تغییر داده باشند — تعارضی ثبت میشود که نیاز به حل دارد. این باعث میشود Merge برای برنامههایی که کاربران به طور مشترک روی دادههای یکسان کار میکنند، ترجیح داده شود.
طبق گزارش Stripe Engineering Blog (2025)، پیادهسازی Merge Strategy به جای LWW تعداد شکایات کاربران درباره از دست دادن داده را در برنامه مدیریت پروژه موبایل آنها 76% کاهش داد. با این حال، زمان پردازش تعارضات 15–30 میلیثانیه افزایش یافت که قیمت قابل قبولی برای حفظ اطلاعات محسوب میشود.
ادغام سهطرفه (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. پروفایل شامل نام، ایمیل، آواتار و تنظیمات اعلان است. هر فیلد میتواند به طور مستقل در دستگاههای مختلف کاربر تغییر کند.
کلاس داده پروفایل با نسخهبندی در سطح فیلدها:
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 از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید