Kotlin বনাম SwiftUI: iOS ও Android-এ একটি প্রোডাক্ট কনসিস্টেন্ট রাখুন
Kotlin বনাম SwiftUI সামনাসামনি গাইড — Android ও iOS জুড়ে একটি প্রোডাক্ট কিভাবে সম্মতি রাখে: ন্যাভিগেশন, স্টেট, ফর্ম, ভ্যালিডেশন ও প্রায়োগিক চেক।

কেন দুইটি স্ট্যাক জুড়ে একটি প্রোডাক্ট মিলিয়ে রাখা কঠিন\n\nফিচার তালিকা মিললেও, অভিজ্ঞতা iOS ও Android-এ আলাদা হতে পারে। প্রতিটি প্ল্যাটফর্মের নিজস্ব ডিফল্ট আছে। iOS তুলো-ভিত্তিতে ট্যাব বার, সোয়াইপ জেসচার, এবং মডাল শিটে আরো নির্ভর করে। Android ব্যবহারকারীরা দৃশ্যমান Back বাটন, সিস্টেম ব্যাকের প্রত্যাশিত আচরণ, এবং ভিন্ন মেনু/ডায়ালগ প্যাটার্ন আশা করে। একই প্রোডাক্ট দুইবার বানালে সেই ছোট ডিফল্টগুলো যোগ হয়ে যায়।\n\nKotlin বনাম SwiftUI শুধুই ভাষা বা ফ্রেমওয়ার্কের বিষয় নয়—এটা কীভাবে স্ক্রিন দেখা যায়, ডেটা কিভাবে আপডেট হয়, এবং ইউজার ইনপুট কিভাবে আচরণ করবে—এসব বিষয়ে দুই সেট ধারনা। যদি রিকোয়ারমেন্ট লেখা হয় “iOS-এর মতো কর” বা “Android কপি কর,” তাহলে একপাশ সবসময় আপস মনে হবে।\n\nটিমগুলো সাধারণত কনসিস্টেন্সি হারায় সেই জায়গাগুলোতে যেখানে হ্যাপি-পাথ স্ক্রিনগুলোর মধ্যে ফাঁক আছে। ডিজাইন রিভিউ-এ ফ্লো মেলের মতো দেখায়, কিন্তু লোডিং স্টেট, পারমিশন প্রম্পট, নেটওয়ার্ক এরর, এবং “ব্যবহারকারী ছেড়ে ফিরে এলে” কেস যোগ করলে তা ভিন্ন হয়ে যায়।\n\nপারিটি সাধারণত প্রেডিক্টেবল জায়গায় প্রথম ভেঙে যায়: স্ক্রিনের অর্ডার টিম যখন “সরল” করতে যাবে তখন বদলে যায়, Back ও Cancel ভিন্নভাবে আচরণ করে, empty/loading/error স্টেটগুলোর লেখা আলাদা হয়, ফর্ম ইনপুট ভিন্ন ক্যারেক্টার গ্রহণ করে, এবং ভ্যালিডেশনের সময় (টাইপিং সময় বনাম ব্লার বনাম সাবমিট) সরে যায়।\n\nপ্র্যাকটিক্যাল লক্ষ্য একই UI নয়। লক্ষ্য হচ্ছে একটি রিকোয়ারমেন্ট সেট যা আচরণ পরিষ্কার করে বর্ণনা করে—তাহলে উভয় স্ট্যাক একই জায়গায় পৌঁছাবে: একই ধাপ, একই সিদ্ধান্ত, একই এজ কেস, এবং একই আউটকাম।\n\n## শেয়ারড রিকোয়ারমেন্টের একটি প্রায়োগিক পদ্ধতি\n\nকঠিন অংশ উইজেট নয়—একটি প্রোডাক্ট ডেফিনিশন রাখাই কঠিন যাতে উভয় অ্যাপ একইভাবে আচরণ করে, যদিও UI খানিকটা ভিন্ন হতে পারে।\n\nপ্রথমে রিকোয়ারমেন্ট দুইটি বাকেটে ভাগ করুন:\n\n- ম্যাস্ট ম্যাচ করতে হবে: ফ্লো অর্ডার, কী স্টেট (লোডিং/এমটি/এরর), ফিল্ড নিয়ম, এবং ব্যবহারকারী-দৃশ্যমান কপি।\n- প্ল্যাটফর্ম-নেটিভ হতে পারে: ট্রানজিশন, কন্ট্রোল স্টাইলিং, এবং ছোট লেআউট সিদ্ধান্ত।\n\nকোনও কোড লেখার আগে সাধারণ ভাষায় শেয়ারড কনসেপ্ট সংজ্ঞায়িত করুন। “স্ক্রিন” মানে কি, “রুট” মানে কি (প্যারামিটার সহ যেমন userId), “ফর্ম ফিল্ড” কি (টাইপ, প্লেসহোল্ডার, রিকোয়ার্ড, কী-বোর্ড), এবং “এরর স্টেট” কী অন্তর্ভুক্ত করে (মেসেজ, হাইলাইট, কখন ক্লিয়ার হয়)। এই সংজ্ঞাগুলো পরে বিতর্ক কমায় কারণ উভয় দল একই লক্ষ্যেই কাজ করছে।\n\nআকসেপ্টেন্স ক্রাইটেরিয়া আউটকাম বর্ণনা করে লিখুন, ফ্রেমওয়ার্ক নির্ধারণ না করে। উদাহরণ: “ব্যবহারকারী Continue ট্যাপ করলে বাটন ডিসেবল করুন, একটি স্পিনার দেখান, এবং রিকোয়েস্ট শেষ না হওয়া পর্যন্ত ডাবল-সাবমিট প্রতিরোধ করুন।” এটা উভয় স্ট্যাকের জন্য পরিষ্কার, কীভাবে ইমপ্লিমেন্ট করতে হবে সেটা না বলে।\n\nকপি (টাইটেল, বাটন টেক্সট, হেল্পার টেক্সট, এরর মেসেজ), স্টেট আচরণ (লোডিং/সাকসেস/এমটি/অফলাইন/পারমিশন ডিনাইড), ফিল্ড নিয়ম (রিকোয়ার্ড, মিন লেন্থ, অনুমোদিত ক্যারেক্টার, ফরম্যাটিং), কী ইভেন্ট (submit/cancel/back/retry/timeout), এবং অ্যানালিটিক্স নাম (যদি ট্র্যাক করেন) —এগুলোর জন্য একটি সিংগেল সোর্স অফ ট্রুথ রাখুন।\n\nসহজ উদাহরণ: সাইন-আপ ফর্মের জন্য সিদ্ধান্ত নিন “পাসওয়ার্ড হতে হবে 8+ অক্ষর, প্রথম ব্লারের পরে রুল হিন্ট দেখাবেন, এবং ব্যবহারকারী টাইপ করার সময় এরর মুছে যাবে।” UI ভিন্ন হতে পারে; আচরণ না হওয়া উচিত।\n\n## ন্যাভিগেশন: একই ফ্লো মিলিয়ে নিন, একই UI জোর করে বাধ্য না করে\n\nইউজার জার্নি ম্যাপ করুন, স্ক্রিন নয়। একটি কাজ শেষ করতে ব্যবহারকারী কোন ধাপগুলো নেয়—“ব্রাউজ - ডিটেইল খুলুন - এডিট - কনফার্ম - সম্পন্ন”—এভাবে লিখুন। একবার পথ পরিষ্কার হলে, প্রতিটি প্ল্যাটফর্মের জন্য সেরা ন্যাভিগেশন স্টাইল বেছে নিতে পারবেন, প্রোডাক্ট যা করে তা বদলাতে না দিয়ে।\n\niOS ছোট কাজের জন্য মডাল শিট পছন্দ করে এবং স্পষ্ট ডিসমিসাল দেয়। Android ব্যাক-স্ট্যাক ইতিহাস ও সিস্টেম Back বাটনের ওপর নির্ভর করে। উভয়ই একই ফ্লো সাপোর্ট করতে পারে যদি নিয়ম আগে থেকেই সংজ্ঞায়িত করা থাকে।\n\nউপরের বিল্ডিং ব্লকগুলো মিশিয়ে ব্যবহার করা যায় (টপ-লেভেল এলাকায় ট্যাব, ড্রিল-ডাউন জন্য স্ট্যাক, ফোকাসড টাস্কের জন্য মডাল/শিট, ডিপ লিংক, উচ্চ-রিস্ক অ্যাকশনের জন্য কনফার্মেশন স্টেপ) যতক্ষণ ফ্লো ও আউটকাম বদলে না যায়।\n\nরিকোয়ারমেন্ট কনসিস্টেন্ট রাখতে, উভয় প্ল্যাটফর্মেই রুটগুলোর নাম একই রাখুন এবং ইনপুট সঙ্গত রাখুন। “orderDetails(orderId)” প্রত্যেক জায়গায় একই অর্থ বহন করবে, এমনকি ID মিসিং বা অবৈধ হলে কি হবে তাও।\n\nব্যাক আচরণ ও ডিসমিসাল নীতিগুলো স্পষ্টভাবে উল্লেখ করুন, কারণ এখানেই ড্রিফট হয়:\n\n- প্রতিটি স্ক্রিন থেকে Back কী করে (সেভ, ডিকর্ড, জিজ্ঞেস)\n- একটি মডাল ডিসমিস হতে পারে কি না (এবং ডিসমিস মানে কি)\n- কোন স্ক্রিনগুলো কখনোই দুইবার পৌঁছনো যাবে না (ডুপ্লিকেট পুশ এড়ান)\n- ব্যবহারকারী সাইন ইন না থাকলে ডিপ লিংক কিভাবে আচরণ করে\n\nউদাহরণ: সাইন-আপ ফ্লোতে, iOS সম্ভবত “Terms” একটি শিট হিসাবে দেখাবে এবং Android স্টাকে পুশ করবে। এটা ঠিক আছে যদি উভয়ই একই ফলাফল দেয় (গ্রহণ বা প্রত্যাখ্যান) এবং সাইন-আপ একই ধাপে পুনরায় শুরু হয়।\n\n## স্টেট: আচরণ কনসিস্টেন্ট রাখার উপায়\n\nস্ক্রিনগুলো “ভিন্ন লাগে” করলে প্রায়শই কারণ স্টেট আলাদা। ইমপ্লিমেন্টেশনের বিস্তারিত তুলনা করার আগে, একটি স্ক্রিন কিসে থাকতে পারে এবং প্রতিটি স্টেটে ব্যবহারকারী কী করতে পারবে তা নিয়ে সম্মত হন।\n\nপ্রথমে সাধারণ ভাষায় স্টেট প্ল্যান লিখুন, এবং তা পুনরাবৃত্তিযোগ্য রাখুন:\n\n- Loading: একটি স্পিনার দেখান এবং প্রধান অ্যাকশানগুলো নিষ্ক্রিয় করুন\n- Empty: কি অনুপস্থিত তা বোঝান এবং পরবর্তী সেরা অ্যাকশন দেখান\n- Error: স্পষ্ট মেসেজ দেখান এবং একটি Retry অপশন দিন\n- Success: ডেটা দেখান এবং অ্যাকশন সক্রিয় রাখুন\n- Updating: রিফ্রেশ চলাকালীন পুরনো ডেটা দৃশ্যমান রাখুন\n\nতারপর সিদ্ধান্ত নিন স্টেট কোথায় থাকে। স্ক্রিন-লেভেল স্টেট লোকাল UI ডিটেইলের জন্য ঠিক আছে (ট্যাব সিলেকশন, ফোকাস)। অ্যাপ-লেভেল স্টেট সব অ্যাপের জন্য জরুরি জিনিসের জন্য ভালো (সাইন ইন করা ব্যবহারকারী, ফিচার ফ্ল্যাগ, ক্যাশড প্রোফাইল)। কন্সিস্টেন্সি হলো কী: যদি “লগআউট” Android-এ অ্যাপ-লেভেল ধরে কিন্তু iOS-এ স্ক্রিন-লেভেল হিসেবে দেখা হয়, তাহলে এক প্ল্যাটফর্ম স্টেলে ডেটা দেখাবে।\n\nসাইড-এফেক্টগুলো স্পষ্ট করে লিখুন। রিফ্রেশ, রিট্রাই, সাবমিট, ডিলিট, এবং অপ্টিমিস্টিক আপডেট—এসব স্টেট পরিবর্তন করে। সফলতা এবং ব্যর্থতায় কি হবে, এবং কবে ব্যবহারকারী কী দেখবে তা সংজ্ঞায়িত করুন।\n\nউদাহরণ: একটি “Orders” তালিকা।\n\nপুল-টু-রিফ্রেশে, আপনি কি পুরনো তালিকাটি দৃশ্যমান রাখবেন (Updating) নাকি পুরো পেজ Loading দিয়ে প্রতিস্থাপন করবেন? ব্যর্থ রিফ্রেশে আপনি কি শেষ ভাল তালিকাটা রেখে ছোট একটি এরর দেখাবেন, নাকি পুরো Error স্টেটে স্যুইচ করবেন? যদি উভয় দল আলাদা উত্তর দেয়, প্রোডাক্ট দ্রুত অসমঞ্জত লাগবে।\n\nশেষে, ক্যাশিং ও রিসেট নিয়মে সম্মত হন। কোন ডেটা পুনরায় ব্যবহার করা নিরাপদ (যেমন শেষ লোড করা তালিকা) এবং কোনটা অবশ্য তাজা হতে হবে (যেমন পেমেন্ট স্ট্যাটাস) তা সিদ্ধান্ত নিন। কখন স্টেট রিসেট হবে—স্ক্রিন ছেড়ে গেলে, অ্যাকাউন্ট বদলালে, বা সাবমিট সফল হলে—এসবও নির্ধারণ করুন।\n\n## ফর্ম: এমন ফিল্ড আচরণ যেটা বদলে যাওয়া উচিত নয়\n\nফর্মগুলোই সেই জায়গা যেখানে ছোট পার্থক্যগুলো দ্রুত সাপোর্ট টিকিটে পরিণত হয়। দেখতে “কিছুটা মিল” এমন একটি সাইন-আপ স্ক্রিনও আচরণে ভিন্ন হলে ব্যবহারকারী সেটা দ্রুত লক্ষ্য করে।\n\nএকটি ক্যানোনিকাল ফর্ম স্পেক দিয়ে শুরু করুন যা কোনো UI ফ্রেমওয়ার্কে বাঁধা নয়। এটাকে একটি কন্ট্র্যাক্ট হিসেবে লিখুন: ফিল্ড নাম, টাইপ, ডিফল্ট, এবং কখন প্রতিটি ফিল্ড দৃশ্যমান। উদাহরণ: “Company name লুকানো থাকবে যদি না Account type = Business. ডিফল্ট Account type = Personal. ডিভাইস লোকেল থেকে Country ডিফল্ট নেওয়া হবে. Promo code ঐচ্ছিক।”\n\nতারপর একইভাবে অনুভব করার প্রত্যাশা করা ইন্টারঅ্যাকশনগুলো নির্ধারণ করুন। এগুলোকে “স্ট্যান্ডার্ড আচরণ” হিসেবে ছেড়ে দেবেন না, কারণ “স্ট্যান্ডার্ড” প্ল্যাটফর্মে ভিন্ন হবে।\n\n- প্রতিটি ফিল্ডের কী-বোর্ড টাইপ\n- Autofill ও সেভড ক্রেডেনশিয়াল আচরণ\n- ফোকাস অর্ডার ও Next/Return লেবেল\n- সাবমিট নিয়ম (ভ্যালিড না হওয়া পর্যন্ত ডিসেবল বনাম এরর দেখিয়ে অনুমোদন করা)\n- লোডিং আচরণ (কি লক হবে, কি এডিটেবল থাকবে)\n\nএররগুলো কিভাবে দেখাবে তা নির্ধারণ করুন (ইনলাইন, সারাংশ, বা দুটোই) এবং কখন দেখাবে (ব্লার-এ, সাবমিট-এ, অথবা প্রথম এডিটের পরে)। একটি সাধারণ নিয়ম যেটা ভাল কাজ করে: ব্যবহারকারী সাবমিট না করা পর্যন্ত এরর দেখাবেন না, তারপর ইন্টারনাল ইনলাইন এররগুলো টাইপ করার সাথে আপডেট থাকুক।\n\nঅ্যাসিঙ্ক ভ্যালিডেশন আগেই পরিকল্পনা করুন। যদি “username available” নেটওয়ার্ক কল প্রয়োজন, ধীর বা ব্যর্থ রিকোয়েস্ট কিভাবে হ্যান্ডেল করবেন তা নির্ধারণ করুন: “Checking…” দেখানো, টাইপ ডিবান্স করা, স্টেল রেস্পন্স উপেক্ষা করা, এবং “username taken” আলাদা করা “network error, try again” থেকে। এরকম না করলে ইমপ্লিমেন্টেশনে সহজে ড্রিফট হবে।\n\n## ভ্যালিডেশন: এক নিয়ম সেট, দুই ইমপ্লিমেন্টেশন\n\nভ্যালিডেশনই যেখানে পারিটি নীরবে ভেঙে যায়। এক অ্যাপ ইনপুট ব্লক করছে, অন্যটি এনাবল করে রাখছে—তারপর সাপোর্ট টিকিট। সমাধান কোনো চতুর লাইব্রেরি নয়। সেটা এক নিয়মসেট নিয়ে সম্মতি, তারপর দুটো অ্যাপে তা বাস্তবায়ন করা।\n\nপ্রতিটি নিয়ম এমন বাক্যে লিখুন যেটা একটি নন-ডেভেলপারও টেস্ট করতে পারে। উদাহরণ: “Password কমপক্ষে 12 অক্ষর হতে হবে এবং একটি সংখ্যা থাকা উচিত।” “Phone number-এ country code থাকা আবশ্যক।” “Date of birthটা বাস্তব তারিখ হতে হবে এবং ব্যবহারকারীকে 18+ হতে হবে।” এই বাক্যগুলো আপনার সোর্স-অফ-ট্রুথ হবে।\n\n### ফোনে কী চলবে বনাম সার্ভারে কী চলবে—এটা ভাগ করুন\n\nক্লায়েন্ট-সাইড চেক দ্রুত ফিডব্যাক ও সহজ ভুল ধরার উপর ফোকাস করা উচিত। সার্ভার-সাইড চেক চূড়ান্ত গেট এবং আরো কঠোর হওয়া উচিৎ কারণ সেগুলো ডেটা ও সিকিউরিটি রক্ষা করে। যদি ক্লায়েন্ট কিছু আলাউ করে এবং সার্ভার তা প্রত্যাখ্যান করে, তাহলে উভয় প্ল্যাটফর্মে একই মেসেজ দেখান এবং একই ফিল্ড হাইলাইট করুন যাতে ব্যবহারকারী বিভ্রান্ত না হয়।\n\nএরর টেক্সট ও টোন একবার লিখে দুটো প্ল্যাটফর্মেই পুনরায় ব্যবহার করুন। “Enter” বলবেন নাকি “Please enter”, sentence case ব্যবহার করবেন নাকি না—এধরনের ছোট মismatch-ও দুইটি আলাদা প্রোডাক্টের মতো মনে করায়।\n\nলোকেল ও ফরম্যাটিং নিয়মগুলো লেখা না করে অনুমান করবেন না। ফোন নম্বর, তারিখ (টাইমজোন অনুমানসহ), কারেন্সি, এবং নাম/ঠিকানার মতো ক্ষেত্রে কি গ্রহণযোগ্য এবং কিভাবে দেখাবেন তা নির্ধারণ করুন।\n\nসহজ দৃশ্য: আপনার সাইন-আপ ফর্ম Android-এ “+44 7700 900123” গ্রহণ করে কিন্তু iOS সিঙ্গেল স্পেস অপসারণ করে ফেলছে। যদি নিয়ম হয় “স্পেস অনুমোদিত, সংরক্ষণে কেবল ডিজিট থাকবে,” তাহলে উভয় অ্যাপ একইভাবে ব্যবহারকারীকে গাইড করবে এবং একই পরিষ্কার মান সেভ করবে।\n\n## ধাপে ধাপে: বিল্ড চলাকালীন পারিটি কিভাবে রাখবেন\n\nকোড থেকে শুরু করবেন না। একটি নিরপেক্ষ স্পেক দিয়ে শুরু করুন যেটাকে উভয় দল সোর্স অফ ট্রুথ হিসেবে মানবে।\n\n### 1) প্রথমে একটি নিরপেক্ষ স্পেক লিখুন\n\nপ্রতিটি ফ্লোর জন্য একটি পৃষ্ঠা ব্যবহার করুন, এবং সেটা কনক্রিট রাখুন: একটি ইউজার স্টোরি, একটি ছোট স্টেট টেবিল, এবং ফিল্ড নিয়ম।\n\n“Sign up” এর জন্য Idle, Editing, Submitting, Success, Error মতো স্টেট ডিফাইন করুন। তারপর প্রতিটি স্টেটে ব্যবহারকারী কী দেখে এবং অ্যাপ কী করে তা লিখুন। স্পেস ট্রিম করা, কখন এরর দেখানো হয় (ব্লার বনাম সাবমিট), এবং সার্ভার ইমেইল রিজেকশন হলে কি হবে—এসব অন্তর্ভুক্ত করুন।\n\n### 2) পারিটি চেকলিস্ট দিয়ে বিল্ড করুন\n\nইউআই ইমপ্লিমেন্ট করার আগে একটি স্ক্রিন-বাই-স্ক্রিন চেকলিস্ট তৈরি করুন যা উভয় iOS ও Android পাস করতে হবে: রুট ও ব্যাক আচরণ, কী ইভেন্ট ও আউটকাম, স্টেট ট্রানজিশন ও লোডিং আচরণ, ফিল্ড আচরণ, এবং এরর হ্যান্ডলিং।\n\n### 3) উভয় প্ল্যাটফর্মে একই সিনারিও টেস্ট করুন\n\nপ্রতিবার একই সেট চালান: এক হ্যাপি পাথ, তারপর এজ কেস (ধীর নেটওয়ার্ক, সার্ভার এরর, অবৈধ ইনপুট, এবং ব্যাকগ্রাউন্ড থেকে রিসিউম)।\n\n### 4) সাপ্তাহিক ডেল্টা রিভিউ করুন\n\nএকটি ছোট পারিটি লগ রাখুন যাতে ভিন্নতা স্থায়ী হয়ে না যায়: কী পরিবর্তন হয়েছে, কেন হয়েছে, সেটা requirement বনাম platform convention বনাম bug—কোনটি আপডেট করা উচিত (স্পেক, iOS, Android, বা সবগুলো)। ড্রিফট দ্রুত ধরলে ফিক্স ছোট থাকে।\n\n## টিমগুলো যে সাধারণ ভুলগুলো করে\n\niOS ও Android-এর মধ্যে পারিটি হারানোর সহজ উপায় হল কাজকে “একই করে দেখানোর” মতো বিবেচনা করা। আচরণ মিলানো পিক্সেল মেলানোর চাইতে বেশি গুরুত্বপূর্ণ।\n\nআরেকটা ফাঁদ হলো এক প্ল্যাটফর্ম থেকে UI কপিয়ে অন্যটিতে বসিয়ে দেওয়া, বদলে আচরণের ইরদি ইরাদা লিখে দেওয়ার বদলে। দুইটি স্ক্রিন দেখতে আলাদা হলেও যদি তারা একইভাবে লোড, ব্যর্থ এবং রিকভার করে, তখন সেগুলো "একই" বলা যায়।\n\nআরও একটি ভুল হলো প্ল্যাটফর্ম প্রত্যাশাকে উপেক্ষা করা। Android ব্যবহারকারী সিস্টেম Back নির্ভর করে, iOS ব্যবহারকারী সাধারণত সোয়াইপ ব্যাক ও সিস্টেম শিট/ডায়ালগগুলোর নেটিভ অভিজ্ঞতা আশা করে। এই প্রত্যাশার বিরুদ্ধে গেলে মানুষ অ্যাপকে দোষ দেয়।\n\nআবার বারংবার প্রদর্শিত ভুলগুলো:\n\n- আচরণ সংজ্ঞায়িত না করে UI কপি করা (স্টেট, ট্রানজিশন, এমটি/এরর হ্যান্ডলিং)\n- স্ক্রিনগুলো “একই” রাখতে নেটিভ ন্যাভিগেশন অভ্যাস ভাঙা\n- এরর হ্যান্ডলিং ড্রিফট করা (এক প্ল্যাটফর্মে মডাল দিয়ে ব্লক করা, অন্যটিতে নীরবে রিট্রাই করা)\n- ক্লায়েন্ট বনাম সার্ভারে ভিন্ন ভ্যালিডেশন, ফলে conflicting মেসেজ হলে ব্যবহারকারী বিভ্রান্ত হয়\n- আলাদা ডিফল্ট ব্যবহার (অটো-ক্যাপিটালাইজেশন, কী-বোর্ড টাইপ, ফোকাস অর্ডার) ফলে ফর্মগুলো অসমঞ্জত লাগে\n\nদ্রুত উদাহরণ: যদি iOS টাইপ করার সময় “Password too weak” দেখায়, কিন্তু Android সাবমিট পর্যন্ত অপেক্ষা করে, ব্যবহারকারী ভাববে একটি অ্যাপ কঠোর। নিয়ম ও টাইমিং একবার ঠিক করে তা দুটোতেই বাস্তবায়ন করুন।\n\n## শিপ করার আগে দ্রুত চেকলিস্ট\n\nরিলিজের আগে কেবল পারিটির উপর ফোকাস করে একটি পাস করুন: না “একই দেখাচ্ছে কি না?”, বরং “একই মানে কি?”\n\n- ফ্লো ও ইনপুট একই উদ্দেশ্য পূরণ করে: উভয় প্ল্যাটফর্মে রুটগুলো একই প্যারামিটার নিয়ে আছে।\n- প্রতিটি স্ক্রিন মূল স্টেটগুলো হ্যান্ডল করে: লোডিং, এমটি, এরর, এবং একটি রিট্রাই যা একই রিকোয়েস্ট করে এবং ব্যবহারকারীকে একই জায়গায় ফিরিয়ে দেয়।\n- ফর্মগুলো এজে একইভাবে আচরণ করে: রিকোয়ার্ড বনাম ঐচ্ছিক ফিল্ড, স্পেস ট্রিমিং, কী-বোর্ড টাইপ, অটোকরেক্ট, এবং Next/Done কী করে।\n- ভ্যালিডেশন নিয়ম একই ইনপুটের জন্য মিলছে: প্রত্যাখ্যাত ইনপুট দুই প্ল্যাটফর্মেই প্রত্যাখ্যাত, একই কারণ ও টোন দেখায়।\n- অ্যানালিটিক্স (যদি ব্যবহার করেন) একই মুহুর্তে ফায়ার করে: মুহুর্তটি সংজ্ঞায়িত করুন, UI অ্যাকশন নয়।\n\nড্রিফট দ্রুত ধরা পড়াতে, একটি κρίটিকাল ফ্লো (যেমন সাইন-আপ) বেছে নিন এবং সেটি ইচ্ছাকৃতভাবে ভুল করে 10 বার রান করুন: ফিল্ড ফাঁকা রাখুন, অবৈধ কোড দিন, অফলাইন যান, ফোন ঘোরান, রিকোয়েস্ট চলাকালীন অ্যাপ ব্যাকগ্রাউন্ড করুন। যদি আউটকাম আলাদা হয়, তাহলে আপনার রিকোয়ারমেন্টগুলো পুরোপুরি শেয়ার করা হয়নি।\n\n## উদাহরণ দৃশ্য: দুটি স্ট্যাকে একই সাইন-আপ ফ্লো\n\nকল্পনা করুন একই সাইন-আপ ফ্লো দুইবার তৈরি করা হয়েছে: Android-এ Kotlin এবং iOS-এ SwiftUI। রিকোয়ারমেন্টগুলো সাদামাটা: Email ও Password, তারপর Verification Code স্ক্রিন, তারপর Success।\n\nন্যাভিগেশন ভিন্ন দেখাতে পারে কিন্তু ব্যবহারকারীকে যা করতে হবে তা বদলানো যাবে না। Android-এ আপনি স্ক্রিন পুশ ও পপ করে ইমেইল এডিট করতে পারেন। iOS-এ NavigationStack ব্যবহার করে কোড ধাপকে ডেস্টিনেশন হিসেবে উপস্থাপন করতে পারেন। নিয়ম একই থাকে: একই ধাপ, একই এক্সিট পয়েন্ট (Back, Resend code, Change email), এবং একই এরর হ্যান্ডলিং।\n\nআচরণ মিল রাখতে, UI কোড লেখার আগে সাধারণ ভাষায় শেয়ারড স্টেটগুলো সংজ্ঞায়িত করুন:\n\n- Idle: ব্যবহারকারী এখনও সাবমিট করে নি\n- Editing: ব্যবহারকারী ফিল্ড পরিবর্তন করছে\n- Submitting: রিকোয়েস্ট চলছে, ইনপুট নিষ্ক্রিয়\n- NeedsVerification: অ্যাকাউন্ট তৈরি হয়েছে, কোডের অপেক্ষায়\n- Verified: কোড গ্রহণ হয়েছে, এগিয়ে যান\n- Error: মেসেজ দেখান, প্রবেশ করা ডেটা রাখুন\n\nতারপর ভ্যালিডেশন নিয়মগুলো আটকে দিন যাতে ঠিক মিল থাকে, কন্ট্রোল ভিন্ন হলেও:\n\n- Email: আবশ্যক, ট্রিম করা হবে, ইমেইল ফরম্যাট মেলতে হবে\n- Password: আবশ্যক, 8-64 ক্যারেক্টার, অন্তত 1 সংখ্যা, অন্তত 1 অক্ষর\n- Verification code: আবশ্যক, ঠিক 6 ডিজিট, কেবল নমেরিক\n- এরর টাইমিং: একটি নিয়ম বেছে নিন (সাবমিট পরে, বা ব্লার পরে) এবং তা কনসিস্টেন্ট রাখুন\n\nপ্ল্যাটফর্ম-নির্দিষ্ট টুইক ঠিক আছে যদি সেগুলো উপস্থাপনাকে বদলায় কিন্তু মানে না বদলায়। উদাহরণ: iOS এক-টাইম কোড autofill ব্যবহার করতে পারে, আর Android SMS code capture অফার করতে পারে। এটাকে ডকুমেন্ট করুন: কী পরিবর্তন হয় (ইনপুট পদ্ধতি), কী একই থাকে (6 ডিজিট আবশ্যক, একই এরর টেক্সট), এবং উভয়েই কি টেস্ট করবেন (রিট্রাই, রিসেন্ড, ব্যাক ন্যাভিগেশন, অফলাইন এরর)।\n\n## পরবর্তী ধাপ: অ্যাপ বাড়ার সঙ্গে কনসিস্টেন্সি রাখুন\n\nপ্রথম রিলিজের পরে ড্রিফট নীরবে শুরু হয়: Android-এ একটা ছোট টুইক, iOS-এ একটি দ্রুত ফিক্স, এবং দ্রুত আপনি মিল নাও থাকা আচরণে পড়ে যান। সবচেয়ে সহজ প্রতিরোধ হলো সাপ্তাহিক ওয়ার্কফ্লোয়ের অংশ হিসেবে কনসিস্টেন্সিকে রেখা—কোনো ক্লীনআপ প্রকল্প নয়।\n\n### রিকোয়ারমেন্টকে পুনঃব্যবহারযোগ্য ফিচার স্পেসে রূপান্তর করুন\n\nপ্রতিটি নতুন ফিচারের জন্য একটি ছোট টেমপ্লেট তৈরি করুন যেটা পুনরায় ব্যবহার করবেন। আচরণে ফোকাস রাখুন, UI ডিটেইলে নয়, যাতে উভয় স্ট্যাক একইভাবে ইমপ্লিমেন্ট করতে পারে।\n\nঅন্তর্ভুক্ত করুন: ইউজার লক্ষ্য ও সাকসেস ক্রাইটেরিয়া, স্ক্রিন ও ন্যাভিগেশন ইভেন্ট (ব্যাক আচরণসহ), স্টেট নিয়ম (লোডিং/এমটি/এরর/রিট্রাই/অফলাইন), ফর্ম নিয়ম (ফিল্ড টাইপ, মাস্ক, কী-বোর্ড টাইপ, হেল্পার টেক্সট), এবং ভ্যালিডেশন নিয়ম (কখন চলে, মেসেজ, ব্লকিং বনাম সতর্কতা)।\n\nএকটি ভাল স্পেক টেস্ট নোটের মতো পড়ে। কোনো ডিটেইল পরিবর্তিত হলে স্পেক প্রথমে বদলান।\n\n### আপনার ডিফিনিশন অফ ডন-এ পারিটি রিভিউ যোগ করুন\n\nপারিটিকে একটি ছোট, পুনরাবৃত্তিযোগ্য ধাপে পরিণত করুন। যখন একটি ফিচার সম্পন্ন চিহ্নিত হয়, মার্জ বা শিপ করার আগে দ্রুত সাইড-বাই-সাইড চেক করুন। একজন ব্যক্তি উভয় প্ল্যাটফর্মে একই ফ্লো চালিয়ে পার্থক্য নোট করবেন। একটি ছোট চেকলিস্ট সাইন-অফ করাবে।\n\nযদি আপনি ডেটা মডেল ও ব্যবসায়িক নিয়ম একবার সংজ্ঞায়িত করে নেটিভ অ্যাপ জেনারেট করতে চান, AppMaster (appmaster.io) এমন প্ল্যাটফর্ম যেখানে সম্পূর্ণ অ্যাপ্লিকেশন—ব্যাকএন্ড, ওয়েব, এবং নেটিভ মোবাইল আউটপুট—তৈরি করা যায়। তবুও, পারিটি চেকলিস্ট রাখুন: আচরণ, স্টেট, এবং কপি এগুলো প্রোডাক্ট সিদ্ধান্ত, ফ্রেমওয়ার্ক ডিফল্ট নয়।\n\nদীর্ঘমেয়াদী লক্ষ্য সহজ: রিকোয়ারমেন্টগুলো পরিবর্তিত হলে, দুটো অ্যাপ এক সপ্তাহের মধ্যে একইভাবে আপডেট হয়, কোনো অপ্রত্যাশিত পার্থক্য ছাড়াই।
প্রশ্নোত্তর
বিহেভিয়র পারিটি লক্ষ করুন, পিক্সেল পারিটি নয়। যদি উভয় অ্যাপ একই ফ্লো ধাপ অনুসরণ করে, একই স্টেট (লোডিং/এমটি/এরর) হ্যান্ডেল করে, এবং একই আউটকাম দেয়, তাহলে ব্যবহারকারীরা iOS ও Android UI প্যাটার্ন ভিন্ন হলেও প্রোডাক্টকে সঙ্গত মনে করবে।
আউটকাম ও নিয়ম হিসেবে রিকোয়ারমেন্ট লিখুন। উদাহরণ: ব্যবহারকারী Continue ট্যাপ করলে কি হবে, কোন আইটেম নিষ্ক্রিয় হবে, ব্যর্থ হলে কি মেসেজ দেখাবে, কোন ডেটা সংরক্ষণ থাকবে—এগুলো লিখে দিন। “iOS মত কর” অথবা “Android কপি কর” বললে এক প্ল্যাটফর্মকে অদ্ভুত আচরণ করতে বাধ্য করা হয়।
কি ম্যাচ করতে হবে (ফ্লো অর্ডার, ফিল্ড নিয়ম, ব্যবহারকারীর কপি, স্টেট আচরণ) এবং কি প্ল্যাটফর্ম-নেটিভ হওয়া যাবে (ট্রানজিশন, কন্ট্রোল স্টাইলিং, ছোট লেআউট চয়েস) আলাদা করে নিন। “Must match” আইটেমগুলো আগে লক করে দিন এবং সেগুলোকে উভয় দল একটি চুক্তি হিসেবে বাস্তবায়ন করবে।
স্ক্রিন অনুযায়ী স্পষ্টভাবে লিখে রাখুন: Back কী করে, কখন নিশ্চিত করা চায়, এবং unsaved পরিবর্তনগুলোর কী হবে। মডালগুলো কখন ডিসমিস করা যাবে এবং ডিসমিসের মানে কী—এসব না লেখলে প্ল্যাটফর্মগুলোর ডিফল্ট আলাদা হবে এবং ফ্লো অসমঞ্জস হবে।
প্রতিটি স্টেটের নাম এবং সেখানে ব্যবহারকারী কী করতে পারবে তা নিয়ে একটি শেয়ারড স্টেট প্ল্যান তৈরি করুন। পুরনো ডেটা রিফ্রেশের সময় দেখা থাকবে কি না, “Retry” একই রিকোয়েস্ট পুনরায় চালায় কি না, এবং সাবমিট চলাকালীন ইনপুট সক্রিয় থাকবে কি না—এসব নির্ধারণ করুন। বেশিরভাগ “ভিন্ন লাগে” অভিযোগই লেআউট নয়, স্টেট হ্যান্ডলিং থেকে আসে।
একটি ক্যানোনিকাল ফর্ম স্পেসিফিকেশন নিন: ফিল্ড, টাইপ, ডিফল্ট, ভিজিবিলিটি নিয়ম, এবং সাবমিশন আচরণ। তারপর সেইসব ইন্টারঅ্যাকশন নিয়ম নির্ধারণ করুন যেগুলো সাধারণত বিচ্ছিন্ন হয়—কী-বোর্ড টাইপ, ফোকাস অর্ডার, autofill প্রত্যাশা, এবং কখন এরর দেখানো হয়। এগুলো সঙ্গত হলে নেটিভ কন্ট্রোল থাকলেও ফর্ম একই রকম লাগবে।
ভ্যালিডেশনকে পরীক্ষাযোগ্য বাক্য হিসেবে লিখুন, যেগুলো নন-ডেভেলপারও টেস্ট করতে পারে, তারপর উভয় অ্যাপে একইভাবে ইমপ্লিমেন্ট করুন। কখন ভ্যালিডেশন চলে (টাইপিং সময়, ব্লার-এ, না সাবমিট-এ) তা ঠিক করে রাখুন—ব্যবহারকারী লক্ষ্য করে যখন একটি প্ল্যাটফর্ম বেশি আগে “চেঁচিয়ে” বলে।
সার্ভারকে চূড়ান্ত অথরিটি ধরে নিন, কিন্তু ক্লায়েন্টের প্রতিক্রিয়া সার্ভারের আউটকামের সাথে মিল রাখুক। যদি সার্ভার কোনো ইনপুট ফিরিয়ে দেয় যেটা ক্লায়েন্ট অনুমোদন করেছিল, তবে একই ফিল্ড হাইলাইট করে একই শব্দচয়ন দেখান—এটা “Android নেয়, iOS নেয়নি” সমস্যার সবচেয়ে সহজ প্রতিরোধ।
একটি পারিটি চেকলিস্ট ব্যবহার করুন এবং প্রতিবার একই সিনারিও রান করুন: হ্যাপি পাথ, ধীর নেটওয়ার্ক, অফলাইন, সার্ভার এরর, অবৈধ ইনপুট, এবং রিকোয়েস্ট চলাকালীন অ্যাপ ব্যাকগ্রাউন্ড করা। একটা ছোট “parity log” রাখুন যেখানে পার্থক্যগুলো নোট করবেন এবং কনসিসটেন্ট কাজ হিসাবে ঠিক করবেন।
AppMaster আপনাকে একটি জায়গা দেয় যেখানে আপনি ডেটা মডেল ও ব্যবসায়িক লজিক একবার সংজ্ঞায়িত করে নেটিভ মোবাইল আউটপুট, ব্যাকএন্ড ও ওয়েবের জন্য ব্যবহার করতে পারেন। তবুও একটা পরিষ্কার বাইহারফিক স্পেসিফিকেশন দরকারই থাকবে—স্টেট, আচরণ এবং কপি ঐা প্রোডাক্ট সিদ্ধান্ত, ফ্রেমওয়ার্কের ডিফল্ট নয়।


