পাঠ ২১ · ৫৭-এর মধ্যে · মডিউল ৫
Home / Courses / Mobile App Development / ডিক্লারেটিভ vs ইম্পারেটিভ

ডিক্লারেটিভ বনাম ইম্পারেটিভ UI

Declarative vs imperative UI
৭ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • ইম্পারেটিভ ও ডিক্লারেটিভ UI প্যারাডাইমের মূল সংজ্ঞাগত পার্থক্য
  • কেন ডিক্লারেটিভ UI-তে "রেন্ডার প্রতিবার হয়" কিন্তু "DOM/UI মিউটেশন শুধু পরিবর্তন হলেই হয়"
  • Full-Stack Web Frameworks কোর্সের ভার্চুয়াল-DOM ধারণার সাথে এই মোবাইল-প্রেক্ষাপটের সংযোগ
  • Python দিয়ে দুইটি বাস্তবায়ন — একটি ইম্পারেটিভ, একটি ডিক্লারেটিভ — এবং তাদের প্রকৃত অপারেশন সংখ্যার তুলনা

১ · দুইটি ভিন্ন মানসিকতা

ইম্পারেটিভ UIImperative UIUI-এর প্রতিটি পরিবর্তন ম্যানুয়ালি, ধাপে ধাপে কমান্ড দিয়ে ঘটানোর পদ্ধতি -- ডেভেলপারকে বর্তমান স্টেট মনে রেখে সঠিক মিউটেশন কল করতে হয়। -তে ডেভেলপার সরাসরি বলে দেন "স্পিনারটি এখন দেখাও", "লেবেলের টেক্সট এখন এটি করো", "এই বাটনটি এখন disable করো" — প্রতিটি আলাদা কমান্ড, প্রতিটি UI-এর একটি নির্দিষ্ট অংশ মিউটেট করে। UIKit-স্টাইল iOS বা পুরনো Android XML+Activity কোড সাধারণত এভাবেই কাজ করে (L15, L16-এ সংক্ষেপে উল্লেখিত)।

ডিক্লারেটিভ UIDeclarative UIডেভেলপার শুধু বর্তমান ডেটার ভিত্তিতে UI কেমন দেখতে হবে তা বর্ণনা করেন -- ফ্রেমওয়ার্ক নিজে বুঝে নেয় আগের UI থেকে নতুন UI-তে যেতে প্রকৃতপক্ষে কী কী বদলাতে হবে। -তে ডেভেলপার শুধু একটি render(state) ফাংশন লেখেন যা বর্তমান ডেটার ভিত্তিতে "UI-টা কেমন দেখতে হবে" বর্ণনা করে — কোন নির্দিষ্ট মিউটেশন কল করতে হবে তা ডেভেলপারের চিন্তার বিষয় নয়। SwiftUI, Jetpack Compose, React Native, Flutter — সবগুলোই মূলত ডিক্লারেটিভ।

ইম্পারেটিভ
"কীভাবে" বর্ণনা করে — প্রতিটি মিউটেশন আলাদা কমান্ড, ভুল ক্রম বা ভুলে-যাওয়া কল বাগের সাধারণ উৎস।
ডিক্লারেটিভ
"কী" বর্ণনা করে — একই স্টেট সবসময় একই UI বর্ণনা তৈরি করে, ফ্রেমওয়ার্ক ডিফ করে বাস্তব মিউটেশন সিদ্ধান্ত নেয়।
ডিফিং
ডিক্লারেটিভ ফ্রেমওয়ার্ক আগের ও নতুন বর্ণনা তুলনা করে শুধু প্রকৃত পার্থক্যটুকু প্রয়োগ করে — সম্পূর্ণ পুনর্নির্মাণ নয়।
Full-Stack Web Frameworks কোর্সের সাথে সম্পর্ক

Full-Stack Web Frameworks কোর্সে ভার্চুয়াল-DOM ডিফিং অ্যালগরিদম (পুরনো ট্রি বনাম নতুন ট্রি তুলনা করে ন্যূনতম বাস্তব DOM অপারেশন বের করা) বিস্তারিতভাবে ব্রাউজারের প্রেক্ষাপটে শেখানো হয়েছে। মোবাইলে React Native, Flutter-এর মতো ফ্রেমওয়ার্কও একই ধরনের ডিফিং নীতি ব্যবহার করে (Flutter-এর "Element tree" রিকনসিলিয়েশন, React Native-এর নিজস্ব রিকনসিলার) — এই পাঠ সেই পুরো অ্যালগরিদম পুনরায় না বানিয়ে শুধু মূল ধারণাটি — "রেন্ডার প্রতিবার হয়, মিউটেশন শুধু পরিবর্তনেই হয়" — একটি সরল উদাহরণে দেখাচ্ছে।

২ · একই আপডেট, দুই পদ্ধতিতে

