Skip to content

فصل ۱۷ — استفاده از پشته‌ها به‌عنوان کامپوننت

یک پشته معمولاً بالاترین کامپوننت در یک سیستم زیرساخت است. بزرگ‌ترین واحدی است که می‌تواند به‌صورت مستقل تعریف، provision و تغییر داده شود. الگوی پشته قابل بازاستفاده (ببینید «الگو: پشته قابل بازاستفاده» در صفحه ۷۲) شما را تشویق می‌کند پشته را به‌عنوان واحد اصلی برای اشتراک‌گذاری و بازاستفاده زیرساخت treat کنید.

زیرساخت‌هایی که از پشته‌های کوچک ساخته شده‌اند چابک‌تر از پشته‌های بزرگ ساخته‌شده از ماژول‌ها و کتابخانه‌ها هستند. می‌توانید یک پشته کوچک را سریع‌تر، آسان‌تر و ایمن‌تر از یک پشته بزرگ تغییر دهید. پس این استراتژی از چرخه فضیلت استفاده از سرعت تغییر برای بهبود کیفیت، و کیفیت بالا برای امکان‌پذیر کردن تغییر سریع پشتیبانی می‌کند.

ساخت سیستم از چند پشته نیاز دارد هر پشته را با اندازه و طراحی مناسب، cohesive و loosely coupled نگه دارید. توصیه فصل ۱۵ برای پشته‌ها و همچنین انواع دیگر کامپوننت‌های زیرساخت مرتبط است. چالش خاص با پشته‌ها پیاده‌سازی یکپارچه‌سازی بین آن‌ها بدون ایجاد coupling محکم است.

یکپارچه‌سازی بین پشته‌ها معمولاً شامل این است که یک پشته منبعی را مدیریت کند که پشته دیگر استفاده می‌کند. تکنیک‌های محبوب زیادی برای پیاده‌سازی کشف و یکپارچه‌سازی منابع بین پشته‌ها وجود دارد، اما بسیاری از آن‌ها coupling محکمی ایجاد می‌کنند که تغییرات را سخت‌تر می‌کند. پس این فصل رویکردهای مختلف را از دیدگاه تأثیر آن‌ها بر coupling بررسی می‌کند.

کشف وابستگی‌ها در بین پشته‌ها

سیستم ShopSpinner شامل یک پشته consumer، application-infrastructure-stack، است که با عناصر شبکه مدیریت‌شده توسط پشته دیگر، shared-network-stack، یکپارچه می‌شود. پشته شبکه یک VLAN declare می‌کند:

vlan:
  name: "appserver_vlan"
  address_range: 10.2.0.0/8

پشته برنامه یک application server تعریف می‌کند که به VLAN اختصاص داده شده:

virtual_machine:
  name: "appserver-${ENVIRONMENT_NAME}"
  vlan: "appserver_vlan"

این مثال وابستگی بین دو پشته را hardcode می‌کند و coupling بسیار محکمی ایجاد می‌کند. بدون نمونه‌ای از پشته شبکه، تست تغییرات کد پشته برنامه ممکن نخواهد بود. تغییرات پشته شبکه توسط وابستگی پشته دیگر به نام VLAN محدود می‌شود.

اگر کسی تصمیم بگیرد VLANهای بیشتری برای resiliency اضافه کند، consumerها باید پیاده‌سازی کد خود را همزمان با تغییر consumer تغییر دهند.¹ در غیر این صورت، می‌توانند نام اصلی را نگه دارند و messiness اضافه کنند که کد و زیرساخت را سخت‌تر برای درک و نگهداری می‌کند:

vlans:
  - name: "appserver_vlan"
    address_range: 10.2.0.0/8
  - name: "appserver_vlan_2"
    address_range: 10.2.1.0/8
  - name: "appserver_vlan_3"
    address_range: 10.2.2.0/8

Hardcode کردن نقاط یکپارچه‌سازی می‌تواند نگهداری چند نمونه زیرساخت را سخت‌تر کند، مثل محیط‌های مختلف. این ممکن است بسته به API پلتفرم زیرساخت برای منابع خاص جواب دهد. مثلاً، شاید نمونه‌های پشته زیرساخت را برای هر محیط در cloud account متفاوت ایجاد کنید، پس می‌توانید همان نام VLAN را در هر کدام استفاده کنید. اما اغلب، باید با نام‌های منبع مختلف برای چند محیط یکپارچه شوید.

پس باید از hardcode کردن وابستگی‌ها اجتناب کنید. به‌جای آن، یکی از الگوهای زیر برای کشف وابستگی‌ها را در نظر بگیرید.

الگو: تطبیق منبع (Resource Matching)

یک پشته consumer از تطبیق منبع برای کشف وابستگی با جستجوی منابع زیرساختی که با نام‌ها، tagها یا ویژگی‌های شناسایی دیگر match می‌کنند استفاده می‌کند.

مثلاً، یک پشته provider می‌تواند VLANها را بر اساس نوع منابعی که در VLAN تعلق دارند و محیط VLAN نام‌گذاری کند (شکل ۱۷-۱ را ببینید).

شکل ۱۷-۱. تطبیق منبع برای کشف وابستگی‌ها

در این مثال، vlan-appserver-staging برای application serverها در محیط staging در نظر گرفته شده. کد application-infrastructure-stack این منبع را با match کردن الگوی نام‌گذاری پیدا می‌کند:

virtual_machine:
  name: "appserver-${ENVIRONMENT_NAME}"
  vlan: "vlan-appserver-${ENVIRONMENT_NAME}"

مقداری برای ENVIRONMENT_NAME هنگام اعمال کد به ابزار مدیریت پشته پاس داده می‌شود، همان‌طور که در فصل ۷ توصیف شد.

انگیزه (Motivation)

تطبیق منبع با بیشتر ابزارهای مدیریت پشته و زبان‌ها پیاده‌سازی straightforward است. الگو عمدتاً وابستگی‌های hardcode شده را حذف می‌کند و coupling را کاهش می‌دهد.

تطبیق منبع همچنین از coupling روی ابزارها اجتناب می‌کند. زیرساخت provider و پشته consumer می‌توانند با ابزارهای مختلف پیاده‌سازی شوند.

کاربرد (Applicability)

از تطبیق منبع برای کشف وابستگی‌ها وقتی تیم‌های مدیریت کد provider و consumer درک روشنی دارند کدام منابع باید به‌عنوان وابستگی استفاده شوند. اگر با مشکلات شکستن وابستگی‌ها بین تیم‌ها مواجه شدید، به الگوی جایگزین بروید.

تطبیق منبع در سازمان‌های بزرگ‌تر، یا در بین سازمان‌ها، که تیم‌های مختلف ممکن است ابزارهای مختلف برای مدیریت زیرساخت استفاده کنند اما همچنان نیاز به یکپارچه‌سازی در سطح زیرساخت دارند مفید است. حتی جایی که همه فعلاً از یک ابزار استفاده می‌کنند، تطبیق منبع lock-in به آن ابزار را کاهش می‌دهد و گزینه استفاده از ابزارهای جدید برای قسمت‌های مختلف سیستم را ایجاد می‌کند.

پیامدها (Consequences)

به‌محض اینکه یک پشته consumer تطبیق منبع برای کشف منبع از پشته دیگر پیاده‌سازی کند، الگوی تطبیق به قرارداد تبدیل می‌شود. اگر کسی الگوی نام‌گذاری VLAN را در پشته شبکه مشترک تغییر دهد، وابستگی consumer می‌شکند.

پس تیم consumer باید فقط وابستگی‌ها را با تطبیق منابع به روش‌هایی که تیم provider صریحاً پشتیبانی می‌کند کشف کند. تیم‌های provider باید به‌وضوح الگوهای تطبیق منبعی که پشتیبانی می‌کنند را اعلام کنند، و مطمئن شوند یکپارچگی آن الگوها را به‌عنوان قرارداد حفظ کنند.

پیاده‌سازی (Implementation)

چند روش برای کشف منابع زیرساختی با تطبیق وجود دارد. straightforwardترین روش استفاده از متغیرها در نام منبع است، همان‌طور که در کد نمونه قبلی نشان داده شد:

virtual_machine:
  name: "appserver-${ENVIRONMENT_NAME}"
  vlan: "vlan-appserver-${ENVIRONMENT_NAME}"

رشته vlan-appserver-${ENVIRONMENT_NAME} با VLAN مربوطه برای محیط match می‌کند.

بیشتر زبان‌های پشته ویژگی‌هایی برای تطبیق attributeهایی غیر از نام منبع دارند. Terraform data source دارد و AWS CDK از resource importing پشتیبانی می‌کند.

در این مثال (با pseudocode) provider به VLANهای خود tag اختصاص می‌دهد:

vlans:
  - appserver_vlan
    address_range: 10.2.0.0/8
    tags:
       network_tier: "application_servers"
       environment: ${ENVIRONMENT_NAME}

کد consumer VLAN مورد نیاز را با آن tagها کشف می‌کند:

external_resource:
  id: appserver_vlan
  match:
    tag: name == "network_tier" && value == "application_servers"
    tag: name == "environment" && value == ${ENVIRONMENT_NAME}

virtual_machine:
  name: "appserver-${ENVIRONMENT_NAME}"
  vlan: external_resource.appserver_vlan

الگوی تطبیق منبع شبیه الگوی stack data lookup است. تفاوت اصلی این است که تطبیق منبع به پیاده‌سازی همان ابزار پشته در بین پشته‌های provider و consumer وابسته نیست.

الگو: جستجوی داده پشته (Stack Data Lookup)

همچنین شناخته‌شده به‌عنوان: remote statefile lookup، stack reference lookup، یا stack resource lookup.

جستجوی داده پشته منابع provider را با استفاده از ساختارهای داده نگهداری‌شده توسط ابزاری که پشته provider را مدیریت می‌کند پیدا می‌کند (شکل ۱۷-۲).

شکل ۱۷-۲. جستجوی داده پشته برای کشف وابستگی‌ها

بسیاری ابزارهای مدیریت پشته ساختارهای داده برای هر نمونه پشته نگهداری می‌کنند، که شامل مقادیری است که کد پشته export می‌کند. مثال‌ها شامل remote state fileهای Terraform و Pulumi هستند.

انگیزه (Motivation)

فروشندگان ابزار مدیریت پشته استفاده از ویژگی‌های stack data lookup خود را برای یکپارچه‌سازی پروژه‌های مختلف آسان می‌کنند. بیشتر پیاده‌سازی‌های اشتراک‌گذاری داده در بین پشته‌ها نیاز دارند پشته provider صریحاً declare کند کدام منابع را برای استفاده پشته‌های دیگر publish می‌کند. انجام این کار consumerها را از ایجاد وابستگی به منابع بدون آگاهی provider منصرف می‌کند.

کاربرد (Applicability)

استفاده از قابلیت stack data lookup برای کشف وابستگی‌ها در بین پشته‌ها وقتی همه زیرساخت یک سیستم با همان ابزار مدیریت می‌شود کار می‌کند.

پیامدها (Consequences)

جستجوی داده پشته تمایل دارد شما را به یک ابزار مدیریت پشته lock کند. استفاده از الگو با ابزارهای مختلف ممکن است، همان‌طور که در پیاده‌سازی این الگو توصیف شده. اما این پیچیدگی به پیاده‌سازی اضافه می‌کند.

این الگو گاهی در بین نسخه‌های مختلف همان ابزار پشته می‌شکند. ارتقای ابزار ممکن است شامل تغییر ساختارهای داده پشته باشد. این می‌تواند وقتی پشته provider را به نسخه جدیدتر ابزار ارتقا می‌دهید مشکل ایجاد کند. تا وقتی پشته consumer را هم به نسخه جدید ابزار ارتقا ندهید، ممکن است نسخه قدیمی‌تر ابزار نتواند مقادیر منبع را از پشته provider ارتقا یافته استخراج کند. این شما را از rollout تدریجی ارتقاهای ابزار پشته در بین پشته‌ها متوقف می‌کند و احتمالاً ارتقای هماهنگ disruptive در سراسر estate را مجبور می‌کند.

پیاده‌سازی (Implementation)

پیاده‌سازی stack data lookup از قابلیت ابزار مدیریت پشته و زبان تعریف آن استفاده می‌کند.

Terraform مقادیر output را در remote state file ذخیره می‌کند. Pulumi هم جزئیات منبع را در state file ذخیره می‌کند که می‌تواند در پشته consumer با StackReference reference شود. CloudFormation می‌تواند مقادیر output پشته را در بین پشته‌ها export و import کند، که AWS CDK هم می‌تواند به آن‌ها دسترسی داشته باشد.²

provider معمولاً صریحاً منابعی که به consumerها ارائه می‌دهد declare می‌کند:

stack:
  name: shared_network_stack
  environment: ${ENVIRONMENT_NAME}

vlans:
  - appserver_vlan
    address_range: 10.2.0.0/8

export:
  - appserver_vlan_id: appserver_vlan.id

consumer یک reference به پشته provider declare می‌کند و از آن برای اشاره به شناسه VLAN export شده توسط آن پشته استفاده می‌کند:

external_stack:
  name: shared_network_stack
  environment: ${ENVIRONMENT_NAME}

virtual_machine:
  name: "appserver-${ENVIRONMENT_NAME}"
  vlan: external_stack.shared_network_stack.appserver_vlan.id

این مثال reference به پشته خارجی را در کد پشته embed می‌کند. گزینه دیگر استفاده از dependency injection («Dependency Injection» در صفحه ۲۹۶) است تا کد پشته شما کمتر به مکانیزم کشف وابستگی coupled باشد. اسکریپت orchestration شما مقدار output را از پشته provider پیدا می‌کند و به کد پشته به‌عنوان پارامتر پاس می‌دهد.

اگرچه stack data lookupها به ابزاری که پشته provider را مدیریت می‌کند گره خورده‌اند، معمولاً می‌توانید این مقادیر را در یک اسکریپت استخراج کنید، پس می‌توانید با ابزارهای دیگر استفاده کنید، همان‌طور که در مثال ۱۷-۱ نشان داده شده.

مثال ۱۷-۱. استفاده از ابزار پشته برای کشف شناسه منبع از ساختار داده نمونه پشته

bash
#!/usr/bin/env bash

VLAN_ID=$(
  stack value \
    --stack_instance shared_network-staging \
    --export_name appserver_vlan_id
)

این کد دستور stack خیالی را اجرا می‌کند، نمونه پشته (shared_network-staging) را برای جستجو مشخص می‌کند، و متغیر export شده برای خواندن و چاپ (appserver_vlan_id). دستور shell خروجی دستور را که شناسه VLAN است در متغیر shell به نام VLAN_ID ذخیره می‌کند. اسکریپت سپس می‌تواند این متغیر را به روش‌های مختلف استفاده کند.

الگوهای جایگزین اصلی تطبیق منبع («الگو: تطبیق منبع» در صفحه ۲۸۸) و registry lookup هستند.

الگو: جستجوی رجیستری یکپارچه‌سازی (Integration Registry Lookup)

همچنین شناخته‌شده به‌عنوان: integration registry.

یک پشته consumer می‌تواند از جستجوی رجیستری یکپارچه‌سازی برای کشف منبعی که توسط پشته provider publish شده استفاده کند (شکل ۱۷-۳). هر دو پشته به یک رجیستری reference می‌دهند، با استفاده از مکان شناخته‌شده برای ذخیره و خواندن مقادیر.

شکل ۱۷-۳. جستجوی رجیستری یکپارچه‌سازی برای کشف وابستگی‌ها

بسیاری ابزارهای پشته از ذخیره و بازیابی مقادیر از انواع مختلف رجیستری درون کد تعریف پشتیبانی می‌کنند. کد shared-networking-stack مقدار را تنظیم می‌کند:

vlans:
  - appserver_vlan
    address_range: 10.2.0.0/8

registry:
  host: registry.shopspinner.xyz
  set:
    /${ENVIRONMENT_NAME}/shared-networking/appserver_vlan: appserver_vlan.id

کد application-infrastructure-stack سپس مقدار را بازیابی و استفاده می‌کند:

registry:
  id: stack_registry
  host: registry.shopspinner.xyz
  values:
    appserver_vlan_id: /${ENVIRONMENT_NAME}/shared-networking/appserver_vlan

virtual_machine:
  name: "appserver-${ENVIRONMENT_NAME}"
  vlan: stack_registry.appserver_vlan_id

انگیزه (Motivation)

استفاده از configuration registry ابزارهای مدیریت پشته برای پشته‌های زیرساختی مختلف را decouple می‌کند. تیم‌های مختلف می‌توانند ابزارهای مختلف استفاده کنند تا زمانی که موافقت کنند از همان سرویس configuration registry و قراردادهای نام‌گذاری برای ذخیره مقادیر در آن استفاده کنند. این decoupling همچنین ارتقا و تغییر ابزارها را به‌صورت تدریجی، یک پشته در هر بار، آسان‌تر می‌کند.

استفاده از configuration registry نقاط یکپارچه‌سازی بین پشته‌ها را صریح می‌کند. یک پشته consumer فقط می‌تواند از مقادیری که صریحاً توسط پشته provider publish شده‌اند استفاده کند، پس تیم provider می‌تواند آزادانه نحوه پیاده‌سازی منابع خود را تغییر دهد.

کاربرد (Applicability)

الگوی جستجوی رجیستری یکپارچه‌سازی برای سازمان‌های بزرگ‌تر مفید است، جایی که تیم‌های مختلف ممکن است فناوری‌های مختلف استفاده کنند. همچنین برای سازمان‌هایی که نگران lock-in به ابزار مفید است.

اگر سیستم شما از قبل از configuration registry («Configuration Registry» در صفحه ۹۹) استفاده می‌کند، مثلاً برای ارائه مقادیر پیکربندی به نمونه‌های پشته طبق الگوی stack parameter registry («الگو: رجیستری پارامتر پشته» در صفحه ۹۶)، منطقی است همان رجیستری را برای یکپارچه‌سازی پشته‌ها استفاده کنید.

پیامدها (Consequences)

configuration registry وقتی الگوی جستجوی رجیستری یکپارچه‌سازی را adopt می‌کنید به سرویس بحرانی تبدیل می‌شود. ممکن است وقتی رجیستری در دسترس نیست نتوانید منابع را provision یا بازیابی کنید.

پیاده‌سازی (Implementation)

configuration registry پیش‌نیاز استفاده از این الگو است. ببینید «Configuration Registry» در صفحه ۹۹ در فصل ۷ برای بحث رجیستری‌ها. بعضی فروشندگان ابزار زیرساخت سرور رجیستری ارائه می‌دهند، همان‌طور که در «رجیستری‌های ابزار اتوماسیون زیرساخت» در صفحه ۱۰۰ ذکر شد. با هر محصول رجیستری، مطمئن شوید توسط ابزارهایی که استفاده می‌کنید و آن‌هایی که ممکن است در آینده در نظر بگیرید به‌خوبی پشتیبانی می‌شود.

ایجاد قرارداد واضح برای نام‌گذاری پارامترها ضروری است، به‌ویژه وقتی از رجیستری برای یکپارچه‌سازی زیرساخت در بین چند تیم استفاده می‌کنید. بسیاری سازمان‌ها از namespace سلسله‌مراتبی استفاده می‌کنند، شبیه ساختار دایرکتوری یا پوشه، حتی وقتی محصول رجیستری مکانیزم key/value ساده پیاده‌سازی می‌کند. ساختار معمولاً شامل اجزایی برای واحدهای معماری (مثل سرویس‌ها، برنامه‌ها یا محصولات)، محیط‌ها، جغرافیا یا تیم‌ها است.

مثلاً، ShopSpinner می‌تواند مسیر سلسله‌مراتبی بر اساس منطقه جغرافیایی استفاده کند:

/infrastructure/
 ├── au/
 │   ├── shared-networking/
 │   │   └── appserver_vlan=
 │   └── application-infrastructure/
 │       └── appserver_ip_address=
 └── eu/
     ├── shared-networking/
     │   └── appserver_vlan=
     └── application-infrastructure/
         └── appserver_ip_address=

آدرس IP application server برای منطقه اروپا، در این مثال، در مکان /infrastructure/eu/application-infrastructure/appserver_ip_address پیدا می‌شود.

مثل این الگو، الگوی stack data lookup (ببینید «الگو: جستجوی داده پشته» در صفحه ۲۹۱) مقادیر را از رجیستری ذخیره و بازیابی می‌کند. آن الگو از ساختارهای داده خاص ابزار مدیریت پشته استفاده می‌کند، در حالی که این الگو از پیاده‌سازی رجیستری عمومی‌منظوره استفاده می‌کند. الگوی parameter registry (ببینید «الگو: رجیستری پارامتر پشته» در صفحه ۹۶) اساساً همان این الگو است، در اینکه یک پشته مقادیر را از رجیستری برای استفاده در نمونه پشته داده‌شده می‌کشد. تنها تفاوت این است که با این الگو، مقدار از پشته دیگر می‌آید و صریحاً برای یکپارچه‌سازی منابع زیرساختی بین پشته‌ها استفاده می‌شود.

Dependency Injection

این الگوها استراتژی‌هایی برای consumer برای کشف منابع مدیریت‌شده توسط پشته provider توصیف می‌کنند. بیشتر ابزارهای مدیریت پشته از استفاده مستقیم این الگوها در کد تعریف پشته شما پشتیبانی می‌کنند. اما استدلالی برای جداسازی کدی که منابع پشته را تعریف می‌کند از کدی که منابع را برای یکپارچه‌سازی کشف می‌کند وجود دارد.

این snippet از مثال پیاده‌سازی قبلی برای الگوی dependency matching (ببینید «الگو: تطبیق منبع» در صفحه ۲۸۸) را در نظر بگیرید:

external_resource:
  id: appserver_vlan
  match:
    tag: name == "network_tier" && value == "application_servers"
    tag: name == "environment" && value == ${ENVIRONMENT_NAME}

virtual_machine:
  name: "appserver-${ENVIRONMENT_NAME}"
  vlan: external_resource.appserver_vlan

بخش اساسی این کد declaration سرور مجازی است. بقیه snippet peripheral است، جزئیات پیاده‌سازی برای ensamble کردن مقادیر پیکربندی برای سرور مجازی.

مشکلات مخلوط کردن کد وابستگی و تعریف

ترکیب کشف وابستگی با کد تعریف پشته overhead شناختی به خواندن یا کار با کد اضافه می‌کند. اگرچه مانع انجام کار نمی‌شود، اصطکاک ظریف جمع می‌شود.

می‌توانید overhead شناختی را با تقسیم کد به فایل‌های جداگانه در پروژه پشته حذف کنید. اما مشکل دیگر شامل کردن کد کشف در پروژه تعریف پشته این است که پشته را به مکانیزم وابستگی couple می‌کند.

نوع و عمق coupling به مکانیزم وابستگی و نوع تأثیری که coupling دارد برای مکانیزم‌ها و نحوه پیاده‌سازی متفاوت خواهد بود. باید از coupling با پشته provider، و با سرویس‌هایی مثل configuration registry اجتناب یا آن را minimize کنید.

Couple کردن مدیریت وابستگی و تعریف می‌تواند ایجاد و تست نمونه‌های پشته را سخت کند. بسیاری رویکردهای تست از practices مثل نمونه‌های ephemeral («الگو: پشته تست Ephemeral» در صفحه ۱۴۳) یا test doubleها («استفاده از Test Fixtureها برای مدیریت وابستگی‌ها» در صفحه ۱۳۷) برای تست سریع و مکرر استفاده می‌کنند. این می‌تواند چالش‌برانگیز باشد اگر راه‌اندازی وابستگی‌ها کار یا زمان زیادی می‌طلبد.

Hardcode کردن فرضیات خاص درباره کشف وابستگی در کد پشته می‌تواند آن را کمتر قابل بازاستفاده کند. مثلاً، اگر یک پشته زیرساخت application server هسته برای تیم‌های دیگر ایجاد کنید، تیم‌های مختلف ممکن است بخواهند روش‌های مختلف برای پیکربندی و مدیریت وابستگی‌های خود استفاده کنند. بعضی تیم‌ها حتی ممکن است بخواهند پشته‌های provider مختلف را جابه‌جا کنند. مثلاً، ممکن است برای برنامه‌های public-facing و internally facing از پشته‌های شبکه مختلف استفاده کنند.

جداسازی وابستگی‌ها از کشف آن‌ها

Dependency injection (DI) تکنیکی است که در آن یک کامپوننت وابستگی‌هایش را دریافت می‌کند، نه اینکه خودش آن‌ها را کشف کند. یک پروژه پشته زیرساخت منابعی که به آن‌ها وابسته است را به‌عنوان پارامتر declare می‌کند، همان‌طور که پارامترهای پیکربندی نمونه در فصل ۷ توصیف شد. یک اسکریپت یا ابزار دیگر که ابزار مدیریت پشته را orchestrate می‌کند («استفاده از اسکریپت‌ها برای Wrap کردن ابزارهای زیرساخت» در صفحه ۳۳۵) مسئول کشف وابستگی‌ها و پاس دادن آن‌ها به پشته است.

در نظر بگیرید مثال application-infrastructure-stack که برای نشان دادن الگوهای کشف وابستگی قبلاً در این فصل استفاده شد با DI چگونه به نظر می‌رسد:

parameters:
  - ENVIRONMENT_NAME
  - VLAN

virtual_machine:
  name: "appserver-${ENVIRONMENT_NAME}"
  vlan: ${VLAN}

کد دو پارامتر declare می‌کند که هنگام اعمال کد به نمونه باید تنظیم شوند. پارامتر ENVIRONMENT_NAME یک پارامتر پشته ساده است، برای نام‌گذاری سرور مجازی application server. پارامتر VLAN شناسه VLAN برای اختصاص سرور مجازی به آن است.

برای مدیریت نمونه‌ای از این پشته، باید مقداری برای پارامتر VLAN کشف و ارائه کنید. اسکریپت orchestration شما می‌تواند این کار را انجام دهد، با استفاده از هر کدام از الگوهای توصیف‌شده در این فصل. ممکن است پارامتر را بر اساس tagها تنظیم کند، با پیدا کردن outputهای پروژه پشته provider با ابزار مدیریت پشته، یا مقادیر را در رجیستری lookup کند.

یک اسکریپت نمونه با استفاده از stack data lookup (ببینید «الگو: جستجوی داده پشته» در صفحه ۲۹۱) ممکن است از ابزار پشته برای بازیابی شناسه VLAN از نمونه پشته provider استفاده کند، همان‌طور که در مثال ۱۷-۱، و سپس آن مقدار را به دستور پشته برای نمونه پشته consumer پاس دهد:

bash
#!/usr/bin/env bash

ENVIRONMENT_NAME=$1

VLAN_ID=$(
  stack value \
    --stack_instance shared_network-${ENVIRONMENT_NAME} \
    --export_name appserver_vlan_id
)

stack apply \
  --stack_instance application_infrastructure-${ENVIRONMENT_NAME} \
  --parameter application_server_vlan=${VLAN_ID}

دستور اول مقدار appserver_vlan_id را از نمونه پشته provider به نام shared_network-${ENVIRONMENT_NAME} استخراج می‌کند، و سپس آن را به‌عنوان پارامتر به پشته consumer application_infrastructure-${ENVIRONMENT_NAME} پاس می‌دهد.

مزیت این رویکرد این است که کد تعریف پشته ساده‌تر است و می‌تواند در contextهای مختلف استفاده شود. وقتی روی تغییرات کد پشته روی لپ‌تاپ کار می‌کنید، می‌توانید هر مقدار VLAN که می‌خواهید پاس دهید. می‌توانید کد را با API mock محلی (ببینید «تست با Mock API» در صفحه ۱۳۳) اعمال کنید، یا به نمونه شخصی روی پلتفرم زیرساخت (ببینید «نمونه‌های زیرساخت شخصی» در صفحه ۳۴۷). VLANهایی که در این موقعیت‌ها ارائه می‌دهید ممکن است بسیار ساده باشند.

در محیط‌های production-likeتر، VLAN ممکن است بخشی از پشته شبکه جامع‌تر باشد. این توانایی جابه‌جایی پیاده‌سازی‌های provider مختلف، پیاده‌سازی progressive testing (ببینید «تست تدریجی» در صفحه ۱۱۵) را آسان‌تر می‌کند، جایی که مراحل pipeline اولیه سریع اجرا می‌شوند و کامپوننت consumer را به‌صورت ایزوله تست می‌کنند، و مراحل بعدی سیستم یکپارچه‌تر را تست می‌کنند.

منشأ Dependency Injection

DI در دنیای طراحی نرم‌افزار شی‌گرا (OO) در اوایل ۲۰۰۰ها منشأ گرفت. طرفداران XP یافتند unit testing و TDD با نرم‌افزار نوشته‌شده برای DI بسیار آسان‌تر است. فریم‌ورک‌های Java مثل PicoContainer و Spring framework DI را پیشگام کردند. مقاله ۲۰۰۴ Martin Fowler «Inversion of Control Containers and the Dependency Injection Pattern» استدلال رویکرد را برای طراحی نرم‌افزار OO توضیح می‌دهد.

نتیجه‌گیری

ترکیب زیرساخت از پشته‌های خوب طراحی‌شده و با اندازه مناسب که loosely coupled هستند، تغییر سیستم را آسان‌تر، سریع‌تر و ایمن‌تر می‌کند. انجام این کار نیاز دارد راهنمای طراحی عمومی برای ماژولار کردن زیرساخت (مثل فصل ۱۵) را دنبال کنید. همچنین نیاز دارد مطمئن شوید پشته‌ها هنگام اشتراک‌گذاری و ارائه منابع خیلی به هم نزدیک couple نمی‌شوند.


¹ ببینید «تغییر زیرساخت Live» در صفحه ۳۶۸ برای روش‌های کم‌مخرب‌تر مدیریت این نوع تغییر.

² ببینید AWS CDK Developer Guide.