توضیحات

هیچ تصمیم آسانی در معماری نرم افزار وجود ندارد. در عوض، بخش‌های سخت بسیاری وجود دارد؛ مشکلات یا مسائل دشواری که بهترین شیوه ای برای انجام ندارند و شما را مجبور می‌کنند تا با انجام سبک سنگین‌های مختلف، یکی را برای موفقیت انتخاب کنید. با کمک کتاب Software Architecture: The Hard Parts (معماری نرم افزار: قسمت‌های سخت)، شما یاد خواهید گرفت که چگونه به طور انتقادی در مورد سبک سنگین‌های مربوط به معماری‌های توزیع شده فکر کنید.
پیشکسوتان معماری و مشاوران مجرب، نیل فورد، مارک ریچاردز، پرامود سادالاژ و ژامک دهقانی، درباره راهبردهای انتخاب یک معماری مناسب بحث می‌کنند. نویسندگان با سر هم کردن داستانی درباره یک گروه خیالی از متخصصان فناوری - جوخه Sysops - همه چیز را از نحوه تعیین جزئیات سرویس، مدیریت گردش کار و هماهنگ سازی، مدیریت و جداسازی قراردادها و مدیریت تراکنش‌های توزیع شده تا نحوه بهینه سازی ویژگی‌های عملیاتی، مانند مقیاس پذیری، کشش و عملکرد را مورد بررسی قرار می‌دهند.
این کتاب با تمرکز بر سوالات متداول، تکنیک‌هایی را ارائه می‌کند که به شما کمک می‌کند تا هنگام مواجهه با مسائلی که به عنوان یک معمار با آن مواجه هستید، سبک سنگین‌ها را انجام دهید و بررسی کنید.

نظر

نظر

  • امتیاز : 09/10
  • به دیگران توصیه می‌کنم : بله
  • دوباره می‌خوانم : بله
  • ایده برجسته :
  • تاثیر در من :
  • نکات مثبت :
  • نکات منفی :

مشخصات

  • نویسنده : Mark Richards, Neal Ford, Pramod Sadalage, Zhamak Dehghani
  • انتشارات : O’Reilly Media

بخش‌هایی از کتاب

فصل اول کتاب “Software Architecture: The Hard Parts”

آنچه رخ می‌دهد وقتی “بهترین روش” وجود ندارد

چرا معماری نرم‌افزار کار سختی است؟

در این فصل، نویسندگان با یک حقیقت اساسی شروع می‌کنند: در معماری نرم‌افزار، اغلب با مسائلی روبرو هستیم که راه‌حل قطعی و جهانی برای آنها وجود ندارد. مفاهیمی مثل “best practice” فقط تا حدی (و در بعضی فضاها) کاربرد دارند. علت آن:

  • پروژه‌ها و چالش‌ها بسیار متنوع‌اند.
  • انتخاب‌ها همواره وابسته به نیازهای تجاری، محدودیت‌های فنی و شرایط سازمانی است.
  • راه‌حل‌هایی که در یک زمینه جواب می‌دهند، ممکن است در جای دیگر مشکل‌ساز شوند.

هدف فصل

هدف این فصل، تعریف درست مسئله و دادن نگرش درست به مخاطب است که قرار نیست برای هر چالش معماری، یک جواب واحد وجود داشته باشد. معماری، کار تصمیم‌گیری میان گزینه‌های مختلف و یافتن بهترین راه بر اساس شرایط است.

چرایی بخش‌های سخت معماری

Ambiguity و عدم قطعیت: خیلی وقت‌ها اطلاعات ناقص یا مبهم است؛ باید با فرضیات گام برداریم و تصمیمات را مطابق تغییرات اصلاح کنیم. – Trade-off: هر راه‌حلی مزایا و معایبی دارد. لازم است مصالحه (trade-off) را بشناسیم و مدیریت کنیم. – تعاملات انسانی: معماری فقط تکنولوژی نیست؛ شامل سازمان، ذینفعان، تیم‌ها و فرهنگ هم هست.

داده‌ها و اهمیت آنها در معماری

بخشی از فصل به نقش محوری داده می‌پردازد:

  • معماری خوب باید از همان ابتدا به سوال “داده‌ها کجا هستند؟ چه کسی صاحب آن‌هاست؟ چگونه اعمال تغییرات و پردازش اطلاعات انجام می‌شود؟” پاسخ بدهد.
  • در دوران معماری‌های توزیع‌شده (مثل میکروسرویس یا کلود)، داده‌ها تبدیل به کلیدی‌ترین چالش‌ها شده‌اند چون مالکیت داده بین سرویس‌ها تقسیم می‌شود و مسائل consistency، امنیت و کارایی اهمیت مضاعف پیدا می‌‌کند.

سند تصمیم معماری (ADR)

نویسندگان تاکید دارند که معماری یعنی “تصمیم‌گیری”. بنابراین مستندسازی تصمیمات معماری با شفافیت دلایل، الزامی است. معماری باید “قابل توضیح” و “قابل دفاع” باشد تا بتوان به تیم، ذینفعان یا حتی معماران بعدی چرایی انتخاب‌ها را منتقل کرد.

سند “Architectural Decision Record” یا مخفف آن “ADR” برای همین هدف است: ثبت موضوع تصمیم، گزینه‌های قابل بررسی، دلایل انتخاب و رد هر گزینه و اثرات تصمیم. اگر این فرآیند شفاف و مدون شود، هم یادگیری تسهیل می‌شود، هم خطاهای قبلی تکرار نمی‌شود.

تمرین: فکر کن اگر در یک پروژه واقعی، سرویس پرداخت دارید و باید تصمیم بگیرید که اعتبارسنجی کارت بانکی را در همان سرویس انجام دهید یا یک سرویس مستقل ایجاد کنید، چه گزینه‌هایی دارید؟ هر کدام چه مزایا و معایبی دارند؟ دلیل انتخاب نهایی چه خواهد بود؟

Fitness Function در معماری

ایده “Fitness Function” یا توابع سنجش کارایی/سلامت معماری، از یادگیری ماشین گرفته شده است. مشابه زمانی‌که یک معیار (function) داریم تا بفهمیم مدل یادگیری چقدر خوب کار می‌کند، در معماری هم باید معیارهایی داشته باشیم که به‌صورت اتوماتیک یا دستی، کیفیت تصمیمات و ساختار را ارزیابی کند.

مثال‌ها:

  • هیچ سرویسی نباید به بیش از سه سرویس دیگر وابسته باشد.
  • نرخ خطای ارتباطات سرویس‌ها باید زیر 0.5٪ بماند.
  • دیتابیس‌ها باید فقط توسط سرویس‌های مشخص خودش قابل دسترسی باشند.

سوال: آیا تا به حال قانونی (تست یا مانیتورینگ) برای سلامت معماری تعریف کرده‌ای؟ مثلاً در مانیتورینگ‌هایتان چه چیزی را به عنوان “نشانه معماری سالم” می‌شناسید؟

تفاوت معماری و طراحی

این بخش تمایز بین معماری (تصمیمات ساختاری سطح بالا، غیرقابل تغییر یا خیلی سخت قابل تغییر) و طراحی (جزئیات پیاده‌سازی، الگوها و ترکیب‌ها) را شرح می‌دهد.

  • معماری چیزی است که اگر اشتباه شود، هزینه اصلاح آن بالا است.
  • طراحی معمولاً جزئی‌تر است و اصلاحش کم‌هزینه‌تر.

معرفی مطالعه موردی: Sysops Squad

نویسندگان برای ملموس کردن مباحث از مثال یک پروژه تخیلی به نام “Sysops Squad” استفاده می‌کنند و تصمیمات معماری آن را طی فصل‌ها بررسی می‌کنند تا مفاهیم نه صرفاً تئوری بلکه عملی و واقعی تدریس شوند.


خلاصه فصل اول (برای تثبیت)

  • در معماری نرم‌افزار، جواب قطعی وجود ندارد؛ تصمیمات همیشه trade-off دارند.
  • داده‌ها و مالکیت آنها مرکز ثقل معماری توزیع‌شده هستند.
  • مستندسازی تصمیمات با ADR الزامی است.
  • تعریف Fitness Function برای سلامت معماری اهمیت دارد.
  • مرز واضح بین معماری و طراحی را باید بشناسیم.
  • مثال پروژه واقعی، مسیر یادگیری را عملی‌تر می‌کند.

بررسی درک

  • سئوال: معمار نرم‌افزار چه زمانی به سراغ سند ADR می‌رود و قرار است چه موضوعاتی را در آن ثبت کند؟
  • اگر دوست داری بیشتر با ADR یا Fitness Function کار کنیم یا مثالی برای هرکدام بزنم، بگو تا با هم تمرین کنیم.

توضیح عمیق و مثالی از ADR (Architectural Decision Record)

تعریف کامل‌تر

ADR ابزاری ساختاریافته برای ثبت و تحلیل تصمیمات معماری است. این سند، نه تنها انتخاب انجام‌شده، بلکه دلایل، شرایط، گزینه‌های جایگزین و پیامدها را (کامل و با صراحت) مستند می‌کند. کاربردش این است که هر معمار، مدیر یا دولوپری در آینده بتواند منطق تصمیمات را درک کند و اگر نیاز به تغییر بود، آن را آگاهانه و اصولی انجام دهد.

ساختار استاندارد ADR

معمولاً هر ADR شامل چهار بخش کلیدی است:

  1. عنوان (Title): موضوع تصمیم معماری، به‌صورت خلاصه.
  2. زمینه (Context): توضیح شرایط و مشکل/فرصت، به‌همراه گزینه‌های جایگزین.
  3. تصمیم (Decision): شرح تصمیم گرفته‌شده و علت ارجحیت آن.
  4. پیامدها (Consequences): اثرات مثبت/منفی تصمیم و trade-offها.

مثال واقعی ۱: ADR برای سرویس پرداخت

عنوان: جداسازی اعتبارسنجی کارت بانکی به سرویس مستقل

زمینه:
پرداخت کاربران باید بلافاصله تأیید شود تا تجربه کاربری مناسب باشد. دو گزینه وجود دارد:

  • انجام اعتبارسنجی در همان سرویس خرید
  • جدا کردن اعتبارسنجی به یک سرویس مستقل در صورت استقلال، مزیت دیپلوی مستقل و تحمل خطا داریم، اما لَتِنسی و پیچیدگی افزایش می‌یابد.

تصمیم:
اعتبارسنجی کارت بانکی به‌‌عنوان یک سرویس مستقل پیاده‌سازی می‌شود. این سرویس نسخه‌بندی‌شده و مستقل از چک‌آوت عمل می‌کند.

پیامدها:

  • مزیت: دیپلوی مجزا، تحمل بالاتر به خطاهای بانکی، تسهیل تغییر بانک‌های ارائه‌دهنده API.
  • عیب: افزایش لَتِنسی (رفت‌وبرگشت شبکه)، احتمال خطا در ارتباطات، پیچیدگی بیشتر مانیتورینگ مسیر سرویس‌ها.

مثال واقعی ۲: ADR از متن کتاب (Sysops Squad)

عنوان: یکپارچگی سرویس مدیریت مشتری

زمینه:
کاربر برای ثبت‌نام باید اطلاعات پروفایل، کارت، پسورد و محصولات را درج کند. سه گزینه:

  • تجمیع همه قابلیت‌ها در یک سرویس (یکپارچگی)
  • جداسازی بر اساس نوع داده (حساس/غیرحساس)
  • جداسازی هر قابلیت به سرویس مستقل

تصمیم:
یک سرویس یکپارچه ساخته می‌شود تا ضمن حفظ تراکنش اتمیک و ACID، انجام عملیات ثبت‌نام سریع و پایدار باشد. امنیت داده‌های حساس از طریق لایه امنیتی ابزار Tortoise و Service Mesh انجام می‌شود.

پیامدها:

  • مزیت: انجام عملیات ثبت‌نام در یک transaction، سهولت اطمینان از یکپارچگی داده.
  • عیب: در صورت ضعف امنیتی، داده‌های حساس آسیب‌پذیرتر می‌شود؛ وابستگی بیشتر کدها.

توضیح عمیق‌تر درباره Fitness Function

فلسفه Fitness Function

در معماری و DevOps هدف این است که سلامت و تطابق ساختار معماری با اهداف تجاری یا تکنیکی به شیوه‌ای قابل سنجش و اتوماتیک بررسی شود. Fitness Function قاعده‌ای نرم‌افزاری (کد، تست، هشدار، پابنده، یا مانیتورینگ) است که به صورت پیوسته یکی از ویژگی‌های اصلی معماری را اندازه‌گیری می‌کند و اگر سازگاری مختل شد، هشدار یا خطا می‌دهد.

دسته‌بندی

  • اتمی: بررسی صرفاً یک معیار (مثلاً عدم وابستگی سیکلی بین ماژول‌ها)
  • کل‌نگر: ترکیب چند ویژگی (مثلاً حفظ تعادل بین امنیت و کارایی)

مثال Fitness Function اتمی (کد جاوا-سی‌شارپ)

بررسی ضد-وابستگی سیکلی فرض کنیــد می‌خواهیم مطمئن شویم که هیچ cyclic dependency بین ماژول‌ها وجود ندارد. می‌توان از ابزارهایی مثل [NDepend] برای #C یا [JDepend] برای جاوا استفاده کرد.

// با استفاده از NDepend در دات‌نت:
warnif count > 0 from t in Application.Types
where t.IsUsing(t) // چک کردن dependency بر روی خودش یا دیگر ماژول‌های یکسان
select t

این خط کد، گزارشی می‌دهد تا هر circular dependency دیده شد، تیم dev هشدار بگیرد.


مثال Fitness Function کاربردی (سفارشی برای سلامت ارتباطات میکروسرویس‌ها)

سلامت تعداد وابستگی‌های سرویس در سازمانی توافق شده هیچ سرویسی نباید به بیش از ۳ سرویس دیگر وابسته باشد (health of independence):

# pseudo-code:
for each service in all_services:
    if service.dependencies.count > 3:
        alert("Service {service.name} has too many dependencies")

این اسکریپت می‌تواند در pipeline CI/CD یا مانیتورینگ اجرا شود.


مثال پیشرفته: تست performance دوره‌ای (holistic)

فرض کنید تیم شما باید تضمین کند که response time برای endpoint خاص، همیشه زیر ۵۰۰ms باشد.

  • یک تست performance اتوماتیک در pipeline اجرا می‌کند اگر:
    • میانگین پاسخ بالاتر از عدد threshold باشد، build fail شود.
    • (در تست) مصرف منابع کل cluster را در بازه شلوغی هم بررسی کند.

مرور و نکاتی عملی:

  • ADR: هر زمان تصمیم معماری جدی می‌گیرید یا الگوی جدیدی پیاده می‌کنید، همین ساختار را مستند کنید؛ حتی اگر اول کار ساده‌تر بنویسید و بعداً کامل‌تر کنید.
  • Fitness Function: سعی کن برای هر اصل معماری که برات اهمیت حیاتی دارد، یک تست اتوماتیک یا مانیتورینگ قرار دهی تا هر نوع deviation بلافاصله قابل تشخیص باشد.


فصل دوم: درک کوپلینگ (Discerning Coupling in Software Architecture)

در این فصل، تمرکز روی “کوپلینگ” یا وابستگی‌های درونی بخش‌های مختلف یک سیستم نرم‌افزاری است. یکی از سخت‌ترین وظایف معمار، تشخیص و مدیریت همین وابستگی‌هاست. بسیاری از مشکلات پیچیده معماری (مخصوصاً در معماری توزیع‌شده مثل مایکروسرویس‌ها) ناشی از درهم‌تنیدگی غیرشفاف این وابستگی‌هاست.


۱. چرا بحث کوپلینگ مهم است؟

همه جا می‌شنویم: سیستم شُل‌-وابسته (loosely coupled) خوب است!
اما واقعیت ساده‌تر و عمیق‌تر است: بعضی کوپلینگ‌ها اجتناب‌ناپذیر و حتی ضروری‌اند. اگر همه اجزای سیستم کاملاً از هم جدا باشند، چگونه باید همکاری کنند؟ معمار موفق کسی است که بفهمد چه وقت، کجا، و چقدر کوپلینگ لازم و مفید است.

کوپلینگ یعنی: اگر تغییر در یک بخش سیستم، بخش دیگر را مجبور به تغییر کند، آن دو قسمت کوپل شده‌اند.


۲. قدم‌های تحلیل پیچیدگی معماری

نویسندگان یک مسیر سه‌مرحله‌ای معرفی کرده‌اند:

  1. شناسایی بخش‌های به‌هم‌ گره خورده (Entangled Parts)
    باید بفهمیم دقیقا کدام بخش‌ها به هم وابسته‌اند.
  2. تحلیل نوع و شدت کوپلینگ
    کوپلینگ فقط یک معنی ندارد! نوع و سطح آن (ایستا/پویا) اهمیت دارد.
  3. تحلیل تِرِید-آف (Trade-Off)ها
    تغییر چه اثری روی بخش‌های دیگر می‌گذارد؟ هزینه تغییر چیست؟ ممکن است علاوه بر مشکلات کد و فنی، اثرات سازمانی و تجاری هم داشته باشد.

۳. تعریف “کوآنتوم معماری” (Architecture Quantum)

اینجا نویسندگان یک مفهوم بکر معرفی می‌کنند:
“کوآنتوم معماری” یعنی: کوچکترین واحد مستقل از نگاه پیاده‌سازی و دیپلوی که کارایی بالا، کوپلینگ ایستا و کوپلینگ پویا دارد.

  • مثال: یک میکروسرویس کامل که هسته یک بیزینس ‌دومِین (Bounded Context) را پیاده‌سازی می‌کند.
  • هر کوآنتوم ویژگی‌های زیر را باید داشته باشد:
    • دیپلوی مستقل (شما می‌توانید آن را جدا توسعه و دیپلوی کنید)
    • همبستگی داخلی بالا (functional cohesion بالا؛ یعنی اجزای داخلی آن به هم بشدت مرتبط‌اند ولی بیرونش کمترین ارتباط را دارد)
    • کوپلینگ ایستا (Static Coupling) بالا: اجزای درون کوآنتوم از لحاظ کد، کانفیگ، دیتابیس و … به هم وابسته‌اند.
    • کوپلینگ پویا (Dynamic Coupling): اجزای مختلف کوآنتوم در زمان اجرا با هم ارتباط دارند (معمولاً به صورت سینکرون).

پرسش:

  • آیا تجربه کردی که بخواهی بخشی از برنامه را جدا دیپلوی کنی، اما چون دیتابیس مشترک بود، عملاً نتوانستی مستقل این کار را انجام دهی؟
  • نتیجه: کوآنتوم عملی نشده و هنوز کوپلینگ بین دو بخش باقی مانده است.

۴. انواع کوپلینگ: ایستا و پویا

الف) کوپلینگ ایستا (Static Coupling)

این همان وابستگی‌هایی است که در زمان ساخت و Build (نه اجرا) دیده می‌شود: مثلاً

  • Dependency به یک پکیج یا لایبرری خارجی
  • داشتن یک دیتابیس مشترک یا کامپوننت مشترک
  • قراردادهای سخت کد (مثل Strong Typing، یا شِرینگ مدل‌های داده بین سرویس‌ها)

ویژگی: اگر بخواهید فلان سرویس را بدون این وابستگی دیپلوی کنید، شکست می‌خورید.
پس هر عنصر خارجی که برای اجرا لازمه، بخشی از کوپلینگ ایستا است.

ب) کوپلینگ پویا (Dynamic Coupling)

ارتباطاتی که فقط در زمان اجرا ایجاد می‌شود:

  • فراخوانی API بین سرویس‌ها در زمان اجرای برنامه
  • ارسال پیام از طریق پیام‌برها (Message Broker) یا صف‌ها
  • تعامل سرویس‌ها با یکدیگر در طول یک Workflow

ویژگی: بدون وجود ارتباط در لحظه، بخش‌ها می‌توانند “مستقل اجرا شوند” اما workflow به صورت runtime بهم وصل می‌شود.


۵. گیج‌کننده‌ترین چالش معماری: Granularity صحیح سرویس‌ها

سؤال قدیمی: “سرویس‌های من چندتا باشند؟ هرکدام چقدر بزرگ؟”

  • سرویس خیلی کوچک: مشکل تراکنش، اورکستراسیون و اجرای هماهنگ Workflow
  • سرویس خیلی بزرگ: inherit مشکلات مانولیتی؛ scale و توزیع سخت می‌شود

اینجا تحلیل کوپلینگ تمرکز اصلی است؛ باید بفهمیم هر سرویس (یا کوآنتوم) چقدر از سایر سرویس‌ها مستقل است.


۶. مثال‌ها و سناریوها

مثال ۱:

یک سیستم نوبت‌دهی کلینیک داریم:

  • مودل مانولیتی: همه ماژول‌ها (ویزیت، صندوق، پیامک، پرداخت) یکجا دیپلوی می‌شوند و دیتابیس مشترک دارند. فقط یک کوآنتوم تشکیل می‌شود، هرچقدر هم بخش‌بندی کد کنیم.
  • سناریوی توزیع: اگر “پرداخت” را واقعاً جدا کنیم (با دیتابیس مختص و API جدا)، و همه وابستگی‌های Deployment را قطع کنیم، تبدیل به یک کوآنتوم مستقل می‌شود.

مثال ۲ (از فصل):

در یک معماری event-driven، اگر همه سرویس‌ها از یک message broker و یک دیتابیس استفاده کنند (مثلاً Kafka و یک RDBMS مشترک)، باز هم کوآنتوم یکی است، چون هیچ‌کدام بدون آن منابع مشترک کار نمی‌کنند.

ولی، اگر چند سرویس، دیتابیس و message broker جدا داشته باشند، هرکدام کوآنتوم مستقل خواهند بود.

تمرین:

  • در پروژه فعلی‌ات، اگر یک سرویس جدید بسازی:
    • آیا کاملاً جدا دیپلوی می‌شود؟
    • آیا دیتابیس و منابع زیرساخت خودش را دارد؟
    • آیا در زمان اجرایش نیازی به روشن بودن سایر سرویس‌ها نیست؟ اگر به همه بله دادی، تو یک کوآنتوم مستقل داری.

۷. اشکال و الگوهای رایج معماری و وضعیت کوانتوم آنها

  • معماری مانولیتی و نیو-مانولیت (Monolithic): فقط یک کوآنتوم
  • Service-Based: اگر دیتابیس مشترک باشد، باز فقط یک کوآنتوم
  • Microservices واقعی: هر سرویس (با دیتابیس، پیاده‌سازی، و منابع جدا) کوآنتوم جدا.
  • Micro-frontends: هر بخش از UI که توسط یک میکروسرویس جدا ران می‌شود، خودش یک کوآنتوم مجزاست.
  • Shared DB: هر جا هنوز دیتابیس مشترک وجود دارد، حتی اگر سرویس‌ها مستقل باشند، فقط یک کوآنتوم واقعی خواهد بود و جداسازی ناقص است.

۸. ابزار عملی برای تحلیل کوپلینگ

معیار ساده:

“اگر این بخش را در محیط جدید بدون هیچ چیز دیگر بالا بیاوریم و کار کند، کوآنتوم مستقل است.”

ابزارهای کمکی:

  • دیاگرام‌های مدرن وابستگی (Dependency graphs)
  • ابزارهای تحلیل استاتیک کد (مثل SonarQube، NDepend)
  • جداسازی زیرساخت‌های مورد نیاز (Databases، Message Brokers، …)
  • تحلیل کانفیگ و مدیریت اسرار (Secrets Management)

جمعبندی این فصل (کد به ذهن بسپار):

  • کوپلینگ الزاماً بد نیست؛ میزان و محل آن مهم است.
  • کوآنتوم معماری = کمترین واحد واقعا مستقل اجرایی و ساختاری
  • کوپلینگ ایستا = وابستگی‌های ساختاری/قبل اجرای برنامه
  • کوپلینگ پویا = وابستگی‌های ارتباطی/در زمان اجرا
  • هر منبع اشتراکی (حتی UI یا DB) عامل یکی‌کردن کوآنتوم‌هاست
  • در فاز مهاجرت مانولیت به میکروسرویس، تحلیل دقیق و عملی کوپلینگ ضروری است

سؤالات یادگیری و تأمل:

  1. چگونه می‌توانی بفهمی یک کوآنتوم واقعی داری، نه یک شبه-میکروسرویس؟
  2. نمونه‌ای در پروژه‌ات داری که کوپلینگ مانع جدایی کامل یک سرویس شده باشد؟
  3. آیا دیاگرامی از Dependency ها در پروژه رسم کرده‌ای؟ چه چیزهایی را آشکار می‌کند؟

بررسی کوپلینگ و کوآنتوم وقتی Broker و Database زیرساخت مرکزی دارند

۱. سرویس مرکزی Kafka، ولی Topic جدا برای هر سرویس

سناریو:
فرض ‌کن همه سرویس‌ها برای ارسال و دریافت پیام از یک Kafka مرکزی استفاده می‌کنند، اما هر سرویس فقط داخل topic خودش پیام می‌فرستد و مصرف می‌کند.

تحلیل کوپلینگ:

  • زیرساخت مرکزی («Shared Infrastructure»):
    همه سرویس‌ها برای عملکردشان وابسته به Kafka هستند؛ اگر Kafka قطع شود، کل سیستم دچار اختلال خواهد شد.
  • Topic جدا:
    از نظر “business logic”، مستقل‌اند (یعنی داده و پیام‌های هر سرویس با دیگری ترکیب نمی‌شود)، اما از نظر اجرا وابسته به Kafka مرکزی.

نتیجه:

  • این معماری کوآنتوم واقعی نمی‌سازد، چون اگر مثلا بخواهی فقط یکی از سرویس‌ها را در محیطی بدون Kafka بالا بیاوری، کار نمی‌کند.
  • اگر Kafka به طور موازی و مستقل (برای هر سرویس یک instance جدا) داشته باشی، تازه هر سرویس کاملاً مستقل می‌شود و کوآنتوم واقعی شکل می‌گیرد.
  • فقط جدا بودن Topic کافی نیست: dependency روی Kafka مرکزی یعنی کوپلینگ ایستا مشترک، حتی اگر coupling پویا (ارتباطات داده‌ای) جدا باشد.

۲. دیتابیس مرکزی، اما دیتابیس‌های جدا روی آن

سناریو:

  • یک سرور SQL یا RDBMS مرکزی داریم، اما برای هر سرویس schema و دیتابیس جدا تعریف شده است. هیچ سرویسی جدول‌های سرویس دیگر را نمی‌خواند یا نمی‌نویسد.

تحلیل کوپلینگ:

  • زیرساخت مرکزی:
    همه سرویس‌ها نیازمند در دسترس بودن سرور دیتابیس مرکزی هستند. اگر سرور DB قطع شود، تمام سرویس‌ها آسیب می‌بینند.
  • دیتابیس جدا:
    “مرز داده‌ها” رعایت شده، هر سرویس صاحب data و schema خودش است، پس coupling در سطح business logic پایین آمده است.

نتیجه:

  • این هم کوآنتوم کامل نیست، مگر اینکه بتوانی هر سرویس را با دیتابیس خودش (روی instance جدا یا حتی روی سرور مستقل) بالا بیاوری.
  • وقتی دیتابیس مشترک، هرچند با schema جدا، وجود دارد dependency زیرساختی یکجا می‌کند؛ تمام سرویس‌ها به روشن بودن سرور وابسته‌اند.
  • از نظر تغییرپذیری: آپدیت امنیت یا patch سرور روی همه اثر دارد؛ اگر باید یکی را مستقل به روزرسانی کنی و بقیه وابسته باشند، وابستگی باقی مانده است.

برای مقایسه

حالت دیتابیس حالت واقعی
دیتابیس server جدا برای هر سرویس هر سرویس کوآنتوم واقعی/دیپلوی/تغییر مستقل
دیتابیس مشترک، ولی schema جدا کوپلینگ زیرساختی دارد، استقلال ناقص
دیتابیس/جدول مشترک کوپلینگ کامل، فقط یک کوآنتوم
حالت Kafka/Message Broker حالت واقعی
Broker جدا برای هر سرویس کوآنتوم واقعی/سرویس کاملاً منفصل
Broker مشترک، Topic جدا استقلال ناقص، dependency زیرساختی باقی است
Broker و Topic مشترک کوپلینگ کامل، تنها یک کوآنتوم

نکته مهم

در معماری‌های enterprise معمولاً اجتناب کامل از shared infrastructure عملی نیست (به دلایل هزینه، اجرا، DevOps). هدف معماری ایده‌آل این است که لایه زیرساخت طوری مدیریت شود که قطع یا تغییر یک سرویس، سایر سرویس‌ها را مختل نکند و دیپلوی سرویس‌ها صددرصد مستقل باشد. کوآنتوم کامل، این استقلال را ممکن می‌کند.

سوال برای تمرین:

در پروژه فعلی‌ات (یا پروژه‌ای که ساختارش را می‌شناسی)، آیا سرویس‌ها واقعا مستقل‌اند؟ اگر زیرساخت دیتابیس یا Message Broker را قطع کنی، کدام سرویس‌ها واقعا زنده می‌مانند؟
این تست ساده، میزان کوپلینگ را خیلی خوب نشان می‌دهد.

اگر دوست داشتی با هم درباره الگوهای حذف این کوپلینگ (مثل استفاده از دیتابیس‌های آسان-مستقل، Brokerهای Micro-Broker یا containerized) بیشتر کار کنیم، بگو تا راهکار معماری حرفه‌ای را تحلیل کنیم.
آیا دوست داری سناریو و دیاگرام پیشنهادی برای یک کوآنتوم واقعی با ابزارهای دنیای .NET و Kafka عملی‌تر بررسی کنیم؟