আর্কিটেকচারাল স্টাইল — লেয়ার্ড ও ক্লায়েন্ট-সার্ভার
এই পাঠে যা শিখবেন
- M4-M5-এর ক্লাস-লেভেল ডিজাইন ও M6-এর সিস্টেম-লেভেল আর্কিটেকচারের মধ্যে স্কোপের পার্থক্য
- লেয়ার্ড আর্কিটেকচারের strict dependency নিয়ম ও এর honest trade-off
- ক্লায়েন্ট-সার্ভার স্টাইলের request-response ইন্টারঅ্যাকশন প্যাটার্ন
- দুটো স্টাইলই ছোট, বাস্তব Python সিমুলেশন দিয়ে
১ · সফটওয়্যার আর্কিটেকচার — জুম আউট করা লেন্স
সফটওয়্যার আর্কিটেকচারSoftware Architectureএকটি সম্পূর্ণ সিস্টেমের উচ্চ-স্তরের স্ট্রাকচারাল সংগঠন — MAJOR কম্পোনেন্টগুলো কীভাবে সম্পর্কিত, individual ক্লাস কীভাবে ডিজাইন করা তা নয়। M4-M5-এ আমরা দেখেছি individual ক্লাসগুলো কীভাবে ভালোভাবে ডিজাইন করা হয় (SOLID, ডিজাইন প্যাটার্ন) — সফটওয়্যার আর্কিটেকচার সেই লেন্স থেকে "জুম আউট" করে দেখে পুরো সিস্টেমের MAJOR কম্পোনেন্টগুলো কীভাবে সম্পর্কিত, ব্যক্তিগত ক্লাসের ভেতরের ডিজাইন নয়। এই মডিউল vocabulary/style-এর লেভেলে থাকবে — স্কেলেবিলিটি ও ডিস্ট্রিবিউটেড-সিস্টেমস-এর গভীর আলোচনার জন্য System Design কোর্স দেখুন, যেখানে এই স্টাইলগুলো বাস্তবে কীভাবে হাজারো/লক্ষো ইউজারের স্কেলে কাজ করে তা বিস্তারিত কভার করা হয়েছে।
২ · লেয়ার্ড আর্কিটেকচার
লেয়ার্ড আর্কিটেকচারLayered Architectureসিস্টেমকে অনুভূমিক লেয়ারে সংগঠিত করে (যেমন presentation, business-logic, data-access) — প্রতিটি লেয়ার শুধু তার ঠিক নিচের লেয়ারের উপর নির্ভর করে। সিস্টেমকে অনুভূমিক লেয়ারে (যেমন presentation layer, business-logic layer, data-access layer) সংগঠিত করে, যেখানে প্রতিটি লেয়ার শুধু তার ঠিক নিচের লেয়ারের উপর নির্ভর করে — সরাসরি M4/L18-এর DIPDependency Inversion Principleপ্রায়ই প্রতিটি লেয়ার নিচের লেয়ারের একটি ABSTRACTION-এর উপর নির্ভর করে, কংক্রিট বাস্তবায়নের উপর নয় — একটি স্ট্রাকচারাল ইকো। -এর একটি স্ট্রাকচারাল প্রতিধ্বনি। genuinely ব্যাপকভাবে ব্যবহৃত, সহজে বোধগম্য — কিন্তু একটি honest দুর্বলতাও আছে: একটি সাধারণ অপারেশনের জন্যও প্রায়ই রিকোয়েস্টকে প্রতিটি লেয়ার দিয়ে পাস করতে হয়, যা কিছুটা ওভারহেড যোগ করে।
# লেয়ার্ড আর্কিটেকচার সিমুলেশন -- প্রতিটি লেয়ার শুধু তার ঠিক নিচের লেয়ারকে
# চেনে, উপরেরটাকে না -- একটি রিকোয়েস্ট উপর থেকে নিচে নামে, রেসপন্স নিচ থেকে
# উপরে ফেরে।
class DataAccessLayer:
def fetch_record(self, record_id):
print(f" [DataAccessLayer] record #{record_id} ডাটাবেস থেকে fetch করা হলো")
return {"id": record_id, "name": "নাসরিন", "balance": 5000}
class BusinessLogicLayer:
def __init__(self, data_layer):
self.data_layer = data_layer # শুধু ঠিক নিচের লেয়ারকে রেফারেন্স করে
def get_account_summary(self, record_id):
print(" [BusinessLogicLayer] অ্যাকাউন্ট সামারি তৈরি হচ্ছে...")
record = self.data_layer.fetch_record(record_id)
record["status"] = "সক্রিয়" if record["balance"] > 0 else "নিষ্ক্রিয়"
return record
class PresentationLayer:
def __init__(self, business_layer):
self.business_layer = business_layer # শুধু ঠিক নিচের লেয়ারকে রেফারেন্স করে
def render_account_page(self, record_id):
print(f"[PresentationLayer] রিকোয়েস্ট এলো: account #{record_id}")
data = self.business_layer.get_account_summary(record_id)
print(f"[PresentationLayer] ইউজারকে দেখানো হলো: {data['name']} "
f"— ব্যালেন্স {data['balance']} — {data['status']}")
data_layer = DataAccessLayer()
business_layer = BusinessLogicLayer(data_layer)
presentation_layer = PresentationLayer(business_layer)
presentation_layer.render_account_page(7)
৩ · ক্লায়েন্ট-সার্ভার আর্কিটেকচার
ক্লায়েন্ট-সার্ভার আর্কিটেকচারClient-Server Architectureসিস্টেমকে service-requesting client ও service-providing server-এ ভাগ করে, একটি নির্দিষ্ট প্রোটোকল/ইন্টারফেসের মাধ্যমে যোগাযোগ করে। সিস্টেমকে service-requesting client ও service-providing server-এ ভাগ করে, যারা একটি ডিফাইনড প্রোটোকল/ইন্টারফেসের মাধ্যমে যোগাযোগ করে — সবচেয়ে পরিচিত everyday উদাহরণ: ওয়েব ব্রাউজার (client) ও ওয়েব সার্ভার। এই লেসনে আমরা in-process সিমুলেশন দেখবো (দুটোই একই Python প্রসেসে) — বাস্তবে এরা নেটওয়ার্কে আলাদা মেশিনে থাকে, আসল নেটওয়ার্ক-প্রোটোকল মেকানিক্সের জন্য Computer Networks কোর্স দেখুন।
# ক্লায়েন্ট-সার্ভার আর্কিটেকচার -- ইন-প্রসেস সিমুলেশন (বাস্তবে এরা নেটওয়ার্কে
# আলাদা মেশিনে থাকে -- আসল নেটওয়ার্ক-প্রোটোকল মেকানিক্স computer-networks
# কোর্সে)।
class Server:
def __init__(self):
self._catalog = {"101": "ওয়্যারলেস মাউস", "102": "মেকানিক্যাল কিবোর্ড"}
def handle_request(self, request):
product_id = request.get("product_id")
if product_id in self._catalog:
return {"status": 200, "product": self._catalog[product_id]}
return {"status": 404, "product": None}
class Client:
def __init__(self, server):
self.server = server
def request_product(self, product_id):
request = {"product_id": product_id}
print(f"[Client] রিকোয়েস্ট পাঠানো হলো: product_id={product_id}")
response = self.server.handle_request(request)
print(f"[Client] সার্ভার থেকে রেসপন্স: {response}")
return response
server = Server()
client = Client(server)
client.request_product("101")
client.request_product("999")
"101" রিকোয়েস্টে সার্ভার status 200 সহ প্রোডাক্টের নাম ফেরত দেয়, কিন্তু
"999" (যা catalog-এ নেই) status 404 ফেরত দেয়, প্রোডাক্ট None সহ —
ঠিক বাস্তব HTTP status কোডের (200 OK, 404 Not Found) মতোই একটি structured request-response প্যাটার্ন।
লেয়ার্ড ও ক্লায়েন্ট-সার্ভার — দুটো ভিন্ন প্রশ্নের উত্তর দেয়: লেয়ার্ড বলে দেয় একটি সিস্টেমের ভেতরের কোড কীভাবে সংগঠিত হবে (উল্লম্ব দিকে responsibility ভাগ), ক্লায়েন্ট-সার্ভার বলে দেয় সিস্টেমের বিভিন্ন অংশ নেটওয়ার্কে কীভাবে ছড়িয়ে থাকবে (কে রিকোয়েস্ট করে, কে সার্ভ করে) — বাস্তবে এই দুটো প্রায়ই একসাথে ব্যবহৃত হয় (যেমন একটি সার্ভারের ভেতরেই লেয়ার্ড আর্কিটেকচার থাকতে পারে)।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১
লেয়ার্ড আর্কিটেকচারে যদি PresentationLayer সরাসরি DataAccessLayer-এর মেথড কল করতো (মাঝের BusinessLogicLayer স্কিপ করে), এটি কেন লেয়ার্ড আর্কিটেকচারের নিয়ম লঙ্ঘন করবে?
কারণ লেয়ার্ড আর্কিটেকচারের নিয়ম হলো প্রতিটি লেয়ার শুধু তার ঠিক নিচের লেয়ারের উপর নির্ভর করবে — একটি
লেয়ার "স্কিপ" করা মানে PresentationLayer এখন BusinessLogicLayer-এর কোনো
business rule (যেমন balance-ভিত্তিক status নির্ধারণ) ছাড়াই সরাসরি raw ডেটার সাথে কাজ করছে — এটি লেয়ারগুলোর
দায়িত্ব বিভাজন ভেঙে দেয় এবং DataAccessLayer-এর ইন্টারনাল স্ট্রাকচারের সাথে
PresentationLayer-কে সরাসরি couple করে ফেলে।
প্র ০২
ক্লায়েন্ট-সার্ভার কোড সেলে Client কীভাবে জানে Server-এর ইন্টারনাল _catalog ডিকশনারিতে ঠিক কী আছে?
Client এটি জানেই না — এবং জানার দরকারও নেই। Client শুধু একটি
request পাঠায় ও একটি response পায়, handle_request()-এর মধ্য
দিয়ে — _catalog-এর ইন্টারনাল গঠন সম্পূর্ণ Server-এর ভেতরে encapsulated। এটিই
client-server স্টাইলের একটি মূল সুবিধা: server তার ইন্টারনাল ইমপ্লিমেন্টেশন (যেমন catalog একটি ডিকশনারি
থেকে একটি ডাটাবেসে বদলানো) বদলাতে পারে Client-এর কোনো কোড না বদলিয়েই, যতক্ষণ
request/response ফরম্যাট একই থাকে।
প্র ০৩ লেয়ার্ড আর্কিটেকচারের "প্রতিটি রিকোয়েস্ট প্রতিটি লেয়ার দিয়ে পাস করতে হয়" দুর্বলতা কোন ধরনের সিস্টেমে সবচেয়ে বেশি সমস্যা তৈরি করতে পারে?
যেসব সিস্টেমে খুব উচ্চ-ফ্রিকোয়েন্সিতে, লো-লেটেন্সি রিকোয়ারমেন্ট সহ অনেক সাধারণ অপারেশন হয় (যেমন রিয়েল-টাইম ট্রেডিং সিস্টেম বা হাই-থ্রুপুট API) — সেখানে প্রতিটি লেয়ার পার হওয়ার সামান্য ওভারহেডও মোট লেটেন্সিতে যোগ হয়ে যায়। বিপরীতে, কম-ফ্রিকোয়েন্সি বা কম-সময়-সংবেদনশীল অপারেশনে এই ওভারহেড সাধারণত নগণ্য — এটিই কারণ লেয়ার্ড আর্কিটেকচার এখনো ব্যাপকভাবে ব্যবহৃত, নির্দিষ্ট high-performance পরিস্থিতিতে সতর্কতার সাথে প্রয়োগ করা প্রয়োজন।
অনুশীলন
-
চিন্তা করুন: আপনার প্রিয় কোনো ওয়েবসাইট/অ্যাপের কথা চিন্তা করুন — এতে সম্ভাব্য কোন কোন লেয়ার (presentation, business-logic, data-access) থাকতে পারে তার একটি তালিকা করুন।
উদাহরণস্বরূপ একটি ফুড-ডেলিভারি অ্যাপে: presentation layer = মোবাইল অ্যাপের UI (মেনু দেখানো, অর্ডার বাটন); business-logic layer = দাম হিসাব, ডেলিভারি-চার্জ নির্ধারণ, রেস্টুরেন্ট availability চেক; data-access layer = রেস্টুরেন্ট/মেনু/অর্ডার ডেটা ডাটাবেস থেকে fetch/সেভ করা। প্রতিটি লেয়ার আলাদা, এবং presentation layer কখনো সরাসরি ডাটাবেস কোয়েরি করে না — সবসময় business-logic layer-এর মধ্য দিয়ে যায়।
-
পরীক্ষা করুন: ক্লায়েন্ট-সার্ভার কোড সেলে
Server-এর_catalog-এ একটি নতুন প্রোডাক্ট ("103": "USB হাব") যোগ করুন এবংclient.request_product("103")কল করে যাচাই করুন সঠিক রেসপন্স আসছে কিনা।self._catalog = {"101": "...", "102": "...", "103": "USB হাব"}— তারপরclient.request_product("103")কল করলে{"status": 200, "product": "USB হাব"}রেসপন্স আসবে, ঠিক অন্য দুটো প্রোডাক্টের মতোই —Clientক্লাসের কোনো কোড বদলাতে হয়নি, শুধুServer-এর ইন্টারনাল ডেটা আপডেট করা হয়েছে।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৮টি পাঠ পরবর্তী পাঠ — মাইক্রোসার্ভিস বনাম মনোলিথ — শীঘ্রই যুক্ত হবে।
- Client-Server & DNS System Design L05 ক্লায়েন্ট-সার্ভার স্টাইলের গভীর, স্কেল-লেভেল ট্রিটমেন্ট — DNS resolution সহ বাস্তব নেটওয়ার্ক আর্কিটেকচার।
- সব 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 — সব এক জায়গায়।