یک) Modular Monolithic: ترکیبی از اصول طراحی modular و monolithic و هدف از آن، استفاده از سادگی معماری monolithic و انعطافپذیری (flexibility) و مقیاسپذیری (scalability) معماری modular است. این نوع معماری بین معماری monolithic و microservice قرار میگیرد و به نوعی، حد وسط آنها است. در این معماری، تمام ارتباطات درون یک process انجام میشوند و تنها یک فایل برای deploy وجود دارد؛ اما درون این فایل، جداسازی منطقی (نه فیزیکی) براساس ویژگی (feature) انجام شده است و برنامه به چندین ماژول مستقل و loosely coupled تقسیم شده است که از طریق رابطهایی (interface)، با یکدیگر ارتباط دارند. این ماژولها در این معماری، وابستگی بیشتری به یکدیگر نسبت به معماری microservice دارند اما نسبت به معماری monolithic، بسیار مستقلتر هستند. از مشکلات معماری monolithic، وابستگی زیاد بخشهای مختلف آن به یکدیگر (tightly coupled) و سختی توسعه همزمان و مستقل بخشهای نرمافزار و بهرهوری از متودولوژی Agile است که این مشکلات در معماری Modular Monolithic، به دلیل وابستگی کم بین ماژولها (loosely coupled)، از بین رفته اند. یکی دیگر از مشکلات بزرگ معماری monolithic، نیاز به compile مجدد کل برنامه در صورت تغییر یک تابع کوچک است که این مشکل نیز در modular monolithic با طراحی modular برطرف شده است.
دو) AWS: پلتفرم رایانش ابری شرکت آمازون است که خدمات ابری مانند توان پردازشی، فضای ذخیرهسازی، یادگیری ماشین و ... را به صورت Pay-as-you-go میدهد که همین pay-as-you-go، قابلیت autoScale کردن اپلیکیشن را فراهم میکند؛ این قابلیت به این صورت است که در زمان مصرف و درخواستهای بالا، توان پردازشی بیشتری به اپلیکیشن داده میشود و در زمان مصرف و درخواستهای کم، توان پردازشی کاهش یافته تا هزینهها زیاد نشوند. (البته این خدمات به ایرانیها داده نمیشود). Amazon EC2 (Elastic Compute Cloud) و AWS Lambda از جمله خدمات پردازشی این پلتفرم هستند که Amazon EC2، اجازهی اجرای سرورهای مجازی با ظرفیت و قدرتهای مختلف را به کاربران میدهد و سرورهای آن دارای availability بسیار بالا هستند و AWS Lambda هم پردازش Serverless را ارائه میدهد (توضیحات این مفهوم در ادامه متن آمده است). از جمله خدمات ذخیرهسازی در این پلتفرم میتوان Amazon S3 (Simple Storage Service) و Amazon EBS (Elastic Block Store) را معرفی کرد که مورد اول بسیار معروفتر است و پایداری 99.999999999 دارد و Amazon RDS (Relational Database Service) و Amazon DynamoDB از جمله خدمات دیتابیس این پلتفرم هستند که اولی برای دیتابیسهای رابطهای و دومی برای دیتابیسهای NoSQL بکار میرود.
سه) API-First Approach: این رویکرد به این صورت است که به طراحی، مستندسازی و پیادهسازی APIها اولویت بالاتری داده میشود و این اعمال در ابتدای فرایند توسعه نرمافزار، انجام میشوند و سپس، باقی کد با توجه به این APIها نوشته میشوند. با این رویکرد، هزینه توسعه برنامهها کاهش مییابد (به دلیل استفاده مجدد از APIها و عدم نیاز به طراحی مجدد برای اپلیکیشنهای جدید) و دست توسعهدهندگان برای انتخاب روش پیادهسازی اپلیکیشنهایی که از این APIها استفاده کنند، باز است و حتی میتوانند انتخاب framework و زبان را به تاخیر بیاندازند و در نهایت، برای تمام دستگاهها، پلتفرمها و سیستمعاملها برنامهای با تجربه کاربری (UX) مناسب بسازند. این روش همچنین به دلیل داشتن قابلیت تولید اتوماتیک API و آسان بودن اضافه کردن سرویسها و تکنولوژیهای جدید به برنامه، Time to Market سریعتری دارد (سریعتر میتوان آن را عملیاتی و منتشر کرد). در این روش، میتوان همزمان توسعه بخش frontend و backend را انجام داد؛ دلیل این امر، استفاده از mock api است که در اصل مقادیری است که از API واقعی قرار است گرفته شوند.
چهار) NoSQL Databases: دیتابیسهای NoSQL (Not Only SQL) برای دادههای بدون ساختار (ساختار آنها را نمیشود مانند دیتابیسهای SQL از قبل مشخص کرد) استفاده میشوند و از دیتابیسهای SQL و رابطهای، بسیار مقیاسپذیرتر و منعطفتر هستند و استفاده از آنها بسیار آسانتر است. این نوع دیتابیسها میتوانند به صورت document (ذخیره به صورت JSON)، جفتهای Key-Valueای، wide-column (استفاده از ستونهای dynamic و تغییرپذیر) و گراف (بیشتر برای ذخیره اطلاعات درمورد افراد یا مکانها و ارتباط بین آنها) بیایند. بعضی از زمانهایی که این نوع دیتابیس باید استفاده شود عبارتند از: در توسعههای سریع و Agile، زمانی که دیتا با ساختار نامشخص و قابل تغییر داریم، زمانی که حجم زیادی داده داریم و ...؛ مثلاً برای نگهداری اطلاعات یک محصول در دیجیکالا، بهتر است از این نوع دیتابیسها استفاده شود؛ چون اطلاعات محصولها، ساختار مشخصی ندارند (که بخواهیم از دیتابیسهای SQL و جداول رابطهای استفاده کنیم) و ممکن است نیاز به تغییر داشته باشند.
پنج) Serverless Architecture: معمولاً از نوع Faas است (Function as a service) و به این صورت است که مدیریت و نگهداری سرورها توسط سرویسدهنده ابری (مثلاً AWS) انجام میشود و توسعهدهندگان دیگر درگیر نگهداری و مدیریت سرورها به طور مستقیم نمیشوند و روی کد خود تمرکز میکنند و برای مدیریت و ارتباط با سرورها، تابعهای کوچکی مینویسند که هرکدام از این تابعها، با یک رویداد (Event) یا درخواست (Request)، فعال شده و اجرا میشوند و عمل مورد نیاز را انجام میدهند. این تابعها stateless هستند معمولاً زمان اجرای کوتاهی دارند و تنها برای انجام یک عمل خاص، مثلاً آپلود فایل، اجرا میشوند و سپس پایان مییابند. یکی از مشکلات این روش cold start است که به تاخیر در راهاندازی اولیه و اجرای تابعها در صورتی که مدتی صدا زده نشوند، اشاره دارد. هزینهها در این روش معمولاً به صورت pay-as-you-go است و کاربران با توجه به منابعی که برای اجرای تابعها مصرف کردهاند، پول میدهند. همچنین این پلتفرمها معمولاً دارای Automatic Scaling هستند و با توجه ترافیک ورودی، منابع و توان پردازشی را مشخص میکنند. از نمونه پلتفرمهای معروف Serverless میتوان به AWS Lambda اشاره کرد.
شش) Domain Driven Design: این روش تاکید بر این موضوع دارد که در ابتدای طراحی و ساخت سیستمهای نرمافزاری، روی درک و سپس مدلسازی دامنه کسبوکار (Business Domain) تمرکز کنیم و با استفاده از الگوهایی که این روش ارائه میدهد، نرمافزاری بسازیم که تمام نیازمندیهای business را برآورده کند. این روش برای کسبوکارهایی که قوانین پیچیدهای دارند، کاربرد دارد. برای انجام این روش، حتماً به متخصصان آن کسبوکار نیاز داریم و بدون آنها، انجام این روش امکانپذیر نیست. یکی از مواردی که این روش به انجام آن تاکید دارد، استفاده از زبانی مشترک بین افراد فنی (توسعهدهندگان و مهندسان) و افراد غیرفنی (افراد آن کسبوکار) است که باعث میشود ارتباط بهتری بین این افراد برقرار شود (با استفاده از در آوردن لغات و اصطلاحات تخصصی کسبوکار و قرار دادن آنها در سندی به نام Glossary). از این زبان مشترک در طراحی و پیادهسازی و حتی مستندسازی بخشهای مختلف نرمافزار استفاده میشود.
هفت) Hexagonal Architecture: به آن Ports and Adapters هم میگویند. این معماری میگوید که بهتر است سیستم طوری طراحی شود که منطق کسبوکار (Business Logic) از باقی مسائل مانند پایگاه داده، رابط کاربری و ...کاملاً جدا باشد. در این روش منطق کسبوکار همان شش ضلعی است و از وجود بقیه componentها بیخبر است (یعنی اصلاً به آنها وابسته نیست) و این componentها در portهای اطرافش با استفاده از Adapterها به آن وصل میشوند و مقدار میفرستند یا دریافت میکنند. Portها در اصل رابطهایی (interface) هستند که راه ارتباط با اپلیکیشن (منطق کسبوکار) را باز میکنند (شکل کلی ارتباط یعنی تابعهای abstract درون آن است). Adapterها پیادهسازی این Interfaceها هستند که باعث میشوند ارتباط بین منطق کسبوکار (که اصل اپلیکیشن است) و بخشهای دیگر برقرار شود. در این معماری دو بخش driving side و driven side داریم که اولی ارتباط با اپلیکیشن را شروع میکند (مثلاً ورودی کاربر که به اپلیکیشن داده میشود) و دومی رفتاری است که دستورش از طرف اپلیکیشن میآید؛ مانند گرفتن اطلاعات کاربر از پایگاه داده. یکی از دلایل نمایش شکل به صورت ششضلعی، مشخص شدن تفاوت این دو بخش است.
هشت) Event Sourcing: به این صورت است که به جای ذخیرهسازی وضعیت (State) سیستم، دنبالهای از رویدادها (Event)هایی رخ دادهاند را ذخیره میکنیم و وضعیت سیستم را از روی اجرای این رویدادها در میآوریم. تمام این رویدادها درون Event log ذخیره میشوند و به قدری اطلاعات دارند که بتوان از روی آنها، وضعیت برنامه را بدست آورد. نکته مهم درمورد این رویدادها این است که این رویدادها، غیرقابل تغییر هستند (immutable) اما میتوان با استفاده از رویدادهای جدیدتر، اثر آنها را خنثی کرد. یکی از مزایای event sourcing این است که چون تمام رویدادها و تغییرات روی stateها ذخیره میشوند و state در تمام لحظات را میتوان با استفاده از اجرای به ترتیب رویدادها بدست آورد (اصطلاحاً به این عمل Temporal Query میگویند)، عمل دیباگ کردن بسیار آسان میشود. یکی از مثالهای معروف برای برنامههایی که از این قابلیت استفاده میکنند، برنامههای version control مانند Git هستند که دائماً از Temporal Queryها استفاده میکنند تا وضعیت برنامه را در زمانهای مختلف بدست آورند.
نه) Low code platforms: اینها پلتفرمهایی هستند که اجازه تولید اپلیکیشنها را با حداقل میزان کد و برنامهنویسی میدهند و عمل توسعه را سریعتر و آسانتر میکنند. این پلتفرمها معمولاً یک محیط گرافیکی دارند که قابلیت drag and drop دارد و میتوان با استفاده از این قابلیت، بخشهایی از برنامه را طراحی کرد و ساخت. سطح abstraction در این پلتفرمها بسیار بالا است و توسعهدهندگان عملاً با بخشهای فنی کمتری روبرو هستند و اکثر کارها توسط این پلتفرم انجام میشوند که این موضوع باعث میشود افراد غیرفنی هم بتوانند از طریق این پلتفرمها برنامه بسازند. از مزایای این پلتفرمها میتوان به توسعه سریعتر برنامهها اشاره کرد که در مواقعی که میخواهیم سریع MVP برنامه را بسازیم، بسیار مفید و کاربردی هستند.
ده) Business Process Management Systems: BPM یا همان Business Process Management یعنی تغییر و بهبود فرایندهای کسبوکار (Business Process) به شکل سیستماتیک و با یک سری گامهای مشخص و BPMSها، نرمافزارهایی هستند که اجازه این کار را میدهند؛ یعنی این نرمافزارها امکان طراحی و مدلسازی فرایندهای کسبوکار (مثلاً با کشیدن BPMN)، اجرا و پیادهسازی مدل طراحی شده، نظارت بر و گزارشگیری از مدلهای اجرا شده و بهینهسازی با توجه به گزارشها را میدهند و از مزایای آنها میتوان به سریعتر شدن Time to Market (چون مدلسازیها و استخراج فرایندها به صورت خودکار و توسط ابزار انجام میشوند) اشاره کرد. همچنین با استفاده از قدرت آنالیز و نظارتی که این نرمافزارها به ما میدهند، میتوان بسیار آسانتر گلوگاهها (Bottleneck) و مشکلات در فرایندها را پیدا کرد و فرایندهای دیگری برای رفع آن مشکلات طراحی و پیادهسازی کرد.
یازده) Message Queue (such as Kafka and RabbitMQ): به نحوی میتوان گفت همان مسئله تولیدکننده – مصرفکننده را پیادهسازی میکنند که تولیدکننده همان اپلیکیشن Client است و پیامی را تولید میکند و در صف قرار میدهد و مصرفکننده که به بافر (همان صف یا Queue) وصل میشود، آن پیام به صورت آسنکرون دریافت و مصرف میکند. این عمل باعث میشود که بتوان در اپلیکیشن Client، بعد از تولید پیام، جلو رفت و منتظر پاسخ نماند و بعداً با تکنیکهایی مانند polling یا همان سرکشی (در زمانهای مشخص چک کنیم آیا انجام شده است یا نه) و ...، پیشرفت کار را بررسی کنیم. یک روش دیگر نیز این است که در سمت Client، کار را تمام شده نشان دهیم و پشت سر باقی مراحل کار را از Queue بخوانیم و انجام دهیم؛ مثلاً در پست گذاشتن در توییتر، پست به سرعت در صفحه کاربر ارسال میشود و پیام موفقیت به او نشان داده میشود اما نمایش پست در feed افراد و دوستان او به صورت آسنکرون و با تاخیر انجام میشود. برای پیادهسازی این صفها از message brokerهایی (که مسئولیت ارسال، دریافت و ذخیرهسازی پیامها را دارند) مانند Kafka و RabbitMQ استفاده میشود که هرکدام معماری خاص خود را دارند و به نحوی کار را پیش میبرند؛ مثلاً RabbitMQ دارای Exchangeهایی است که producer (برنامه Client)، پیام تولیدی خود را به آنها میفرستد و آنها پیامها را به صفهای موردنظر مسیریابی میکنند و در نهایت Consumer پیامها را از صف میگیرد و مصرف میکند. این نرمافزارها در معماریهایی که از Event Sourcing استفاده میکنند، بسیار استفاده میشوند و میتوان از آنها برای پیادهسازی Load Balancing (تقسیم کار و درخواستها بین چندین مصرفکننده و سرور) استفاده کرد. همچنین از MQ در معماریهای microservice و serverless هم به وفور استفاده میشود.
دوازده) Container orchestration (such as Kubernetes): برای خودکار کردن اعمال استقرار (Deployment)، مقیاسبندی (Scaling) و مدیریت اپلیکیشنهایی که توسط ابزارهایی مانند Docker، به اصطلاح Containerized شدند؛ یعنی خود اپلیکیشن و تمام وابستگیها و نیازمندیهایش کنار هم قرار گرفتهاند تا اجرای آن اپلیکیشن در تمام محیطها آسان باشد. وقتی تعداد این containerها زیاد میشود، به ابزاری برای مدیریت آنها نیاز داریم. مثلاً upgrade کردن تعداد زیادی container با استفاده از این ابزار به راحتی نوشتن در یک فایل است و باقی کارها به صورت خودکار و با توجه به تنظیمات قرار داده شده در فایل انجام میشوند و ابزار سعی میکند به وضعیتی که از آن خواستیم برسد. از دیگر کارهای این ابزار میتوان زمانبندی اجرا و توقف containerها، تخصیص منابع خودکار، نظارت بر containerها و استقرار آنها و upgrade کردن containerها اشاره کرد.
سیزده) Log Management Tools (such as ELK): این ابزارها برای مدیریت logهای تولیدی توسط سیستم بکار میروند و اطلاعات مفیدی در مورد کارایی سیستم و مشکلات و گلوگاههای آن به ما میدهند. با استفاده از این ابزارها، تمام logهای تولیدی توسط سیستم (در بخشهای مختلف مانند شبکه و ...) در یک مکان جمعآوری شده و فرمت آنها یکسان میشود (استانداردسازی) و سپس تحلیل میشوند تا اطلاعاتی در مورد سیستم بدست آید. بررسی Logها به صورت دستی بسیار کند و پرخطا است و به هیچ وجه Scalable نیست (یعنی با زیاد شدن logها و بزرگتر شدن برنامه، به مشکل میخوریم). یکی از مزایای این ابزارها، کاهش MTTR (Mean time to recovery) است و دلیل آن هم این است که با این ابزار، سریعتر logها بررسی میشوند و مشکلات کشف شده و حل میشوند. یکی دیگر از مزایای این ابزارها، کمک به واحد فروش برای تحلیل رفتار مشتری (اگر رفتار مشتری را از قبل log کرده باشیم) است. ELK یا همان ElasticSearch, Logstash, Kibana از معروفترین ابزارها برای مدیریت logها هستند که در آن ElasticSearch مسئولیت ذخیرهسازی و ایندکس کردن logها را برعهده دارد و همچنین قابلیت جستجو روی logها را به ما میدهد؛ Logstash مسئولیت پردازش اطلاعات درون logها و ارسال اطلاعات پردازش شده به ElasticSearch را دارد و Kibana محیطی گرافیکی برای نمایش اطلاعات استخراج شده از logها و جستجو به صورت گرافیکی و نمایش نمودارها و ... است که به ElasticSearch وصل میشود.
چهارده) Monitoring Tools (such as Prometheus): این ابزار روی وضعیت سیستم نظارت میکنند و اعدادی دریافت میکنند و پس میدهند که نشاندهنده وضعیت بخشهای مختلف سیستم هستند و با توجه به آنها میتوان وضعیت سختافزار و نرمافزارهای سیستم را بررسی کرد و روی آنها نظارت داشت تا مطمئن شویم که تمام بخشها به خوبی کار میکنند و دچار مشکل نشدهاند. همچنین میتوان با استفاده از این ابزار کارایی سیستم را بدست آورد، مصرف منابع را بررسی و با توجه به آن برای تخصیص منابع جدید برنامهریزی کرد، گلوگاهها و مشکلات امنیتی را شناسایی کرد و در مورد Availability یا در دسترس بودن سیستم هم نظر داد. این ابزار در صورتی که شرایط خاص از پیش تعریف شدهای رخ دهند یا عددی از آستانهای که از پیش تعریف شده است بگذرد، هشدار میدهند. از مواردی که عدد به آنها نسبت داده میشود و نظارت میشوند، میتوان میانگین زمان پاسخ (Average response time)، مصرف CPU، نرخ رخداد خطا و نرخ درخواستهای سرور و ... را نام برد و با استفاده از این اطلاعات، میتوان درمورد Availability یا در دسترس بودن، کارایی، امنیت و ... سیستم نظر داد.
پانزده) Static Code Analysis (such as SonarQube): لینترها زیرمجموعه آنها هستند (با هم یکی نیستند؛ البته گاهی به اشتباه به جای یکدیگر بکار میروند) و کارشان تحلیل خودکار کد بدون نیاز به اجرای آن است. این ابزارها کد را تحلیل و بررسی میکنند و دنبال مشکلات، حفرههای امنیتی (مثلاً SQL Injection اگر توسعهدهنده مقدار inputها را مستقیم در Query میگذارد)، استفاده از تابعهای مشکل دار و قدیمی و منسوخشده، کثیفی و تکرار کد و مشکلات style و ظاهری کد میگردند. درصورتی که این مشکلات برطرف نشوند، میتوانند در نگهداری کد (اضافه کردن ویژگیهای جدید) چالش ایجاد کنند و منجر به باگ شوند. این عمل (تحلیل خودکار کد) در حین کد زدن و در مرحله توسعه نرمافزار انجام میشود. این ابزارها هم ممکن است خیلی مواقع اشتباه کنند و false positive (چیزی که در اصل درست است اما غلط فرض شده است) و false negative (پیدا نکردن مشکلات) داشته باشند؛ به همین دلیل به code review و بررسی انسانی (توسعهدهنده) نیاز است. از جمله linterهای معروف میتوان به ESLint برای زبان جاوا اسکریپت اشاره کرد.
منابع:
https://www.fullstacklabs.co/blog/modular-monolithic-vs-microservices
https://www.techtarget.com/searchaws/definition/Amazon-Web-Services
https://www.karlancer.com/blog/aws/
https://www.nginx.com/resources/glossary/api-first/
https://swagger.io/resources/articles/adopting-an-api-first-approach/
https://www.mongodb.com/nosql-explained
https://en.wikipedia.org/wiki/NoSQL
https://en.wikipedia.org/wiki/Serverless_computing
https://www.cloudflare.com/learning/serverless/what-is-serverless/
https://www.datadoghq.com/knowledge-center/serverless-architecture/
https://redis.com/glossary/domain-driven-design-ddd/
https://en.wikipedia.org/wiki/Domain-driven_design
https://martinfowler.com/eaaDev/EventSourcing.html
https://www.ibm.com/topics/low-code
https://www.techtarget.com/searchcio/definition/Business-process-management-suite-BPMS
https://scribehow.com/library/business-process-management-examples
https://medium.com/must-know-computer-science/system-design-message-queues-245612428a22
https://phoenixnap.com/blog/what-is-container-orchestration
https://sematext.com/guides/log-management/
https://www.splunk.com/en_us/data-insider/what-is-it-monitoring.html
https://www.techtarget.com/searchitoperations/definition/IT-monitoring
https://www.perforce.com/blog/sca/what-static-analysis
https://www.techtarget.com/whatis/definition/static-analysis-static-code-analysis