معماری نرم افزار چیست؟ – به زبان ساده + اهمیت

۷۸۶۵ بازدید
آخرین به‌روزرسانی: ۲۴ اردیبهشت ۱۴۰۲
زمان مطالعه: ۳۷ دقیقه
معماری نرم افزار چیست؟ – به زبان ساده + اهمیت

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

فهرست مطالب این نوشته

معماری نرم افزار چیست؟

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

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

مهم ترین بخش های معماری نرم افزار کدامند؟

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

  • جزئیات پیاده‌سازی (ساختار پوشه مخزن)
  • تصمیمات طراحی پیاده‌سازی (این که باید از Render سمت سرور استفاده شود یا از رندر سمت کاربر، این که باید از پایگاه داده‌ رابطه‌ای استفاده شود یا از پایگاه داده‌ غیر رابطه‌ای).
  • فناوری‌های مورد استفاده (این که برای API از REST استفاده شده است یا از GraphQl، برای بک‌اند از «پایتون» (Python) و «جنگو» (Django) استفاده شده یا از Node و Express).
  • تصمیمات طراحی سیستم (این که سیستم نرم افزار یکپارچه یا Monolith است یا از «میکروسرویس‌ها» (Microservices) استفاده شده است).
  • تصمیمات زیرساختی (این که نرم افزار در محل میزبانی شده یا توسط یک ارائه‌دهنده خدمات ابری تامین شده است).

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

مفاهیم پایه معماری نرم افزار چیست

مفاهیم مهم معماری نرم افزار چیست ؟

در اینجا برای درک بهتر این که معماری نرم افزار چیست به مفاهیم زیر پرداخته‌ایم.

  • مدل کلاینت-سرور
  • کاربرد API در معماری نرم افزار
  • پیمانه‌بندی (ماژولاریتی) در توسعه کد

مدل کلاینت-سرور در معماری نرم افزار چیست ؟

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

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

API در معماری نرم افزار چیست ؟

همان‌طور‌که پیش‌تر اشاره شد کلاینت‌ها و سرورها موجودیت‌هایی هستند که برای ارسال درخواست و ارسال پاسخ با یکدیگر ارتباط برقرار می‌کنند. API (رابط یا واسط برنامه نویسی اپلیکیشن یا برنامه کاربردی) روشی است که این دو بخش برای برقراری ارتباط استفاده می‌کنند. API مجموعه‌ای از قوانین تعریف شده به حساب می‌آید که نحوه برقراری ارتباط برنامه‌ای را با برنامه دیگر مشخص می‌کند. در واقع API قراردادی بین کلاینت و سرور است که مثلا بیان می‌کند: «اگر A را بفرستید، پاسخ من همیشه B خواهد بود. اگر C را بفرستید، پاسخ من همیشه D خواهد بود» و تا انتها به همین شکل ادامه پیدا می‌کند..

با داشتن این مجموعه قوانین، کلاینت دقیقاً می‌داند برای انجام یک وظیفه خاص به چه چیزی نیاز دارد و سرور دقیقاً می‌داند که هنگام انجام یک عمل خاص، کلاینت به چه چیزی نیاز خواهد داشت. راه‌های مختلفی برای پیاده‌سازی API وجود دارد. رایج‌ترین آنها REST، SOAP و GraphQl هستند. APIها برای برقراری ارتباط اغلب از پروتکل HTTP استفاده می‌کنند و محتوا در قالب JSON یا XML مبادله می‌شود. اما استفاده از سایر پروتکل‌ها و فرمت‌های محتوا نیز امکان پذیر است.

ماژولار بودن در معماری نرم افزار چیست ؟

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

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

در ادامه مثال‌ها و مواردی ارائه خواهد شد که جزئیات بیشتری از مفهوم پیمانه‌بندی را تشریح می‌کنند.

زیرساخت در معماری نرم افزار چیست ؟

زیرساخت فناوری اطلاعات، سیستمی از سخت‌افزار، نرم‌افزار، امکانات و مؤلفه‌های خدمات است که از تحویل سیستم‌های تجاری و فرآیندهای مبتنی بر فناوری اطلاعات پشتیبانی می‌کند. برای این که بدانیم زیرساخت در معماری نرم افزار چیست و برای درک راحت‌تر مفاهیم معماری نرم افزار ، یک برنامه فرضی به‌نام Notflix در ادامه توسعه داده شده است.

معماری مونولیتیک در معماری نرم افزار چیست ؟

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

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

مطابق با تصویر بالا، در سمت چپ سه برنامه مختلف فرانت‌اند داریم که در این سیستم به عنوان کلاینت عمل می‌کنند. برای مثال فرض کنید فرانت برنامه با React و React-native توسعه داده شده باشند. ما یک سرور واحد داریم که درخواست‌ها را از هر سه برنامه کلاینت دریافت می‌کند، در صورت لزوم با پایگاه داده یا همان بانک اطلاعاتی ارتباط برقرار می‌کند و بر اساس آن به هر یک از کلاینت‌ها پاسخی را ارسال می‌کند. فرض کنید بک‌اند برنامه با Node و Express توسعه داده شده است.

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

معماری میکروسرویس در مهندسی نرم افزار چیست ؟

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

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

معماری میکروسرویس در معماری نرم افزار چیست
معماری میکروسرویس

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

تمام این ارتباطات از طریق APIها، درست مانند یک سرور مونولیتیک معمولی (یا از طریق سیستم‌های ارتباطی دیگر مانند کافکا یا RabbitMQ)، انجام می‌شود. در واقع اکنون ما سرورهای متعددی داریم که مسئول عملیات‌ مختلفی هستند. در حالت قبلی صرفا یک سرور وجود داشت که همه عملیات را انجام می‌داد.

مزایای معماری میکروسرویس چه هستند؟

میکروسرویس مزایایی به همراه دارد که برخی از آن‌ها به شرح زیر است:

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

الگوی بک اند برای فرانت اند در معماری نرم افزار چیست؟

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

معمولا این مسئله با اجرای یک لایه میانی بین برنامه‌های فرانت‌اند و میکروسرویس‌ها برطرف می‌شود. این لایه تمام درخواست‌های فرانت‌اند را دریافت می‌کند، آنها را به میکروسرویس مربوطه هدایت می‌کند، پاسخ میکروسرویس را دریافت می‌کند و سپس پاسخ را به برنامه فرانت‌اند مربوطه هدایت می‌کند. این معماری، الگوی «بک‌اند برای فرانت‌اند» (BFF | Back-end For Front-end) نام دارد. مزیت الگوی BFF در معماری نرم افزار این است که باعث می‌شود ما در عین اجتناب از پیچیدگی‌های ارتباط با برنامه‌های فرانت‌اند، از معماری میکروسرویس‌ها نیز بهره ببریم.

معماری میکروسرویس در معماری نرم افزار چیست

نحوه استفاده از تعدیل‌ کننده بار و مقیاس‌بندی افقی در معماری نرم افزار

فرض کنید که برنامه پخش فیلم در مثال بالا موفقیت زیادی کسب کرده و با سرعت بالایی در حال فراگیر شدن است. کاربران زیادی از سرتاسر جهان اشتراک برنامه را تهیه کرده‌اند و فیلم‌ها را ۲۴ ساعته در ۷ روز هفته تماشا می‌کنند. بنابراین برنامه زودتر از انتظار، دوباره با مشکلات عملکردی مواجه خواهد شد. این بار هم سرویس پخش است که باید مورد رسیدگی قرار بگیرد. این درحالی است که ما سرور پخش را به صورت عمودی مقیاس‌بندی کرده بودیم و تقسیم بیشتر این سرویس به میکروسرویس‌های بیشتر، عملاً منطقی نیست. راهکار این است که این سرویس را به صورت افقی مقیاس‌بندی کنیم. پیش‌تر اشاره کردیم که مقیاس‌بندی عمودی به معنای افزودن منابع بیشتر (رم، فضای دیسک، واحد پردازنده گرافیکی و غیره) به یک سرور یا کامپیوتر است.

مقیاس‌بندی افقی به معنای به کارگیری سرورهای بیشتری برای انجام همان کار است. به جای به کارگیری یک سرور واحد برای استریم ویدیو، از ۳ سرور استفاده خواهیم کرد. درخواست‌های ارسال‌شده توسط کلاینت‌ها بین آن ۳ سرور متوازن می‌شوند تا همگی یک بار قابل قبول را تحمل کنند. این توزیع درخواست، معمولاً توسط «متوازن‌کننده بار» (Load Balancer) انجام می‌شود. متوازن‌کننده یا تعدیل‌کننده بار به عنوان «پروکسی معکوس» (Reverse Proxy) برای سرورها عمل می‌کند و درخواست‌های کلاینت را قبل از رسیدن به سرور پیگیری می‌کند و آن درخواست را به سرور مربوطه هدایت می‌کند.

اتصال کلاینت-سرور در حالت عادی
اتصال «کلاینت - سرور» در حالت معمول
متوازن‌کننده بار و توزیع درخواست‌های کلاینت
متوازن‌کننده بار، درخواست‌های کلاینت را در چندین سرور توزیع می‌کند.

مقیاس‌بندی افقی علاوه بر سرورها در پایگاه‌های داده نیز امکان‌پذیر است. یکی از راه‌های پیاده‌سازی مقیاس‌بندی افقی پایگاه داده استفاده از مدل «نسخه تکرار منبع» (Source-Replica) است، که در آن یک منبع خاص پایگاه داده، تمام کوئری‌های نوشتن را دریافت می‌کند و داده‌های آن را در یک یا چند «نسخه کپی‌ پایگاه داده» (Replica DBs) تکرار می‌کند. پایگاه داده‌های Replica تمام کوئری‌های خوانده شده را دریافت می‌کنند و به آن‌ها پاسخ خواهند داد. دو مورد از مهم‌ترین مزایای حاصل از به کارگیری پایگاه‌های Replica در معماری نرم افزار به شرح زیر است.

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

مفاهیم میکروسرویس‌ها، متوازن‌کننده بار و مقیاس‌بندی، اغلب در مورد برنامه‌های بک‌اند مطرح می‌شوند. اپلیکیشن‌های فرانت‌اند، معمولا به‌صورت مونولیتیک یا به صورت «میکرو فرانت‌اند» (Micro-Front End) توسعه می‌یابند.

معرفی فیلم های آموزش مهندسی نرم افزار

فیلم آموزش مهندسی نرم افزار فرادرس

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

  • برای شروع یادگیری مهندسی نرم افزار و دسترسی به تمام دوره‌های این مجموعه + اینجا کلیک کنید.

استقرار زیرساخت در معماری نرم افزار

تا اینجا ایده اولیه و نحوه سازمان‌دهی زیرساخت یک برنامه شرح داده شد. مسئله مهم دیگر، محل قرارگیری زیرساخت و نحوه میزبانی برنامه است که ۳ امکان برای آن وجود دارد. این سه گزینه در ادامه آمده است.

  • میزبانی «در محل» (On Premise)
  • میزبانی توسط ارائه‌دهندگان سنتی سرور
  • میزبانی در فضای ابری

میزبانی در محل

در محل یعنی شما مالک سخت‌افزاری هستید که برنامه شما در آن اجرا می‌شود. این روش از گذشته و به صورت سنتی روش میزبانی برنامه‌ها بوده است. در روش On-Premise، شرکت‌ها اتاق‌هایی ویژه به منظور تعبیه سرورها و تیم‌هایی برای راه‌اندازی و نگهداری سخت‌افزار در اختیار دارند. مزیت این روش این است که شرکت بر سخت‌افزار کنترل کامل دارد. نقطه ضعف این روش این است که هزینه‌های آن شامل تخصیص فضا و زمان، نسبتاً بالا هستند.

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

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

میزبانی ابر و میزبانی در محل در معماری نرم افزار چیست

میزبانی توسط تامین‌ کنندگان سنتی سرور

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

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

میزبانی در بستر ابری

«ابر» (Cloud) در نگاه عمومی شاید مفهومی انتزاعی به نظر برسد، اما در واقع همان دیتاسنتر‌های متعلق به شرکت‌های آمازون، گوگل و مایکروسافت است. تجهیزات مراکز داده این شرکت‌ها توان محاسباتی بالایی دارند، اما همیشه از آن استفاده نمی‌کنند، اما در عین حال هزینه‌های آن را پرداخت می‌کنند. لذا این شرکت‌ها راه‌حل هوشمندانه تجاری‌سازی و به‌ اشتراک‌گذاری آن توان رایانشی با دیگران را مطرح و اجرایی کرده‌اند و این همان «رایانش ابری» (Cloud Computing) است.

ما با استفاده از «سرویس وب آمازون» (AWS | Amazon Web Services)، «سرویس ابری گوگل» (Google Cloud) و «Microsoft Azure» می‌توانیم برنامه خود را در مرکز داده این شرکت‌ها میزبانی کنیم و از توان رایانشی بالای این شرکت‌ها بهره‌مند شویم. روش‌های متعددی برای استفاده از سرویس‌های ابری وجود دارد که در ادامه به برخی از آن‌ها اشاره شده است.

میزبانی ابری در معماری نرم افزار چیست
میزبانی در ابر - بهره‌مندی از دیتا سنتر شرکت‌های آمازون، گوگل و مایکروسافت

روش سنتی برای استفاده از سرویس ابری

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

روش منعطف بر اساس میزان استفاده از سرویس ابري

روش دوم، بهره بردن از رایانش منعطف (الاستیک) است که توسط تامین‌کنندگان ارائه می‌شود. الاستیک بودن به معنی انعطاف‌ در افزایش یا کاهش ظرفیت سخت‌افزار بسته به میزان استفاده از برنامه است. مثلاً شما برای شروع می‌توانید از سروری با ۸ گیگابایت رم و ۵۰۰ گیگابایت فضای دیسک استفاده کنید. اگر درخواست‌های ارسال شده به سرور شما شروع به افزایش کند و ظرفیت‌های موجود امکان عملکرد بهینه را نداشته باشند، در این صورت سیستم می‌تواند به صورت خودکار و به حالت افقی یا عمودی، مقیاس‌بندی شود. مزیت این روش این است که شما می‌توانید پیکربندی را از قبل تنظیم کنید و در صورت مقیاس‌بندی، هزینه را بسته به میزان مصرف‌تان، پرداخت کنید.

روش بدون سرور برای استفاده از سرویس ابری

روش دیگری که با استفاده از آن می‌توان از رایانش ابری برای استقرار زیرساخت‌های معماری نرم افزار استفاده کرد، به کارگیری معماری «بدون سرور» (Serverless) است. مطابق با این الگو، سروری برای دریافت درخواست وجود ندارد و به جای آن، توابع یکتایی وجود دارند که به یک «نقطه دسترسی» (Access Point) نگاشت شده‌اند (مشابه با نقاط انتهایی APIها). این توابع هر بار که یک درخواست را دریافت می‌کنند، اجرا می‌شوند، به این معنی که توابع توسعه داده شده شامل اتصال به پایگاه‌داده، عملیات CRUD و هر عمل دیگری را اجرا می‌کنند که در سرورهای معمولی قابل انجام است.

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

معماری بدون سرور در سرویس ابری در معماری نرم افزار چیست

سایر روش‌های موجود برای استفاده از سرویس ابری

همان‌طور که در بخش‌های قبلی شرح داده شد، روش‌های منعطف (الاستیک) و بدون سرور، راه‌کارهای ساده و راحتی را برای راه‌اندازی زیرساخت نرم افزار ارائه می‌کنند. تامین‌کنندگان خدمات ابری، علاوه بر ارائه خدمات سرور، خدمات دیگری را نیز ارائه می‌کنند که در ادامه به برخی از آن‌ها اشاره شده است.

  • پایگاه داده‌های رابطه‌ای و غیر‌رابطه‌ای
  • «نظارت» (Monitoring)
  • تحلیل عملکرد
  • ذخیره فایل
  • «قابلیت استفاده مجدد حافظه موقت» (Caching)
  • احراز هویت
  • یادگیری ماشین و پردازش داده‌ها

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

علاوه بر فضاهای ابری معرفی‌شده در بالا (سرویس وب آمازون، ابر گوگل و Azure)، سرویس‌های ابری دیگری شامل DigitalOcean ،IBM و اوراکل نیز وجود دارند. سرویس‌دهندگان معمولاً خدمات مشابهی را با نام‌های مختلف ارائه می‌کنند. برای مثال، «تابع بدون سرور» (Serverless Function)، در سرویس وب آمازون به صورت «لاندا» (Lambda) و در سرویس ابری گوگل به صورت «تابع ابری» (Cloud Function) نام‌گذاری شده است.

ساختار پوشه بندی فایل‌ ها در معماری نرم افزار

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

ساختار متمرکز پوشه ها

در اینجا برای توضیح اهمیت ساختار پوشه‌بندی، یک مثال آورده شده است. فرض کنید پایگاه‌داده‌ای از اطلاعات خرگوش‌ها را در دست داریم و می‌خواهیم با استفاده از Node.js و Express.js و به کمک API، عملیات CRUD را پیاده‌سازی کنیم. در ابتدا حالتی را بررسی می‌کنیم که پوشه‌ها سازمان‌دهی نشده‌ باشند. پوشه مخزن شامل پوشه node modules  و فایل‌های app.js  ، package-lock.json  و package.json  خواهد بود.

مخزن - پوشه بندی بدون ساختار

فایل app.js، در اینجا، حاوی یک سرور کوچک، پایگاه داده و دو «نقطه‌ پایانی» (Endpoint) است.

1// App.js
2const express = require('express');
3
4const app = express()
5const port = 7070
6
7// Mock DB
8const db = [
9    { id: 1, name: 'John' },
10    { id: 2, name: 'Jane' },
11    { id: 3, name: 'Joe' },
12    { id: 4, name: 'Jack' },
13    { id: 5, name: 'Jill' },
14    { id: 6, name: 'Jak' },
15    { id: 7, name: 'Jana' },
16    { id: 8, name: 'Jan' },
17    { id: 9, name: 'Jas' },
18    { id: 10, name: 'Jasmine' },
19]
20
21/* Routes */
22app.get('/rabbits', (req, res) => {
23    res.json(db)
24})
25
26app.get('/rabbits/:idx', (req, res) => {
27    res.json(db[req.params.idx])
28})
29
30app.listen(port, () => console.log(`⚡️[server]: Server is running at http://localhost:${port}`))

با تست نقطه انتهایی‌ها، ملاحظه می‌کنیم که آن‌ها به درستی عمل می‌کنند:

1http://localhost:7070/rabbits
2
3# [
4#   {
5#     "id": 1,
6#     "name": "John"
7#   },
8#   {
9#     "id": 2,
10#     "name": "Jane"
11#   },
12#   {
13#     "id": 3,
14#     "name": "Joe"
15#   },
16#   ....
17# ]
18
19###
20
21http://localhost:7070/rabbits/1
22
23# {
24#   "id": 2,
25#   "name": "Jane"
26# }

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

ساختار پوشه بندی لایه ای در معماری نرم افزار

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

معماری لایه ای
لایه‌های برنامه

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

  • لایه برنامه:
    • راه‌اندازی و تنظیمات اولیه سرور
    • اتصال به مسیرها (لایه بعدی)
  • لایه مسیرها:
    • تعریف مسیرها
    • اتصال به کنترل‌گرها (لایه بعدی)
  • لایه کنترل:
    • منطق عملیاتی‌ (که قصد داریم در نقطه انتهایی‌ها آن را پیاده سازیم.)
    • اتصال به لایه مدل (لایه بعدی)
  • لایه آخر، لایه تداوم شامل پایگاه‌داده

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

معماری لایه‌ ای - معماری نرم افزار چیست
شمای دیگری از معماری لایه‌ای

با استفاده از معماری لایه‌ای، ساختار پوشه‌ها به شکل زیر خواهد بود.

ساختار پوشه‌ بندی - معماری لایه ای

مهم‌ترین فایل‌ها و پوشه‌ها شامل موارد زیر می‌شود.

  • در معماری لایه‌ای، پوشه جدیدی به نام db  وجود دارد که حاوی فایل پایگاه داده است.
  • پوشه rabbits  حاوی مسیرها، کنترل‌گرها و مدل‌های این موجودیت است.
  • app.js  راه‌اندازی سرور و اتصال به مسیرها را شامل می‌شود.
1// App.js
2const express = require('express');
3
4const rabbitRoutes = require('./rabbits/routes/rabbits.routes')
5
6const app = express()
7const port = 7070
8
9/* Routes */
10app.use('/rabbits', rabbitRoutes)
11
12app.listen(port, () => console.log(`⚡️[server]: Server is running at http://localhost:${port}`))

rabbits.routes.js  حاوی نقطه انتهایی‌های مربوط به این موجودیت است و هر یک از این نقطه انتهایی‌ها را به کنترل‌گر متناظر آن (تابعی که می‌خواهیم در هنگام ارسال درخواست به نقطه انتهایی، اجرا کنیم) مرتبط می‌سازد.

1// rabbits.routes.js
2const express = require('express')
3const bodyParser = require('body-parser')
4
5const jsonParser = bodyParser.json()
6
7const { listRabbits, getRabbit, editRabbit, addRabbit, deleteRabbit } = require('../controllers/rabbits.controllers')
8
9const router = express.Router()
10
11router.get('/', listRabbits)
12
13router.get('/:id', getRabbit)
14
15router.put('/:id', jsonParser, editRabbit)
16
17router.post('/', jsonParser, addRabbit)
18
19router.delete('/:id', deleteRabbit)
20
21module.exports = router

rabbits.controllers.js  حاوی منطق متناظر با هر نقطه انتهایی است. در این قسمت، کد ورودی تابع، پردازشی که روی آن صورت می‌گیرد و خروجی بازگردانده شده توسعه می‌یابد. علاوه بر این، هر کنترل‌گری به تابع مدل متناظر (که عملیات مربوط به پایگاه‌داده را انجام می‌دهد)، مرتبط می‌شود.

1// rabbits.controllers.js
2const { getAllItems, getItem, editItem, addItem, deleteItem } = require('../models/rabbits.models')
3
4const listRabbits = (req, res) => {
5    try {
6        const resp = getAllItems()
7        res.status(200).send(resp)
8
9    } catch (err) {
10        res.status(500).send(err)
11    }
12}
13
14const getRabbit = (req, res) => {
15    try {
16        const resp = getItem(parseInt(req.params.id))
17        res.status(200).send(resp)
18
19    } catch (err) {
20        res.status(500).send(err)
21    }
22}
23
24const editRabbit = (req, res) => {
25    try {
26        const resp = editItem(req.params.id, req.body.item)
27        res.status(200).send(resp)
28    } catch (err) {
29        res.status(500).send(err)
30    }
31}
32
33const addRabbit = (req, res) => {
34    try {
35        console.log( req.body.item )
36        const resp = addItem(req.body.item)
37        res.status(200).send(resp)
38    } catch (err) {
39        res.status(500).send(err)
40    }
41}
42
43const deleteRabbit = (req, res) => {
44    try {
45        const resp = deleteItem(req.params.idx)
46        res.status(200).send(resp)
47    } catch (err) {
48        res.status(500).send(err)
49    }
50}
51
52module.exports = { listRabbits, getRabbit, editRabbit, addRabbit, deleteRabbit }

rabbits.models.js  فایلی است که توابع مربوط به عملیت CRUD در آن توسعه می‌یابد. این عملیات شامل خواندن یک رکورد، خواندن همه رکوردها، ویرایش، حذف و غیره می‌شود.

1// rabbits.models.js
2const db = require('../../db/db')
3
4const getAllItems = () => {
5    try {
6        return db
7    } catch (err) {
8        console.error("getAllItems error", err)
9    }
10}
11
12const getItem = id => {
13    try {
14        return db.filter(item => item.id === id)[0]
15    } catch (err) {
16        console.error("getItem error", err)
17    }
18}
19
20const editItem = (id, item) => {
21    try {
22        const index = db.findIndex(item => item.id === id)
23        db[index] = item
24        return db[index]
25    } catch (err) {
26        console.error("editItem error", err)
27    }
28}
29
30const addItem = item => {
31    try {
32        db.push(item)
33        return db
34    } catch (err) {
35        console.error("addItem error", err)
36    }
37}
38
39const deleteItem = id => {
40    try {
41        const index = db.findIndex(item => item.id === id)
42        db.splice(index, 1)
43        return db
44        return db
45    } catch (err) {
46        console.error("deleteItem error", err)
47    }
48}
49
50module.exports = { getAllItems, getItem, editItem, addItem, deleteItem }

db.js  میزبانی پایگاه‌داده را برعهده دارد و عمل اتصال به پایگاه داده در این فایل انجام می‌شود.

1// db.js
2const db = [
3    { id: 1, name: 'John' },
4    { id: 2, name: 'Jane' },
5    { id: 3, name: 'Joe' },
6    { id: 4, name: 'Jack' },
7    { id: 5, name: 'Jill' },
8    { id: 6, name: 'Jak' },
9    { id: 7, name: 'Jana' },
10    { id: 8, name: 'Jan' },
11    { id: 9, name: 'Jas' },
12    { id: 10, name: 'Jasmine' },
13]
14
15module.exports = db

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

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

ساختار پوشه بندی MVC

MVC که مخفف عبارت «Model, View, Controller» (مدل، نما، کنترل‌گر» ) است، الگویی محبوب در معماری نرم افزار به حساب می‌آید و می‌توان آن را حالت ساده‌تری از معماری لایه‌ای دانست با این تفاوت که «فرانت‌اند» (Front-end) یا همان رابط کاربری (UI) را هم شامل می‌شود. برای درک بهتر این که MVC در معماری نرم افزار چیست و چگونه عمل می‌کند، این الگو را در مثال جاری توسعه می‌دهیم. همچنین، توصیه می‌شود مطلب اختصاصی مربوط به MCV را هم مطالعه کنید.

در معماری MVC سه لایه وجود دارد:

  • لایه «نما» (View) که وظیفه رندر کردن UI را بر عهده خواهد داشت.
  • کنترل‌گر که مسئول تعریف مسیرها و منطق برای آن‌ها است.
  • لایه مدل که مسئول ارتباط با پایگاه داده است.
معماری MVC در معماری نرم افزار چیست
معماری MVC

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

 لایه‌ ها در معماری MVC
شمای دیگری از ساختار لایه‌بندی در الگوی MVC

فریم‌ورک‌های متعددی مثل «جنگو» (Django)، «روبی‌ آن‌ ریلز» (Ruby on Rails) و .. برای پیاده‌سازی معماری MVC توسعه داده شده‌اند. در مثال مورد بحث، برای اجرای MVC به کمک Node و Express، به یک «موتور قالب» (Template Engine) همانند EJS نیاز داریم. تمپلیت انجین‌ها ابزاری برای رندر کردن HTML هستند و در عین حال امکان به کارگیری ویژگی‌های برنامه‌نویسی شامل متغیر، لوپ‌، شرط‌ و .. در آن‌ها وجود دارد. اگر با JSX‌ در ری‌اکت آشنا هستید، می‌توان گفت تمپلیت انجین‌ها شبیه به JSX هستند.

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

ساختار پوشه‌بندی در الگوی MVC
ساختار پوشه‌بندی در الگوی MVC
  • این الگو فاقد بسیاری از پوشه‌هایی است که در معماری لایه‌ای وجود دارند. در اینجا تنها سه پوشه db ، controllers  و models  وجود دارند.
  • در اینجا، پوشه views  به منظور رندر کردن صفحات و پاسخ‌های ارسالی اضافه شده است.
  • db,js  و models.js  مشابه با معماری لایه‌ای همچنان موجود هستند.
  • فایل app.js  به شکل زیر خواهد بود:
1// App.js
2const express = require("express");
3var path = require('path');
4
5const rabbitControllers = require("./rabbits/controllers/rabbits.controllers")
6
7const app = express()
8const port = 7070
9
10// Ejs config
11app.set("view engine", "ejs")
12app.set('views', path.join(__dirname, './rabbits/views'))
13
14/* Controllers */
15app.use("/rabbits", rabbitControllers)
16
17app.listen(port, () => console.log(`⚡️[server]: Server is running at http://localhost:${port}`))
  • rabbits.controllers.js  این‌طور تغییر یافته که مسیرها در آن تعریف می‌شوند، به تابع مدل مربوطه متصل می‌شود و نمای مربوط به درخواست‌ها را رندر می‌کند. توجه داشته باشید، در متد رندر، پاسخ به درخواست، به صورت یک پارامتر به نما ارسال می‌شود.
1// rabbits.controllers.js
2const express = require('express')
3const bodyParser = require('body-parser')
4
5const jsonParser = bodyParser.json()
6
7const { getAllItems, getItem, editItem, addItem, deleteItem } = require('../models/rabbits.models')
8
9const router = express.Router()
10
11router.get('/', (req, res) => {
12    try {
13        const resp = getAllItems()
14        res.render('rabbits', { rabbits: resp })
15
16    } catch (err) {
17        res.status(500).send(err)
18    }
19})
20
21router.get('/:id', (req, res) => {
22    try {
23        const resp = getItem(parseInt(req.params.id))
24        res.render('rabbit', { rabbit: resp })
25
26    } catch (err) {
27        res.status(500).send(err)
28    }
29})
30
31router.put('/:id', jsonParser, (req, res) => {
32    try {
33        const resp = editItem(req.params.id, req.body.item)
34        res.render('editRabbit', { rabbit: resp })
35
36    } catch (err) {
37        res.status(500).send(err)
38    }
39})
40
41router.post('/', jsonParser, (req, res) => {
42    try {
43        const resp = addItem(req.body.item)
44        res.render('addRabbit', { rabbits: resp })
45
46    } catch (err) {
47        res.status(500).send(err)
48    }
49})
50
51router.delete('/:id', (req, res) => {
52    try {
53        const resp = deleteItem(req.params.idx)
54        res.render('deleteRabbit', { rabbits: resp })
55
56    } catch (err) {
57        res.status(500).send(err)
58    }
59})
60
61module.exports = router
  • در نهایت، در فایل‌های نما، متغیر (پارامتر) ارسالی، دریافت شده و به صورت HTML رندر می‌شود.
1<!-- Rabbits view -->
2<!DOCTYPE html>
3<html lang="en">
4    <body>
5        <header>All rabbits</header>
6        <main>
7            <ul>
8                <% rabbits.forEach(function(rabbit) { %>
9                    <li>
10                        Id: <%= rabbit.id %>
11                        Name: <%= rabbit.name %>
12                    </li>
13                <% }) %>
14            </ul>
15        </main>
16    </body>
17</html>
1<!-- Rabbit view -->
2<!DOCTYPE html>
3<html lang="en">
4    <body>
5        <header>Rabbit view</header>
6        <main>
7                <p>
8                    Id: <%= rabbit.id %>
9                    Name: <%= rabbit.name %>
10                </p>
11        </main>
12    </body>
13</html>

حال اگر آدرس اینترنتی http://localhost:7070/rabbits   را در مرورگر مشاهده کنیم، خواهیم داشت:

خروجی برنامه در مثال Node.js

و آدرس اینترنتی http://localhost:7070/rabbits/2 در مرورگر به این شکل خواهد بود:

خروجی برنامه توسط express.js

اهداف معماری نرم افزار

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

  • امکان توسعه سریع
  • تست‌پذیر بودن در حین توسعه
  • معماری آسان و قابل درک 
  • معماری قابل اندازه گیری 
  • امکان استقرار مجدد: چه نرم افزار شما در حال توسعه باشد و چه انجام شده باشد، «استقرار» (Deploy) نسخه جدید باید امکان‌پذیر باشد.
  • معماری پایدار: هدف ما ایجاد سیستمی است که در برابر هر عامل خارجی مقاوم باشد. مثالی جالب پیرامون ساخت و طراحی این نوع معماری‌، روش Chaos Monkey ابداع شده توسط نتفلیکس است.
  • معماری ماژولار: در این نوع معماری، تبادل بسیار آسان عناصر و حذف ماژول‌ها به شیوه‌ای ایمن امکان‌پذیر است.
  • معماری تکاملی: یکی از اهداف معماری این است که سیستم همراه با کسب و کار تکامل یابد. وظیفه ما این است که توسعه‌دهندگان را قادر سازیم تا به سرعت و به راحتی نرم افزار را توسعه دهند.
  • نظارت آسان بر معماری: معماری مبتنی بر «نظارت» (Monitor)، به مفهومی محبوب در زمان‌های اخیر تبدیل شده است. ردیابی صحیح رفتار سیستم به ما بینشی از مشکلات آینده می‌دهد و به لطف آن، زمانی که در داشبورد رنگارنگ ما چیزی مزاحم ظواهر شود، می‌توانیم به آن، واکنش مناسب نشان دهیم.
  • معماری مقیاس پذیر: رویکرد زیرساخت یا معماری پیاده‌سازی در اینجا اهمیت دارد. ساخت مناسب بخش‌های خاص سیستم بر اساس سرویس‌های کوچک و مستقل، مقیاس‌بندی افقی را ممکن می‌سازد.

الگوهای رایج معماری نرم افزار چه هستند؟

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

الگوی قطع کننده مدار

الگوی «قطع کننده مدار» (Circuit Breaker) با تغییر مسیر ترافیک به سرویسی دیگر، ریسک را به حداقل می‌رساند، به مقاوم‌تر شدن سیستم‌ها برای جلوگیری از حوادث کمک می‌کند، اما به تست به‌روز و استفاده از فناوری مدیریت زیرساخت مانند سرویس Mesh نیاز دارد.

الگوی کلاینت سرور

الگوی «کلاینت-سرور» (Client-Server) یک معماری همتا به همتا است که از دو مولفه «کلاینت» (درخواست‌کننده سرویس) و «سرور» (ارائه‌دهنده سرویس) تشکیل شده است. از موارد استفاده این الگوی معماری می‌توان به بانکداری، اشتراک فایل، ایمیل و شبکه جهانی وب اشاره کرد. یکی از مزایای این الگو این است که داده‌ها و تجهیزات جانبی شبکه به صورت مرکزی مدیریت می‌شوند، با این حال، هزینه سرور هزینه‌ قابل توجهی است.

الگوی تفکیک مسئولیت کوئری فرمان

الگوی «تفکیک مسئولیت کوئری فرمان» (Command Query Responsibility Segregation | CQR) موقعیتی را کنترل می‌کند که در آن کوئری‌های پایگاه داده بیشتر از تغییرات داده‌ها اتفاق می‌افتند، فعالیت‌های خواندن و نوشتن را برای ایجاد ثبات و مقیاس‌پذیری بیشتر و عملکرد بهتر از هم جدا می‌کنند، اما از طرفی، نیازمند به فناوری‌های پایگاه داده بیشتری است و بنابراین ممکن است هزینه‌ها را افزایش دهد.

الگوی کنترل‌کننده پاسخ‌دهنده

الگوی کنترل‌کننده-پاسخ‌دهنده» (Controller-Responder) معماری را به دو بخش کنترل‌گر و پاسخ‌دهنده تقسیم می‌کند. کنترل‌کننده داده‌ها را مدیریت و بارهای کاری را توزیع می‌کند و پاسخ‌دهنده، داده‌های کنترل‌کننده را تکرار و نتایج را تولید می‌کند. این که کاربر می‌تواند داده‌ها را از پاسخ‌دهنده بخواند، بدون اینکه روی داده‌های کنترل‌گر تأثیر بگذارد، مزیت این الگو به حساب می‌آید. اما اگر کنترل‌گر از کار بیفتد، ممکن است داده‌ها از دست بروند و نیاز به راه‌اندازی مجدد برنامه وجود داشته باشد.

الگوی منبع یابی رویداد

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

الگوی لایه‌ای

الگوی «لایه‌ای» (Layered) مناسب برنامه‌هایی است که شامل گروه‌هایی از وظایف فرعی هستند و با ترتیب خاصی اجرا می‌شوند، مثلاً وب اپلیکیشن‌های تجارت الکترونیکی و برنامه‌های دسکتاپ را می‌توان مثال زد. الگوی لایه‌ای، توسعه سریع برنامه‌ها را آسان می‌کند، اما نقطه ضعف آن این است که بعداً تقسیم لایه‌ها دشوار خواهد بود.

الگوی میکروسرویس

الگوی «میکروسرویس» (Microservice) چندین سرویس را که به طور وابسته به یکدیگر و برای ایجاد برنامه کاربردی بزرگتر در تعامل هستند، ترکیب می‌کند. به‌روزرسانی برنامه‌های کوچک در این الگو آسان‌تر است، اما مدیریت پیچیدگی آن به تخصص معماری بیشتری نیاز دارد.

الگوی MVC

الگوی «مدل-نما-کنترل‌گر» (MVC) برنامه کاربردی را به سه مولفه تقسیم می‌کند. مدل شامل داده‌ها و کارکرد اصلی برنامه است. نما داده‌ها را نمایش می‌دهد و با کاربر تعامل دارد. و کنترل‌کننده ورودی کاربر را کنترل می‌کند و به عنوان واسطه بین مدل و نما عمل می‌کند. این الگو برنامه را قادر می‌سازد تا نما‌های مختلفی تولید کند، اما لایه‌های انتزاعی آن پیچیدگی را افزایش می‌دهد.

الگوی ناشر و مشترک

الگوی «ناشر و مشترک» (Pub-Sub) پیام‌های مربوطه را به مکان‌هایی ارسال می‌کند (منتشر می‌کند) که در یک موضوع «مشترک» (Subscribed) شده‌اند. پیکربندی این الگو آسان است، اما تست آن دشواری دارد زیرا تعاملات بین ناشر و مشترک، ناهمزمان هستند.

الگوی Saga

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

الگوی «اشتراک‌گذاری داده‌ها» (Sharding)

الگوی «اشتراک‌گذاری داده‌ها» (Sharding)، داده‌ها را در یک پایگاه داده برای سرعت بخشیدن به دستورات یا کوئری‌ها، تقسیم می‌کند. این الگو تضمین می‌کند که فضای ذخیره‌سازی توسط نمونه‌ها به طور برابر مصرف می‌شود، اما نیاز به یک مدیر پایگاه داده ماهر و با تجربه وجود دارد تا به طور مؤثر اشتراک‌گذاری را مدیریت کند.

الگوی میزبانی محتوای ایستا

الگوی «میزبانی محتوای ایستا» (Static Content Hosting) برای بهینه‌سازی زمان بارگذاری صفحه وب استفاده می‌شود. محتوای ثابت یعنی اطلاعاتی که اغلب تغییر نمی‌کنند، مانند بیوگرافی نویسنده یا یک فایل MP3 را جدا از محتوای پویا (مانند قیمت سهام) ذخیره می‌کند. برای ارائه محتوا و رسانه‌هایی بسیار کارآمد است که اغلب تغییر نمی‌کنند. از معایب آن می‌توان به هزینه‌های بالاتر ذخیره‌سازی اشاره کرد.

الگوی معماری نرم افزار Strangler

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

الگوی نرخ محدود کننده

الگوی «نرخ محدود کننده» (Throttling) سرعت جریان داده به یک هدف را کنترل می‌کند. اغلب برای جلوگیری از شکست در طول حمله، انکار سرویس توزیع شده یا مدیریت هزینه‌های زیرساخت ابری استفاده می‌شود. برای استفاده موفقیت‌آمیز از این الگو، نیاز به «ساز و کارهای افزونگی» (Redundancy Mechanisms) وجود دارد، و اغلب در کنار الگوی Circuit Breaker برای حفظ عملکرد سرویس استفاده می‌شود.

سند معماری نرم افزار چیست؟

یک سند معماری نرم افزار نقشه‌ای از نرم افزار است که از آن برای مشاهده ساختار نرم افزار به صورت شماتیک و در یک نگاه استفاده می‌شود. سند معماری نرم افزار به شما کمک می‌کند تا ماژول‌ها و مؤلفه‌های نرم افزار را بدون بررسی عمیق کدها درک کنید. سند معماری نرم افزار ابزاری برای برقراری ارتباط با دیگران (شامل توسعه‌دهندگان و غیرتوسعه‌دهندگان) است.

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

محدودیت ها در معماری نرم افزار چیست ؟

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

محدودیت های فنی در معماری نرم افزار

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

  • زبان برنامه نویسی: اغلب اوقات یک زبان برنامه نویسی یا یک فریم‌ورک خاص به دلایل مختلف برای توسعه برنامه انتخاب می‌شود. هنگامی که یک زبان برنامه‌نویسی  انتخاب شد، بقیه پروژه الزاماً متناسب با آن زبان‌ برنامه‌نویسی باید توسعه یابد.
  • سیستم عامل یا پلتفرم‌های پشتیبانی شده: نرم افزار باید روی یک از سیستم‌ عامل‌های ویندوز، لینوکس، iOS، یا Qt در Solaris، یا IE6 در ویندوز XP، یا در دیگر پلت‌فرم‌ها کار کند. ساختن نرم افزاری که محدودیت پلت‌فرم را برآورده نمی‌کند به این معنی است که شما در طراحی یک سیستم نرم افزاری که نگرانی‌های کلیدی ذینفعان را برآورده می‌کند شکست خورده‌اید.
  • استفاده از یک کتابخانه یا چارچوب خاص: گاهی اوقات ممکن است نیاز به استفاده از یک کتابخانه خاص وجود داشته باشد که آن ممکن است ناشی از کسب و کار باشد، اما تأثیر آن فنی است. یک مثال رایج در بسیاری از شرکت‌ها استفاده از کتابخانه‌های منبع باز خاص است. برخی از شرکت‌ها ممکن است نیاز داشته باشند که برای توسعه همیشه از متاب‌خانه‌های منبع باز استفاده کنند.

محدودیت های کسب و کار در معماری نرم افزار

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

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

اهمیت معماری نرم افزار چیست ؟

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

1. تعریف راه حل برای برآوردن الزامات

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

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

2. توانمندسازی و مهار ویژگی‌های کیفیتی

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

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

3. امکان پیش بینی کیفیت سیستم نرم افزاری

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

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

4. تسهیل ارتباط بین ذینفعان

مستندات معماری نرم افزار به شما این امکان را می‌دهد تا طرح کلی معماری را به اشتراک بگذارید و آن را برای دیگران توضیح دهید. سند معماری می‌تواند مبنایی برای بررسی جوانب پروژه، مانند هزینه‌ها و مدت زمان اجرا باشد. معماری نرم افزار به اندازه کافی انتزاعی است، به‌ طوری‌ که بسیاری از سهامداران با راهنمایی اندک یا بدون راهنمایی، می‌توانند در مورد سیستم نرم افزاری اظهار نظر کنند.

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

۵. آموزش اعضای تیم

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

سوالات رایج و پرتکرار معماری نرم افزار

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

متوازن سازی بار در معماری نرم افزار چیست ؟

متوازن‌سازی بار تکنیک ساده‌ای برای توزیع بار کاری بین چندین ماشین است. رایج‌ترین و ساده‌ترین الگوریتم متعادل کننده بار، «Round Robin» نام دارد. در این نوع متوزان‌سازی بار، درخواست به ترتیب و به صورت مدور تقسیم می‌شود تا اطمینان حاصل شود که همه ماشین‌ها تعداد درخواست‌های مساوی را دریافت می‌کنند و هیچ ماشینی دچار بار اضافه یا بار کم نمی‌شود. هدف از متعادل کردن بار در ادامه فهرست شده است.

  • بهینه سازی استفاده از منابع (جلوگیری از تحمیل اضافه‌بار یا بار کم هر یک از ماشین‌ها)
  • دستیابی به حداکثر توان عملیاتی
  • به حداقل رساندن زمان پاسخگویی

منظور از تعامل با تاخیر کمتر در معماری نرم افزار چیست؟

تأخیر کم به این معنی است که بین زمان ارسال درخواست و زمانی که پاسخ دریافت می‌شود، تأخیر بسیار کمی وجود دارد. این فرایند در وب‌سوکت‌ها اجرا می‌شود، به این معنی که  داده‌ها می‌توانند سریع‌تر ارسال شوند (مخصوصاً از طریق پیوندهای آهسته | Slow Links). زیرا اتصال قبلاً برقرار شده است و بنابراین برای ایجاد اتصال TCP | Transmission Control Protocol نیازی به «رفت و برگشت» (Roundtrips) بسته اضافی نیست.

خوشه در معماری نرم افزار چیست؟

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

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

عبارت «شکست زودهنگام» در معماری نرم افزار به چه معناست؟

«شکست سریع» (Fail Early) به این معنی است که کدهای نرم افزار طوری توسعه یابند که در صورت بروز مشکل، برنامه بلافاصله و در حد امکان از کار بیفتد، نه اینکه در حالت ناپایدار به کار خود ادامه دهد. این روش که "Fail Fast" هم نامیده می‌شود، تعداد کلی باگ‌ها را در ابتدا کاهش نمی‌دهد، اما یافتن بیشتر نقص‌ها را بسیار آسان‌تر می‌کند.

چرا در HTTP از وب‌سوکت استفاده می‌کنیم؟

WebSocket یک اتصال مداوم بین کلاینت و سرور است. این اتصال پیوسته مزیت‌های زیر را به همراه دارد.

  • داده‌ها را می‌توان در هر زمان از سرور به کلاینت ارسال کرد، حتی بدون اینکه کلاینت آن را درخواست کند. این فرایند «فشار سرور» (Server Push) نامیده می‌شود. فشار سرور در برنامه‌هایی که کلاینت باید سریعا از اتفاقی که روی سرور رخ می‌دهد آگاه شود (مانند دریافت پیام‌های چت جدید یا به‌روزرسانی قیمت جدید) بسیار مفید است. نمی‌توان داده‌ها را از طریق HTTP به کلاینت منتقل کرد. کلاینت برای دریافت داده‌های جدید و به‌ موقع، باید مرتباً و در هر چند ثانیه، یک درخواست HTTP ارسال کند، اما این عملیات کارآمد نیست.
  • داده‌ها را می‌توان از طریق دیگری و به‌صورت کارآمد ارسال کرد. قاب داده وب‌سوکت بسیار کارآمد سازمان‌دهی شده و اتصال آن قبلا برقرار شده است و در نتیجه می‌توان داده‌ها را بسیار کارآمدتر از HTTP که لزوماً حاوی هدرها، کوکی‌ها و غیره است ارسال کرد.

مقیاس پذیری در معماری نرم افزار چیست؟

مقیاس‌پذیری توانایی یک سیستم، شبکه یا فرآیند برای مدیریت بار فزاینده به کمک افزودن منابعی بیشتر است. افزودن منابع به دو صورت انجام می‌شود:

  • «مقیاس‌بندی به بالا» (Scaling Up): که شامل افزودن منابعی مثل رم، حافظه یا قدرت پردازشی بیشتر به گره‌های موجود است.
  • «مقیاس‌بندی به بیرون» (Scaling Out): که شامل اضافه کردن گره‌های بیشتر برای پشتیبانی از تعداد بیشتر کاربران است.

هر یک از این رویکردها را می‌توان برای افزایش یا کاهش مقیاس یک برنامه استفاده کرد. توجه داشته باشید که هزینه افزودن منابع (به ازای هر کاربر) بسته به مقیاس و با افزایش حجم متغیر است. اگر منابعی را به سیستم اضافه کنیم، باید توانایی برنامه را افزایش دهد تا بار بیشتری را، به شیوه‌ای متناسب، از منابع اضافه شده دریافت کند.

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

ضرورت خوشه بندی در معماری نرم افزار چیست؟

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

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

منظور از اصل KISS در معماری نرم افزار چیست؟

KISS که مخفف کلمه «Keep It Simple, Stupid» است، یک اصل طراحی است و بیان می‌کند که اکثر سیستم‌ها در صورتی به بهترین شکل ممکن کار خواهند کرد که ساده، و نه پیچیده، نگه داشته شوند. بنابراین سادگی باید یک هدف کلیدی در طراحی باشد و از پیچیدگی‌های غیرضروری خودداری شود.

کشسانی در مقابل مقیاس پذیری به چه معناست؟

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

قانون CAP در معماری نرم افزار چیست؟

قضیه CAP برای محاسبات توزیع شده که توسط Eric Brewer منتشر شد، بیان می‌کند که یک سیستم کامپیوتری توزیع شده نمی‌تواند هر سه ضمانت زیر را به‌صورت هم‌زمان ارائه دهد.

  • «سازگاری» (Consistency): همه گره‌ها با به‌روزرسانی‌های همزمان، داده‌های مشابهی را می‌بینند.
  • «در دسترس بودن» (Availability): هر درخواست، پاسخی در مورد موفقیت یا شکست آن دریافت می‌کند.
  • «تحمل پارتیشن» (Partition Tolerance): سیستم با وجود از دست دادن یک پیام یا خرابی بخشی از سیستم به کار خود ادامه می‌دهد.

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

جمع‌بندی

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

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

بر اساس رای ۲۶ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
freeCodeCamp
۳ دیدگاه برای «معماری نرم افزار چیست؟ – به زبان ساده + اهمیت»

مقاله خوبی بود
کامل و در عین حال ساده

سلام یه سوال نیازمندی ها در معماری چی هست ؟

بسیار تحقیق جامع و کاربردی تری نسبت به دیگر افراد داشتید. کارتان بسیار عالی بود

نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *