মোবাইল ডেভেলপমেন্টে, ডেটা নিয়ে কাজ করা, ক্যাশিং এবং সিঙ্ক্রোনাইজেশন — তিনটি মূল দিক যা অ্যাপ্লিকেশনের কর্মক্ষমতা এবং নির্ভরযোগ্যতা নির্ধারণ করে। Google Android Architecture Guide অনুসারে, ডেটা হ্যান্ডলিংয়ের সঠিক আর্কিটেকচার সরাসরি প্রতিক্রিয়ার গতি এবং ব্যবহারকারীর অভিজ্ঞতাকে প্রভাবিত করে। Repository প্যাটার্ন সমস্ত ডেটা উৎসে একটি একক অ্যাক্সেস পয়েন্ট সরবরাহ করে।
মূল পয়েন্ট
Repository প্যাটার্ন একটি আর্কিটেকচারাল পদ্ধতি যেখানে একটি একক রিপোজিটরি ক্লাস সমস্ত ডেটা অপারেশন পরিচালনা করে, দূরবর্তী REST API এবং স্থানীয় স্টোরেজ Room বা SwiftData-কে বিমূর্ত করে। ডেটা নিয়ে কাজ করার এই পদ্ধতি অ্যাপ্লিকেশনকে প্রথমে Memory Cache বা Disk Cache থেকে তথ্য পেতে দেয়, তারপর নেটওয়ার্ক থেকে, প্রতিক্রিয়ার সময় কমিয়ে। মোবাইল ডেভেলপমেন্টে, Google এবং Apple-এর সুপারিশের কারণে Repository ডি-ফ্যাক্টো স্ট্যান্ডার্ড হয়ে গেছে।
Remote Data Source HTTP অনুরোধের মাধ্যমে সার্ভার থেকে আপ-টু-ডেট তথ্য সরবরাহ করে। Local Data Source ডিভাইসে স্থানীয় স্টোরেজ, যা Android-এ Room বা iOS-এ SwiftData-এর মাধ্যমে বাস্তবায়িত। রিপোজিটরি উভয় উৎসকে একত্রিত করে: প্রথমে স্থানীয় ক্যাশ চেক করে, এবং ডেটা না থাকলে দূরবর্তী API থেকে অনুরোধ করে। ডেটা হ্যান্ডলিংয়ের এই সংগঠন অ্যাপ্লিকেশনকে অফলাইন মোডে কাজ করতে দেয় এবং সার্ভারের লোড কমায়।
class UserRepository(
private val remoteDataSource: UserRemoteDataSource,
private val localDataSource: UserLocalDataSource
) {
suspend fun getUsers(): List<User> {
localDataSource.getCachedUsers()?.let { return it }
val users = remoteDataSource.fetchUsers()
localDataSource.cacheUsers(users)
return users
}
}
class UserRepository {
private let remote: UserRemoteDataSource
private let local: UserLocalDataSource
func getUsers() async throws -> [User] {
if let cached = await local.getCached() { return cached }
let users = try await remote.fetch()
await local.save(users)
return users
}
}
LRU Cache (Least Recently Used) একটি ক্যাশিং অ্যালগরিদম যেখানে, সীমায় পৌঁছালে, যে উপাদানটি সবচেয়ে বেশি সময় ধরে অ্যাক্সেস করা হয়নি তা সরিয়ে ফেলা হয়। মোবাইল অ্যাপ্লিকেশনে, LRU Cache ছবি, API প্রতিক্রিয়া এবং সিরিয়ালাইজড অবজেক্টের জন্য ব্যবহৃত হয়। সঠিক ডেটা ক্যাশিং নেটওয়ার্ক অনুরোধের সংখ্যা কমায় এবং কন্টেন্ট লোডিং দ্রুত করে। মোবাইল অ্যাপ্লিকেশনে ক্যাশ উচ্চ কর্মক্ষমতার জন্য একটি অপরিহার্য উপাদান।
Memory Cache RAM-এ ডেটা সংরক্ষণ করে — অ্যাক্সেস অত্যন্ত দ্রুত, কিন্তু ক্ষমতা অ্যাপ্লিকেশনের হিপ আকার দ্বারা সীমিত। Disk Cache ফাইল সিস্টেমে তথ্য সংরক্ষণ করে — ধীরগতির কিন্তু বেশি ধারণ করতে পারে এবং সেশনের মধ্যে টিকে থাকে। মোবাইল ডেভেলপমেন্টে সর্বোত্তম কৌশল হল দ্বি-স্তরের ক্যাশ: গরম ডেটার জন্য Memory Cache এবং ঠান্ডা ডেটার জন্য Disk Cache। ডেটা নিয়ে কাজ করার সময়, প্রথমে মেমরিতে প্রথম স্তরের ক্যাশ চেক করা হয়, তারপর ডিস্কে দ্বিতীয় স্তরের ক্যাশ।
class MemoryCache<K, V>(
private val maxSize: Int = 100
) {
private val cache = LinkedHashMap<K, V>(0, 0.75f, true)
fun get(key: K): V? = cache[key]
fun put(key: K, value: V) {
if (cache.size >= maxSize) {
cache.remove(cache.keys.first())
}
cache[key] = value
}
}
TTL ক্যাশ (Time To Live) নির্দিষ্ট সময় ব্যবধানের পরে স্বয়ংক্রিয়ভাবে এন্ট্রি মুছে দেয় — API ডেটার জন্য উপযুক্ত। ইভেন্ট-চালিত ইনভ্যালিডেশন পরিবর্তন সম্পর্কে push নোটিফিকেশন পাওয়ার পর ক্যাশ পরিষ্কার করে। মোবাইল অ্যাপ্লিকেশনে, ক্যাশিং কৌশলের পছন্দ ডেটার ধরনের উপর নির্ভর করে: ছবি দীর্ঘ সময়ের জন্য ক্যাশ করা হয়, যখন খবরের ফিড ঘন ঘন ইনভ্যালিডেশন প্রয়োজন। Android-এ Coil এবং iOS-এ Kingfisher ইতিমধ্যেই ছবির সাথে কাজ করার জন্য LRU Cache অন্তর্ভুক্ত করেছে।
Offline Queue একটি ডেটা স্ট্রাকচার যা ডিভাইস অফলাইন থাকাকালীন ব্যবহারকারীর অপারেশন (তৈরি, আপডেট, মুছে ফেলা) স্থানীয় ডেটাবেসে সংরক্ষণ করে। সংযোগ পুনরুদ্ধার করা হলে, Sync Manager ক্রমান্বয়ে এই অপারেশনগুলি সার্ভারে প্রয়োগ করে। এই ধরণের ডেটা সিঙ্ক্রোনাইজেশন নিশ্চিত করে যে অস্থায়ী নেটওয়ার্ক হারানোর সময় কোনও পরিবর্তন হারিয়ে না যায়। মোবাইল ডেভেলপমেন্টে, Offline Queue অস্থির সংযোগযুক্ত অ্যাপ্লিকেশনের জন্য একটি গুরুত্বপূর্ণ উপাদান।
কিউটি Room বা SwiftData-তে একটি টেবিলের উপর নির্মিত যার ফিল্ড: অপারেশনের ধরন, JSON অনুরোধ বডি, টাইমস্ট্যাম্প এবং অবস্থা। Sync Manager একটি ব্যাকগ্রাউন্ড সার্ভিস যা মুলতুবি অপারেশনগুলি প্রক্রিয়া করে, সেগুলি সার্ভারে পাঠায়, অবস্থা আপডেট করে এবং সফল এন্ট্রি মুছে দেয়। Android-এ WorkManager বা iOS-এ BGTaskScheduler-এর মাধ্যমে ডেটা সিঙ্ক্রোনাইজেশন ডিভাইস রিবুটের পরেও অব্যাহত থাকে। সঠিক ডেটা হ্যান্ডলিংয়ের সাথে Offline Queue ব্যবহার একটি নির্বিঘ্ন ব্যবহারকারীর অভিজ্ঞতা নিশ্চিত করে।
@Entity
data class SyncOperation(
@PrimaryKey val id: Long,
val endpoint: String,
val method: String,
val body: String,
val createdAt: Long
)
class SyncManager(
private val dao: SyncOperationDao,
private val api: ApiService
) {
suspend fun syncPending() {
dao.getPendingOperations().forEach { op ->
try {
api.execute(op.endpoint, op.method, op.body)
dao.delete(op.id)
} catch (e: Exception) {
// retry on next cycle
}
}
}
}
পুনঃচেষ্টার মধ্যে এক্সপোনেনশিয়াল ব্যাকঅফ (1s, 2s, 4s, 8s) সার্ভারকে ভিড় থেকে রক্ষা করে এবং অসীম পুনঃচেষ্টা প্রতিরোধ করে। ৫টি প্রচেষ্টার সীমা কিউ ওভারফ্লো প্রতিরোধ করে। সার্ভার-সাইড আইডেম্পোটেন্সি সমর্থন সহ মোবাইল অ্যাপ্লিকেশনে ডেটা সিঙ্ক্রোনাইজেশন নিরাপদ পুনঃচেষ্টা অনুমতি দেয়, ডুপ্লিকেট এড়িয়ে। এটি বিশেষ করে আর্থিক লেনদেন এবং অর্ডারের জন্য গুরুত্বপূর্ণ।
Conflict Resolution এমন পরিস্থিতির জন্য কৌশলগুলির একটি সেট যেখানে একই ডেটা বিভিন্ন ডিভাইসে একই সাথে পরিবর্তিত হয়। মৌলিক ডেটা সিঙ্ক্রোনাইজেশনের জন্য একটি পদ্ধতি বেছে নেওয়া প্রয়োজন: Last-Write-Wins (সর্বশেষ লেখা জেতে), সংস্করণকরণ (উচ্চ সংস্করণ জেতে) বা ম্যানুয়াল সমাধান। জটিল পরিস্থিতিতে, CRDT (Conflict-Free Replicated Data Types) ব্যবহার করা হয়, যা ডেটার গাণিতিক অভিসরণের নিশ্চয়তা দেয়।
Last-Write-Wins বাস্তবায়নে সবচেয়ে সহজ কিন্তু ব্যবহারকারীর পরিবর্তন হারাতে পারে। Version Vector — প্রতিটি রেকর্ড একটি সংস্করণ নম্বর এবং ডিভাইস শনাক্তকারী সংরক্ষণ করে; সংস্করণ মেলে না গেলে দ্বন্দ্ব দেখা দেয়। CRDT সবচেয়ে নির্ভরযোগ্য কিন্তু জটিল কৌশল: কেন্দ্রীয় সমন্বয়ক ছাড়াই ডেটা গাণিতিকভাবে একক অবস্থায় অভিসৃত হয়। CRDT-ভিত্তিক মোবাইল অ্যাপ্লিকেশনে ডেটা সিঙ্ক্রোনাইজেশন Google Docs-এ সহযোগিতামূলক সম্পাদনা এবং Notion নোট সিঙ্ক্রোনাইজেশনে ব্যবহৃত হয়।
যখন কোনো অ্যাপ্লিকেশন আপডেট করা হয়, স্থানীয় ডেটাবেস কাঠামো পরিবর্তিত হয়: কলাম, টেবিল, ইনডেক্স যোগ করা হয়। Schema Migration ডেটা না হারিয়ে বিদ্যমান ডেটাবেসকে নতুন স্কিমায় রূপান্তরের প্রক্রিয়া। Room পুরানো এবং নতুন সংস্করণ সহ Migration ক্লাসের মাধ্যমে মাইগ্রেশন সমর্থন করে। SwiftData পরিবর্তন বর্ণনা করতে VersionedSchema ব্যবহার করে। অ্যাপ্লিকেশন সংস্করণগুলির মধ্যে সঠিক ডেটা সিঙ্ক্রোনাইজেশনের জন্য মাইগ্রেশনগুলি আইডেম্পোটেন্টভাবে পরীক্ষা করা প্রয়োজন।
val migration1to2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE users ADD COLUMN avatar_url TEXT")
}
}
@Database(
entities = [User::class],
version = 2
)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
enum ConflictStrategy {
case lastWriteWins
case versionVector
case crdt
}
struct VersionedDocument {
let id: String
let version: Int
let data: Data
let editedBy: String
func resolve(with remote: VersionedDocument) -> VersionedDocument {
return version >= remote.version ? self : remote
}
}
Room Android-এ স্থানীয় স্টোরেজের জন্য Google-এর লাইব্রেরি, SQLite-এর উপর নির্মিত এবং ডিক্লারেটিভ কোয়েরি বর্ণনার জন্য অ্যানোটেশন সরবরাহ করে। SwiftData iOS, macOS, watchOS এবং visionOS-এর জন্য Apple-এর ফ্রেমওয়ার্ক, সংক্ষিপ্ত Swift Macro সিনট্যাক্স সহ Core Data-র উত্তরসূরি। উভয় টুলই ডিভাইসে ডেটা নিয়ে কাজ করার কাজ সমাধান করে, কিন্তু কোড সংগঠনের জন্য ভিন্ন পদ্ধতির সাথে। মোবাইল অ্যাপ্লিকেশনে ক্যাশ প্রায়শই এই প্রযুক্তিগুলির উপরই নির্মিত হয়।
Room টেবিলের জন্য @Entity অ্যানোটেশন এবং কোয়েরির জন্য @Dao ব্যবহার করে। DAO কম্পাইল-টাইম চেকিং সহ সমস্ত SQL অপারেশন এনক্যাপসুলেট করে — SQL সিনট্যাক্স ত্রুটি রানটাইমের আগে ধরা পড়ে। Type Converter জটিল ধরন (Date, List) কে SQLite প্রিমিটিভে রূপান্তর করে। Android অ্যাপ্লিকেশনে আধুনিক ডেটা হ্যান্ডলিং Room + Flow-এর চারপাশে নির্মিত, যা ক্যাশ বা স্থানীয় ডেটাবেস পরিবর্তন হলে রিঅ্যাকটিভ UI আপডেট প্রদান করে।
SwiftData সত্তা সংজ্ঞায়িত করতে ম্যাক্রো @Model এবং ডেটা পর্যবেক্ষণ করতে @Query ব্যবহার করে। ফ্রেমওয়ার্ক স্বয়ংক্রিয়ভাবে নির্ভরতা ট্র্যাক করে এবং পরিবর্তনে ইন্টারফেস আপডেট করে। স্কিমা মাইগ্রেশন সমস্ত সংস্করণ বর্ণনাকারী VersionedSchema ব্যবহার করে। SwiftData এবং সার্ভারের মধ্যে ডেটা সিঙ্ক্রোনাইজেশন @Query-এর মাধ্যমে আপডেট সাবস্ক্রাইব করা কাস্টম Sync Manager-এর মাধ্যমে বাস্তবায়িত হয়।
@Model
final class UserModel {
var id: String
var name: String
var email: String
var updatedAt: Date
init(id: String, name: String, email: String) {
self.id = id
self.name = name
self.email = email
self.updatedAt = Date()
}
}
| নির্ণায়ক | Room | SwiftData |
|---|---|---|
| প্ল্যাটফর্ম | Android | Apple (iOS, macOS, visionOS) |
| ভিত্তি | SQLite | SQLite (Core Data stack) |
| সিনট্যাক্স | Kotlin অ্যানোটেশন | Swift Macro |
| মাইগ্রেশন | Migration ক্লাস | VersionedSchema |
| রিঅ্যাকটিভিটি | Flow / LiveData | @Query প্রপার্টি র্যাপার |
| ক্রস-প্ল্যাটফর্ম | শুধু Android | শুধু Apple |
প্রায়শই জিজ্ঞাসিত প্রশ্ন
LRU Cache একটি ক্যাশিং অ্যালগরিদম যা সীমায় পৌঁছালে সবচেয়ে কম ব্যবহৃত আইটেম সরিয়ে দেয়। এটি মোবাইল অ্যাপ্লিকেশনে ছবি এবং API ডেটার জন্য ব্যবহৃত হয়।
Offline Queue নেটওয়ার্ক না থাকলে ব্যবহারকারীর অপারেশন স্থানীয় ডেটাবেসে সংরক্ষণ করে। Sync Manager সংযোগ পুনরুদ্ধার হলে সেগুলি কার্যকর করে, সার্ভারে পরিবর্তন পৌঁছানোর নিশ্চয়তা দিয়ে।
Conflict Resolution ডেটা সিঙ্ক্রোনাইজেশনের সময় দ্বন্দ্ব সমাধানের কৌশল। প্রধান পদ্ধতি: বিতরণ সিস্টেমের জন্য Last-Write-Wins, Version Vector এবং CRDT।
Android-এর জন্য Room বেছে নিন — কম্পাইল-টাইম SQL যাচাইকরণ সহ পরিপক্ক লাইব্রেরি। iOS-এর জন্য — ডিক্লারেটিভ সিনট্যাক্স সহ SwiftData। ক্রস-প্ল্যাটফর্ম প্রজেক্টের জন্য SQLDelight বা Realm উপযুক্ত হবে।
গুরুত্বপূর্ণ অপারেশনের জন্য প্রতিটি পরিবর্তনে এবং বাকিগুলির জন্য প্রতি ১৫–৩০ মিনিটে ব্যাকগ্রাউন্ড ডেটা সিঙ্ক্রোনাইজেশন সর্বোত্তম। তাত্ক্ষণিক বিতরণের জন্য push নোটিফিকেশন ব্যবহার করুন।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।