همبنیانگذار کافه بازار و دیوار
چه شد که مایکروسرویس؟!
چه استارتآپ چه گروئنآپ، تقسیم تسکها بین اعضای تیم در یک کسب و کار پویا مثل کسب و کارهای اینترنتی چالش قابل توجهی است؛ مهمترین کار مجموعه نیست ولی مهم است (مهمترین احتمالاً تشخیص تسکهایی است که لازم است انجام بدهید از تسکهایی که چندان هم ضرورت ندارند، و یا حتی آنهایی که بعداً از اینکه انجامشان ندادهاید خیلی هم خوشحال میشوید). در این پست میخواهم با تکیه به تجربیاتم در بازار و دیوار در این موضوع خاص از جنبهٔ فنی بنویسم، و اینکه چه شد که به مایکروسرویس رسیدیم.
البته که جنبهٔ انسانی موضوع تقسیم کار در تیم پرچالشتر است و احتمالاً برای اکثر مخاطبین این مطلب وزن و اهمیت بیشتری دارد. ولی در آن موضوع مطلب زیاد است و انواع متدولوژیها برای کار تیمهای نرمافزاری ایجاد شده که بعضیهایشان هم خوب جوابشان را پس دادهاند. لذا سعی کردهام در جنبهٔ انسانی به حداقلِ نیاز متن بسنده کنم.*

تا قبل اینکه از چهار پنج نفر بزرگتر شویم، تقسیم کارها نسبتاً راحت بود:
مصطفی: من رفتم سراغ جلالی تو تقویم.
رضا: ایول. من برم سراغ فارسی تو SMS؟
رضا: برم سراغ کلاینت بازار؟
مصطفی: حله، منم رفتم سرور.
مشکل وقتی شروع میشود که تعداد افراد متمرکز روی یک پروژه زیاد شده و لازم میشود که دو نفر همزمان روی یک چیز کار کنند؛ یک Feature، یک Codebase، یک ماژول، یک فایل، زبانم لال یک Class. مشکل اصلی هم نیاز به هماهنگی است، به Communication. و این نیاز به ارتباط به نوعی ستون متدولوژیهای مختلف است. متدولوژیها هم هر یک به نحوی ارتباطات اعضای تیم را سامان میدهند. Kanban سعی میکند با قوانینش نیاز به ارتباط در راستای تقسیم تسک را کم کند و Scrum هم جلسات مختلف مثل Sprint Planning و Daily Scrum، با اهداف مختلف در نظر گرفته است. انتخاب متدولوژی مناسب تیم کار خیلی راحتی نیست ولی میتوانید از تجربههای فراوانِ موجود در جهان استفاده کنید.
(پیشنهاد من اینست که برای ایده گرفتن به سراغ تیمهایی بروید که شباهتهایی با شما دارند؛ مشتریهای مشابهای دارند، ارزشهای مشابه دارند، دغدغههایشان مشترک است، ... شاید با کپی کردن از تیمهای تجربهکرده حس کنید که شبیه میمونی شدهاید که از دست زدن به موز میترسد چون دوستانش او را از این کار ترساندهاند (بلانسبت!)، ولی احتمالش کمه که واقعاً در قفسی تحت نظر یه سری پژوهشگر مردمآزار (یا میمونآزار؟) باشیم؛ احتمالش خیلی بیشتر است که موز مورد بحث یک ایرادی داشته باشد که عزیز کهنهکار میگوید بهش دست نزن! البته که هر وقت فرصتش را پیدا کردید پیگیر دلیل پشت راهکارهای نسخهٔ مربوطه شوید، و اگر بعد کپی کردن هم احساس میکنید اوضاع خراب است و همین الانش هم رو سرتون سطل آب رو خالی کردهاند، دیگر چارهای نیست! باید دست به کار بشوید و نسخهٔ خودتان را بپیچید).
وقتی که تعداد تیمها زیاد میشود، ارتباط بین تیمها تبدیل به یک چالش میشود. اینجاست که متدولوژیها هم تبدیل به موجودات عجیب و غریبی میشوند (مثل SAFe و LeSS) که چندان هم جوابشان را پس ندادهاند و Case Study دندانگیری ازشان موجود نیست. اینجا یک مقدار پیدا کردن الگو سختتر است و گریزی از Customization نیست. خوشبختانه در لایهٔ فنی اینقدر نظرات متنوع نیست. راهکارهای فنی نسبتاً مشابهی را میتوانیم در شرکتهای متفاوت ببینیم که Robust یا حتی Anti-Fragile هستند و مجموعه را برای تغییرات که ذات این صنعت است، چه در لایهٔ انسانی و چه در لایهٔ هدف و محصول، آماده میکنند.
اولین تجربهٔ مرتبط ما در این فاز وقتی بود که تیم فنی بازار از دو تیم کلاینت (۴-۵ نفر) و سرور (۱۰-۱۱ نفر) تشکیل شده بود. چیزی که مشخصاً به یاد دارم تسک «کارت هدیه» است که در تیم کلاینت اولویت گرفته بود و پیاده شده بود ولی در تیم سرور بعد چندین هفته از اتمام پیادهسازیِ تیم کلاینت هنوز حتی وارد فهرست تسکهای ایتریشن هم نشده بود. اینجا بود که رفتیم سراغ ساختارتکانی و بعد بررسیها به این نتیجه رسیدیم که از اسپاتیفای الگو بگیریم. در آن زمان اسپاتیفای مقالهای داشت به تاریخ دو سال قبلش که تیمبندی خود را توصیف کرده بود، و پست بلاگ تازهای داشت که خیلی منطبق بر مقاله بود و این نشان میداد که ساختار مربوطه حداقل دو سال را دوام آورده است (برای دوستان ناآشنا به صنعت: دو سال در این صنعت خیلی است). خوبی دیگر مدل مربوطه این بود که اولاً توسط اسپاتیفای به اشکال ترتمیزی در موردش مطلب منتشر شده بود و لازم نبود به کامنتهایی از کارمندان تصادفی در مجموعه استناد کنیم. خوبیهای دیگری هم داشت مثل اینکه از نظر ابعاد در حد یک صفر بیشتر با ما اختلاف تعداد نیروی فنی نداشت و همچنین اگر به جای Album میگفتیم Application و به جای Track میگفتیم Package، محصول فنیاش هم شبیه محصولمان میشد.
خلاصهٔ ماجرا اینکه ساختار بازار تغییر میکند به چند تیم ارزش محور به جای تکنولوژی محور (تقریباً). بعد این تغییر بود که احساس کردیم که نیازهای فنیمان هم دارد تغییر میکند. بعدتر بود که در این مقاله از جناب Martin Fowler متوجه شدیم که این حس از کجا میآید: Conway s law. این عبارت قصار میگوید که در هر سازمانی که سیستم نرمافزاری در آن شکل میگیرد، طراحی کلان سیستم کپیِ ساختار ارتباطات سازمان مربوطه میشود. یعنی مثلاً اگر سازمان مربوطه تیم دیتابیس داشته باشد، خواهد دید که در معماری کلان سیستماش روی تخته وایتبورد مجموعهٔ دیتابیس یک بخش مستقل از سیستم شده است.
در این دوره مایکروسرویس برای ما معنی پیدا کرد. تیمهای جدا که روی ارزشهای بیزینسی تا حدی مستقل کار میکردهاند، طبیعتاً دوست دارند که کنترل بخشهای مربوط به خودشان را در دست بگیرند. و روش فنیای که آزمایشش را خوب پس داده بود جدا کردن سرویسها و API دادن به مشتری/دیگر تیمها و سرویس گرفتن از طریق API از دیگر تیمها بود.
نکتهٔ جالب مایکروسرویس این است که خیلی هم روی نحوهٔ تیمبندی حساس نیست. یعنی برای مثال سیستمهای تیمهای زیرساختی (که تا حدودی Technology-Based هستند) هم میتوانند در کنار دیگر مایکروسرویسها ایفای نقش کنند، البته به شرط اینکه خود را تأمینکنندهٔ خدمات/محصول ببینند و نه اینکه بخواهند در کار تیمهای دیگر دخالت کنند.
این مسیری بود که ما طی کردیم. بعدتر که این ارائهٔ فوقالعاده از خانم Mary Poppendieck در مورد آیندهٔ نرمافزار را دیدم، متوجه شدم که مسیری که طی کرده بودیم کاملاً قابل پیشبینی بود و احتمالاً حداقل تا چند سال آتی هم این مسیر معقول بماند.

توصیههای دست به نقد
تا اینجای مقاله، اسمی از تکنولوژی خاصی نبردهام. بدین ترتیب خیالم راحت است که تا چند سالی مطالب بالا هنوز معنی خواهند داشت. بدی این کار این است که برای خوانندهٔ دست به آچار این مطالب زیادی نظری است و چیزی برای ور رفتن و تست کردن و حس پیدا کردن به آدم نمیدهد. در ادامه میخواهم یک سری تجربه/توصیهٔ دست به نقد در راستای پیاده کردن تئوریهای بالا مطرح کنم. از الان هشدار بدهم که ممکن است ترفندها و تکنولوژیهایی که مطرح میکنم در زمانی که این مطلب را میخوانید دیگر منقرض شده باشند.
- وقتی هنوز اول کار هستید: توصیههای دوگانهای شده است که به سراغ مایکروسرویس بروید/نروید. به نظرم منطقیست که بپذیریم که مایکروسرویس برای وقتی که هنوز دارید MVP/MLP/MSP تان را تست میکنید بیشتر دستوپاگیر است تا ارزشمند. ولی در هر صورت پیشنهاد میکنم توصیهٔ بعدی را در همان زمان هم رعایت کنید.
- محل حمله به مسألهٔ شکستن: به نظر من API یکی از بهترین نقاط برای شکستن ابعاد فنی مسأله است، حتی برای وقتی که فقط دو نفر هستید. با تر تمیز مستند کردن API میشود نیاز به مکالمات غیر ضروری را کم کرد. و بهترین روش مستند کردن این است که از ابزاری استفاده کنید که لایهٔ ارتباطی کلاینت و سرور مربوطه را از روی API شما Generate میکند. بدین ترتیب مطمئن میشوید که API تان به خاطر تنبلی عزیزان و پیچاندن بهروزکردن مستندات از اعبتار ساقط نمیشود. من به شخصه gRPC را خیلی میپسندم. هم ویژگیهایی که گفتم را دارد، و هم در لایهٔ فنی بسیار بهینه است؛ بارها کوچکتر و سریعتر از پروتکلهای متنیای مانند JSON API است. پروژهٔ gRPC عضوی از CNCF هم است که من از طرفدارانشان هستم ?.
البته آخرش هم هر چقدر که مستند کنید باز اشتباه پیش میآید حتی در ناسا! - وقتی که تعداد تیمهایتان شروع به زیاد شدن میکنند، رفتن به سراغ مایکروسرویس دیگر منطقی خواهد بود. منظورم از «رفتن» لزوماً یک Big Rewrite نیست؛ میتوانید امکانات جدید را در سرویسهای کوچک جدید پیاده کنید و صرفاً قسمتها مربوط را از Monolith اولیه جدا کنید. برای مثال زمانی که در بازار به سراغ امکان In-app Billing رفتیم، امکانات مربوطه را در یک Codebase جدید پیاده کردیم و خرید اپلیکیشن از بازار را طوری تغییر دادیم که آن هم عملاً In-app Billing ای بود که در آن فروشنده خود اپ بازار بود. در زمان به آب انداختن این تغییرات، هر دو کد خرید قدیمی و تغییرات جدید در سورس کد سرور بازار بودند و صرفاً با یک Flag مشخص میشد که کدام کد فعال است. یکی دو هفته بعد اینکه سرویس جدید جواب خود را پس داد، کدهای خرید قدیمی را از کد سرور بازار حذف کردیم و بدین ترتیب Monolith قدیمی هم خودش در این پروسه کوچکتر شد و یک قدم به مایکروسرویس شدن نزدیک شد.
در باب Big Rewrite این مقاله جالب است؛ میگوید که مشکل Rewrite در زمان مواجهه با کد کمکیفیت اینست که یک راهحل فنی برای یک مشکل فرهنگی است. از این نظر این مقاله را پیشنهاد میکنم که اگر انگیزهٔ شما هم از مهاجرت به مایکروسرویس صرفاً همینهایی باشد که این مقاله اشاره میکند، و نه برخواسته از نیاز سازمانتان به رشد تعداد تیمها، شاید دارید مسیر اشتباهی میروید. - ارتباطات بین مایکروسرویسها را هم جدی بگیرید تا مثل ما دچار اسپاگتیای از مایکروسرویسها نشوید! روشهای مختلفی برای ایجاد نظم در میان مایکروسرویسها وجود دارد که چون کلیت موضوع جدید است هنوز هیچکدام تبدیل به عرف نشده است. شخصاً روشی لایهبندی زیر را دوست دارم چون به نظرم چندان پیچیده و غریب نیست. در این روش شما لایههایی تعریف میکنید که مایکروسرویسهایتان را افراز میکند، و چنین قانونی میگذارید که مایکروسرویسهای هر لایه فقط میتواند به مایکروسرویسهای لایهٔ پایینی درخواست دهد. هر زمان که لازم شد مایکروسرویسی درخواستی از مایکروسرویسی دیگر در لایهٔ خود و یا بالایی انجام دهد، این کار را از طریق Message Queue انجام دهد. این قوانین ساختگی باعث ایجاد نظمی در مایکروسرویسهای شما میشود که در زمان پیدا کردن باگ باعث صرفهجویی در استفاده از کلمات ناپسند میگردد.

- چنانچه شما هم از نوعی از لایهبندی استفاده میکنید، پیشنهاد من اینست که بالای هر لایه یک Load Balancer مینیمال قرار دهید که بتوانید از طریقش سرویسها و قرادادهای سرویسها را یک شکل مونیتور کنید، و به شما کمک کند که سرویسها را High Available کنید، و همچنین مکانیسم Circuit Break پیاده کنید تا جلوی سرایت یک مشکل به دیگر سرویسها را بگیرد.
- میتوانید برای لایههای میانی ویژگیهایی که گفتم را در خود سرویسها پیاده کنید تا نیازی به Load Balancer نباشد، ولی لایهٔ Edge متفاوت است. در اسلاید بالایی از ارائهٔ مدیر فنی Wunderlist در کنفرانس GOTO 2015 شیکاگو، Chad Fowler در مورد معماریای** که برای مایکروسرویس کردن Wunderlist رسیدن صحبت کرده است. آن Smart Proxy به نوعی همان Load Balancer ای است که میخواهم در موردش صحبت کنم. ما در بازار به عنوان گام اول برای نظمدهی سرویسهایمان، برای همین نقطه یک Load Balancer نوشتیم که به کمک Middleware ها امکانات مورد نظر ما را فراهم میکرد. البته به خاطر اینکه به خاطر پرفورمنس پروتکل بازار در آن Embed شده بود، آنرا Open Source نکردیم.
این Load Balancer به ما این امکان را داد که مایکروسرویسهایمان را واقعاً مینیمال درست کنیم. برای مثال وقتی درخواستی به Load Balancer ما میرسد، از میان Middlewareهای موجود میگذرد و بهش دادههایی اضافه میشود. برای مثال Authentication Middleware به دادههای ورودی id کاربر را هم اضافه میکند و یا Metrics Middleware در زمان برگشت جواب از مایکروسرویس مربوطه، مدت زمان و کد جواب برگشتی را در سیستم مونیتورینگ شرکت ثبت میکند بدون آنکه لازم باشد هر کدام از این مایکروسرویسها جداگانه احراز هویت و یا ارتباط با سیستم مونیتورینگ را پیاده کنند.
این ابزار، که به خاطر عملکردش در ترجمهٔ API قدیم بازار به API جدید داخل ابر سرویسهایمان «دیلماج» نامیدیمش، بهمان کمک کرد که میانگین Latency یکی از سرویسهایمان را از 500ms به 50ms برسانیم، علیرغم اینکه یک Hop هم نسبت به حالت Monolithic اضافه شده بود.

- قرارداد: گام بعدی در کم کردن نیاز به ارتباطات، و کم کردن سوء تفاهمها، تعهد میزان در دسترس بودن سرویسها توسط تیمهاست. بدون چنین تعهدی تیمها نمیتوانند از سرویسهای تیمهای دیگر استفاده کنند و سرویسی به کاربر نهایی ارائه بدهند که روی میزان کیفیتش اطمینان داشته باشند. در این موضوع فصل Service Level Objectives کتاب فوقالعادهٔ Site Reliability Engineering را پیشنهاد میکنم. همچنین اخیراً این مقاله را دیدم که کمی فراتر رفته و تست API را هم در قرارداد میآورد.
طولانی شد! شاید بعداً کمی بیشتر در مورد دیلماج بنویسم. در انتها میخواهم این ویدئو را معرفی کنم که خیلی سریع ده تا از مهمترین چالشهای مهاجرت به دنیای مایکروسرویسها را مطرح میکند. در این مقاله به بعضیهایش اشاره کردهام ولی مرورش ضرری ندارد.
[*] در باب جنبهٔ انسانی موضوع، اگر علاقه دارید، به نظرم همچنان کتاب کلاسیک و پر عمق Peopleware: Productive Projects and Teams یکی از برترینهای این موضوع است. هر چند در زمان نوشتنش هنوز Scrum و دیگر متدلوژیهای اسمدار امروز معرفی نشده بودند، فصل مربوط به متدولوژیاش و تفاوت methodology با Big M Methodology اش کاملاً شما را به یاد بحثهای امروزه در مورد متدولوژیهای امروزه میاندازد. و البته راستش را بخواهید، فکر نکنم نویسندگان کتاب اگر نوشتهٔ درون پرانتز من در مورد کپی کردن متدولوژی را ببیند، خیلی خوششان بیاید! به هر حال هر کس نظری دارد.
[**] شاید عبارت شهرسازی بهتر باشد، چرا که دیگر با مجموعهای از نرمافزارها روبرو هستیم.
مطلبی دیگر از این نویسنده
ایراد تلگرام
مطلبی دیگر در همین موضوع
زبان برنامه نویسی M
بر اساس علایق شما
با هم برای هم 💚🤍❤️