مسعود مقینی
مسعود مقینی
خواندن ۸ دقیقه·۵ سال پیش

چرا نباید بر مبنای بنچمارک ها تصمیم بگیریم؟


مسئله

1- «ما چون محصولمون قراره به کاربرای زیادی سرویس بده ، تصمیم گرفتیم از Go برای توسعه استفاده کنیم»
2-«از تکنولوژی عقبی ،‌ بنچمارک 2019 میگه NETCORE. از Node.js بهتره،‌ به خاطر همین ما تصمیم گرفتیم به NETCORE. مهاجرت کنیم»
3-«با توجه به اینکه نرم افزار ما با Scala نوشته شده خیالمون راحته که کاربرای زیادی میتونند ازش استفاده کنند»
احتمال اینکه شما هم در محیط کارتون ، یا در مصاحبت با همکارتون که مدیرعامل شرکت نرم افزاری هست همچین چیز هایی شنیدید،‌ فصل مشترک همه ی این قبیل اظهارات یک چیز هست ، زبانی که با استفاده از ، نرم افزار پیاده سازی میشه ، تاثیر قابل ملاحضه ای در مقیاس سرویس دهی دارد . بعضی ها معتقدند این گونه اظهارات ناشی از انگاره ی خطرناک تری هست ، برای نرم افزاری که قابلیت سرویس دهی در مقیاس بالا رو داره کافیه از زبان برنامه نویسی خاصی استفاده کنیم . در ادامه سعی میکنم بگم که چرا این دو نتیجه گیری غلط هست و بنچمارک ها نباید در تصمیم گیری مون نقش داشته باشند، به چند شاخص مهم در تصمیم گیری برای ابزار پیاده سازی نرم افزار می پردازم و نهایتا چند توصیه کوچیک راجع به مسئله ی مقیاس پذیری میکنم (با توجه به اینکه فرهنگستان زبان و ادب فارسی اصطلاح محک‌زنی رو برای Benchmarking به عنوان برابرنهاده انتخاب کرده، در ادامه از واژه‌ی محک به جای بنچمارک استفاده می‌کنیم)

دلیل اول( خاص منظوره بودن محک ها)


اون چیزی که در محک ها اندازه‌گیری میشه شبیه‌سازی کامل یک برنامه‌ی کامپیوتری نیست، عملگر های خاص‌منظوره مورد بررسی قرار می‌گیرند، کافیه نگاهی به یکی از مشهور ترین محک هایی که سالانه توسط تیمی از کاربران متن‌باز جامعه‌ی توسعه دهنگان دبیان گرفته میشه بکنید https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/rust-go.html
تست ها شامل فقراتی از محاسبات زیستی هست یا بیاید به یک محک دیگه برای زبان برنامه‌نویسی Go نگاه کنیم https://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go همون‌طور که میبینید بیشتر تعداد محاسبات عددی مورد ملاک هست، اون چیزی که واضحه اینه که ممکنه یک زبان برنامه نویسی در یک عملیات بسیار خوب عمل کنه( مثلاْ‌ ضرب دو عدد طبیعی) اما در عملیات دیگه ای بسیار بدتر عمل کنه( به عنوان مثال مکمل 2 اعداد بزرگ اعشاری) بنابراین هیچ محکی ، کارآیی زبان برنامه نویسی را در همه‌‌ی عملیات های ممکن بررسی نمی‌کنه .
اما در توسعه‌ی اپلیکیشن های تحت وب چنین چیزی وجود نداره، طیف پردازش های انجام گرفته بسیار گسترده ست ، از کار با اعداد و آرایه ها گرفته ، تا پرس و جو های پایگاه داده ای و رسیدگی به درخواست های http.

دلیل دوم ( استفاده از کتاب‌خانه های خارجی)


شما استفاده‌ی گسترده ای از کتاب‌خانه های خارجی میکنید و اون ها ضمن اینکه شما رو از یک سری پیچیدگی های پیاده‌سازی دور نگه میدارند ، با کارآیی خودشون مسائل رو حل میکنند، به زبان ساده تر فرض کنید که node.js بالاترین کارآیی رو در بنچمارک ها بدست آورده ، زمانی که شما از کتاب‌خانه ی axios برای درخواست های http استفاده می‌کنید بسیار محتمل هست که این کارآیی از نحوه ی پیاده‌سازی axios تاثیر بپذیره ، یا فرض کنید Java کارآیی بالایی در ارتباط با پایگاه داده از خودش نشون میده، زمانی که از hibernate استفاده می‌کنید ،صرفاْ بحث کارآیی جاوا موضوعیت نداره و کارآیی hibernate هم مطرح خواهد بود.

دلیل سوم (نحوه‌ی مهندسی مهم‌تر از ابزار مهندسی هست)

