Separation of Concerns একটি নীতি যেখানে অ্যাপ্লিকেশনের প্রতিটি মডিউল বা স্তর দায়িত্বের একটি ক্ষেত্রের জন্য দায়ী। Wikipedia অনুযায়ী, শব্দটি Edsger Dijkstra 1974 সালে প্রবর্তন করেছিলেন এবং তারপর থেকে এটি সফটওয়্যার আর্কিটেকচারের ভিত্তি হয়ে উঠেছে। দায়িত্বের পৃথকীকরণ ডেভেলপারদের কোডের একটি স্তর পরিবর্তন করতে দেয় অন্যগুলোকে প্রভাবিত না করে, যা দীর্ঘ সমর্থন চক্রের মোবাইল প্রকল্পে গুরুত্বপূর্ণ।
মূল বিষয়
Separation of Concerns একটি সফটওয়্যার সিস্টেমকে স্বাধীন অংশে বিভক্ত করার নীতি, যার প্রতিটি একটি কাজ সমাধান করে। concern (দায়িত্বের ক্ষেত্র) শব্দটি কার্যকারিতার যেকোনো পৃথকযোগ্য অংশ নির্দেশ করে: স্ক্রিন প্রদর্শন, ট্যাপ প্রক্রিয়াকরণ, ডেটা বৈধতা বা নেটওয়ার্ক যোগাযোগ। নীতিটি কোডকে এমনভাবে গোষ্ঠীবদ্ধ করার নির্দেশ দেয় যাতে একটি ক্ষেত্রের পরিবর্তনের জন্য অন্যগুলিতে পরিবর্তনের প্রয়োজন না হয়।
মোবাইল ডেভেলপমেন্টে, SoC বিভিন্ন স্তরে প্রকাশ পায়: অ্যাপ্লিকেশনকে স্ক্রিনে বিভাজন থেকে শুরু করে একটি ক্লাসের ভিতরে কোড সংগঠিত করা পর্যন্ত। একটি Activity বা ViewController যা একসাথে নেটওয়ার্ক থেকে ডেটা লোড করে, JSON পার্স করে এবং UI রেন্ডার করে, তা Separation of Concerns লঙ্ঘন করে — এই ধরনের কোড রক্ষণাবেক্ষণ, পরীক্ষা এবং সম্প্রসারণ কঠিন। বিকল্প হল প্রতিটি দায়িত্ব আলাদা কম্পোনেন্টে বের করে নেওয়া।
নীতিটি অ্যাবস্ট্রাকশন ধারণার সাথে ঘনিষ্ঠভাবে সম্পর্কিত: প্রতিটি স্তর কঠোরভাবে সংজ্ঞায়িত ইন্টারফেস প্রদান করে এবং বাস্তবায়নের বিবরণ লুকায়। এর জন্য ধন্যবাদ, একজন ডেভেলপার UI লজিক পুনর্লিখন না করেই নেটওয়ার্কিং লাইব্রেরি বা ডেটাবেস প্রতিস্থাপন করতে পারে। এটি দীর্ঘস্থায়ী প্রকল্পে বিশেষভাবে মূল্যবান যেখানে প্রয়োজনীয়তা এবং প্রযুক্তি সময়ের সাথে পরিবর্তিত হয়।
Edsger Dijkstra প্রথমবারের মতো ১৯৭৪ সালের তার নিবন্ধ «On the Role of Scientific Thought»-এ Separation of Concerns ধারণাটি প্রণয়ন করেন। তিনি যুক্তি দিয়েছিলেন যে সফটওয়্যার সিস্টেমের জটিলতা নিয়ন্ত্রণ করা যায় সেগুলিকে অংশে বিভক্ত করে যা পৃথকভাবে বিশ্লেষণ করা হয়। এই পদ্ধতি সেই সময়ের একীভূত প্রোগ্রামের বিপরীত ছিল, যেখানে কোড গণনা, ইনপুট-আউটপুট এবং ব্যবহারকারী ইন্টারফেস মিশ্রিত করত।
১৯৮০-এর দশকে, ধারণাটি গঠনমূলক প্রোগ্রামিং-এর সমর্থকদের দ্বারা বিকশিত হয়েছিল, এবং পরে অবজেক্ট-ওরিয়েন্টেড পদ্ধতি দ্বারা। Smalltalk এবং C++-এর মতো ভাষাগুলি এনক্যাপসুলেশন এবং মডুলারিটি প্রক্রিয়া সরবরাহ করেছিল যা SoC-কে একটি ব্যবহারিক সরঞ্জামে পরিণত করেছিল। আধুনিক আর্কিটেকচারাল প্যাটার্ন — MVC, MVP, MVVM এবং Clean Architecture — Separation of Concerns নীতির সরাসরি মূর্ত প্রতীক।
মোবাইল ডেভেলপমেন্টের জগতে, Apple iOS-এর জন্য MVC-কে মান হিসাবে প্রচার করেছিল, যেখানে Model-View-Controller ডেটা, প্রদর্শন এবং নিয়ন্ত্রণ যুক্তি পৃথক করে। Google Android-এর জন্য ViewModel এবং Repository-এর উপর ভিত্তি করে আর্কিটেকচারাল নির্দেশিকা প্রস্তাব করেছিল — প্রতিটি কম্পোনেন্ট তার নিজস্ব সীমিত কাজ সমাধান করে। SoC ছাড়া, মোবাইল অ্যাপ্লিকেশন Massive View Controller-এ পরিণত হয় — হাজার হাজার লাইনের ক্লাস যেখানে কোনও পরিবর্তন পুরো কার্যকারিতা ভেঙে ফেলার ঝুঁকি নেয়।
চারটি প্রধান স্তর একটি সাধারণ মোবাইল অ্যাপ্লিকেশন আর্কিটেকচার গঠন করে যা Separation of Concerns প্রয়োগ করে। প্রতিটি স্তর শুধুমাত্র তার ডোমেনের জন্য দায়ী এবং ইন্টারফেসের মাধ্যমে প্রতিবেশীদের সাথে যোগাযোগ করে।
View একচেটিয়াভাবে ডেটা প্রদর্শন এবং ব্যবহারকারীর ইভেন্ট প্রক্রিয়াকরণের জন্য দায়ী। iOS-এ এটি UIViewController এবং UIView, Android-এ — Fragment বা Activity। ViewModel-এ স্ক্রিনের অবস্থা এবং প্রদর্শনের জন্য প্রস্তুত ফর্ম্যাটে ডেটা রূপান্তরের যুক্তি থাকে। পৃথকীকরণ নিশ্চিত করে যে UIKit-কে SwiftUI দিয়ে প্রতিস্থাপন করা বা Jetpack Compose দিয়ে স্ক্রিন পুনর্লিখন করা ব্যবসায়িক যুক্তিকে প্রভাবিত করবে না।
ViewModel পরীক্ষার জন্য এমুলেটর বা সিমুলেটর চালানোর প্রয়োজন নেই — ইউনিট টেস্ট যা ডেটা রূপান্তর এবং ব্যবহারকারীর ক্রিয়ায় প্রতিক্রিয়া যাচাই করে তা যথেষ্ট। এটি Separation of Concerns-এর সরাসরি ফলাফল: UI ব্যবসায়িক নিয়মের সাথে মিশ্রিত হয় না, এবং প্রতিটি কম্পোনেন্ট পৃথকভাবে পরীক্ষা করা হয়।
Use Case (বা Interactor) অ্যাপ্লিকেশনের ব্যবসায়িক নিয়ম ধারণ করে — গণনা, বৈধতা, ডেটা কলের অর্কেস্ট্রেশন। এই স্তর UI এবং প্ল্যাটফর্ম ফ্রেমওয়ার্কের অস্তিত্ব সম্পর্কে জানে না। Use Case Repository থেকে ডেটা গ্রহণ করে, তাতে যুক্তি প্রয়োগ করে এবং প্রস্তুত ফলাফল ViewModel-এ ফেরত দেয়। পৃথকীকরণ একটি Use Case কে বিভিন্ন স্ক্রিনে পুনরায় ব্যবহার করার অনুমতি দেয়।
উদাহরণস্বরূপ, LoginUseCase ইমেলের বৈধতা পরীক্ষা করে, প্রমাণীকরণের জন্য AuthRepository কল করে এবং ফলাফল ফেরত দেয়। এটি লগইন স্ক্রিন কেমন দেখায় তার উপর নির্ভর করে না — SwiftUI, UIKit বা Compose। যদি ব্যবসায়িক নিয়ম পরিবর্তিত হয়, UI বা ডেটাবেস স্পর্শ না করে একটি Use Case পরিবর্তন করাই যথেষ্ট।
Repository ডেটা উত্সগুলিকে অ্যাবস্ট্রাক্ট করে: রিমোট API, লোকাল ডেটাবেস বা মেমরি ক্যাশ। ViewModel এবং Use Case জানে না ডেটা কোথা থেকে আসছে — Repository সিদ্ধান্ত নেয় নেটওয়ার্ক থেকে লোড করবে কিনা বা ক্যাশ থেকে। এই পৃথকীকরণ ব্যবসায়িক যুক্তি বা UI প্রভাবিত না করে স্টোরেজ বাস্তবায়ন পরিবর্তনের অনুমতি দেয়।
DataSource আরও নিম্ন-স্তরের পৃথকীকরণ: NetworkDataSource শুধুমাত্র HTTP অনুরোধের জন্য দায়ী, LocalDataSource — Room বা CoreData-এর সাথে কাজ করার জন্য। Repository বিভিন্ন DataSources-এর কলগুলিকে একটি সমন্বিত ইন্টারফেসে একত্রিত করে। প্রতিটি DataScope মক বা ফেক সার্ভার ব্যবহার করে স্বাধীনভাবে পরীক্ষা করা হয়।
DataSource স্তরের সঠিক বাস্তবায়ন নিশ্চিত করে যে ডেটাবেস স্কিমা পরিবর্তন বা REST API-কে GraphQL দিয়ে প্রতিস্থাপন শুধুমাত্র একটি DataSource-কে প্রভাবিত করবে, কিন্তু Repository বা তার ভোক্তাদের নয়। এটি অবকাঠামো স্তরে Separation of Concerns-এর সরাসরি ফলাফল: প্রতিটি প্রযুক্তিগত ক্ষেত্র বিচ্ছিন্ন এবং ক্যাসকেডিং পরিবর্তন ছাড়াই প্রতিস্থাপনযোগ্য।
MVVM (Model-View-ViewModel) মোবাইল ডেভেলপমেন্টের জন্য সবচেয়ে জনপ্রিয় প্যাটার্ন, যা সরাসরি Separation of Concerns প্রয়োগ করে। Model ডেটা এবং ব্যবসায়িক যুক্তি ধারণ করে, View প্রদর্শনের জন্য দায়ী, এবং ViewModel প্রতিক্রিয়াশীল প্রক্রিয়ার মাধ্যমে তাদের সংযুক্ত করে। Flutter-এ, BLoC ইভেন্ট, স্টেট এবং ব্যবসায়িক যুক্তিতে পৃথকীকরণের সাথে অনুরূপ ভূমিকা পালন করে।
রবার্ট মার্টিনের (আঙ্কেল বব) Clean Architecture SoC-কে সর্বোচ্চে নিয়ে যায়: সিস্টেম স্বাধীন রিংয়ে বিভক্ত — এন্টিটি, ইউজ কেস, অ্যাডাপ্টার এবং ফ্রেমওয়ার্ক। অভ্যন্তরীণ রিং (এন্টিটি) বাহ্যিক রিং (ফ্রেমওয়ার্ক) এর উপর নির্ভর করে না। এটি অ্যাপ্লিকেশনের মূল যুক্তি পুনর্লিখন না করেই ডেটাবেস, UI ফ্রেমওয়ার্ক এবং এমনকি প্ল্যাটফর্ম পরিবর্তনের অনুমতি দেয়।
অনুশীলনে, মোবাইল প্রকল্পগুলি খুব কমই সম্পূর্ণ Clean Architecture প্রয়োগ করে — বেশিরভাগ অ্যাপ্লিকেশনের জন্য তিন-স্তর আর্কিটেকচার যথেষ্ট: UI, Domain এবং Data। Domain স্তরে Use Cases এবং ব্যবসায়িক মডেল থাকে এবং এটি Android SDK বা iOS SDK থেকে সম্পূর্ণ বিচ্ছিন্ন। এই ধরনের পৃথকীকরণ ২০% প্রচেষ্টায় ৮০% সুবিধা দেয়।
// Data layer — শুধুমাত্র ডেটা পাওয়ার জন্য দায়ী
class UserRepository(private val api: UserApi) {
suspend fun getUser(id: String): User = api.fetchUser(id)
}
// Domain layer — ব্যবসায়িক যুক্তি, API বা ডেটাবেস সম্পর্কে জানে না
class GetUserNameUseCase(
private val repo: UserRepository
) {
suspend fun invoke(id: String): String {
val user = repo.getUser(id)
return "${user.firstName} ${user.lastName}"
}
}
// UI layer — শুধুমাত্র প্রদর্শন
class UserViewModel(
private val getUserName: GetUserNameUseCase
) {
fun onUserLoaded(id: String) {
viewModelScope.launch {
_name.value = getUserName.invoke(id)
}
}
}
উপরের কোডটি বিশুদ্ধ পৃথকীকরণ প্রদর্শন করে: UserRepository শুধুমাত্র API-এর সাথে কাজ করে, GetUserNameUseCase নাম ফর্ম্যাটিংয়ের ব্যবসায়িক যুক্তি ধারণ করে, এবং UserViewModel UI অবস্থা পরিচালনা করে। প্রতিটি ক্লাসের পরিবর্তনের একটি কারণ আছে, যা Separation of Concerns-এর সারমর্ম।
SoC-এর প্রধান সুবিধা হল রক্ষণাবেক্ষণযোগ্যতা। স্বাধীন স্তরে বিভক্ত কোড বিশ্লেষণ করা সহজ: ডেভেলপার কেবল সেই স্তরটি দেখে যেখানে ত্রুটি ঘটে এবং অন্যগুলি দ্বারা বিভ্রান্ত হয় না। দীর্ঘমেয়াদী প্রকল্পে, এটি একীভূত কোডের তুলনায় বাগ খোঁজা এবং ঠিক করার সময় ৩০-৫০% কমিয়ে দেয়।
দ্বিতীয় গুরুত্বপূর্ণ সুবিধা হল পরীক্ষাযোগ্যতা। যখন ব্যবসায়িক যুক্তি UI এবং ফ্রেমওয়ার্ক থেকে বিচ্ছিন্ন হয়, তখন এটি এমুলেটর চালানো ছাড়াই ইউনিট টেস্ট দ্বারা আচ্ছাদিত হয়। উচ্চ ইউনিট টেস্ট কভারেজ সহ Android এবং iOS প্রকল্পে নতুন বৈশিষ্ট্য যোগ করার সময় উল্লেখযোগ্যভাবে কম রিগ্রেশন হয়।
প্রধান সীমাবদ্ধতা হল বর্ধিত জটিলতা। মাইক্রো-স্তর এবং অ্যাবস্ট্রাকশনে অত্যধিক বিভাজন এই দিকে নিয়ে যায় যে একটি সাধারণ বাটন যোগ করতে ডেভেলপারকে পাঁচটি ফাইল সম্পাদনা করতে হয়। Separation of Concerns নীতির জন্য যুক্তিসঙ্গত ভারসাম্য প্রয়োজন: শুধুমাত্র সেই ক্ষেত্রগুলি পৃথক করুন যা প্রকৃতপক্ষে স্বাধীনভাবে পরিবর্তিত হয়। ছোট প্রকল্পের জন্য, অতিরিক্ত অ্যাবস্ট্রাকশন ছাড়া UI, যুক্তি এবং ডেটাতে মৌলিক পৃথকীকরণ যথেষ্ট।
সচরাচর জিজ্ঞাসিত প্রশ্ন
SoC দায়িত্বের ক্ষেত্র অনুসারে পৃথকীকরণের একটি নীতি, যখন মডুলারিটি কোডকে ভৌত মডিউলে সংগঠিত করার একটি উপায়। SoC একটি মডিউলের ভিতরে স্তর বা ক্লাসের মাধ্যমে প্রয়োগ করা যেতে পারে, যখন মডুলারিটির জন্য স্বাধীন বিল্ডে বিভাজন প্রয়োজন।
SoC হল SOLID নীতির উপরে একটি অধির্নিমাণ। একক দায়িত্ব নীতি (S) একটি ক্লাসের স্তরে SoC। নির্ভরতা বিপরীত নীতি (D) ইন্টারফেস এবং নির্ভরতা ইনজেকশনের মাধ্যমে স্তরগুলির মধ্যে SoC প্রয়োগ করতে সহায়তা করে।
হ্যাঁ, তবে মধ্যম মাত্রায়। একটি সাধারণ অ্যাপ্লিকেশনের জন্য, UI এবং ব্যবসায়িক যুক্তি পৃথক করাই যথেষ্ট। স্তরগুলির অত্যধিক সংখ্যা ব্যবহারিক সুবিধা ছাড়াই কোড জটিল করবে। প্রকল্প বাড়ার সাথে সাথে স্তরের সংখ্যা ধীরে ধীরে বাড়ানো হয়।
কর্মক্ষমতা-র উপর কোনও সরাসরি প্রভাব নেই — SoC কোড আর্কিটেকচার সম্পর্কিত, নির্বাহ নয়। তবে, স্তরে পৃথকীকরণ স্তরগুলির মধ্যে অতিরিক্ত কলের কারণে পরোক্ষ ওভারহেড যোগ করতে পারে। অনুশীলনে, রক্ষণাবেক্ষণযোগ্যতার সুবিধার তুলনায় এই প্রভাব নগণ্য।
নির্ভরতা ইনজেকশন (Hilt, Koin, Swinject) স্পষ্টভাবে স্তরগুলির মধ্যে সীমানা পরিচালনা করে। Detekt (Android) এবং SwiftLint (iOS)-এ আর্কিটেকচারাল লিন্টার নিয়ম অননুমোদিত স্তর থেকে আমদানি নিষিদ্ধ করে। Git hooks পরীক্ষা করতে পারে যে ব্যবসায়িক স্তর UI লাইব্রেরি আমদানি করে না।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন