অ্যাপ আর্কিটেকচারের জন্য গাইড

অ্যাপ আর্কিটেকচার হলো একটি উচ্চ-মানের অ্যান্ড্রয়েড অ্যাপ্লিকেশনের ভিত্তি। একটি সুসংজ্ঞায়িত আর্কিটেকচার আপনাকে এমন একটি স্কেলেবল ও রক্ষণাবেক্ষণযোগ্য অ্যাপ তৈরি করতে সাহায্য করে, যা ফোন, ট্যাবলেট, ফোল্ডেবল, ক্রোমওএস ডিভাইস, গাড়ির ডিসপ্লে এবং এক্সআর-সহ অ্যান্ড্রয়েড ডিভাইসের ক্রমবর্ধমান ইকোসিস্টেমের সাথে নিজেকে মানিয়ে নিতে পারে।

অ্যাপ রচনা

একটি সাধারণ অ্যান্ড্রয়েড অ্যাপ একাধিক অ্যাপ কম্পোনেন্ট , যেমন সার্ভিস , কন্টেন্ট প্রোভাইডার এবং ব্রডকাস্ট রিসিভার নিয়ে গঠিত। আপনি আপনার অ্যাপ ম্যানিফেস্টে এই কম্পোনেন্টগুলো ঘোষণা করেন।

একটি অ্যাপের ইউজার ইন্টারফেসও একটি কম্পোনেন্ট। ঐতিহাসিকভাবে, ইউআই একাধিক অ্যাক্টিভিটি ব্যবহার করে তৈরি করা হতো। তবে, আধুনিক অ্যাপগুলো সিঙ্গেল-অ্যাক্টিভিটি আর্কিটেকচার ব্যবহার করে। একটিমাত্র Activity স্ক্রিন বা জেটপ্যাক কম্পোজ ডেস্টিনেশনের জন্য কন্টেইনার হিসেবে কাজ করে।

একাধিক ফর্ম ফ্যাক্টর

অ্যাপগুলো শুধু ফোনই নয়, ট্যাবলেট, ফোল্ডেবল ডিভাইস , ক্রোমওএস ডিভাইস এবং আরও অনেক ধরনের ডিভাইসে চলতে পারে। আপনার অ্যাপ সবসময় পোর্ট্রেট বা ল্যান্ডস্কেপ ওরিয়েন্টেশনে স্থির থাকে, এমনটা ধরে নেবেন না। কনফিগারেশনের পরিবর্তন, যেমন ডিভাইস ঘোরানো বা ফোল্ডেবল ডিভাইস ভাঁজ করা ও খোলা, আপনার অ্যাপকে তার UI নতুন করে সাজাতে বাধ্য করে, যা অ্যাপের অবস্থাকে প্রভাবিত করে।

সম্পদের সীমাবদ্ধতা

মোবাইল ডিভাইস—এমনকি বড় স্ক্রিনের ডিভাইসগুলোও—সম্পদের সীমাবদ্ধতার সম্মুখীন হয়, তাই যেকোনো সময় অপারেটিং সিস্টেম তার সম্পদ অন্য প্রসেসগুলোকে দেওয়ার জন্য আপনার অ্যাপ প্রসেসটি বন্ধ করে দিতে পারে।

পরিবর্তনশীল উৎক্ষেপণ পরিস্থিতি

সীমিত সম্পদের পরিবেশে, আপনার অ্যাপের উপাদানগুলো আলাদাভাবে এবং এলোমেলোভাবে চালু হতে পারে; শুধু তাই নয়, অপারেটিং সিস্টেম বা ব্যবহারকারী যেকোনো সময় সেগুলোকে বন্ধ করে দিতে পারে। ফলে, আপনার অ্যাপের উপাদানগুলোতে কোনো অ্যাপ্লিকেশন ডেটা বা স্টেট সংরক্ষণ করবেন না। আপনার অ্যাপের উপাদানগুলোকে স্বয়ংসম্পূর্ণ এবং একে অপরের থেকে স্বাধীন করে তুলুন।

সাধারণ স্থাপত্য নীতি

অ্যাপ্লিকেশনের ডেটা ও স্টেট সংরক্ষণের জন্য যদি অ্যাপ কম্পোনেন্ট ব্যবহার করা না যায়, তাহলে আপনার অ্যাপটি কীভাবে ডিজাইন করা উচিত?

অ্যান্ড্রয়েড অ্যাপের আকার বাড়ার সাথে সাথে এমন একটি আর্কিটেকচার নির্ধারণ করা জরুরি, যা অ্যাপটিকে প্রয়োজন অনুযায়ী বড় বা ছোট হতে সাহায্য করে। একটি সুপরিকল্পিত অ্যাপ আর্কিটেকচার অ্যাপের বিভিন্ন অংশের মধ্যেকার সীমানা এবং প্রতিটি অংশের দায়িত্ব নির্ধারণ করে দেয়।

উদ্বেগের পৃথকীকরণ

আপনার অ্যাপের আর্কিটেকচার কয়েকটি নির্দিষ্ট নীতি অনুসরণ করে ডিজাইন করুন।

সবচেয়ে গুরুত্বপূর্ণ নীতিটি হলো দায়িত্বের পৃথকীকরণ : আপনার অ্যাপকে মেথড, ক্লাস, ফাইল, প্যাকেজ, মডিউল এবং লেয়ারে বিভক্ত করা, যেগুলোর সুস্পষ্টভাবে সংজ্ঞায়িত দায়িত্ব এবং সীমানা রয়েছে।

আপনার সমস্ত কোড একটি Activity তে লেখা একটি সাধারণ ভুল।

একটি Activity প্রধান কাজ হলো আপনার অ্যাপের ইউজার ইন্টারফেস (UI) ধারণ করা। অ্যান্ড্রয়েড অপারেটিং সিস্টেম এদের জীবনচক্র নিয়ন্ত্রণ করে এবং স্ক্রিন ঘোরানোর মতো ব্যবহারকারীর কার্যকলাপ বা মেমরি কমে যাওয়ার মতো সিস্টেম ইভেন্টের প্রতিক্রিয়ায় এদেরকে ঘন ঘন ধ্বংস ও পুনরায় তৈরি করে।

এই ক্ষণস্থায়ী প্রকৃতির কারণে এগুলি অ্যাপ্লিকেশন ডেটা বা স্টেট ধারণ করার জন্য অনুপযুক্ত। আপনি যদি কোনো Activity ডেটা সংরক্ষণ করেন, তাহলে কম্পোনেন্টটি পুনরায় তৈরি হলে সেই ডেটা হারিয়ে যায়। ডেটার স্থায়িত্ব নিশ্চিত করতে এবং একটি স্থিতিশীল ব্যবহারকারীর অভিজ্ঞতা প্রদান করতে, এই UI কম্পোনেন্টগুলির উপর স্টেটের দায়িত্ব অর্পণ করবেন না।

অভিযোজিত বিন্যাস

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

ডেটা মডেল থেকে UI চালনা করুন

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

নিম্নলিখিত কারণগুলোর জন্য স্থায়ী মডেলগুলো আদর্শ:

  • রিসোর্স খালি করার জন্য অ্যান্ড্রয়েড ওএস আপনার অ্যাপটি মুছে ফেললেও ব্যবহারকারীদের কোনো ডেটা নষ্ট হয় না।

  • নেটওয়ার্ক সংযোগ অনিয়মিত বা অনুপলব্ধ হলেও আপনার অ্যাপটি কাজ করতে থাকে।

আপনার অ্যাপকে শক্তিশালী ও পরীক্ষাযোগ্য করে তুলতে ডেটা মডেল ক্লাসের উপর ভিত্তি করে এর আর্কিটেকচার তৈরি করুন।

সত্যের একমাত্র উৎস

আপনার অ্যাপে যখন একটি নতুন ডেটা টাইপ সংজ্ঞায়িত করা হয়, তখন সেটির জন্য একটি একক নির্ভরযোগ্য উৎস (SSOT) নির্ধারণ করুন। SSOT হলো সেই ডেটার মালিক , এবং শুধুমাত্র SSOT-ই এটিকে পরিবর্তন বা পরিবর্ধন করতে পারে। এটি করার জন্য, SSOT একটি অপরিবর্তনশীল টাইপ ব্যবহার করে ডেটা প্রকাশ করে; ডেটা পরিবর্তন করার জন্য, SSOT এমন ফাংশন প্রকাশ করে বা ইভেন্ট গ্রহণ করে যা অন্য টাইপগুলো কল করতে পারে।

এই বিন্যাসটির একাধিক সুবিধা রয়েছে:

  • একটি নির্দিষ্ট ধরণের ডেটার সমস্ত পরিবর্তন এক জায়গায় কেন্দ্রীভূত করে।
  • তথ্যকে সুরক্ষিত রাখে যাতে অন্য কেউ এতে হস্তক্ষেপ করতে না পারে।
  • ডেটার পরিবর্তনগুলো আরও সহজে শনাক্তযোগ্য করে তোলে, ফলে বাগ খুঁজে বের করা সহজ হয়।

একটি অফলাইন-ফার্স্ট অ্যাপ্লিকেশনে, অ্যাপ্লিকেশন ডেটার নির্ভরযোগ্য উৎস সাধারণত একটি ডেটাবেস হয়ে থাকে। অন্য কিছু ক্ষেত্রে, নির্ভরযোগ্য উৎস একটি ViewModel হতে পারে।

একমুখী ডেটা প্রবাহ

তথ্যের একক উৎস নীতিটি প্রায়শই একমুখী ডেটা প্রবাহ (UDF) প্যাটার্নের সাথে ব্যবহৃত হয়। UDF-এ, স্টেট কেবল এক দিকে প্রবাহিত হয়, সাধারণত প্যারেন্ট কম্পোনেন্ট থেকে চাইল্ড কম্পোনেন্টের দিকে। যে ইভেন্টগুলো ডেটা প্রবাহকে পরিবর্তন করে, সেগুলো বিপরীত দিকে প্রবাহিত হয়।

অ্যান্ড্রয়েডে, স্টেট বা ডেটা সাধারণত হায়ারার্কির উচ্চ-স্কোপের টাইপগুলো থেকে নিম্ন-স্কোপের টাইপগুলোর দিকে প্রবাহিত হয়। ইভেন্টগুলো সাধারণত নিম্ন-স্কোপের টাইপগুলো থেকে ট্রিগার হতে থাকে যতক্ষণ না সেগুলো সংশ্লিষ্ট ডেটা টাইপের জন্য SSOT-তে পৌঁছায়। উদাহরণস্বরূপ, অ্যাপ্লিকেশন ডেটা সাধারণত ডেটা সোর্স থেকে UI-তে প্রবাহিত হয়। বাটন প্রেসের মতো ইউজার ইভেন্টগুলো UI থেকে SSOT-তে প্রবাহিত হয়, যেখানে অ্যাপ্লিকেশন ডেটা পরিবর্তিত হয় এবং একটি ইমিউটেবল টাইপে প্রকাশ করা হয়।

এই প্যাটার্নটি ডেটার সামঞ্জস্য আরও ভালোভাবে বজায় রাখে, এতে ভুলের সম্ভাবনা কম থাকে, ডিবাগ করা সহজ এবং এটি SSOT প্যাটার্নের সমস্ত সুবিধা প্রদান করে।

UDF সম্পর্কে আরও তথ্যের জন্য, Jetpack Compose-এ একমুখী ডেটা প্রবাহ দেখুন।

সাধারণ স্থাপত্য নীতিগুলো বিবেচনা করে, প্রতিটি অ্যাপ্লিকেশন কমপক্ষে দুটি লেয়ার দিয়ে ডিজাইন করুন:

  • UI লেয়ার: স্ক্রিনে অ্যাপ্লিকেশন ডেটা প্রদর্শন করে।
  • ডেটা লেয়ার: এতে আপনার অ্যাপের ব্যবসায়িক যুক্তি থাকে এবং অ্যাপ্লিকেশন ডেটা প্রকাশ করে।

UI এবং ডেটা লেয়ারের মধ্যেকার মিথস্ক্রিয়াকে সরল করতে ও পুনঃব্যবহার করার জন্য আপনি ডোমেইন লেয়ার নামক একটি অতিরিক্ত লেয়ার যোগ করতে পারেন।

একটি সাধারণ অ্যাপ আর্কিটেকচারে, UI লেয়ার অ্যাপ্লিকেশন ডেটা পায় ডেটা লেয়ার থেকে অথবা ঐচ্ছিক ডোমেইন লেয়ার থেকে, যা UI লেয়ার এবং ডেটা লেয়ারের মাঝে অবস্থান করে।
চিত্র ১. একটি সাধারণ অ্যাপ স্থাপত্যের চিত্র।

আধুনিক অ্যাপ স্থাপত্য

একটি আধুনিক অ্যান্ড্রয়েড অ্যাপ আর্কিটেকচারে (অন্যান্য কৌশলের পাশাপাশি) নিম্নলিখিত কৌশলগুলো ব্যবহার করা হয়:

  • অভিযোজিত এবং স্তরযুক্ত স্থাপত্য
  • অ্যাপের সকল স্তরে একমুখী ডেটা প্রবাহ (UDF)
  • UI-এর জটিলতা ব্যবস্থাপনার জন্য স্টেট হোল্ডার সহ UI লেয়ার।
  • কোরাউটিন এবং ফ্লো
  • ডিপেন্ডেন্সি ইনজেকশনের সর্বোত্তম অনুশীলন
  • R8 ও বেসলাইন প্রোফাইল ব্যবহার করে পারফরম্যান্স অপ্টিমাইজেশন, এবং ম্যাক্রোবেঞ্চমার্ক দিয়ে পরিমাপ।

আরও তথ্যের জন্য, অ্যান্ড্রয়েড আর্কিটেকচারের সুপারিশসমূহ দেখুন।

UI স্তর

UI লেয়ারের (বা প্রেজেন্টেশন লেয়ারের ) কাজ হলো স্ক্রিনে অ্যাপ্লিকেশন ডেটা প্রদর্শন করা। যখনই ব্যবহারকারীর ইন্টারঅ্যাকশনের (যেমন বাটন চাপা) বা বাহ্যিক ইনপুটের (যেমন নেটওয়ার্ক রেসপন্স) কারণে ডেটা পরিবর্তিত হয়, UI সেই পরিবর্তনগুলো প্রতিফলিত করার জন্য আপডেট হয়।

UI স্তরটি দুই ধরনের কাঠামো নিয়ে গঠিত:

  • UI এলিমেন্টগুলো স্ক্রিনে ডেটা রেন্ডার করে। অ্যাডাপ্টিভ লেআউট সমর্থন করার জন্য আপনি Jetpack Compose ফাংশন ব্যবহার করে এই এলিমেন্টগুলো তৈরি করেন।
  • স্টেট হোল্ডার (যেমন ViewModel ) ডেটা ধারণ করে, সেটিকে UI-তে প্রকাশ করে এবং লজিক পরিচালনা করে। স্টেট হোল্ডারগুলোর স্থায়িত্বকাল সেই UI এলিমেন্টের সমান হওয়া উচিত, যার জন্য তারা স্টেট সরবরাহ করছে। উদাহরণস্বরূপ, একটি স্ক্রিনের ViewModel ততক্ষণ মেমরিতে থাকা উচিত, যতক্ষণ না অ্যাপের নেভিগেশন ব্যাক স্ট্যাক থেকে স্ক্রিনটি সরিয়ে ফেলা হয়। আরও তথ্যের জন্য, স্টেট লাইফস্প্যানস (State Lifespans ) দেখুন।
একটি সাধারণ আর্কিটেকচারে, UI লেয়ারের UI এলিমেন্টগুলো স্টেট হোল্ডারদের উপর নির্ভর করে,  যারা আবার ডেটা লেয়ার অথবা  ঐচ্ছিক ডোমেইন লেয়ারের ক্লাসগুলোর উপর নির্ভর করে।
চিত্র ২. অ্যাপ আর্কিটেকচারে UI লেয়ারের ভূমিকা।

অ্যাডাপ্টিভ UI-এর ক্ষেত্রে, ViewModel অবজেক্টের মতো স্টেট হোল্ডাররা এমন UI স্টেট প্রকাশ করে যা বিভিন্ন উইন্ডো সাইজ ক্লাসের সাথে খাপ খাইয়ে নেয়। এই UI স্টেটটি পাওয়ার জন্য আপনি currentWindowAdaptiveInfo() ব্যবহার করতে পারেন। এরপর NavigationSuiteScaffold মতো কম্পোনেন্টগুলো উপলব্ধ স্ক্রিন স্পেসের উপর ভিত্তি করে বিভিন্ন নেভিগেশন প্যাটার্নের (যেমন, NavigationBar , NavigationRail , বা NavigationDrawer ) মধ্যে স্বয়ংক্রিয়ভাবে পরিবর্তন করার জন্য এই তথ্য ব্যবহার করতে পারে।

আরও জানতে, UI লেয়ার এবং কম্পোজ UI আর্কিটেকচার দেখুন।

অ্যাডাপ্টিভ অ্যাপস এবং নেভিগেশন সম্পর্কে আরও তথ্যের জন্য, ' বিল্ড অ্যাডাপ্টিভ অ্যাপস' এবং 'বিল্ড অ্যাডাপ্টিভ নেভিগেশন' দেখুন।

ডেটা স্তর

একটি অ্যাপের ডেটা লেয়ারে বিজনেস লজিক থাকে। বিজনেস লজিকই আপনার অ্যাপকে মূল্যবান করে তোলে—এতে এমন কিছু নিয়ম থাকে যা নির্ধারণ করে আপনার অ্যাপ কীভাবে ডেটা তৈরি, সংরক্ষণ এবং পরিবর্তন করবে।

ডেটা লেয়ারটি রিপোজিটরি দিয়ে গঠিত, যার প্রতিটিতে শূন্য থেকে একাধিক ডেটা সোর্স থাকতে পারে। আপনার অ্যাপে ব্যবহৃত প্রতিটি ভিন্ন ধরনের ডেটার জন্য একটি করে রিপোজিটরি ক্লাস তৈরি করুন। উদাহরণস্বরূপ, আপনি সিনেমা সম্পর্কিত ডেটার জন্য একটি MoviesRepository ক্লাস অথবা পেমেন্ট সম্পর্কিত ডেটার জন্য একটি PaymentsRepository ক্লাস তৈরি করতে পারেন।

একটি প্রচলিত আর্কিটেকচারে, ডেটা লেয়ারের রিপোজিটরিগুলো অ্যাপের বাকি অংশে ডেটা সরবরাহ করে এবং ডেটা সোর্সগুলোর উপর নির্ভর করে।
চিত্র ৩. অ্যাপ আর্কিটেকচারে ডেটা লেয়ারের ভূমিকা।

রিপোজিটরি ক্লাসগুলো নিম্নলিখিত বিষয়গুলোর জন্য দায়ী:

  • অ্যাপের বাকি অংশে ডেটা প্রকাশ করা
  • ডেটার পরিবর্তনগুলিকে কেন্দ্রীভূত করা
  • একাধিক ডেটা উৎসের মধ্যে দ্বন্দ্ব নিরসন করা
  • অ্যাপের বাকি অংশ থেকে ডেটার উৎসগুলোকে আলাদা করা
  • ব্যবসায়িক যুক্তি ধারণ করে

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

আরও জানতে, ডেটা লেয়ার পৃষ্ঠাটি দেখুন।

ডোমেইন স্তর

ডোমেইন লেয়ার হলো UI এবং ডেটা লেয়ারের মধ্যে অবস্থিত একটি ঐচ্ছিক লেয়ার।

ডোমেইন লেয়ার জটিল বিজনেস লজিক অথবা একাধিক ভিউ মডেল দ্বারা পুনঃব্যবহৃত সরল বিজনেস লজিককে এনক্যাপসুলেট করার জন্য দায়ী। ডোমেইন লেয়ার ঐচ্ছিক, কারণ সব অ্যাপের এই ধরনের প্রয়োজনীয়তা থাকে না। এটি কেবল প্রয়োজনের সময়ই ব্যবহার করুন — উদাহরণস্বরূপ, জটিলতা সামলাতে বা পুনঃব্যবহারযোগ্যতাকে প্রাধান্য দিতে।

যখন এটি অন্তর্ভুক্ত করা হয়, তখন ঐচ্ছিক ডোমেইন লেয়ারটি UI লেয়ারকে নির্ভরতা প্রদান করে এবং ডেটা লেয়ারের উপর নির্ভর করে।
চিত্র ৪. অ্যাপ আর্কিটেকচারে ডোমেইন লেয়ারের ভূমিকা।

ডোমেইন লেয়ারের ক্লাসগুলোকে সাধারণত ইউজ কেস বা ইন্টারঅ্যাক্টর বলা হয়। প্রতিটি ইউজ কেস একটিমাত্র কার্যকারিতার জন্য দায়ী থাকে। উদাহরণস্বরূপ, আপনার অ্যাপে একটি GetTimeZoneUseCase ক্লাস থাকতে পারে, যদি একাধিক ভিউ মডেল স্ক্রিনে সঠিক বার্তা দেখানোর জন্য টাইম জোনের উপর নির্ভর করে।

আরও জানতে, ডোমেইন লেয়ার পৃষ্ঠাটি দেখুন।

উপাদানগুলির মধ্যে নির্ভরতা পরিচালনা করুন

আপনার অ্যাপের ক্লাসগুলো সঠিকভাবে কাজ করার জন্য অন্যান্য ক্লাসের উপর নির্ভরশীল। কোনো নির্দিষ্ট ক্লাসের নির্ভরতাগুলো একত্রিত করতে আপনি নিম্নলিখিত ডিজাইন প্যাটার্নগুলোর যেকোনো একটি ব্যবহার করতে পারেন:

  • ডিপেন্ডেন্সি ইনজেকশন (DI) : ডিপেন্ডেন্সি ইনজেকশন ক্লাসগুলোকে তাদের ডিপেন্ডেন্সিগুলো কনস্ট্রাক্ট না করেই সংজ্ঞায়িত করার সুযোগ দেয়। রানটাইমে, অন্য একটি ক্লাস এই ডিপেন্ডেন্সিগুলো সরবরাহ করার দায়িত্বে থাকে।
  • সার্ভিস লোকেটর : সার্ভিস লোকেটর প্যাটার্ন এমন একটি রেজিস্ট্রি প্রদান করে, যেখান থেকে ক্লাসগুলো তাদের ডিপেন্ডেন্সিগুলো তৈরি করার পরিবর্তে সংগ্রহ করতে পারে।

এই প্যাটার্নগুলো আপনার কোডকে প্রয়োজন অনুযায়ী পরিবর্তন করতে সাহায্য করে, কারণ এগুলো কোডের পুনরাবৃত্তি বা জটিলতা না বাড়িয়েই ডিপেন্ডেন্সি ব্যবস্থাপনার জন্য সুস্পষ্ট কাঠামো প্রদান করে। এই প্যাটার্নগুলো আপনাকে টেস্ট এবং প্রোডাকশন ইমপ্লিমেন্টেশনের মধ্যে দ্রুত পরিবর্তন করার সুযোগও দেয়।

সাধারণ সর্বোত্তম অনুশীলন

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

যদিও নিম্নলিখিত সুপারিশগুলো বাধ্যতামূলক নয়, তবে বেশিরভাগ ক্ষেত্রে এগুলো অনুসরণ করলে আপনার কোডবেস আরও শক্তিশালী, পরীক্ষাযোগ্য এবং রক্ষণাবেক্ষণযোগ্য হয়ে ওঠে।

অ্যাপের কম্পোনেন্টগুলোতে ডেটা সংরক্ষণ করবেন না।

আপনার অ্যাপের এন্ট্রি পয়েন্টগুলোকে—যেমন অ্যাক্টিভিটি, সার্ভিস এবং ব্রডকাস্ট রিসিভার—ডেটার উৎস হিসেবে চিহ্নিত করা থেকে বিরত থাকুন। এন্ট্রি পয়েন্টগুলোকে অন্যান্য কম্পোনেন্টের সাথে সমন্বয় করতে দিন, যাতে শুধুমাত্র সেই এন্ট্রি পয়েন্টের জন্য প্রাসঙ্গিক ডেটার একটি উপসেটই পুনরুদ্ধার করা হয়। ব্যবহারকারীর ডিভাইসের সাথে মিথস্ক্রিয়া এবং সিস্টেমের ক্ষমতার উপর নির্ভর করে প্রতিটি অ্যাপ কম্পোনেন্টের স্থায়িত্বকাল স্বল্প হয়।

অ্যান্ড্রয়েড ক্লাসের উপর নির্ভরতা কমান।

আপনার অ্যাপের কম্পোনেন্টগুলোকেই একমাত্র ক্লাস হিসেবে তৈরি করুন যেগুলো অ্যান্ড্রয়েড ফ্রেমওয়ার্ক SDK API, যেমন Context বা Toast উপর নির্ভর করে। অ্যাপের কম্পোনেন্টগুলো থেকে অন্যান্য ক্লাসকে অ্যাবস্ট্রাক্ট করলে তা টেস্টেবিলিটি বাড়াতে সাহায্য করে এবং অ্যাপের অভ্যন্তরীণ কাপলিং কমায়।

আপনার অ্যাপের মডিউলগুলোর মধ্যে দায়িত্বের সুস্পষ্ট সীমারেখা নির্ধারণ করুন।

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

প্রতিটি মডিউল থেকে যথাসম্ভব কম তথ্য প্রকাশ করুন।

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

আপনার অ্যাপের অনন্য মূল বৈশিষ্ট্যের উপর মনোযোগ দিন, যাতে এটি অন্যান্য অ্যাপ থেকে স্বতন্ত্র হয়ে ওঠে।

একই গতানুগতিক কোড বারবার লিখে নতুন করে চাকা আবিষ্কার করবেন না। এর পরিবর্তে, আপনার অ্যাপটিকে যা অনন্য করে তোলে, সেদিকে আপনার সময় এবং শক্তিকে মনোনিবেশ করুন। পুনরাবৃত্তিমূলক গতানুগতিক কোডগুলো Jetpack লাইব্রেরি এবং অন্যান্য প্রস্তাবিত লাইব্রেরিগুলোকে সামলাতে দিন।

আদর্শ লেআউট এবং অ্যাপ ডিজাইন প্যাটার্ন ব্যবহার করুন।

Jetpack Compose লাইব্রেরিগুলো অ্যাডাপ্টিভ ইউজার ইন্টারফেস তৈরির জন্য শক্তিশালী এপিআই (API) প্রদান করে। একাধিক ফর্ম ফ্যাক্টর এবং ডিসপ্লে সাইজে ব্যবহারকারীর অভিজ্ঞতা অপ্টিমাইজ করতে আপনার অ্যাপে ক্যানোনিকাল লেআউটগুলো ব্যবহার করুন। আপনার ব্যবহারের ক্ষেত্রগুলোর জন্য সবচেয়ে উপযুক্ত লেআউটগুলো নির্বাচন করতে অ্যাপ ডিজাইন প্যাটার্নের গ্যালারিটি পর্যালোচনা করুন।

কনফিগারেশন পরিবর্তনের পরেও UI অবস্থা অপরিবর্তিত রাখুন।

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

পুনরায় ব্যবহারযোগ্য এবং সংযোজনযোগ্য UI উপাদান ডিজাইন করুন।

অ্যাডাপ্টিভ ডিজাইন সমর্থন করার জন্য পুনঃব্যবহারযোগ্য ও সংযোজনযোগ্য UI কম্পোনেন্ট তৈরি করুন। এটি আপনাকে উল্লেখযোগ্য রিফ্যাক্টরিং ছাড়াই বিভিন্ন স্ক্রিনের আকার ও ভঙ্গির সাথে মানিয়ে নিতে কম্পোনেন্টগুলোকে একত্রিত ও পুনর্বিন্যাস করার সুযোগ দেয়।

আপনার অ্যাপের প্রতিটি অংশকে কীভাবে আলাদাভাবে পরীক্ষাযোগ্য করা যায়, তা বিবেচনা করুন।

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

টাইপগুলো তাদের কনকারেন্সি পলিসির জন্য দায়ী।

যদি কোনো টাইপ দীর্ঘ সময় ধরে চলা ব্লকিং কাজ সম্পাদন করে, তবে সেই গণনাটিকে সঠিক থ্রেডে স্থানান্তর করার দায়িত্ব টাইপটিরই হওয়া উচিত। টাইপটি জানে যে এটি কী ধরনের গণনা করছে এবং কোন থ্রেডে গণনাটি চালাতে হবে। টাইপগুলো মেইন-সেফ হওয়া উচিত, অর্থাৎ মেইন থ্রেডকে ব্লক না করেই সেখান থেকে সেগুলোকে নিরাপদে কল করা যায়।

যথাসম্ভব প্রাসঙ্গিক ও নতুন তথ্য সংরক্ষণ করুন।

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

স্থাপত্যের সুবিধা

আপনার অ্যাপে একটি ভালো আর্কিটেকচার প্রয়োগ করা হলে তা প্রজেক্ট এবং ইঞ্জিনিয়ারিং টিমের জন্য অনেক সুবিধা বয়ে আনে:

  • সামগ্রিক অ্যাপটির রক্ষণাবেক্ষণযোগ্যতা, গুণমান এবং দৃঢ়তা উন্নত করে।
  • অ্যাপটিকে স্কেল করতে দেয়। আরও বেশি ব্যক্তি এবং আরও বেশি দল ন্যূনতম কোড দ্বন্দ্বের সাথে একই কোডবেসে অবদান রাখতে পারে।
  • নতুন সদস্যদের অন্তর্ভুক্তিতে সাহায্য করে। যেহেতু আর্কিটেকচার আপনার প্রকল্পে সামঞ্জস্য নিয়ে আসে, তাই দলের নতুন সদস্যরা দ্রুত কাজ শিখে নিতে পারে এবং কম সময়ে আরও দক্ষ হয়ে উঠতে পারে।
  • পরীক্ষা করা সহজ। একটি ভালো আর্কিটেকচার সরল টাইপগুলোকে উৎসাহিত করে, যেগুলো সাধারণত পরীক্ষা করা সহজ হয়।
  • এটি আপনাকে সুনির্দিষ্ট প্রক্রিয়ার মাধ্যমে পদ্ধতিগতভাবে ত্রুটি অনুসন্ধান করতে সাহায্য করে।

যদিও ভালো আর্কিটেকচারের জন্য শুরুতে সময়ের বিনিয়োগ প্রয়োজন, এটি ব্যবহারকারীদের উপরও সরাসরি প্রভাব ফেলে। একটি অধিক কর্মদক্ষ প্রকৌশল দলের কারণে ব্যবহারকারীরা আরও স্থিতিশীল অ্যাপ্লিকেশন এবং আরও বেশি ফিচার থেকে উপকৃত হন।

নমুনা

নিম্নলিখিত নমুনাগুলো ভালো অ্যাপ আর্কিটেকচারের উদাহরণ:

,

অ্যাপ আর্কিটেকচার হলো একটি উচ্চ-মানের অ্যান্ড্রয়েড অ্যাপ্লিকেশনের ভিত্তি। একটি সুসংজ্ঞায়িত আর্কিটেকচার আপনাকে এমন একটি স্কেলেবল ও রক্ষণাবেক্ষণযোগ্য অ্যাপ তৈরি করতে সাহায্য করে, যা ফোন, ট্যাবলেট, ফোল্ডেবল, ক্রোমওএস ডিভাইস, গাড়ির ডিসপ্লে এবং এক্সআর-সহ অ্যান্ড্রয়েড ডিভাইসের ক্রমবর্ধমান ইকোসিস্টেমের সাথে নিজেকে মানিয়ে নিতে পারে।

অ্যাপ রচনা

একটি সাধারণ অ্যান্ড্রয়েড অ্যাপ একাধিক অ্যাপ কম্পোনেন্ট , যেমন সার্ভিস , কন্টেন্ট প্রোভাইডার এবং ব্রডকাস্ট রিসিভার নিয়ে গঠিত। আপনি আপনার অ্যাপ ম্যানিফেস্টে এই কম্পোনেন্টগুলো ঘোষণা করেন।

একটি অ্যাপের ইউজার ইন্টারফেসও একটি কম্পোনেন্ট। ঐতিহাসিকভাবে, ইউআই একাধিক অ্যাক্টিভিটি ব্যবহার করে তৈরি করা হতো। তবে, আধুনিক অ্যাপগুলো সিঙ্গেল-অ্যাক্টিভিটি আর্কিটেকচার ব্যবহার করে। একটিমাত্র Activity স্ক্রিন বা জেটপ্যাক কম্পোজ ডেস্টিনেশনের জন্য কন্টেইনার হিসেবে কাজ করে।

একাধিক ফর্ম ফ্যাক্টর

অ্যাপগুলো শুধু ফোনই নয়, ট্যাবলেট, ফোল্ডেবল ডিভাইস , ক্রোমওএস ডিভাইস এবং আরও অনেক ধরনের ডিভাইসে চলতে পারে। আপনার অ্যাপ সবসময় পোর্ট্রেট বা ল্যান্ডস্কেপ ওরিয়েন্টেশনে স্থির থাকে, এমনটা ধরে নেবেন না। কনফিগারেশনের পরিবর্তন, যেমন ডিভাইস ঘোরানো বা ফোল্ডেবল ডিভাইস ভাঁজ করা ও খোলা, আপনার অ্যাপকে তার UI নতুন করে সাজাতে বাধ্য করে, যা অ্যাপের অবস্থাকে প্রভাবিত করে।

সম্পদের সীমাবদ্ধতা

মোবাইল ডিভাইস—এমনকি বড় স্ক্রিনের ডিভাইসগুলোও—সম্পদের সীমাবদ্ধতার সম্মুখীন হয়, তাই যেকোনো সময় অপারেটিং সিস্টেম তার সম্পদ অন্য প্রসেসগুলোকে দেওয়ার জন্য আপনার অ্যাপ প্রসেসটি বন্ধ করে দিতে পারে।

পরিবর্তনশীল উৎক্ষেপণ পরিস্থিতি

সীমিত সম্পদের পরিবেশে, আপনার অ্যাপের উপাদানগুলো আলাদাভাবে এবং এলোমেলোভাবে চালু হতে পারে; শুধু তাই নয়, অপারেটিং সিস্টেম বা ব্যবহারকারী যেকোনো সময় সেগুলোকে বন্ধ করে দিতে পারে। ফলে, আপনার অ্যাপের উপাদানগুলোতে কোনো অ্যাপ্লিকেশন ডেটা বা স্টেট সংরক্ষণ করবেন না। আপনার অ্যাপের উপাদানগুলোকে স্বয়ংসম্পূর্ণ এবং একে অপরের থেকে স্বাধীন করে তুলুন।

সাধারণ স্থাপত্য নীতি

অ্যাপ্লিকেশনের ডেটা ও স্টেট সংরক্ষণের জন্য যদি অ্যাপ কম্পোনেন্ট ব্যবহার করা না যায়, তাহলে আপনার অ্যাপটি কীভাবে ডিজাইন করা উচিত?

অ্যান্ড্রয়েড অ্যাপের আকার বাড়ার সাথে সাথে এমন একটি আর্কিটেকচার নির্ধারণ করা জরুরি, যা অ্যাপটিকে প্রয়োজন অনুযায়ী বড় বা ছোট হতে সাহায্য করে। একটি সুপরিকল্পিত অ্যাপ আর্কিটেকচার অ্যাপের বিভিন্ন অংশের মধ্যেকার সীমানা এবং প্রতিটি অংশের দায়িত্ব নির্ধারণ করে দেয়।

উদ্বেগের পৃথকীকরণ

আপনার অ্যাপের আর্কিটেকচার কয়েকটি নির্দিষ্ট নীতি অনুসরণ করে ডিজাইন করুন।

সবচেয়ে গুরুত্বপূর্ণ নীতিটি হলো দায়িত্বের পৃথকীকরণ : আপনার অ্যাপকে মেথড, ক্লাস, ফাইল, প্যাকেজ, মডিউল এবং লেয়ারে বিভক্ত করা, যেগুলোর সুস্পষ্টভাবে সংজ্ঞায়িত দায়িত্ব এবং সীমানা রয়েছে।

আপনার সমস্ত কোড একটি Activity তে লেখা একটি সাধারণ ভুল।

একটি Activity প্রধান কাজ হলো আপনার অ্যাপের ইউজার ইন্টারফেস (UI) ধারণ করা। অ্যান্ড্রয়েড অপারেটিং সিস্টেম এদের জীবনচক্র নিয়ন্ত্রণ করে এবং স্ক্রিন ঘোরানোর মতো ব্যবহারকারীর কার্যকলাপ বা মেমরি কমে যাওয়ার মতো সিস্টেম ইভেন্টের প্রতিক্রিয়ায় এদেরকে ঘন ঘন ধ্বংস ও পুনরায় তৈরি করে।

এই ক্ষণস্থায়ী প্রকৃতির কারণে এগুলি অ্যাপ্লিকেশন ডেটা বা স্টেট ধারণ করার জন্য অনুপযুক্ত। আপনি যদি কোনো Activity ডেটা সংরক্ষণ করেন, তাহলে কম্পোনেন্টটি পুনরায় তৈরি হলে সেই ডেটা হারিয়ে যায়। ডেটার স্থায়িত্ব নিশ্চিত করতে এবং একটি স্থিতিশীল ব্যবহারকারীর অভিজ্ঞতা প্রদান করতে, এই UI কম্পোনেন্টগুলির উপর স্টেটের দায়িত্ব অর্পণ করবেন না।