برای ارتقای کارآیی محاسباتی لازم هست روش های پیچیده تری اتخاذ بشه، پردازش توزیع شده، چند ریسه‌ای کردن محاسبات[1] ، استفاده از شبکه های تحویل محتوا[2] و ... ، حالا فرض کنید شما برای پیاده‌سازی کارآمد یک سرویس ، مبادرت به استفاده از برنامه‌نویسی غیر همزمان[3] می‌کنید ، مجدداْ‌ لازم به یادآوری هست ، ممکنه Go در محاسبات نتایج بهتری رو رقم زده باشه، اما بسیار محتمل تر خواهد بود که این قابلیت رو در حالت پردازش موازی نداشته باشه و سربار محاسبات موازی قابل ملاحضه ای داشته باشه .



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



ملاک های درست برای تصمیم‌گیری

سوال اینجاست ، اگر بر مبنای محک ها تصمیم‌گیری نکنیم، پس معیار درست چی هست، به طور فهرست وار:
1- نیروی انسانی متخصص ، شاید جدی ترین معیار برای استفاده از زبان این باشه که تا چه حد نیروی انسانی متخصص در اون زبان وجود داره، هم در مقیاس سازمانی و هم در مقیاس بیرونی، به عنوان مثال ، اگر تصمیم به استفاده از زبان برنامه نویسی Go یا Rust برای توسعه‌ی محصولاتتون دارید، بودجه تون هم برای به کار گیری نیرو محدوده و زمان هم پارامتر اساسی براتون محسوب میشه ، در نظر داشته باشید توسعه دهندگان کارکشته در این زبان ها (یا زبان های دیگری مثل Elixir و Erlang) محدود هستند و وابستگی زیادی به توسعه دهنده خواهید داشت.

2-اگر قصد پیاده‌سازی یک راه‌کار نرم افزاری دارید ، و اون راهکار بر مبنای اصول شی‌گرایی پیاده‌سازی شده، در نظر داشته باشید زبان هایی نظیر Python و Javascript از تمام قابلیت های یک زبان برنامه نویسی شی‌گرا پشتیبانی نمیکنند ، مفاهیمی نظیر میانا [4] ها ، ارث بری ، چند ریختی [5] ، تزریق وابستگی [6] و الگو های طراحی شی‌گرایانه به مانند یک زبان ذاتاً شی گرا در این زبان ها وجود ندارند، از من میشنوید برای پروژه های سازمانی به سراغ چارچوب های مبتنی بر Java/Kotlin و یا .NET برید

3- برای پیاده‌سازی سرویس های نرم‌افزاری نه چندان بزرگ مقیاس، به سراغ زبانی برید که دستتون بازتره و روش خودش رو کمتر تحمیل میکنه ، زبان های مبتنی بر مفسر به خصوص Javascript رو من توصیه می‌کنم.




راه‌کار های افزایش مقیاس‌پذیری نرم افزار

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

1-از سرویس های ابری استفاده کنید : سرویس های ابری به شما این امکان رو میدن که به سادگی توان پردازشی و حافظه‌ی سخت افزار و سرورتون رو افزایش بدید ، ماشین های مجازی سنتی برای افزایش توان محاسباتی محدودیت هایی دارند

2-از معماری میکروسرویس استفاده کنید ، البته این موضوع خودش سرفصل بسیار گسترده ایه ، اما به طور خلاصه میکروسرویس بهتون این امکان رو میده که بخش های مختلف نرم افزاری رو به صورت جداگانه توسعه بدید، در سرور های جداگانه مستقر کنید و برای افزایش توان محاسباتی برنامه ، مجبور به هزینه ی هنگفت برای ارتقای سرور اصلی نباشید

3- سعی کنید از برنامه نویسی غیر انسدادی [7] استفاده کنید، البته برنامه هایی که بر مبنای اصول غیر انسدادی نوشته میشن ، در محیط های با هسته های محاسباتی محدود کارآیی پایینی دارند، بنابراین سروری با چندین هسته ی پردازشی ، به نحو بهتری قادر به پاسخگویی به این برنامه هاست

4- برای ذخیره سازی داده هایی که بیانگر موجودیت ها نیستند (مثل داده های پایش [8] سیستم یا داده های تراکنش ها) از پایگاه داده های غیر رابطه‌ای[9] استفاده کنید

5- حتماً تست های عملیاتی بگیرید ، در مواقع بسیاری لازم هست مدیریت حافظه و عملیات زباله‌روبی [10] برای آزادسازی حافظه رو خودتون کنترل کنید



نتیجه‌گیری

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


[1]:multi-threading
[2]: Content Delivery Network (CDN)
[3]: Asynchronous
[4]: Interface
[5]: Polymorphism
[6]: Non-Blocking
[7]: Dependency Injection
[8]: Monitoring
[9]: NoSql database
[10]: Garbage Collection


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