কম্পিউটার টিউটোরিয়াল

অ্যান্ড্রয়েড MVVM ডিমিস্টিফাইড: ক্লিন আর্কিটেকচারের জন্য সঠিক প্যাটার্ন বেছে নেওয়া

এই আর্টিকেলে আমার লক্ষ্য হলো ব্যাখ্যা করা যে মডেল-ভিউ-ভিউমডেল আর্কিটেকচারাল প্যাটার্ন কীভাবে কিছু পরিস্থিতিতে GUI আর্কিটেকচারের প্রেজেন্টেশন লজিকের সংবর্ধে খুব clumsy separation of concerns প্রসেন্সেন্ট করে।

আমরা MVVM-এর দুটি ভ্যারিয়েন্ট এক্সপ্লোর করব (এখানে শুধু এক পদ্ধতি নেই), এবং কেন আপনি একটি ভ্যারিয়েন্ট অন্যটির চেয়ে পছন্দ করতে পারেন, প্রজেক্ট রিকোয়ারমেন্টের ওপর ভিত্তি করে।

MVVM vs MVP/MVC?

অনেক সম্ভব যে আমার লাইভ সানডে Q&A সেশনগুলোর সময় আমাকে যে প্রশ্নটি সবচেয়ে বেশি জিজ্ঞেস করা হয়, সেটি হচ্ছে:

MVVM vs MVP/MVC?

যখন আমাকে এই প্রশ্ন করা হয়, আমি দ্রুত এই ধারণায় জোর দিই যে কোনো একক GUI আর্কিটেকচার সব পরিস্থিতিতে চমৎকার কাজ করে না।

কেন, আপনি জিজ্ঞেস করতে পারেন? একটি প্রদত্ত অ্যাপ্লিকেশনের জন্য সেরা আর্কিটেকচার (অথবা কমপক্ষে একটি ভালো পছন্দ) হাতে থাকা রিকোয়ারমেন্টের ওপর ভরপূরভাবে নির্ভর করে।

আমরা সংক্ষেপে চিন্তা করি এই শব্দ requirements আসলে কী বোঝায়:

  • আপনার UI কতটুকু জটিল? একটি সিম্পল UI সাধারণত এটি কোঅর্ডিনেট করার জন্য জটিল লজিক দরকার নয়, যখন একটি জটিল UI এক্সটেনসিভ লজিক এবং ফাইন-গ্রেইনড কন্ট্রোল দরকার করতে পারে স্মুথলি কাজ করার জন্য।
  • আপনি টেস্টিং-কে কতটুকু গুরুত্ব দেন? সাধারণত বলা যায়, ক্লাসগুলো যা ফ্রেমওয়ার্ক এবং OS (বিশেষ করে ইউজার ইন্টারফেস) এর সাথে টাইটলি কাপল্ড, সেগুলো টেস্ট করতে এক্সট্রা ওয়ার্ক দরকার।
  • আপনি কতটুকু রি-ইউজেবিলিটি এবং অ্যাবস্ট্রাকশন প্রচার করতে চান? কি হবে যদি আপনি আপনার অ্যাপ্লিকেশনের ব্যাক এন্ড, ডোমেইন, এবং এমনকি প্রেজেন্টেশন লজিক বিভিন্ন প্ল্যাটফর্মে শেয়ার করতে চান?
  • আপনি কি প্রাকৃতিকভাবে প্র্যাগম্যাটিক, পারফেকশনিস্ট, আলসী, অথবা উপরের সবই różne সময়ে, ভিন্ন পরিস্থিতিতে?

আমি কি একটি আর্টিকেল লিখতে চাই যেখানে আমি ব細詳細ে আলোচনা করব MVVM কীভাবে উপরের রিকোয়ারমেন্ট এবং কনসার্নগুলোর সাথে কাজ করে। দুর্ভাগ্যক্রমে, আপনার মধ্যে কিছু লোক সম্ভবত ভুল ধারণায় পড়েছেন যে MVVM করার শুধু একটি পদ্ধতি আছে।