অভিযোজিত বিন্যাস

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

ডেটা মডেল থেকে UI চালনা করুন

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

নিম্নলিখিত কারণগুলোর জন্য স্থায়ী মডেলগুলো আদর্শ:

  • রিসোর্স খালি করার জন্য অ্যান্ড্রয়েড ওএস আপনার অ্যাপটি মুছে ফেললেও ব্যবহারকারীদের কোনো ডেটা নষ্ট হয় না।

  • নেটওয়ার্ক সংযোগ অনিয়মিত বা অনুপলব্ধ হলেও আপনার অ্যাপটি কাজ করতে থাকে।

আপনার অ্যাপকে শক্তিশালী ও পরীক্ষাযোগ্য করে তুলতে ডেটা মডেল ক্লাসের উপর ভিত্তি করে এর আর্কিটেকচার তৈরি করুন।

সত্যের একমাত্র উৎস

আপনার অ্যাপে যখন একটি নতুন ডেটা টাইপ সংজ্ঞায়িত করা হয়, তখন সেটির জন্য একটি একক নির্ভরযোগ্য উৎস (SSOT) নির্ধারণ করুন। SSOT হলো সেই ডেটার মালিক , এবং শুধুমাত্র SSOT-ই এটিকে পরিবর্তন বা পরিবর্ধন করতে পারে। এটি করার জন্য, SSOT একটি অপরিবর্তনশীল টাইপ ব্যবহার করে ডেটা প্রকাশ করে; ডেটা পরিবর্তন করার জন্য, SSOT এমন ফাংশন প্রকাশ করে বা ইভেন্ট গ্রহণ করে যা অন্য টাইপগুলো কল করতে পারে।

এই বিন্যাসটির একাধিক সুবিধা রয়েছে:

  • একটি নির্দিষ্ট ধরণের ডেটার সমস্ত পরিবর্তন এক জায়গায় কেন্দ্রীভূত করে।
  • তথ্যকে সুরক্ষিত রাখে যাতে অন্য কেউ এতে হস্তক্ষেপ করতে না পারে।
  • ডেটার পরিবর্তনগুলো আরও সহজে শনাক্তযোগ্য করে তোলে, ফলে বাগ খুঁজে বের করা সহজ হয়।

একটি অফলাইন-ফার্স্ট অ্যাপ্লিকেশনে, অ্যাপ্লিকেশন ডেটার নির্ভরযোগ্য উৎস সাধারণত একটি ডেটাবেস হয়ে থাকে। অন্য কিছু ক্ষেত্রে, নির্ভরযোগ্য উৎস একটি ViewModel হতে পারে।

একমুখী ডেটা প্রবাহ

তথ্যের একক উৎস নীতিটি প্রায়শই একমুখী ডেটা প্রবাহ (UDF) প্যাটার্নের সাথে ব্যবহৃত হয়। UDF-এ, স্টেট কেবল এক দিকে প্রবাহিত হয়, সাধারণত প্যারেন্ট কম্পোনেন্ট থেকে চাইল্ড কম্পোনেন্টের দিকে। যে ইভেন্টগুলো ডেটা প্রবাহকে পরিবর্তন করে, সেগুলো বিপরীত দিকে প্রবাহিত হয়।

অ্যান্ড্রয়েডে, স্টেট বা ডেটা সাধারণত হায়ারার্কির উচ্চ-স্কোপের টাইপগুলো থেকে নিম্ন-স্কোপের টাইপগুলোর দিকে প্রবাহিত হয়। ইভেন্টগুলো সাধারণত নিম্ন-স্কোপের টাইপগুলো থেকে ট্রিগার হতে থাকে যতক্ষণ না সেগুলো সংশ্লিষ্ট ডেটা টাইপের জন্য SSOT-তে পৌঁছায়। উদাহরণস্বরূপ, অ্যাপ্লিকেশন ডেটা সাধারণত ডেটা সোর্স থেকে UI-তে প্রবাহিত হয়। বাটন প্রেসের মতো ইউজার ইভেন্টগুলো UI থেকে SSOT-তে প্রবাহিত হয়, যেখানে অ্যাপ্লিকেশন ডেটা পরিবর্তিত হয় এবং একটি ইমিউটেবল টাইপে প্রকাশ করা হয়।

এই প্যাটার্নটি ডেটার সামঞ্জস্য আরও ভালোভাবে বজায় রাখে, এতে ভুলের সম্ভাবনা কম থাকে, ডিবাগ করা সহজ এবং এটি SSOT প্যাটার্নের সমস্ত সুবিধা প্রদান করে।

UDF সম্পর্কে আরও তথ্যের জন্য, Jetpack Compose-এ একমুখী ডেটা প্রবাহ দেখুন।

সাধারণ স্থাপত্য নীতিগুলো বিবেচনা করে, প্রতিটি অ্যাপ্লিকেশন কমপক্ষে দুটি লেয়ার দিয়ে ডিজাইন করুন:

  • UI লেয়ার: স্ক্রিনে অ্যাপ্লিকেশন ডেটা প্রদর্শন করে।
  • ডেটা লেয়ার: এতে আপনার অ্যাপের ব্যবসায়িক যুক্তি থাকে এবং অ্যাপ্লিকেশন ডেটা প্রকাশ করে।

UI এবং ডেটা লেয়ারের মধ্যেকার মিথস্ক্রিয়াকে সরল করতে ও পুনঃব্যবহার করার জন্য আপনি ডোমেইন লেয়ার নামক একটি অতিরিক্ত লেয়ার যোগ করতে পারেন।

একটি সাধারণ অ্যাপ আর্কিটেকচারে, UI লেয়ার অ্যাপ্লিকেশন ডেটা পায় ডেটা লেয়ার থেকে অথবা ঐচ্ছিক ডোমেইন লেয়ার থেকে, যা UI লেয়ার এবং ডেটা লেয়ারের মাঝে অবস্থান করে।
চিত্র ১. একটি সাধারণ অ্যাপ স্থাপত্যের চিত্র।

আধুনিক অ্যাপ স্থাপত্য

একটি আধুনিক অ্যান্ড্রয়েড অ্যাপ আর্কিটেকচারে (অন্যান্য কৌশলের পাশাপাশি) নিম্নলিখিত কৌশলগুলো ব্যবহার করা হয়:

  • অভিযোজিত এবং স্তরযুক্ত স্থাপত্য
  • অ্যাপের সকল স্তরে একমুখী ডেটা প্রবাহ (UDF)
  • UI-এর জটিলতা ব্যবস্থাপনার জন্য স্টেট হোল্ডার সহ UI লেয়ার।
  • কোরাউটিন এবং ফ্লো
  • ডিপেন্ডেন্সি ইনজেকশনের সর্বোত্তম অনুশীলন
  • R8 ও বেসলাইন প্রোফাইল ব্যবহার করে পারফরম্যান্স অপ্টিমাইজেশন, এবং ম্যাক্রোবেঞ্চমার্ক দিয়ে পরিমাপ।

আরও তথ্যের জন্য, অ্যান্ড্রয়েড আর্কিটেকচারের সুপারিশসমূহ দেখুন।

UI স্তর

UI লেয়ারের (বা প্রেজেন্টেশন লেয়ারের ) কাজ হলো স্ক্রিনে অ্যাপ্লিকেশন ডেটা প্রদর্শন করা। যখনই ব্যবহারকারীর ইন্টারঅ্যাকশনের (যেমন বাটন চাপা) বা বাহ্যিক ইনপুটের (যেমন নেটওয়ার্ক রেসপন্স) কারণে ডেটা পরিবর্তিত হয়, UI সেই পরিবর্তনগুলো প্রতিফলিত করার জন্য আপডেট হয়।

UI স্তরটি দুই ধরনের কাঠামো নিয়ে গঠিত:

  • UI এলিমেন্টগুলো স্ক্রিনে ডেটা রেন্ডার করে। অ্যাডাপ্টিভ লেআউট সমর্থন করার জন্য আপনি Jetpack Compose ফাংশন ব্যবহার করে এই এলিমেন্টগুলো তৈরি করেন।
  • স্টেট হোল্ডার (যেমন ViewModel ) ডেটা ধারণ করে, সেটিকে UI-তে প্রকাশ করে এবং লজিক পরিচালনা করে। স্টেট হোল্ডারগুলোর স্থায়িত্বকাল সেই UI এলিমেন্টের সমান হওয়া উচিত, যার জন্য তারা স্টেট সরবরাহ করছে। উদাহরণস্বরূপ, একটি স্ক্রিনের ViewModel ততক্ষণ মেমরিতে থাকা উচিত, যতক্ষণ না অ্যাপের নেভিগেশন ব্যাক স্ট্যাক থেকে স্ক্রিনটি সরিয়ে ফেলা হয়। আরও তথ্যের জন্য, স্টেট লাইফস্প্যানস (State Lifespans ) দেখুন।
একটি সাধারণ আর্কিটেকচারে, UI লেয়ারের UI এলিমেন্টগুলো স্টেট হোল্ডারদের উপর নির্ভর করে,  যারা আবার ডেটা লেয়ার অথবা  ঐচ্ছিক ডোমেইন লেয়ারের ক্লাসগুলোর উপর নির্ভর করে।
চিত্র ২. অ্যাপ আর্কিটেকচারে UI লেয়ারের ভূমিকা।

অ্যাডাপ্টিভ UI-এর ক্ষেত্রে, ViewModel অবজেক্টের মতো স্টেট হোল্ডাররা এমন UI স্টেট প্রকাশ করে যা বিভিন্ন উইন্ডো সাইজ ক্লাসের সাথে খাপ খাইয়ে নেয়। এই UI স্টেটটি পাওয়ার জন্য আপনি currentWindowAdaptiveInfo() ব্যবহার করতে পারেন। এরপর NavigationSuiteScaffold মতো কম্পোনেন্টগুলো উপলব্ধ স্ক্রিন স্পেসের উপর ভিত্তি করে বিভিন্ন নেভিগেশন প্যাটার্নের (যেমন, NavigationBar , NavigationRail , বা NavigationDrawer ) মধ্যে স্বয়ংক্রিয়ভাবে পরিবর্তন করার জন্য এই তথ্য ব্যবহার করতে পারে।

আরও জানতে, UI লেয়ার এবং কম্পোজ UI আর্কিটেকচার দেখুন।

অ্যাডাপ্টিভ অ্যাপস এবং নেভিগেশন সম্পর্কে আরও তথ্যের জন্য, ' বিল্ড অ্যাডাপ্টিভ অ্যাপস' এবং 'বিল্ড অ্যাডাপ্টিভ নেভিগেশন' দেখুন।

ডেটা স্তর

একটি অ্যাপের ডেটা লেয়ারে বিজনেস লজিক থাকে। বিজনেস লজিকই আপনার অ্যাপকে মূল্যবান করে তোলে—এতে এমন কিছু নিয়ম থাকে যা নির্ধারণ করে আপনার অ্যাপ কীভাবে ডেটা তৈরি, সংরক্ষণ এবং পরিবর্তন করবে।

ডেটা লেয়ারটি রিপোজিটরি দিয়ে গঠিত, যার প্রতিটিতে শূন্য থেকে একাধিক ডেটা সোর্স থাকতে পারে। আপনার অ্যাপে ব্যবহৃত প্রতিটি ভিন্ন ধরনের ডেটার জন্য একটি করে রিপোজিটরি ক্লাস তৈরি করুন। উদাহরণস্বরূপ, আপনি সিনেমা সম্পর্কিত ডেটার জন্য একটি MoviesRepository ক্লাস অথবা পেমেন্ট সম্পর্কিত ডেটার জন্য একটি PaymentsRepository ক্লাস তৈরি করতে পারেন।

একটি প্রচলিত আর্কিটেকচারে, ডেটা লেয়ারের রিপোজিটরিগুলো অ্যাপের বাকি অংশে ডেটা সরবরাহ করে এবং ডেটা সোর্সগুলোর উপর নির্ভর করে।
চিত্র ৩. অ্যাপ আর্কিটেকচারে ডেটা লেয়ারের ভূমিকা।

রিপোজিটরি ক্লাসগুলো নিম্নলিখিত বিষয়গুলোর জন্য দায়ী:

  • অ্যাপের বাকি অংশে ডেটা প্রকাশ করা
  • ডেটার পরিবর্তনগুলিকে কেন্দ্রীভূত করা
  • একাধিক ডেটা উৎসের মধ্যে দ্বন্দ্ব নিরসন করা
  • অ্যাপের বাকি অংশ থেকে ডেটার উৎসগুলোকে আলাদা করা
  • ব্যবসায়িক যুক্তি ধারণ করে

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

আরও জানতে, ডেটা লেয়ার পৃষ্ঠাটি দেখুন।

ডোমেইন স্তর

ডোমেইন লেয়ার হলো UI এবং ডেটা লেয়ারের মধ্যে অবস্থিত একটি ঐচ্ছিক লেয়ার।

ডোমেইন লেয়ার জটিল বিজনেস লজিক অথবা একাধিক ভিউ মডেল দ্বারা পুনঃব্যবহৃত সরল বিজনেস লজিককে এনক্যাপসুলেট করার জন্য দায়ী। ডোমেইন লেয়ার ঐচ্ছিক, কারণ সব অ্যাপের এই ধরনের প্রয়োজনীয়তা থাকে না। এটি কেবল প্রয়োজনের সময়ই ব্যবহার করুন — উদাহরণস্বরূপ, জটিলতা সামলাতে বা পুনঃব্যবহারযোগ্যতাকে প্রাধান্য দিতে।

যখন এটি অন্তর্ভুক্ত করা হয়, তখন ঐচ্ছিক ডোমেইন লেয়ারটি UI লেয়ারকে নির্ভরতা প্রদান করে এবং ডেটা লেয়ারের উপর নির্ভর করে।
চিত্র ৪. অ্যাপ আর্কিটেকচারে ডোমেইন লেয়ারের ভূমিকা।

ডোমেইন লেয়ারের ক্লাসগুলোকে সাধারণত ইউজ কেস বা ইন্টারঅ্যাক্টর বলা হয়। প্রতিটি ইউজ কেস একটিমাত্র কার্যকারিতার জন্য দায়ী থাকে। উদাহরণস্বরূপ, আপনার অ্যাপে একটি GetTimeZoneUseCase ক্লাস থাকতে পারে, যদি একাধিক ভিউ মডেল স্ক্রিনে সঠিক বার্তা দেখানোর জন্য টাইম জোনের উপর নির্ভর করে।

আরও জানতে, ডোমেইন লেয়ার পৃষ্ঠাটি দেখুন।

উপাদানগুলির মধ্যে নির্ভরতা পরিচালনা করুন

আপনার অ্যাপের ক্লাসগুলো সঠিকভাবে কাজ করার জন্য অন্যান্য ক্লাসের উপর নির্ভরশীল। কোনো নির্দিষ্ট ক্লাসের নির্ভরতাগুলো একত্রিত করতে আপনি নিম্নলিখিত ডিজাইন প্যাটার্নগুলোর যেকোনো একটি ব্যবহার করতে পারেন:

  • ডিপেন্ডেন্সি ইনজেকশন (DI) : ডিপেন্ডেন্সি ইনজেকশন ক্লাসগুলোকে তাদের ডিপেন্ডেন্সিগুলো কনস্ট্রাক্ট না করেই সংজ্ঞায়িত করার সুযোগ দেয়। রানটাইমে, অন্য একটি ক্লাস এই ডিপেন্ডেন্সিগুলো সরবরাহ করার দায়িত্বে থাকে।
  • সার্ভিস লোকেটর : সার্ভিস লোকেটর প্যাটার্ন এমন একটি রেজিস্ট্রি প্রদান করে, যেখান থেকে ক্লাসগুলো তাদের ডিপেন্ডেন্সিগুলো তৈরি করার পরিবর্তে সংগ্রহ করতে পারে।

এই প্যাটার্নগুলো আপনার কোডকে প্রয়োজন অনুযায়ী পরিবর্তন করতে সাহায্য করে, কারণ এগুলো কোডের পুনরাবৃত্তি বা জটিলতা না বাড়িয়েই ডিপেন্ডেন্সি ব্যবস্থাপনার জন্য সুস্পষ্ট কাঠামো প্রদান করে। এই প্যাটার্নগুলো আপনাকে টেস্ট এবং প্রোডাকশন ইমপ্লিমেন্টেশনের মধ্যে দ্রুত পরিবর্তন করার সুযোগও দেয়।

সাধারণ সর্বোত্তম অনুশীলন

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

যদিও নিম্নলিখিত সুপারিশগুলো বাধ্যতামূলক নয়, তবে বেশিরভাগ ক্ষেত্রে এগুলো অনুসরণ করলে আপনার কোডবেস আরও শক্তিশালী, পরীক্ষাযোগ্য এবং রক্ষণাবেক্ষণযোগ্য হয়ে ওঠে।

অ্যাপের কম্পোনেন্টগুলোতে ডেটা সংরক্ষণ করবেন না।

আপনার অ্যাপের এন্ট্রি পয়েন্টগুলোকে—যেমন অ্যাক্টিভিটি, সার্ভিস এবং ব্রডকাস্ট রিসিভার—ডেটার উৎস হিসেবে চিহ্নিত করা থেকে বিরত থাকুন। এন্ট্রি পয়েন্টগুলোকে অন্যান্য কম্পোনেন্টের সাথে সমন্বয় করতে দিন, যাতে শুধুমাত্র সেই এন্ট্রি পয়েন্টের জন্য প্রাসঙ্গিক ডেটার একটি উপসেটই পুনরুদ্ধার করা হয়। ব্যবহারকারীর ডিভাইসের সাথে মিথস্ক্রিয়া এবং সিস্টেমের ক্ষমতার উপর নির্ভর করে প্রতিটি অ্যাপ কম্পোনেন্টের স্থায়িত্বকাল স্বল্প হয়।

অ্যান্ড্রয়েড ক্লাসের উপর নির্ভরতা কমান।

আপনার অ্যাপের কম্পোনেন্টগুলোকেই একমাত্র ক্লাস হিসেবে তৈরি করুন যেগুলো অ্যান্ড্রয়েড ফ্রেমওয়ার্ক SDK API, যেমন Context বা Toast উপর নির্ভর করে। অ্যাপের কম্পোনেন্টগুলো থেকে অন্যান্য ক্লাসকে অ্যাবস্ট্রাক্ট করলে তা টেস্টেবিলিটি বাড়াতে সাহায্য করে এবং অ্যাপের অভ্যন্তরীণ কাপলিং কমায়।

আপনার অ্যাপের মডিউলগুলোর মধ্যে দায়িত্বের সুস্পষ্ট সীমারেখা নির্ধারণ করুন।

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

প্রতিটি মডিউল থেকে যথাসম্ভব কম তথ্য প্রকাশ করুন।

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

আপনার অ্যাপের অনন্য মূল বৈশিষ্ট্যের উপর মনোযোগ দিন, যাতে এটি অন্যান্য অ্যাপ থেকে স্বতন্ত্র হয়ে ওঠে।

একই গতানুগতিক কোড বারবার লিখে নতুন করে চাকা আবিষ্কার করবেন না। এর পরিবর্তে, আপনার অ্যাপটিকে যা অনন্য করে তোলে, সেদিকে আপনার সময় এবং শক্তিকে মনোনিবেশ করুন। পুনরাবৃত্তিমূলক গতানুগতিক কোডগুলো Jetpack লাইব্রেরি এবং অন্যান্য প্রস্তাবিত লাইব্রেরিগুলোকে সামলাতে দিন।

আদর্শ লেআউট এবং অ্যাপ ডিজাইন প্যাটার্ন ব্যবহার করুন।

Jetpack Compose লাইব্রেরিগুলো অ্যাডাপ্টিভ ইউজার ইন্টারফেস তৈরির জন্য শক্তিশালী এপিআই (API) প্রদান করে। একাধিক ফর্ম ফ্যাক্টর এবং ডিসপ্লে সাইজে ব্যবহারকারীর অভিজ্ঞতা অপ্টিমাইজ করতে আপনার অ্যাপে ক্যানোনিকাল লেআউটগুলো ব্যবহার করুন। আপনার ব্যবহারের ক্ষেত্রগুলোর জন্য সবচেয়ে উপযুক্ত লেআউটগুলো নির্বাচন করতে অ্যাপ ডিজাইন প্যাটার্নের গ্যালারিটি পর্যালোচনা করুন।

কনফিগারেশন পরিবর্তনের পরেও UI অবস্থা অপরিবর্তিত রাখুন।

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

পুনরায় ব্যবহারযোগ্য এবং সংযোজনযোগ্য UI উপাদান ডিজাইন করুন।

Build UI components that are reusable and composable to support adaptive design. This lets you combine and rearrange components to fit various screen sizes and postures without significant refactoring.

Consider how to make each part of your app testable in isolation.

A well-defined API for fetching data from the network facilitates testing the module that persists that data in a local database. If instead, you mix the logic from these two functions in one place, or distribute your networking code across your entire codebase, testing becomes much more difficult, if not impossible.

Types are responsible for their concurrency policy.

If a type is performing long-running blocking work, the type should be responsible for moving that computation to the right thread. The type knows the kind of computation that it is doing and in which thread to run the computation. Types should be main‑safe, meaning they're safe to call from the main thread without blocking it.

Persist as much relevant and fresh data as possible.

That way, users can enjoy your app's functionality even when their device is in offline mode. Remember that not all of your users enjoy constant, high‑speed connectivity, and even if they do, they can get bad reception in crowded places.

Benefits of architecture

Having a good architecture implemented in your app brings a lot of benefits to the project and engineering teams:

  • Improves the maintainability, quality, and robustness of the overall app.
  • Lets the app scale. More people and more teams can contribute to the same codebase with minimal code conflicts.
  • Helps with onboarding. As architecture brings consistency to your project, new members of the team can quickly get up to speed and be more efficient in less time.
  • Is easier to test. A good architecture encourages simpler types which are generally easier to test.
  • Lets you investigate bugs methodically with well defined processes.

Although good architecture requires an up-front time investment, it also has a direct impact on users. They benefit from a more stable application and more features due to a more productive engineering team.

Samples

The following samples demonstrate good app architecture: