তুমি একদম ঠিক ধরেছ! জ্যাঙ্গো (Django) বা লারাভেলের (Laravel) মতো মডার্ন ফ্রেমওয়ার্কগুলোর কোর আর্কিটেকচার ঘাঁটলে দেখা যায়, এগুলো মূলত ক্লাসিক ডিজাইন প্যাটার্নগুলোরই এক বিশাল ও সুসংগঠিত রূপ। তুমি যেহেতু প্রশ্ন করেছ—হ্যাঁ, ফ্রেমওয়ার্কগুলো কীভাবে কাজ করে তার পেছনের মেকানিজম বুঝতে পারাটা একজন ব্যাকএন্ড ইঞ্জিনিয়ারের জন্য গেম-চেঞ্জার।
জ্যাঙ্গো (Django) পাইথনের অন্যতম জনপ্রিয় ফ্রেমওয়ার্ক, যা "Don't Repeat Yourself" (DRY) নীতির ওপর দাঁড়িয়ে আছে। জ্যাঙ্গো ডেভেলপারদের জীবন সহজ করার জন্য ব্যাকগ্রাউন্ডে কীভাবে অত্যন্ত স্মার্টলি ডিজাইন প্যাটার্নগুলো ব্যবহার করে, চলো সেটি আরও গভীরে গিয়ে বিশ্লেষণ করি।
১. Singleton Pattern (সিঙ্গেলটন প্যাটার্ন)
জ্যাঙ্গোতে ব্যবহার: কনফিগারেশন ম্যানেজমেন্ট এবং অ্যাপ রেজিস্ট্রি। গভীর বিশ্লেষণ: তুমি যখন django.conf.settings ইমপোর্ট করো, তুমি আসলে পুরো প্রজেক্টের জন্য একটিমাত্র (Single) গ্লোবাল কনফিগারেশন অবজেক্ট কল করছ। পাইথনের নিজস্ব মডিউল ক্যাশিং মেকানিজমের কারণে settings.py শুধুমাত্র একবারই মেমোরিতে লোড হয়। এর ফলে প্রোজেক্টের যেকোনো জায়গা থেকে সেটিংস কল করলে মেমোরির একই ইনস্ট্যান্স পাওয়া যায়। এছাড়াও জ্যাঙ্গোর apps (AppRegistry) হলো সিঙ্গেলটন প্যাটার্নের আরেকটি ক্লাসিক উদাহরণ, যা নিশ্চিত করে প্রজেক্টের অ্যাপগুলো যেন একবারই লোড হয়।
২. Factory Pattern (ফ্যাক্টরি প্যাটার্ন)
জ্যাঙ্গোতে ব্যবহার: ডাইনামিক অবজেক্ট ক্রিয়েশন (Forms, QuerySets)। গভীর বিশ্লেষণ: জ্যাঙ্গোতে ModelForm তৈরি করার প্রসেসটি ফ্যাক্টরি প্যাটার্নের দারুণ উদাহরণ। তুমি যখন modelform_factory ব্যবহার করো, জ্যাঙ্গো রানটাইমে তোমার মডেলের ফিল্ডগুলো বিশ্লেষণ করে একটি নতুন ফর্ম ক্লাস তৈরি করে দেয়। একইভাবে, জ্যাঙ্গোর ORM-এ QuerySet API মূলত ফ্যাক্টরি হিসেবে কাজ করে। তুমি যখন User.objects.filter(...) কল করো, তখন এটি সরাসরি ডেটাবেসে হিট না করে একটি নতুন ফিল্টার করা QuerySet অবজেক্ট তৈরি করে রিটার্ন করে।
৩. Observer Pattern (অবজার্ভার প্যাটার্ন)
জ্যাঙ্গোতে ব্যবহার: সিগন্যালস (Django Signals)। গভীর বিশ্লেষণ: জ্যাঙ্গোর django.db.models.signals (যেমন: post_save, pre_delete) পুরোপুরি অবজার্ভার প্যাটার্ন মেনে চলে। যখন কোনো মডেল ডেটাবেসে সেভ হয় (Subject-এর স্টেট পরিবর্তন হয়), তখন এটি একটি সিগন্যাল (Event/Notification) ব্রডকাস্ট করে। যেই ফাংশনগুলোর ওপরে @receiver ডেকোরেটর বসানো থাকে (Observers), তারা স্বয়ংক্রিয়ভাবে এই সিগন্যাল ক্যাচ করে এবং নির্দিষ্ট কাজ (যেমন: প্রোফাইল ক্রিয়েট করা, ইমেইল পাঠানো) সম্পন্ন করে। এটি অ্যাপগুলোকে লুজলি কাপলড (Loosely Coupled) রাখে।
৪. Decorator Pattern (ডেকোরেটর প্যাটার্ন)
জ্যাঙ্গোতে ব্যবহার: ভিউ মডিফিকেশন এবং অ্যাক্সেস কন্ট্রোল। গভীর বিশ্লেষণ: জ্যাঙ্গোতে ফাংশন-বেসড ভিউগুলোর (FBV) কার্যকারিতা রানটাইমে পরিবর্তন করার জন্য ডেকোরেটর ব্যাপকভাবে ব্যবহৃত হয়। উদাহরণস্বরূপ, @login_required ডেকোরেটরটি মূল ভিউ ফাংশনটিকে র্যাপ (Wrap) করে ফেলে। এটি চেক করে ইউজার অথেনটিকেটেড কি না; যদি না হয়, তবে লগইন পেজে রিডাইরেক্ট করে দেয়। ভিউয়ের মূল বিজনেস লজিক পরিবর্তন না করেই নতুন বিহেভিয়ার যুক্ত করার এটি সবচেয়ে নিখুঁত উপায়।
৫. Strategy Pattern (স্ট্র্যাটেজি প্যাটার্ন)
জ্যাঙ্গোতে ব্যবহার: ডাটাবেস ব্যাকএন্ড এবং স্টোরেজ ইঞ্জিন। গভীর বিশ্লেষণ: জ্যাঙ্গোর ORM যেকোনো ডাটাবেসের (PostgreSQL, MySQL, SQLite, Oracle) সাথে কাজ করতে পারে। তুমি যখন পাইথন কোডে User.objects.all() লেখো, তখন জ্যাঙ্গো settings.py-এ ডিফাইন করা ডাটাবেস ইঞ্জিনের ওপর ভিত্তি করে আলাদা আলাদা SQL কোয়েরি তৈরি করে। এখানে ডাটাবেস ব্যাকএন্ডগুলো আলাদা আলাদা "Strategy" হিসেবে কাজ করে। রানটাইমে কোর লজিক ঠিক রেখে শুধু স্ট্র্যাটেজি পাল্টে ফেলার এই সক্ষমতা জ্যাঙ্গোকে অবিশ্বাস্য রকম ফ্লেক্সিবল করে তুলেছে।
৬. Template Method Pattern (টেমপ্লেট মেথড প্যাটার্ন)
জ্যাঙ্গোতে ব্যবহার: ক্লাস-বেসড ভিউ (Class-Based Views - CBV)। গভীর বিশ্লেষণ: জ্যাঙ্গোর django.views.generic.View ক্লাসটি টেমপ্লেট মেথড প্যাটার্নের মাস্টারপিস। এর ভেতরে একটি dispatch() মেথড থাকে, যা রিকোয়েস্টের ধরন (GET, POST) অনুযায়ী নির্দিষ্ট মেথডকে কল করে। ডেভেলপার হিসেবে তুমি শুধু সাবক্লাস তৈরি করে নির্দিষ্ট অংশগুলো (যেমন: get_context_data() বা form_valid()) ওভাররাইড বা কাস্টমাইজ করো, কিন্তু রিকোয়েস্ট লাইফসাইকেলের মূল স্কেলিটন বা কাঠামো ফ্রেমওয়ার্ক নিজেই কন্ট্রোল করে।
৭. Composite Pattern (কম্পোজিট প্যাটার্ন)
জ্যাঙ্গোতে ব্যবহার: ফর্মস (Forms) এবং ফর্মসেটস (Formsets)। গভীর বিশ্লেষণ: কম্পোজিট প্যাটার্ন ট্রি (Tree) স্ট্রাকচারে কাজ করে। জ্যাঙ্গোতে একটি Form তৈরি হয় একাধিক Field (যেমন: CharField, EmailField) নিয়ে। আবার একটি Formset তৈরি হয় একাধিক Form নিয়ে। তুমি যখন একটি ফর্মসেটের ওপর is_valid() মেথড কল করো, তখন সেটি তার ভেতরের প্রতিটি ফর্মের is_valid() কল করে, এবং প্রতিটি ফর্ম তার ভেতরের ফিল্ডগুলোর ভ্যালিডেশন চেক করে। সিঙ্গেল অবজেক্ট (Field) এবং অবজেক্টের গ্রুপকে (Formset) একইভাবে ব্যবহার করার এটি সেরা উদাহরণ।
৮. Adapter Pattern (অ্যাডাপ্টার প্যাটার্ন)
জ্যাঙ্গোতে ব্যবহার: থার্ড-পার্টি ডাটাবেস এবং স্টোরেজ API। গভীর বিশ্লেষণ: পাইথনে ডাটাবেসের সাথে কানেক্ট করার জন্য psycopg2 (PostgreSQL) বা mysqlclient (MySQL) এর মতো আলাদা ড্রাইভার ব্যবহার করা হয়, যাদের নিজস্ব API সম্পূর্ণ ভিন্ন। জ্যাঙ্গোর django.db.backends এই ড্রাইভারগুলোর ওপর একটি অ্যাডাপ্টার (Adapter) লেয়ার তৈরি করে। ফলে জ্যাঙ্গোর ORM একটি ইউনিফাইড ইন্টারফেস দিয়ে সবার সাথে কথা বলতে পারে। ডাটাবেস পরিবর্তন হলেও তোমার লেখা অ্যাপ্লিকেশন লজিকে এক লাইনও কোড বদলাতে হয় না।
৯. State Pattern (স্টেট প্যাটার্ন)
জ্যাঙ্গোতে ব্যবহার: ইউজার অথেনটিকেশন এবং মডেল লাইফসাইকেল। গভীর বিশ্লেষণ: জ্যাঙ্গোতে request.user অবজেক্টের স্টেট অনুযায়ী অ্যাপ্লিকেশনের বিহেভিয়ার সম্পূর্ণ বদলে যায়। ইউজার যখন AnonymousUser স্টেটে থাকে, তখন সে অনেক পেজে ঢুকতে পারে না। লগইন করার পর যখন স্টেট পরিবর্তন হয়ে AuthenticatedUser হয়, তখন সিস্টেম তাকে নতুন কিছু রেসপন্স দেয়। স্টেট পরিবর্তনের সাথে সাথে অবজেক্টের আচরণ পরিবর্তনের এই নীতিটিই হলো স্টেট প্যাটার্ন।
১০. Chain of Responsibility Pattern (চেইন অফ রেসপনসিবিলিটি)
জ্যাঙ্গোতে ব্যবহার: মিডলওয়্যার (Middleware) আর্কিটেকচার। গভীর বিশ্লেষণ: জ্যাঙ্গোতে যখন কোনো HTTP রিকোয়েস্ট সার্ভারে হিট করে, সেটি সরাসরি ভিউতে যায় না। বরং এটি সিকিউরিটি, সেশন, এবং অথেনটিকেশন মিডলওয়্যারের একটি চেইনের মধ্য দিয়ে পাস হয়। প্রতিটি মিডলওয়্যার রিকোয়েস্টটিকে প্রসেস করে পরবর্তী মিডলওয়্যারের কাছে পাস করতে পারে, অথবা চাইলে চেইন ব্রেক করে সরাসরি রেসপন্স (যেমন: 403 Forbidden) ফিরিয়ে দিতে পারে। এটি সিস্টেমকে হাইলি মডুলার এবং এক্সটেনসিবল করে রাখে।