علیرضا ارومند
علیرضا ارومند
خواندن ۱۲ دقیقه·۵ سال پیش

قسمت اول Micro Front-end: آشنایی با میکرو فرانت اند

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

1. مقدمه:

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

برای بهبود شرایط معمولا در این شرایط نرم‌افزار به چندین قسمت شکسته می‌شود. یکی از راهکارهای معمول برای انجام این کار شکستن افقی پروژه و ساختار تیم بر اساس تکنولوژی است. معمولا تیم‌های دیتابیس، back-end و front-end تشکیل می‌شوند و هر تیم مسئولیت بخشی از نرم افزار را بر عهده گرفته و کار را پیش می‌برد. به جای استفاده از این روش، Micro front-end استفاده از شکستن عمودی پروژه را پیشنهاد می‌دهد. هر کدام از این بخش‌ها از پایین ترین لایه تا خروجی کاربر توسط یک تیم جداگانه توسعه داده می‌شود. تفاوت این روش با میکروسرویس در لایه UI است. در این روش توسعه، به جز سرویس لایه UI نیز برای هریک از بخش‌های نرم‌افزار توسط تیم تولید می‌شود و نیاز به تولید یک UI مرکزی را از بین می‌برد. این روش توسعه مزایای زیادی دارد که برخی از آن‌ها عبارتند از:

  • سرعت بالا در تولید ویژگی‌ها: هر تیم مسئولیت 0 تا 100 یک کار را به عهده داشته و نیازی به هماهنگی با سایر تیم‌ها کم می‌شود.
  • به روز رسانی ساده‌تر خروجی: هر تیم مسئولیت کلیه لایه‌ها را بر عهده دارد و هر تیم به سادگی و بدون وابستگی به سایر تیم‌ها می‌تواند ابزارها و روش‌های خود را به روز رسانی کند.این ویژگی مانند میکروسرویس‌ها است با این تفاوت که این بار حتی تکنولوژی و روش پیاده سازی UI نیز توسط خود تیم انتخاب می‌شود.
  • تمرکز بیشتر روی مشتری: هر تیم دقیقا یک کار را انجام می‌دهد و مستقیما با مشتری‌های خود در ارتباط است و لایه واسطی بین تیم پیاده سازی و مشتری وجود ندارد.

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

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

یک دید کلی از Micro front-end
یک دید کلی از Micro front-end

2. سیستم‌ها و تیم‌ها:

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

نحوه تعامل این سیستم‌ها در لایه Back-end مسئله ای است که در حوزه میکروسرویس‌ها قرار می‌گیرد. در این مجموعه اما به بررسی چالش‌های لایه UI خواهیم پرداخت.

2.1. ماموریت‌های تیم‌ها:

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

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

همانطور که مشاهده می‌کنید، این تیم‌ها از ابتدای کار مشتریان در فرایند‌های کسب و کار در مراحل مختلف در کنار آن‌ها هستند تا مشتریان و کاربران به هدفشان برسند.

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

2.2. تجمع تیم حول محصول یا تخصص:

در یک مجموعه نرم‌افزاری تیم‌ها به دو شکل مختلف قابلیت چیدمان دارند. حالت اول اینکه تیم‌ها حول توانایی‌هایی خود جمع شوند، مثل تیم‌های UI و Backend و Database

تشکیل تیم‌ها حول توانایی‌ها و تخصص‌ها
تشکیل تیم‌ها حول توانایی‌ها و تخصص‌ها

حالت دوم تجمع تیم‌هایی تشکیل شده از اعضایی با تخصص‌های متفاوت برای به انجام رساندن کامل یک ماموریت

تشکیل تیم‌هایی از تخصص‌های مختلف برای یک هدف خاص
تشکیل تیم‌هایی از تخصص‌های مختلف برای یک هدف خاص

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

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

3. خروجی کار - Front-end:

این قسمت نتیجه همه کارهای تیم است یعنی جایی که کار به خروجی می‌رسد و هر تیم به طور کاملا مجزا مسئول به ثمر رساندن کار خود است. این به این معناست که هر تیم مسئول تولید مقادیری کدهای HTML, CSSو JavaScript برای ارائه خروجی کار خود است. احتمالا تیم‌ها برای اینکه لذت بیشتری از زندگی ببرند و عذاب دنیا و آخرت کمتری را تجربه کنند برای انجام این کارها سراغ فریم‌ورک‌هایی می‌روند. اما با توجه به ماهیت جداگانه این تیم‌ها هیچ اجبار و تضمینی برای انتخاب ابزار و فریم‌ورک مشترک بین تیم‌ها نیست. هر تیم با توجه به توانایی و علاقه و نیاز‌های خود فریم‌ورک خود را انتخاب می‌کند.

3.1. مالک صفحه:

بیایید کمی در مورد صفحات نرم‌افزار صحبت کنیم. به سراغ مثال قبلی خود یعنی یک سیستم تجارت الکترونیک می‌رویم. نرم افزار ما صفحات زیر را خواهد داشت:

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

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

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

3.2. قطعات - Fragments:

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

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

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

4. ادغام - Integration:

در نهایت همه این بخش باید با هم ترکیب شوند و ساختار نهایی صفحات و نرم‌افزار را ایجاد کنند.

4.1. ادغام Front-end:

فرایند دریافت Fragmentها و قراردادن آن‌ها در محل‌های صحیح داخل صفحه در این قسمت انجام می‌شود. در اصل این کار توسط تیمی که مسئول صفحه است انجام نمی‌شود بلکه آن‌ها در فرایند تولید صفحات خود بخش‌هایی را برای سایرین در نظر می‌گیرند و این بخش‌ها را در صفحات خود علامت گذاری می‌کنند یا به اصطلاح در صفحات خود Placeholderهایی را قرار می‌دهند که Fragmentها باید در این قسمت‌ها قرار بگیرند.

در نهایت سرویس یا بخشی مسئولیت دریافت صفحات و یافتن Fragmentهای مناسب برای هر Placeholder و سرهم کردن آن‌ها را بر عهده دارد. به طور کلی این فرایند را می‌توان به دو دسته تقسیم کرد که با توجه به نیاز خود می‌توانید یکی یا ترکیبی از هر دو را انتخاب کنید:

  • انجام به صورت Server Side: تجمیع با SSI, ESI, Tailor و Podiom
  • انجام به صورت Client Side: استفاده از IFrame, Ajax یا Web Component

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

4.2. انتقال بین صفحات:

تا اینجای کار به بالا ترین سطح برنامه یعنی Front-End رسیده‌ایم. به هر حال نیاز داریم تا از صفحه ای به صفحه دیگر پیمایش کنیم، این کار را می‌توانیم به کمک لینک‌های عادی و بارگذاری کامل صفحه انجام دهیم یا به کمک روش‌های هوشمندانه‌ای به صورت کاملا client-side و بخش به بخش صفحه‌ها را به روز رسانی کنیم.

5. موضوعات مشترک:

هرچند که Micro Front-End تلاش می‌کند تیم‌های غیروابسته و خودمختار کوچک با مسئولیت‌ها و عملکردهای مشخص ایجاد کند، اما به هر حال مطالب مشترکی وجود دارد که باید برای همه تیم‌ها حل و فصل شود.

5.1. بهینگی:

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

5.2. طراحی سیستم:

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

5.3. اشتراک دانش:

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

6. خلاصه:

در این قسمت سعی کردیم به طور کلی با مفهموم Micro Front-End آشنا شویم. و مزایا و معایب استفاده از این روش و چالش‌هایی که با آن‌ها روبرو هستیم را بشناسیم. در قسمت‌های بعدی جزئیات بیشتری را در مورد این روش توسعه بررسی خواهیم کرد.

micro frontendsoftware architectureُمعماری نرم‌افزارمیکروسرویسمیکرو فرانت اند
شاید از این پست‌ها خوشتان بیاید