বদলে, আমি MVVM-এর সাধারণ ধারণার দুটি ভিন্ন পদ্ধতি আলোচনা করব যা খুব ভিন্ন সুবিধা এবং অসুবিধা প্রসেন্সেন্ট করে। কিন্তু প্রথমে, সাধারণ ধারণা থেকে শুরু করি।

তুমি তোমার ভিউ ক্লাসগুলো রেফারেন্স করবে না

আমার যেসব বন্ধু পুরনো ইংরেজি পড়তে পারেন না তাদের জন্য: “আপনি ভিউ ক্লাসগুলো রেফারেন্স করতে পারবেন না."

ভিউমডেল নাম ব্যবহার করার পাশাপাশি (যেটি খুব কনফিউজিং যদি ক্লাসটি লজিক-এর সাথে ভরা থাকে), MVVM আর্কিটেকচার এর একমাত্র লৌহ-নিতি হলো আপনি কখনো ভিউমডেল থেকে ভিউ রেফারেন্স করতে পারবেন না।

এখন, প্রথম কনফিউশন এই শব্দ "রেফারেন্স" থেকে উদ্ভূত হতে পারে, যা আমি কয়েকটি ভিন্ন জার্গন লেভেলে পুনরাবৃত্তি করছি:

  • আপনার ভিউমডেলগুলো কোনো ভিউর কোনো রেফারেন্স (মেম্বার ভেরিয়েবল, প্রোপার্টি, মিউটেবল/ইমিউটেবল ফিল্ড) ধারণ করতে পারবে না
  • আপনার ভিউমডেলগুলো কোনো ভিউর ওপর ডিপেন্ড করতে পারবে না
  • আপনার ভিউমডেলগুলো আপনার ভিউগুলোর সাথে সরাসরি কথা বলতে পারবে না

এখন, অ্যান্ড্রয়েড প্ল্যাটফর্মে, এই নিয়মের কারণ শুধু এই নয় যে এটা ভাঙলে খারাপ কারণ কেউ যিনি সফটওয়্যার আর্কিটেকচার সম্পর্কে জানেন বলে তিনি বলেছেন এটা খারাপ।

আর্কিটেকচার কম্পোনেন্টস থেকে ভিউমডেল ক্লাস ব্যবহার করার সময় (যেটি ডিজাইন করা হয়েছে এর ইনস্ট্যান্স পারসিস্ট করতে ফ্র্যাগমেন্ট/অ্যাক্টিভিটি লাইফসাইকেলের চেয়ে বেশি সময় যখন উপযুক্ত), একটি ভিউ রেফারেন্স করা SERIOUS MEMORY LEAKS-এর জন্য আহ্বান জানায়।

MVVM সাধারণত কেন এমন রেফারেন্স অনুমতি দেয় না, তার লক্ষ্য হাইপোথেটিক্যালি ভিউ এবং ভিউমডেল দুটোকেই টেস্ট করা এবং লেখা সহজ করতে।

অন্যান্য লোকজন আরো নির্দেশ করতে পারেন যে এটি ভিউমডেলের রি-ইউজেবিলিটি প্রচার করে, কিন্তু এটি ঠিক সেখানে এই প্যাটার্নটি ভাঙতে শুরু করে।

কোড দেখার আগে, দয়া করে নোট করুন যে আমি ব্যক্তিগতভাবে LiveData ব্যবহার করি না আমার নিজস্ব প্রোডাকশন কোডে। আমি আজকাল নিজের পাবলিশার-সাবস্ক্রাইবার প্যাটার্ন লিখতে পছন্দ করি, কিন্তু আমি নিচে যা বলবো তা যেকোনো লাইব্রেরির ওপর প্রযোজ্য যেটি ভিউমডেল থেকে ভিউতে PubSub/Observer প্যাটার্ন লিংক করার অনুমতি দেয়।

এই আর্টিকেলের সাথে একটি ভিডিও টিউটোরিয়াল রয়েছে যেটি এখানে আলোচনা করা অনেক আইডিয়া কভার করে:

ViewLogic + ViewModel বা View + ViewModelController?

যখন আমি পূর্ববর্তী সেকশনে "ব্রেক ডাউন" বললাম, আমি এতে বোঝাতে চেয়েছিলাম না যে প্যাটার্নটি শाब্দিকভাবে ভেঙে যায়। আমি বোঝাতে চেয়েছিলাম যে এটি (কমপক্ষে) দুটি ভিন্ন পদ্ধতিতে ভেঙে যায় যাদের চেহারা, সুবিধা, এবং ফলাফল খুব ভিন্ন।

আসুন এই দুটি পদ্ধতি বিবেচনা করি, এবং কখন আপনি একটিকে অন্যটির চেয়ে পছন্দ করতে পারেন।

অ্যান্ড্রয়েড MVVM ডিমিস্টিফাইড: ক্লিন আর্কিটেকচারের জন্য সঠিক প্যাটার্ন বেছে নেওয়া
বোরোমির ব্যাখ্যা যে MVVM আপনার অ্যাপ্লিকেশনের প্রেজেন্টেশন লজিক অদৃশ্য করার একটি ম্যাজিক ওয়ান্ড নয়।

প্রথম পদ্ধতি: রি-ইউজেবল ভিউমডেল প্রায়োরিটি দিন

য япон我知道, MVVM ইমপ্লিমেন্ট করা অধিকাংশ লোক ভিউমডেলের রি-ইউজেবিলিটি প্রচার কে একটি গোল করে, যাতে সেগুলো n সংখ্যক ভিন্ন ভিউর জন্য পুনর্ব্যবহার করা যায় (মেনি-টু-ওয়ান রেশিও)।

সহজ ভাষায়, এটি অর্জনের দুটি পদ্ধতি আছে:

  • একটি নির্দিষ্ট ভিউ রেফারেন্স না করে। আশা করি এখন পর্যন্ত এটি আপনার জন্য খবর নয়।
  • UI-র বিস্তারিতের बाबতে যতটুকু সম্ভব জানেন না

দ্বিতীয় পয়েন্টটি অস্পষ্ট বা কাউন্টার-ইন্টুইটিভ লাগতে পারে (এটা কীভাবে যেন যেটি রেফারেন্স করে না সেটি সম্পর্কে কিছু জানতে পারে?), তাই আমি মনে করি কোড দেখানোর সময় এসেছে:

class NoteViewModel(val repo: NoteRepo): ViewModel(){ //Note: আপনি ডেটা ভিউতে পাবলিশ করতে পারেন ডেটাবাইন্ডিং, RxJava Observables, এবং অন্যান্য পদ্ধতির মাধ্যমে। যদিও আমি ব্যাকএন্ড ক্লাসে LiveData ব্যবহার পছন্দ করি না, এটি অ্যান্ড্রয়েড ফ্রন্টএন্ডে AAC-র সাথে চমৎকার কাজ করে val noteState: MutableLiveData<Note>() //... fun handleEvent(event: NoteEvent) { when (event) { is NoteEvent.OnStart -> getNote(event.noteId) //... } } private fun getNote(noteId: String){ noteState.value = repo.getNote(noteId) } }

এটি একটি খুব সরলীকৃত উদাহরণ হলেও, পয়েন্টটি হলো এই নির্দিষ্ট ভিউমডেল শুধু একটি সিম্পল Note অবজেক্ট পাবলিকলি এক্সপোজ করে (handleEvent ফাংশন বাদে):

data class Note(val creationDate:String, val contents:String, val imageUrl: String, val creator: User?)

এই নির্দিষ্ট পদ্ধতিতে, ভিউমডেল শুধু একটি নির্দিষ্ট ভিউর থেকে নন, বরং যেকোনো নির্দিষ্ট ভিউর বিস্তারিত এবং এর এক্সটেনশনে, প্রেজেন্টেশন লজিক-র থেকে ও ভালোভাবে ডিকাপলড।

যদি আমার কথা এখনও অস্পষ্ট লাগে, আমি প্রতিশ্রুতি দিচ্ছি এটি স্পষ্ট হয়ে যাবে একবার আমি অন্য পদ্ধতিটি বর্ণনা করি।

যদিও আমার আগের হেডিং, "ViewLogic + ViewModel…" সিরিয়াসলি নেওয়া বা ব্যবহার করা উচিত নয়, আমি বোঝাতে চেছিলাম যে খুব ডিকাপলড এবং রি-ইউজেবল ভিউমডেল থাকা মানে আমরা এখন ভিউটিইতে নির্ভর করছি এই Note অবজেক্টটি স্ক্রিনে কীভাবে রেন্ডার/বাইন্ড করতে হয় সেটি বের করার জন্য।

আমাদের মধ্যে কিছু লোক ভিউ ক্লাসগুলোক লজিক দিয়ে ভরতে পছন্দ করি না।

এখানেই বিষয়টি খুব গোলামাল হয়ে যায় এবং প্রজেক্ট রিকোয়ারমেন্ট-এর ওপর নির্ভরশীল। আমি বলছি না যে ভিউ ক্লাসগুলোক লজিক দিয়ে ভরানো যেন…:

private fun observeViewModel() { viewModel.notes.observe( viewLifecycleOwner, Observer { notes: List<Note> -> if (notes.isEmpty()) showEmptyState() else showNoteList(notes) } ) //.. }

…সদা একটি খারাপ জিনিস, কিন্তু ক্লাসগুলো যা প্ল্যাটফর্মের সাথে টাইটলি কাপল্ড (যেমন ফ্র্যাগমেন্ট) সেগুলো টেস্ট করা কঠিন, এবং যেসব ক্লাসে লজিক থাকে সেগুলো সবচেয়ে গুরুত্বপূর্ণ ক্লাস টেস্ট করার জন্য!

এক শব্দে, এটি যেকোনো ভালো আর্কিটেকচারের স্বর্ণ সিদ্ধান্ত: Separation of concerns.-এর লাগু করার ব্যর্থতা।

আমার ব্যক্তিগত মতামত হলো separation of concerns খুব উচ্চ ডিগ্রিতে লাগু করা মানসিকভাবে উপযুক্ত। কিন্তু ভুল করবেন না যে অনেক ক্যাশ কাও অ্যাপ্লিকেশন লোকেরা লিখেছে যাদের separation of concerns মানে কী সেটি ধुँয়ো ধারণা নেই।

যাহোক, আমরা পরবর্তীতে যে পদ্ধতিটি আলোচনা করব, সেটি নিজস্ব পার্শ্বপ্রতিক্রিয়া থাকা সত্ত্বেও, একবার nữa প্রেজেন্টেশন লজিক ভিউ থেকে সরিয়ে দেয়।

বেলiers, তার অধিকাংশ।

দ্বিতীয় পদ্ধতি: হাম্বল ভিউ, কন্ট্রোল-ফ্রিক ভিউমডেল

কখনও কখনও আপনার ভিউগুলোর ওপর ফাইন-গ্রেইনড কন্ট্রোল না থাকা (যা রি-ইউজেবল ভিউমডেল প্রায়োরিটি দেয়ার ফলাফল), আসলে খুব খারাপ লাগে।

আমাকে এই পূর্ববর্তী পদ্ধতিকে অন্ধাধুঁধি অ্যাপ্লাই করার প্রতি আরও কম উদ্বুদ্ধ করে দেয় এই ফ্যাক্ট যে আমি প্রায়শই ভিউমডেল রি-ইউজ করতে হয় না।

বিপরীতভাবে, "খুব বেশি অ্যাবস্ট্রাকশন" MVP-এর ওপর MVVM-এর একটি সাধারণ সমালোচনা।

そう言うと, কেউ সরাসরি ভিউমডেলে একটি রেফারেন্স ফিরিয়ে যোগ করে ভিউর ওপর ফাইন-গ্রেইনড কন্ট্রোল ফিরিয়ে পেতে পারে না। সেটি মূলত MVP + মেমোরি লিক হবে (যদি আপনি এখনও AAC থেকে ভিউমডেল ব্যবহার করেন)।

বিকল্পটি হলো, আপনার ভিউমডেল এমনভাবে বানান যাতে সেটি একটি প্রদত্ত ভিউর প্রায় সকল ব্যবহার, স্টেট, এবং প্রেজেন্টেশন লজিক ধারণ করে। ভিউটি অবশ্যই ভিউমডেলের সাথে বাইন্ড করবে, কিন্তু ভিউর যথেষ্ট ডিটেইল ভিউমডেলে থাকায় ভিউর ফাংশনগুলো वन-লাইনারে রিডিউস হয়ে যায় (ছোট এক্সেপশন বাদে)।

মার্টিন ফাউলারের নামকরণ কনভেনশনে, এটি প্যাসিভ ভিউ/স্ক্রিন হিসেবে পরিচিত। এই পদ্ধতির একটি আরও সাধারণ প্রযোজ্য নাম হলো Humble Object Pattern।

এটি অর্জনের জন্য, আপনাকে অনুশীলন করতে হবে আপনার ভিউমডেলে ভিউতে থাকা প্রতিটি কন্ট্রোল বা উইডজেটের জন্য একটি অবজার্ভেবল ফিল্ড থাকে (আপনি যেভাবেই অর্জন করুন — ডেটা বাইন্ডিং, Rx, LiveData, যেকোনো):

class UserViewModel( val repo: IUserRepository, ){ //আসল ডেটা মডেল প্রাইভেট রাখা হয় অযাচিত টেম্পারিং এড়াতে private val userState = MutableLiveData<User>() //কন্ট্রোল লজিক internal val authAttemptState = MutableLiveData<Unit>() internal val startAnimation = MutableLiveData<Unit>() //UI বাইন্ডিং internal val signInStatusText = MutableLiveData<String>() internal val authButtonText = MutableLiveData<String>() internal val satelliteDrawable = MutableLiveData<String>() private fun showErrorState() { signInStatusText.value = LOGIN_ERROR authButtonText.value = SIGN_IN satelliteDrawable.value = ANTENNA_EMPTY } //... }

পরপর, ভিউটিকে অবশ্যই নিজেকে ভিউমডেলের সাথে ওয়ার আপ করতে হবে, কিন্তু এটি করার জন্য প্রয়োজনীয় ফাংশনগুলো טרিভিয়ালি সিম্পল হয়ে যায়:

class LoginView : Fragment() { private lateinit var viewModel: UserViewModel //... //ভিউমডেল তৈরি ও বাইন্ড করুন override fun onStart() { super.onStart() viewModel = ViewModelProviders.of( //... ).get(UserViewModel::class.java) //ব্যাকগ্রাউন্ড অ্যানিমেশন শুরু (root_fragment_login.background as AnimationDrawable).startWithFade() setUpClickListeners() observeViewModel() viewModel.handleEvent(LoginEvent.OnStart) } private fun setUpClickListeners() { //... } private fun observeViewModel() { viewModel.signInStatusText.observe( viewLifecycleOwner, Observer { //"it" হলো MutableLiveData অবজেক্টের ভ্যালু, যা স্ট্রিং হিসেবে ইনফার করা হয় lbl_login_status_display.text = it } ) viewModel.authButtonText.observe( viewLifecycleOwner, Observer { btn_auth_attempt.text = it } ) viewModel.startAnimation.observe( viewLifecycleOwner, Observer { imv_antenna_animation.setImageResource( resources.getIdentifier(ANTENNA_LOOP, "drawable", activity?.packageName) ) (imv_antenna_animation.drawable as AnimationDrawable).start() } ) viewModel.authAttemptState.observe( viewLifecycleOwner, Observer { startSignInFlow() } ) viewModel.satelliteDrawable.observe( viewLifecycleOwner, Observer { imv_antenna_animation.setImageResource( resources.getIdentifier(it, "drawable", activity?.packageName) ) } ) }

এই উদাহরণের পূর্ণ কোড এখানে পাওয়া যাবে।

আপনি সম্ভবত লক্ষ্য করেছেন, আমরা সম্ভবত এই ভিউমডেলটি অন্য কোথাও রি-ইউজ করতে যাচ্ছি না। এছাড়া, আমাদের ভিউ যথেষ্ট হাম্বল হয়ে গেছে (আপনার স্ট্যান্ডার্ড এবং কোড কভারেজের পছন্দের ওপর নির্ভর করে), এবং খুব সহজে লিখা যায়।

কখনও কখনও আপনি এমন পরিস্থিতিতে পড়বেন যেখানে আপনাকে প্রেজেন্টেশন লজিক-এর ভারসাম্য ভিউ এবং ভিউমডেলের মধ্যে খুঁজে বের করতে হবে, যেটি এই দুটি পদ্ধতির কোনোটিই কঠোরভাবে ফলো করে না।

আমি একটি পদ্ধতিকে অন্যটির চেয়ে אדভোকেট করছি না, বরং আপনাকে আপনার পদ্ধতিতে লচকدار হওয়ায় উৎসাহিত করছি, হাতে থাকা রিকোয়ারমেন্টের ওপর ভিত্তি করে।

পছন্দ এবং রিকোয়ারমেন্টের ওপর ভিত্তি করে আপনার আর্কিটেকচার বেছে নিন

এই আর্টিকেলের পয়েন্ট ছিল অ্যান্ড্রয়েড প্ল্যাটফর্মে (কিছু ক্যারি-ওভার অন্যান্য প্ল্যাটফর্মেও) MVVM স্টাইল GUI আর্কিটেকচার কনস্ট্রাক্ট করার কোমতে একজন ডেভেলপার যেসব পদ্ধতি নিতে পারে সেগুলোর মধ্যে দুটি আলোচনা করা।

সত্যি, আমরা এই দুটি পদ্ধতির ভিতরেও ছোট পার্থক্যগুলো সম্পর্কে আরও স্পেসিফিক হতে পারতাম।

  • ভিউ কি প্রতিটি ইনডিভিজুয়াল উইডজেট/কন্ট্রোলের জন্য একটি ফিল্ড অবজার্ভ করবে, অথবা একটি ফিল্ড অবজার্ভ করবে যা একটি একক মডেল পাবলিশ করে পুরো ভিউটিকে নতুন করে রেন্ডার করার জন্য?
  • হয়তো আমরা ভিউমডেলকে এক-টু-ওয়ান হওয়া থেকে বাঁচাতে পারি, এবং ভিউকে হাম্বল অবজেক্ট রেখে, সadece একটি প্রেজেন্টার বা কন্ট্রোলার যোগ করে মিক্সে?

কথা সস্তা, এবং আমি দৃঢ়ভাবে পরামর্শ দিচ্ছি আপনি এই জিনিসগুলো কোডে ট্রাই করুন এবং শিখুন যাতে আপনাকে আমার মতো লোকদের ওপর নির্ভর করতে না হয় যে কী করতে হবে।

চূড়ান্তে, আমি মনে করি দুটি উপাদান যা একটি মহান আর্কিটেকচার তৈরি করে সেগুলো নিচের বিবেচনাগুলোতে আউট হয়:

প্রথমে, কয়েকটি পদ্ধতির সাথে খেলুন যতক্ষণ না আপনি একটি পাওয়া যাচ্ছি যা আপনি পছন্দ করেন। এটি সেরা করা যায় একটি অ্যাপ্লিকেশন বিল্ড করে (এটি সিম্পল হতে পারে) প্রতিটি স্টাইলে, এবং দেখে কী ফিল রাইট।

দ্বিতীয়ে, বুঝুন যে পছন্দদের বাদে, ভিন্ন স্টাইল বিভিন্ন বেনিফিটকে এক্সচেঞ্জে olika ডিফিসিটের সাথে emphasise করে। জ্লদে, আপনি প্রজেক্ট রিকোয়ারমেন্টের আপনার বোঝাপড়ার ওপর ভিত্তি করে ভালো পছন্দ করতে পারবেন ব্লাইন্ড ফেইথ-এর বদলে।

সফটওয়্যার আর্কিটেকচার সম্পর্কে আরও জানুন:

সোশ্যাল

https://www.instagram.com/rkay301/
https://www.facebook.com/wiseassblog/
https://twitter.com/wiseass301
https://wiseassblog.com/

  1. Android-এ NavigationView ব্যবহার করে নেভিগেশন ড্রয়ার তৈরির পদ্ধতি

  2. অ্যান্ড্রয়েডে স্ক্রিনশট ও ছবি এনোটেট করার প্রো টিপস

  3. উইন্ডোজ ১১/১০ টাস্ক ম্যানেজার আইটি প্রো처럼 ব্যবহার করুন

  4. গুগল ইমেজ সার্চ মास্টার করুন: প্রফেশনালদের জন্য অ্যাডভান্সড টিপস ও ট্রিকস