নিচের কোড সেলে আমরা একটি সাধারণ পরিস্থিতি বাস্তবায়ন করব: একটি বুলিয়ান loading ফ্ল্যাগের ভিত্তিতে একটি লোডিং স্পিনার দেখানো বা লুকানো। একই ইনপুট-সিকোয়েন্সের উপর দুইটি সংস্করণ চালানো হবে — একটি ইম্পারেটিভ (প্রতিটি ইভেন্টেই একটি মিউটেশন কল, নিঃশর্তভাবে), আরেকটি ডিক্লারেটিভ (render() প্রতিবার কল হয়, কিন্তু প্রকৃত "DOM অপারেশন" শুধু তখনই গণনা হয় যখন নতুন রেন্ডার আউটপুট আগের থেকে আলাদা)।

Python
# একই UI আপডেট -- ইম্পারেটিভ বনাম ডিক্লারেটিভ, প্রকৃত অপারেশন সংখ্যা গণনা করে

# ---------- ইম্পারেটিভ সংস্করণ ----------
class ImperativeUI:
    def __init__(self):
        self.spinner_visible = False
        self.log = []

    def start_loading(self):
        self.spinner_visible = True
        self.log.append("mutate: show_spinner()")

    def stop_loading(self):
        self.spinner_visible = False
        self.log.append("mutate: hide_spinner()")


# ব্যবহারকারীর ঘটনাক্রম -- loading শুরু/শেষ কয়েকবার, কিছু ধাপ ডুপ্লিকেট (একই স্টেট দুইবার)
events = ["start", "start", "stop", "stop", "start", "stop"]

imperative_ui = ImperativeUI()
for event in events:
    if event == "start":
        imperative_ui.start_loading()
    else:
        imperative_ui.stop_loading()

print("=== ইম্পারেটিভ ===")
for line in imperative_ui.log:
    print(f"  {line}")
print(f"মোট মিউটেশন অপারেশন: {len(imperative_ui.log)}")


# ---------- ডিক্লারেটিভ সংস্করণ ----------
def render(state):
    """স্টেটের ভিত্তিতে কাঙ্ক্ষিত UI বর্ণনা রিটার্ন করে -- প্রতিবার সম্পূর্ণ ফ্রেশ"""
    return {"spinner_visible": state["loading"]}


# events-এর সমতুল্য loading বুলিয়ান সিকোয়েন্স
loading_sequence = [True, True, False, False, True, False]

previous_render = None
dom_ops = []
render_call_count = 0

for loading in loading_sequence:
    new_render = render({"loading": loading})
    render_call_count += 1
    if new_render != previous_render:
        if new_render["spinner_visible"]:
            dom_ops.append("dom-op: show_spinner()")
        else:
            dom_ops.append("dom-op: hide_spinner()")
    previous_render = new_render

print("\n=== ডিক্লারেটিভ ===")
print(f"render() কল হয়েছে: {render_call_count} বার (প্রতিটি স্টেট-পরিবর্তনেই, শর্তহীনভাবে)")
for line in dom_ops:
    print(f"  {line}")
print(f"প্রকৃত DOM/UI মিউটেশন অপারেশন (diff-এর পর): {len(dom_ops)}")

print(f"\nতুলনা -- ইম্পারেটিভ মিউটেশন: {len(imperative_ui.log)}, ডিক্লারেটিভ প্রকৃত মিউটেশন: {len(dom_ops)}")

    
লক্ষ্য করুন events-এ ৬টি ইভেন্ট আছে, আর ইম্পারেটিভ সংস্করণ নিঃশর্তভাবে ৬টি মিউটেশন কল করে — এমনকি যখন পরপর দুইবার একই কমান্ড আসে ("start", "start" বা "stop", "stop"), তখনও। ডিক্লারেটিভ সংস্করণে render()ও ৬ বার কল হয় (প্রতিটি স্টেটের জন্য একবার), কিন্তু আসল dom_ops মাত্র ৪টি — কারণ ডিফ-চেক (new_render != previous_render) পরপর একই মান দুইবার দেখলে দ্বিতীয়বার কোনো অপারেশন যোগ করে না। এটিই ডিক্লারেটিভ পদ্ধতির মূল সুবিধা প্রদর্শন করে — বর্ণনা যতবারই "রিফ্রেশ" হোক না কেন, প্রকৃত ব্যয়বহুল UI মিউটেশন শুধু সত্যিকারের পরিবর্তনেই ঘটে।
মূল কথা · Key takeaway

ইম্পারেটিভ UI-তে প্রতিটি কমান্ড একটি সরাসরি মিউটেশন, তাই ডুপ্লিকেট বা অপ্রয়োজনীয় কল সহজেই ঘটে যায়। ডিক্লারেটিভ UI-তে render(state) প্রতিবার ফ্রেশ কল হয়, কিন্তু ফ্রেমওয়ার্কের ডিফিং লজিক শুধু প্রকৃত পরিবর্তনের সময়ই বাস্তব মিউটেশন প্রয়োগ করে — একই মূলনীতি যা Full-Stack Web Frameworks কোর্সের ভার্চুয়াল-DOM-এ বিস্তারিতভাবে দেখা যায়।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ ডিক্লারেটিভ সংস্করণে render() কি সবসময় ইম্পারেটিভের চেয়ে কম কল হয়?

না — বরং উল্টো। উপরের উদাহরণে render() ৬ বার কল হয়েছে (ইম্পারেটিভের সমান)। ডিক্লারেটিভ পদ্ধতির সুবিধা render()-এর কল-সংখ্যা কমানো নয়, বরং প্রকৃত ব্যয়বহুল মিউটেশন অপারেশন-এর সংখ্যা কমানো — কারণ ডিফ-চেক অপ্রয়োজনীয় মিউটেশন ফিল্টার করে দেয়।

প্র ০২ যদি loading_sequence-এ কোনো দুইটি পরপর মান কখনো একই না হতো, তাহলে dom_ops-এর দৈর্ঘ্য কত হতো?

তাহলে dom_ops-এর দৈর্ঘ্য render_call_count-এর সমান হতো (এই উদাহরণে ৬) — কারণ প্রতিটি ধাপেই আগের ও নতুন রেন্ডার আউটপুট আলাদা হতো, ফলে ডিফ-চেক প্রতিবারই একটি অপারেশন যোগ করত। অর্থাৎ ডিক্লারেটিভ পদ্ধতির সুবিধা তখনই সবচেয়ে বেশি দেখা যায় যখন স্টেট বারবার একই মানে থাকে বা ফিরে আসে।

প্র ০৩ ইম্পারেটিভ পদ্ধতিতে যদি ডেভেলপার ভুলে একটি stop_loading() কল বাদ দিয়ে দেন, তাহলে কী ঘটতে পারে?

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

অনুশীলন

  1. চিন্তা করুন: SwiftUI বা Jetpack Compose-এর মতো ডিক্লারেটিভ ফ্রেমওয়ার্কে ডেভেলপার কখনো সরাসরি "এই লেবেলের টেক্সট বদলাও" কমান্ড লেখেন না — তাহলে UI আপডেট হয় কীভাবে?

    অন্তর্নিহিত স্টেট (যেমন একটি observable ভ্যারিয়েবল) বদলালে ফ্রেমওয়ার্ক নিজে থেকেই সংশ্লিষ্ট render/body ফাংশনটি আবার কল করে, নতুন বর্ণনা বের করে, এবং আগের বর্ণনার সাথে তুলনা করে শুধু প্রকৃত পরিবর্তিত অংশটুকু (এখানে, লেবেলের টেক্সট) বাস্তবে আপডেট করে — পুরো লজিকটি এই পাঠের render() + ডিফ-চেক প্যাটার্নের মতোই, শুধু ফ্রেমওয়ার্ক নিজেই এটি স্বয়ংক্রিয়ভাবে পরিচালনা করে।

  2. পরীক্ষা করুন: উপরের কোড সেলে loading_sequence-কে [True, False, True, False, True, False]-এ পরিবর্তন করুন (কোনো পরপর ডুপ্লিকেট নেই), তারপর কোড আবার চালিয়ে dom_ops-এর দৈর্ঘ্য দেখুন।

    এই নতুন সিকোয়েন্সে প্রতিটি পরপর মান আগেরটির থেকে আলাদা, তাই ডিফ-চেক প্রতিটি ধাপেই একটি নতুন অপারেশন যোগ করবে — dom_ops-এর দৈর্ঘ্য ৬ হবে, render_call_count-এর সমান। এটি নিশ্চিত করে যে ডিক্লারেটিভ পদ্ধতির সুবিধা ডুপ্লিকেট/অপরিবর্তিত স্টেট থাকা অবস্থাতেই সবচেয়ে বেশি প্রকাশ পায়, প্রতিটি পরিস্থিতিতে নয়।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

  • কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ অ্যাপ লাইফসাইকেল, মোবাইল UI/UX, MVVM/MVI আর্কিটেকচার, নেটিভ বনাম ক্রস-প্ল্যাটফর্ম, নেভিগেশন, স্টেট ম্যানেজমেন্ট, লোকাল স্টোরেজ, ডিভাইস ফিচার ও ডিপ্লয়মেন্ট — বাকি পাঠগুলো শীঘ্রই যুক্ত হবে।
  • Full-Stack Web Frameworks কোর্স সহোদর কোর্স ভার্চুয়াল-DOM ডিফিং অ্যালগরিদম সম্পূর্ণভাবে সেই কোর্সে ওয়েবের প্রেক্ষাপটে শেখানো হয়েছে — এখানে আমরা শুধু মূল ধারণাটি একটি ছোট মোবাইল উদাহরণে প্রয়োগ করেছি।
  • সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity, Cloud Computing & DevOps, Computer Networks, Operating Systems, Computer Architecture, Programming Languages & Compiler Design, Software Engineering & Git, Theory of Computation, Engineering Economics, Full-Stack Web Frameworks ও Mobile App Development — সব এক জায়গায়।
আগের পাঠ
ভিউ/উইজেট হায়ারার্কি