این مطلب به عنوان تمرین درس «معماری نرمافزار» دانشگاه شهید بهشتی نوشته میشود.
در این مطلب ۲۰ عبارت مرتبط با مهندسی نرمافزار یا معماری نرم افزار بررسی میشود. هدف این بررسی ارائه دانش سطحی است و با خواندن همین یک مطلب نمیتوان متخصص حوزه شد!
یکی از ملزومات توسعهی نرمافزار به کمک متودولوژیهای چابک، پاسخ سریع به تغییرات است، و معماری نرمافزار نیز باید این مورد را رعایت کند. DDD در واقع پاسخی به این نیاز است، به این صورت که یکسری قواعد وضع میکند که به معمار کمک میکند تصمیمات طراحی درستی را به شکل سریعتر بگیرد. DDD برای ما ابزارهای جدید یا تکنولوژیهای جدید به ارمغان نمیآورد، بلکه مزیت اصلیاش کمک به طراحی در همان ابزارهای قبلی است.
همانطور که از اسمش نیز بر میآید، روش کار به این صورت است که طراحی بر پایهی دامنهی مسئله صورت میگیرد. به شکل دقیقتر، نرم افزار طوری طراحی میشود که تا حد امکان اجزای نرمافزار با اجزای مسئله که متخصصان آن زمینه شرح دادهاند مطابقت داشتهباشد. این قوانین برای ما چیز تازهای نیست البته، قبلا هم در طراحی شیگرا (Object-oriented Design) میخواستیم اشیایی داشته باشیم که در دنیای واقعی وجود داشته باشند، در اینجا نیز هدف همین است که ساختارهای زبان برنامهنویسی مانند نام کلاس، متدهای کلاس و متغیرهای کلاسها، با دامنهی مسئله مطابقت داشته باشند.
یکی از مزایای مهم این روش، نزدیک شدن زبان توسعهدهندگان به متخصصان آن حوزهی خاص است و برای مواردی که برنامهنویسان دانش زمینهی کافی ندارند میتواند کمک کننده باشد. البته میکروسافت توصیه میکند که این رویه را برای جاهایی که هم با دامنهی مسئله آشنا نیستیم و هم مسئله خیلی پیچیده است نگه داریم، چرا که در حالات دیگر ممکن است کار را بیش از حد لازم پیچیده کند.
منابع:
بیاید به این معماری، بگوییم پورت و آداپتور چرا که چندان ارتباطی با ۶ ضلعی ندارد و اسم غلطاندازی است! در واقع اسم ۶ضلعی از شکل زیر آمده که برای توضیح این معماری به کار برده شده اما ۶ در آن عدد خاصی نیست.
هدف این معماری کاهش جفتشدگی (coupling) بین اجزای متفاوت سیستم است، در عین حال که به سادگی به هم متصل میشوند. برای همین منظور نیز پورتها و آداپتورها را پیشنهاد میکند. به این ترتیب ورودی و خروجیهای سیستم به گوشهی طراحی رانده میشوند و منطق اصلی برنامه (Core) از ورودی/خروجی ایزوله میشود و بدون توجه به آنها طراحی میشود. این ایزوله بودن این امکان را میدهد که بین هندلرهای مختلف ورودی/خروجیها را داشته باشیم بدون اینکه منطق اصلی برنامه اصلا از آنها خبر داشتهباشد.
مشکلی که به شکل طبیعی در طراحیهای شیگرا پیش میآید این است که بین لایههای مختلف اپلیکیشن (مثلا در معماری ۳ لایه) وابستگی ایجاد میشود، مثلا لایههای بالا به لایههای پایین وابسته میشوند و یا کد رابط کاربری به منطق بیزینس آلوده میشود.
یکی از مزایای بزرگ این معماری، ساده شدن تست کردن است، چرا که همانطور که گفته شد منطق برنامه از این هندلرها آگاه نیست و میتوانیم زمان تست یک هندلر مناسب تست را به جای هندلر اصلی قرار دهیم. حتی میتوان به عنوان قانون گفت که یک پورت همواره به دو جیز متصل است که یکی از آنها برای تست استفاده میشود.
تفاوت پورت و آداپتور به این ترتیب است که پورت یک مسیر ورود یا خروج اطلاعات است مثل پورت USB که مبرا از تکنولوژی است. با کمک پورت برنامه امکان ارتباط با اجزای خارجی مثل مسیج بروکرها، دیتابیسها و .. را خواهد داشت. اما آداپتور، با کمک یک تکنولوژی امکان اتصال برنامه با بیرون از طریق پورت را فراهم میکند، مثلا یک کنترلر REST یک اداپتور است که با یک تکنولوژی خاص نوشته میشود و امکان ارتباط برنامه با بیرون را میدهد.
منابع:
پترن CQRS یا همان Command Query Responsibility segregation به حالتی گفته میشود که سیستم را به دو قسمت «دستورات» و «پرسوجوها» تقسیم کنیم. به بیان دیگر می توانیم دو روش جدا برای «ذخیرهی اطلاعات» و «بازیابی اطلاعات» به کار بریم. در در حالی است که به شکل عادی سیستمها ۴ عملیات مختلف کار با داده دارند که به عنوان CRUD شناخته میشود (Create/Read/Update/Delete) اما مدل ذهنی ما برای داده بین همهی این ۴ عملیات با هم برابر است. و یا نهایتا میتوانیم تسهیلاتی ایجاد کنیم، مثلا چند رکورد را به شکل تجمیع شده به عنوان یک رکورد ببینیم یا موقع ذخیرهی اطلاعات، چیزی متفاوت با چیزی که برای ذخیره فرستاده میشود ذخیره کنیم.
پترن معماری CQS
از آنجا که CQRS حالت عمومیشدهای از CQS است، بهتر است اول CQS را خوب بشناسیم. CQS در واقع یک الگوی طراحی مخفف Command query separation است و همانطور که از اسم آن برمیآید دو قسمت مختلف برای «دستور» که یک عملیات را انجام میدهد و یک «پرسوجو» که اطلاعات برمیگرداند در نظر میگیرد. همچنین گفته میشود در این الگو هرگز نباید یک تابع هردو کار را انجام دهد.
اما CQRS حالت عمومیتری است و میگوید بازیابی اطلاعات و ذخیره/تغییر اطلاعات باید به چشم دو امر جدا نگاه شود.
از مزایای CQRS میتوان به کاهش coupling، نزدیکتر شدن کد به کسب و کار (همانند آنچه در DDD داشتیم)، اسکیل راحتتر و هماهنگی با پترنهای دیگر مثل Event sourcing و Event-based programming اشاره کرد.
منابع:
https://www.ibm.com/cloud/architecture/architectures/event-driven-cqrs-pattern/
پترن طراحی MVVM مخفف Model-View-viewmodel است. هدف این پترن کاهش وابستگی و جدا کردن رابط کاربری (مثلا گرافیکی) یا همان View و منطق برنامه یا همان Model است. همچنین امکان تست و نگهداری و اضافه کردن ویژگی به برنامه در طولانی مدت ساده میشود.
Model وظیفهی نگهداری دادهها و هندل کردن منطق کسبوکار را دارد. در دید شیگرایی میتوان به آن domain model نیز گفت و در دید داده-محور به آن data access layer نیز میگویند.
در طرف مقابل، View نهایتا اطلاعاتی را نگه میدارد که برای کاربر لازم است. در واقع خود view ساختار، شکل و چیزی است که کاربر میبیند، مشابه چیزی که در MVC و MVP نیز داریم. به این ترتیب وظیفهی دریافت اطلاعات و eventها از سمت کاربر نیز هست. سپس این اطلاعات با کمک viewmodel یا همان binder به مدل انتخاب داده میشود.
در این میان، viewmodel نیز یک ارتباط بین این دو جز برقرار میکند، در واقع مشابه یک تبدیلگر اطلاعات مورد نیاز هر یک را از فرمت دیگری تبدیل میکند، همچنین می توان گفت viewmodel به model نزدیکتر است چرا که از جنس منطق برنامه است و اکثر منطق گرافیک نیز در همین قسمت هندل می شود. به این قسمت binder نیز گفته میشود که در این صورت به کل مدل model-view-binder خواهیم گفت. این قسمت به جای Presenter در MVP و یا Controller در MVC میآید.
منابع:
یکی از روشهای مرسوم نگهداری داده این است که حالت فعلی (یا همان آخرین اپدیت) را به شکل کامل نگهداریم، مثلا اگر یک حساب بانکی داریم، موجودی نهایی آن را نگه داریم، اما اگر گرههای مختلفی داشته باشیم که داده را مینویسند دچار مشکل میشویم، چرا که ممکن است چندین نسخهی آپدیت تقریبا همزمان داشته باشیم و نمیدانیم کدام نهایی است. (اصلا آیا فقط یکی نهایی است؟)
برای حل این مشکل، «نگهداری حالت نهایی» را کنار میگذاریم و برای هر موجودیتی که میخواهیم ذخیره کنیم، لیستی از اتفاقاتی که روی آن افتاده را مبنا قرار میدهیم. (event sourcing یا همان مبنا قرار دادن eventها!) به این ترتیب با دنبال هم گذاشتن اتفاقات و دنبال کردن state بعد از هر کدام، میتوانیم به حالت نهایی برسیم، در مثال حساب بانکی میتوان تغییراتی که روی موجودی اتفاق افتاده مثل همهی برداشتها و واریزها را دنبال کرد تا به موجودی نهایی رسید. به این ترتیب اگر دو اتفاق تقریبا همزمان بیفتد میتوانیم آنها را به ترتیب دلخواه اعمال کنیم و به نتیجه نهایی برسیم.
یکی از بزرگترین چالشهای این روش، زیاد شدن eventها و در نتیجه کند شدن سیستم است چون هربار بخواهیم وضعیت سیستم را به دست بیاوریم باید تعداد زیادی event را دنبال کنیم.
Model information about activity in the domain as a series of discrete events. Represent each event as domain object.
Eric Evans, Domain-Driven Design Reference
یکی دیگر از مشکلاتی که وجود دارد این است که اگرچه ما می توانیم به تاریخچهی وضعیتها و تغییرات در زمانهای مختلف دسترسی داشته باشیم، اما اتفاقاتی که موجب این تغییر شده نمیدانیم و فقط میتوانیم آن را حدس بزنیم، مثلا اگر موجودی حسابی کم شده باید حدس بزنیم بابت برداشت بوده یا پاس شدن چک یا قسط وام یا ... یعنی میدانیم برداشتی انجام شده اما نمیدانیم این برداشت بابت چه بوده و جزئیات بیشتر را از دست دادهایم.
منابع:
به طور خلاصه، micro front-end، یک سبک طراحی و تلاشی برای پیادهسازی و گسترش الگوی micro serviceها در برنامهنویسی سمت کاربر است. اما ابتدا خوب است مزیتهای میکروسرویس را در همان سمت سرور مرور کنیم. به کمک میکروسرویس کد هر سرویس کوچکتر و قابل مدیریتتر بود و هر تیم میتوانست برای خود و به شکل مستقل یک یا چند سرویس را نگهداری کند در حالی که بدون میکروسرویس، یک سایت یکپارچهی کامل (یا همان monolithic) توسعه داده میشود اما نگهداری این تکه کد یکپارچه برای برنامهنویسان سخت بود.
با میکروسرویس (و بدون میکروفرانتاند) به مزیتهای گفته شده فقط در سمت بکاند دست یافتهایم اما تیم های فرانتاند هنوز مشکل کار بر روی یک سیستم بزرگ یکپارچه با مدیریت دشوار را دارند. در عوض میکروفرانتاند میگوید یک تیم که برنامهنویسانی با مهارتهای گوناگون (مثلا فرانتاند و بکاند) را دارد داشته باشیم و در همین تیم یک قابلیت مدیریت و پیادهسازی شود. علاوه بر مزیتهای گفته شده، در این حالت امکان این وجود دارد که قسمتهای مختلف سایت با چارچوبهای نرمافزاری متفاوتی نیز توسعه داده شوند، برای مثال یک تیم علاقه دارد vue.js را به کار برد و تیم دیگر انگولار را ترجیح میدهد.
چالشی که در این حالت وجود دارد، حفظ یکپارچگی بین قسمتهای مختلف وبسایت است. چرا که برای جدا طبق اصول میکروفرانتاند، تکههای کوچک باید حداقل کد ممکن را با یکدیگر به اشتراک بگذارند و از state سراسری باید پرهیز شود.
منبع:
بدون برنامهنویسی هم میتوان برنامهنویسی کرد؟ پلتفرمهای low code تلاش میکنند به این سوال جواب مثبت دهند. به این ترتیب کسانی که تجربه برنامهنویسی کمی دارند یا حتی اصلا تجربه برنامهنویسی ندارند با کمک رابط کاربری گرافیکی (مثلا شکلها و فلشها و ارتباطشان) روندی که در نظر دارند را پیادهسازی کنند.
شاید در ابتدا به نظر برسد که این روشها کارآمد نیستند و در نهایت برای کودکان مناسب هستند (مثلا زبان برنامهنویسی scratch) اما اینطور نیست. با کمک همین ابزارهای بدون کد و یا نهایتا با افزودن مقدار کمی برنامهنویسی، میتوان به برنامههای کاربردی دست یافت. همچنین در این صورت محدود به نیرویانسانی برنامهنویس خبره برای توسعهی سیستم نیستیم و برنامهنویسان مبتدی، متخصصان در حوزههای مختلف (مثلا آمار یا کشاورزی) که نیاز برنامهنویسی دارند یا حتی کاربران نهایی سیستم میتوانند در ساخت سیستم مشارکت کنند و آن چه در ذهنشان است را وارد دنیای صفر و یک کنند.
از مزایای سیستمهای low-code، علاوه بر مشارکت نیروهای وابسته ولی غیر برنامهنویس، میتوان به خلوت شدن سر برنامهنویسان برای قسمتهای دیگر سیستم، تولید سامانههای تستشده و قابل اطمینان و امن اشاره کرد. همچنین یکی از مهمترین ویژگیها، هدر ندادن زمان و انرژی است چرا که هرکس میتواند خودش پیادهسازیای از ایدهی مدنظرش داشته باشد و دیگر نیاز نیست برنامهنویس استخدام کند و مدت زمان زیادی منتظر بماند.
خوب است به عنوان مقایسه، پلتفرمهای No Code را هم بشناسیم. در این سامانهها همهی کار طراحی توسط همان رابط گرافیکی انجام میشود و سامانه به کمک کار برنامهنویسان قابل گسترش نیست. اگرچه شاید این مورد ترس کاربران مبتدی را حل کند چرا که هیچوقت قرار نیست مجبور شوند تا کد بنویسند، ولی در عمل Low Codeها مشکل مهم قابل گسترش نبودن را حل کردهاند و سامانهی طراحی شده به کمک Low Code آیندهدار خواهد بود. شاید با اغراق بتوان گفت low code برای کسانی که آشنایی با برنامهنویسی دارند یا حداقل دسترسی به برنامهنویسی دارند کمک کننده خواهد بود که سرعت و کیفیت کارشان را در توسعهی یک سیستم واقعی و پیچیده بهبود دهند ولی no code برای کسانی که اصلا تجربه برنامهنویسی ندارند مناسب است تا بتوانند یک چیز ساده پیاده کنند.
منابع:
برای فهمیدن ESB یا Enterprise System Bus اول باید خود مفهوم Bus را در کامپیوتر متوجه شویم.
اولین تصویری که از Bus به ذهن خود من متبادر میشود اما اگرچه ذهن خلاق شما میتواند اشتراکات پیدا کند ولی این اتوبوس به باس در کامپیوتر ارتباطی ندارد.
اما دوستانی که دانش سختافزاری بیشتری داشتهباشند میدانند که Bus در کامپیوتر به تعدادی سیم میگویند که از همگی از یک مبدا واحد به یک مقصد واحد میروند. ممکن است در کامپیوتر تعدادی باس خارجی (مثل تصویر زیر) داشته باشیم که مثلا به کارت گرافیک و .. متصل شوند و یک با بین پردازنده و مموری اصلی باشد.
اما باس نرمافزاری که اینجا مورد صحبت است این هم نیست! حتی به توپولوژی باس شبکه نیز ارتباطی ندارد. بلکه باس نرمافزاری بین دو یا چند نرمافزار ارتباط برقرار میکند. بهترین مثالش هم همان باس سرویس سازمانی است. این مدل از باسها، زمانی به کار میآیند که چند نرمافزار مختلف داریم و میخواهیم آنها را به هم متصل کنیم. مثلا در حالت سازمانی، چند سرویس متفاوت داریم که از خدمات یکدیگر استفاده میکنند، حالا به جای اینکه هر دوتای اینها، یا همهی آنها که به هم نیاز دارند متصل به هم وصل باشند، هرکس به باس متصل است و همهی اتصالات از این طریق مدیریت میشوند.
مهمترین کاربردی که میتواند داشته باشد این است که ارتباط مستقیم بین سرویسهای مختلف از بین میرود و به این ترتیب دیکاپلینگ اتفاق میافتد. همچنین میتواند بین پروتکلها نیز تبدیل انجام دهد، مثلا اگر یک سرویس به rest نیاز دارد ولی سرویس دیگر امکان عرضهی soap را دارد، یک باس میتواند این تبدیل فرمت را انجام دهد، حتی بعضی باسها امکان اسکریپتنویسی دارند. از خدمات دیگری که ممکن است باسها ارائه دهند میتوان به مدیریت ورژنهای api ها و مانیتور کردن ارتباطات اشاره کرد.
لازم به ذکر است که کاربرد عمدهی این باسها در معماری مبتنی بر سرویس (service oriented) است که سرویسهای متفاوتی در سیستم وجود دارند و هریک میتوانند از دیگران خدمت بگیرند.
منابع:
یکی از ابزارهایی که به نیاز API Management پاسخ میدهد، API Gateway است. این ابزار اینقدر مهم است که کمتر سرویس سازمانیای را میتوان یافت که بدون یک API Gateway مستقر شده باشد. این ابزار به نیازهای مختلفی مثل محدود کردن سرعت درخواستها، ارائهی آمار و ارقام و بررسی و تایید هویت کاربر می تواند پاسخ دهد. حتی ممکن است این gateway به یک سیستم دیگر نظیر پرداخت متصل باشد و بررسی کند که آیا کاربر اعتبار لازم را دارد یا خیر.
در واقع، یک نگاه به gateway، میتواند یک پروکسی معکوس باشد که تا حدی پیادهسازی پشت API را از دید کاربر بیرونی مخفی کند، مثلا مانند مثال پرداخت که گفته شد ممکن است چند سرویس با هم ترکیب شوند یا اصلا پیادهسازی نسخه جدید عوض شده باشد ولی کاربر بتواند از نسخهی قدیمی به همان شکلی که قبلا استفاده میکرد استفاده کند. همهی اینها به این دلیل میسر میشوند که کاربران به جای کار کردن مستقیم با سروری که خدمت مورد نظرشان را ارائه میدهد، به یک واسط (پروکسی معکوس) متصل شوند و مدیریت لازم آنجا انجام شود.
به عنوان جمعبندی میتوان گفت یک api gateway، خدماتی نظیر مانیتورینگ را به کاربران بیزینسی سامانه میدهد و برای کاربران بیرونی سامانه، عملیات ترکیب نتیجهی کار میکروسرویسها، تبدیل پروتوکل پیامها و ارائهی خدمات مختلف برای فرانتهای مختلف (مثلا وبسایت یا اپلیکیشن اندروید) اشاره کرد.
منابع:
سیستم BPMS ، یک سیستم برای اتوماتیک کردن و مستند کردن و آنالیز کردن پروسههای بیزینس است. اما در ابتدا باید دید BPM چیست که حالا یک سامانه برای مدیریت و خودکار کردن آن میخواهیم؟
خود BPM عملیاتی است که شرکتها انجام میدهند تا پروسههای کسب و کار خود را بهبود دهند. این عملیات شامل شناسایی اتفاقات، مستند کردن و بهبود دادن پروسه هاست.
منابع:
https://www.integrify.com/what-is-bpms/
یک سامانهی BRMS، هدفش مدیریت قوانین سازمان است اما اصلا قوانین سازمان چه چیزهایی هستند؟
سازمان وقتی میخواهد تصمیمی بگیرد از اطلاعات زیادی استفاده میکند مثلا اطلاعات مشتریان و فروش و .. اما این اطلاعات به چه طریقی تبدیل به تصمیم میشوند؟ راههای مختلف وجود دارد مثلا استفاده از هوش مصنوعی یا قوانین سازمان (همین BRها)
پسBRMS یک ابزار است که به سازمان این امکان را میدهد که قوانینش را تعریف کرده، نگهداری و مدیریت و بهینه و از همه مهمتر اجرا کند، یعنی با کمک منطقی که تعریف میشود تصمیمات به شکل خودکار گرفته شوند.
منابع:
https://research.aimultiple.com/business-rules-management-system/
https://www.processmaker.com/blog/what-is-a-business-rules-management-system-brms/
مسئلهی تولیدکننده و مصرفکننده را حتما به یاد دارید. یک تولید کننده داریم که با نرخی پیام تولید میکند و یک مصرفکننده داریم که با یک نرخ دیگری پیامها را مصرف میکند. در این بین یک صف داریم که پیامها از زمان ارسال تا زمان مصرف شدن باید داخل آن قرار داشته باشند چرا که تولید کننده و مصرف کننده مستقیما به هم متصل نیستند. حالا حتی ممکن است چند مصرف کننده یا چند تولید کننده به جای یکی داشته باشیم. در این صورت که اصلا امکان اتصال به هم را نخواهند داشت! در این مثال صف و در دنیای واقعی یک مسیج کیو (که همان صف پیامهاست) بین سرویسهای تولید کننده و مصرف کننده قرار میگیرد و مانند چسب آنها را به هم متصل میکند.
نکته دیگری که وجود دارد این است که چه میشود اگر یکی از دریافتکنندههای پیام با مشکل مواجه شود؟ یک صف خوب باید پیامهای آن را در خودش نگه دارد با بتواند به کار برگردد و بعد از آن پیامهایش را در اختیارش بگذارد، یا مثلا بسته به قواعدی آن پیامها را در اختیار یک مصرفکنندهی دیگر بگذارد.
در تصویر بالا به طور مثال چند تولید کننده داریم که همگی پیامهایشان را در یک صف میریزند تا بعدا توسط مصرف کننده استفاده شود. حالا اگر مصرف کننده کمی کُند کار کند یا اصلا مدتی در دسترس نباشد صف باید پیامها را در خود نگه دارد یا دوباره شرابط عادی شود.
در این بین پیامها چه چیزهایی هستند؟ به طور کلی محدویت خاصی روی آن ها نیست به جز اینکه ترجیح میدهیم اندازهشان کوچک باشد، مثلا اندازهی ۲۵۶ کیلوبایت برای یک پیام، یکی از قواعد رایج است، اما اگر نیاز به اطلاعاتی با حجن بالا داریم باید ابتدا آنها را در محلی ذخیره کنیم و URI آنها را به عنوان پیام به صف دهیم.
یکی از مثالهای صفها، برای فرستادن کوئری ها به دیتابیس است، به این شکل که کوئری ها در صف قرار میگیرند تا به تعداد مشخصی برسند و سپس با هم ارسال میشوند با همه با هم پردازش شوند، در این صورت کارایی دیتابیس بالا میرود به نسبت حالتی که جدا جدا و تکتک کوئری ها را گرفته و پردازش کند.
منابع:
https://www.howtogeek.com/devops/what-are-messaging-queues-and-how-do-you-use-them/
https://www.ibm.com/cloud/learn/message-queues
https://aws.amazon.com/message-queue/
تصویر زیر را ببینید، به یکی از مشکلات مهم توسعهی نرمافزار اشاره میکند. برنامهنویس کدی را مینویسد که بالاخره روی سیستم خودش کار میکند اما آیا روی سیستم مشتری یا سرورهای عملیاتی نیز کار میکند؟ باید کار کند ولی لزوما این اتفاق نمیافتاد! اما با کمک کانتینر کردن (که داکر یکی از ابزارهای مهم آن است) این مشکل حل میشود. یعنی برنامهنویس با نوشتن یک داکرفایل مشخص میکند دقیقا برنامه به چه محیط عملیاتیای نیاز دارد و در سییستم خودش نیز در همان محیط اجرا میکند، در سرور نیز همان محیط فراهم میشود و برنامه (انشالا) کار میکند.
اما مزیت بالا تنها مزیت این روش نیست. مزیت دیگر را باید در مشکلات مجازیسازی جستوجو کنیم. اما ابتدا خلاصه ای از مجازیسازی داشته باشیم. مجازیسازی به ما این امکان را میدهد که یک سرور فیزیکی قدرتمند را بین چند کاربر یا چند کار مختلف به اشتراک بگذاریم. کاربران خانگی معمولا در این حد از مجازیسازی بهره میبرند که در کنار سیستمعامل اصلی خود که بالاست و کار میکند یک سیستم عامل دیگر به شکل مجازی میآورند و از مزایای هردو کنار هم بهره میبرند. مثلا یک کاربر ویندوز می تواند به شکل مجازی لینوکس نصب کند و از آن برای برنامهنویسی استفاده کند. در سرورها نیز یک سرور قدرتمند را تبدیل به مثلا ۵ سرور مجازی با منابع محدود و مشخص میکنند و هر کدام را به یک کاربر اجاره میدهند. حتی ممکن است یک کاربر دو یا چند تا از آنها را اجاره کند تا برنامه و کاربرهای متفاوت را روی آنها اجرا کند. ویژگی خوب مجازیسازی این است که برنامهها و اتفاقات روی سرورهای مجازی مختلف اگرچه واقعا روی همان پردازنده و مموری یک سرور فیزیکی هستند، از یکدیگر جدا است و حتی از وجود همدیگر خبر ندارند.
اما مشکل بزرگ مجازیسازی، این است که در کنار یک hypervisor مثلا vmware که وظیفه مدیریت ماشینهای مجازی را دارد، به ازای هر ماشین مجازی یک سیستمعامل نیز در حال اجراست و سیستمعامل ذاتا سنگین و با سربار بالاست. کانتینریزشن در واقع تلاشی برای استفاده از یک هستهی مشترک سیستمعامل و جدا کردن برنامههای مختلف در قالب کانتینر است. یعنی مثلا یک ماشین لینوکسی داریم و چندین کانتینر داریم که هر کدام از همین کرنل لینوکس استفاده میکند و با کمک امکانات هسته مثل فضای نام و cgroups، کانتینرها از هم مستقل هستند و از وجود هم با خبر نیستند.
مزیت کانتینرها این است که با به اشتراک گذاشتن هستهی سیستمعامل، سربار بسیار کمتری دارند و از چند گیگابایت به چند مگابایت حافظه رسیدهایم و سرعت راهاندازی آنها نیز بسیار بالاتر است.
داکر به عنوان بازیگر اصلی حوزهی کانتینریزیشن، یک مکانیسم برای این مورد ارائه میکند که اگرچه تنها بازیگر نیست ولی رقایبش را تا حد زیادی کنار زده است. داکر با راهندازی پلتفرم ابری و فراهم کردن بستری برای به اشتراک گذاشتن imageهای متفاوت، کار را برای برنامهنویسان راحت کرده است.
منابع:
https://www.ibm.com/cloud/learn/containerization
https://www.ibm.com/cloud/blog/5-benefits-of-virtualization
https://blog.adamchalmers.com/kubernetes-problems/#containers
https://matt-rickard.ghost.io/what-are-containers/
https://www.ibm.com/cloud/learn/docker
فرض کنیم تقسیم برنامهمان به کانتینرها را خیلی خوب انجام دادیم و یک برنامهمان تبدیل به دهها کانتینر شد، اما حالا چی؟ برای استقرار به جای یک موجودیت که باید فعالش کنیم الان دهها مشکل داریم! حالا تصور کنید که CI هم داریم و به ازای هر کامیت برای ما یک کانتینر آمادهی اجرا میسازد، حالا از کجا بفهمیم کدام مجموعه از کانتینرها با چه تریبی باید اجرا شوند؟ با کمک رهبر کانتینرها
رهبر ارکستر چه میکند؟ تنظیم! اینجا نیز نیاز به رهبری برای تنظیم این همه کانتینر و سرور مختلف داریم. کوبرنتیز به عنوان یک ابزار، این کار را برای ما انجام میدهد، به او میگوییم چه ترتیبی از کانتینرها را در کجاها اجرا کن و این کار را میکند. حتی کارهای پیشرفتهتر و کاربردیای نیز انجام میدهد مثلا اینکه اگر یک کانتینر کرش کرد و دیگر کار نکرد آن را ریستارت میکند، یا مثلا با اضافه کردن replica از کانتینرهای موجود، موجب تقسیم بار کاری بین آنها میشود.
در اینجا خوب است به docker-compose نیز اضافه شود که یک ابزار بسیار سادهتر برای هماهنگسازی است که در زمانی کاربرد دارد که در حال توسعهی سیستم هستیم و میخواهیم فقط روی یک سرور سیستم را بالا بیاروریم و نه روی چندین سرور مجزا و به همین ترتیب سبک تر و بیامکانات تر است.
منابع:
https://blog.adamchalmers.com/kubernetes-problems/#container-orchestration
https://www.redhat.com/en/topics/containers/what-is-container-orchestration
https://www.ibm.com/cloud/learn/container-orchestration
لاگها برای ما بسیار مهم و حیاتی هستند، مثلا با کمک آنها میتوانیم سریعتر بفهمیم که منبع یک مشکل کجا بوده تا راحتتر بتوانیم آن را حل کنیم. اما مشکلی که داریم این است که حجم لاگها زیاد است و به راحتی مثلا با فایلهای متنی ساده و انتقال از طریق شبکه به روش معمولی نمیتوان به شکل مناسب از آنها استفاده کرد.
لازم به یادآوری است که در معماری میکروسرویس، ما چندین سرویس ریزدانهی مختلف خواهیم داشت که هر کدام برای خودش در کانتینر خودش لاگ میزند و پیدا کردن یک مشکل با بررسی همه ی لاگها که ترتیب زمانی هم لزوما ندارند اصلا آسان نخواهد بود. پس نیاز به یک مکانیسم مشخص برای بررسی لاگها خواهیم داشت.
استک Elastic یا همان ELK یکی از راههای مدیریت لاگ است. ELK در واقع به شکل عمومی تر برای مانیتور و بررسی زیرساخت استفاده میشود و به ما این امکان را میدهد که به شکل real-time لاگها را مدیریت و آنالیز کنیم. ELK استکی متشکل از ۳ ابزار دارد که اسم مخفف آن را نیز تشکیل داده اند: Elastic search و Logstash و Kibana. در این کاربرد Logstash لاگهای ورودی را دریافت و ادغام کرده و به الاستیک سرچ میفرستد. سپس الاستیک سرچ آنها را ایندکس میکند که قابلیت سرچ و آنالیز داشته باشند. سپس با کمک کیبانا و استفاده از یک زبان کوئری، میتوانید اطلاعات را از الاستیک سرچ استخراج کنید، مثلا برای نمودارهای گرافیکی و ...
منابع:
https://www.educba.com/log-management-tools/
https://www.cprime.com/resources/blog/log-management-elk-and-why-you-should-care/
https://sematext.com/guides/elk-stack/
آیا سیستمها همه سالم هستند و کار میکنند؟ نمیدانم اجازه بده تک تک همه آنها را پینگ بگیرم. یا اصلا پینگ هم دارند، آیا واقعا زنده و عملیاتی هستند؟ بگذار یک درخواست هم با postman بفرستم. شاید این رویه در یک شرکت کوچک امکانپذیر باشد ولی در سازمانی با تعداد کاربران بالا معموال امکانپذیر نیست، برای همین نیاز به ابزاری است که به شکل مداوم از فعال و در حال کار بودن سیستمها اطمینان حاصل کند و در صورتی که مشکلی وجود دارد سریعا بتواند گزارش کند.
برای مانیتور کردن معمولا موارد زیر مدنظر است: بالا بودن سرورها، کارایی شبکه، بالا بودن کانتینرها، بالا بودن زیرساختهای ابری (چه پابلیک و چه پرایوت) و در نهایت بالا بودن خود اپلیکیشن.
در این بین ابزارهای زیادی وجود دارند که براساس معیارهای مختلف مانند اسکیلیبل بودن، رابط کاربری، real-time بودن و غیره میتوانیم از بین آنها انتخاب کنیم. به عنوان مثال prometheus یک ابزار متنباز برای آنالیز دیتای سریزمانی است که با کمک جعبهابزار داخل خودش امکان مانیتورینگ سرورها را میدهد.
منابع:
https://devopscube.com/best-opensource-monitoring-tools/
https://prometheus.io/docs/introduction/overview/
یکی از مراحل مفید و مهم در بررسی سورسکد یا همان تست جعبهی سفید، اجرای یک ابزار بررسی کد به شکل ایستا روی سورسکد است. منظور از static یا همان ایستا این است که در حالتی که کد در حال اجرا نیست و فقط روی سورس کد این بررسی انجام میشود مثلا اطلاعی از مصرف مموری یا پردازنده در زمان اجرا نداریم.
از مزیتهای این روش میتوان به اجرای نسبتا سریع (به نسبت انسان) و خودکار اشاره کرد که امکان اجرای مرتب مثلا شبانه را میدهد. همچنین در پیدا کردن برخی مشکلات مثلا SQL injection یا سرریز بافر میتواند خوب عمل کند. اما مشکلاتی که دارد این است که بسیاری از مشکلات را نمیتواند گزارش دهد مثلا استفادهی نامناسب از امکانات رمزنگاری، کنترل نامناسب یا ناکافی دسترسی، و ... اگرچه این موارد در حال بهبود است ولی همچنان بسیار جای کار دارد. همچنین در طرف مقابل مقدار زیادی false positive وجود دادر که باعث میشود اعتماد برنامهنویس به این خطاها کاهش یابد. همچنین در مواقعی که نمیتوانند کد را کامپایل کنند (چرا که مثلا کتابخانههای صحیح را پیدا نمیکنند) دچار مشکل میشوند.
سونارکیوب یکی از ابزارهای مطرح این حوزه است که به شکل آنلاین و سریع امکان بررسی سورسکد به زبانهای مختلف را میدهد. همچنین مانند بسیاری از ابزارهای لینک دیگر امکان افزوده شدن به IDEها و ادیتورها به عنوان پلاگین را دارد که چرخهی بازخورد برنامه نویسان را سریع تر میکند.
منابع:
https://owasp.org/www-community/controls/Static_Code_Analysis
https://en.wikipedia.org/wiki/SonarQube
یکی از اهدافی که برای DevOps ذکر میشود، کاهش زمان مابین توسعهی نرمافزار توسط برنامهنویس و استقرار آن است، در واقع جدا از DevOps هم این یک هدف در توسعهی نرمافزار است. مثلا در متودولوژی مدرن اجایل نیز گفته میشود که «به شکل مستمر ارزش آفرینی کنید». در دنیای واقعی با کمک ابزارهای CI/CD این اتفاق میافتد. CI یا همان continues integration بخش اول این روال است که باعث میشود همهی کد کنار هم قرار گرفته کامپایل و بیلد و البته تست شود. تستها میتوانند از یونیتتست تا تستهای پیشرفته تر باشند.
در اینجا اما تمرکزمان روی CD (در اینجا مخفف continues delivery) است. CD یک تکرار و هدف است برای از اتوماتیکسازی برای افزایش سرعت و کاهش تناوب عرضهی نسخهی جدید کد به مشتری. به نوعی دنبالهی روال CI است که کد جدیدی که نوشته شد و از هر نظر بررسی شد، تبدیل به یک artifact قابل deploy شود، در مثال جاوایی یک jar همراه با همهی پیشنیازها ایجاد شود تا به راحتی قابل استقرار باشد.
در اینجا خوب است اشاره شود که CD میتوانند به معنی continues deployment نیز باشد که هدف والاتری است و رواج کمتری دارد. این هدف به این شکل است که علاوه بر تست نرم افزار (در CI) و ساخت artifact قابل دیپلوی (در مرحلهی continues deiivery) واقعا نسخهی جدید به دست مشتری هم برسد. این مورد اگرچه جالب به نظر میآید اما میتواند برای کسبوکار ترسناک باشد و برای همین رواج کمتری دارد. همچنین راههای بینابینی مثلا استقرار روی یک سرور staging نیز راه حل مناسبی به نظر میرسد.
منابع:
https://medium.com/agile-insights/deliver-value-continuously-a-modern-agile-guiding-principle-712ef9db2225
https://www.redhat.com/en/topics/devops/what-is-continuous-delivery
https://learn.microsoft.com/en-us/devops/deliver/what-is-continuous-delivery
حتما پیش آمده که برای لاگین در یک سایت، ایکون لاگین با گوگل را دیدهاید و روی همان زدهاید، چرا که دیگر نیاز نیست در این سایت هم یک اکانت بسازید و رمز قوی بگذارید و ... حتی خود همین ویرگول با همهی نقصهایش (مثل سرعت پایین ادیتور بعد از طولانی شدن مطلب) این امکان را دارد. به شکل فنی، روال کار به این صورت است که وقتی کاربر در یک سرویس مرجع که SSO یا فراهم میکند مثل گوگل یا گیتهاب لاگین میکند، میتواند به سایتهای مستقل با همان ID لاگین کند بدون اینکه پسور خاصی برای آن سایت جدید داشته باشد.
در سادهترین حالت ممکن، میتوانیم با اشتراک گذاشتن کوکیها در یکسری سایت با دامنهی یکسان، این قابلیت را عملی کنیم ولی در حالت ایدهآل نباید سایتها به هم ارتباط خاصی داشته باشند.
از مزایای این روش میتوان به حذف شدن مشکلات پسوردها اشاره کرد (مثلا فراموشی پسورد، لو رفتن دیتابیس پسوردها، یکسان بودن پسورد کاربران بین سایتهای مختلف) همچنین بهبود تجربه کاربری و صرف زمان کمتر برای کاربر و همچنین افزایش امنیت کلی سایت اشاره کرد.
منابع:
https://en.wikipedia.org/wiki/Single_sign-on
https://cloud.google.com/architecture/identity/single-sign-on
در یک معماری سرویسگرا یا میکروسرویس، تعداد سرویس داریم که برای عملکرد صحیح نیاز به سرویسهای دیگر دارند، پس طبیعتا باید هر سرویس با سرویسهای دیگر (یا تعدادی سرویس دیگر) بتواند ارتباط داشته باشد. service mesh یک ابزار برای کنترل و مدیریت این است که سرویسهای مختلف چطور دیتا با هم تبادل میکنند. در واقع service mesh به شکل یک لایهی زیرساختی است که در کنار برنامه قرار میگیرد. این لایهی زیرساختی همچنین میتواند مشخص و مستند کند که قسمتهای مختلف چطور با هم در ارتباط هستند در نتیجه مدیریت و بهینه کردن آنها ساده تر میشود.
اما چرا اصلا نیاز به چنین چیزی داریم؟ مگر خود هر سرویس نمیتواند به شکل مستقیم با سرویس مقصد خود ارباط برقرار کند؟ البته که میتواند، در این صورت باید مشخصات سرویس مقصد را در خود سرویسِ سرویسگیرنده داشته باشیم تا بتواند به شکل مناسب متصل شده و اطلاعات تبادل کند ولی با زیاد شدن میکروسرویسها و پیچیده شدن ارتباطشان، ترجیح داده میشود که از چیزی برای مدیریت این پروسه استفاده شود. برنامههای بزرگ ابری معمولا از این راهکار برای مدیریت استفاده میکنند تا میکروسرویسهای مجزا به عنوان یک کل یکپارچه سرویس دهند.
منابع:
https://www.redhat.com/en/topics/microservices/what-is-a-service-mesh#don%E2%80%99t-microservices-already-do-this
https://sweetcode.io/service-mesh-service-fabric-service-bus-what-does-mean/