تفاوت بین معماری نرم افزار و طراحی نرم افزار

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

 تفاوت بین معماری نرم افزار و طراحی نرم افزار

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

تعریف معماری نرم افزار

در یک تعریف ساده می توان گفت، معماری نرم افزار فرایند تبدیل ویژگی های نرم افزار، از قبیل انعطاف پذیری، مقایس پذیری، قابلیت استفاده ی مجدد و امنیت به یک راه حل ساخت یافته است که انتظارات تکنیکی و تجارت را برآورده می کند. این تعریف معماری نرم افزار باعث ایجاد سؤالاتی راجع به ویژگی های نرم افزاری می شود که می تواند بر طراحی معماری نرم افزار تأثیر بگذارد. یک لیست طولانی از ویژگی های نرم افزاری وجود دارد که اساساً نیازمندی های کسب و کار یا عملی را در کنار نیازمندهای تکنیکی نشان می دهد. در اینجا به برخی از ویژگی های معماری نرم افزار و طراحی نرم افزار اشاره خواهد شد.

ویژگی های معماری نرم افزار

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

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

شاید بیشتر مردم کلمه «میکرو سرویس/MicroServices» را قبلاً شنیده باشند. میکرو سرویس یکی از الگوهای معماری نرم افزار مانند الگوی لایه ای (Layered Patten)، الگوی رویداد محور (Event-Driven Pattern)، الگوی سرورلس (Severless Pattern) و غیره است که در معماری نرم افزار به چشم می خورند. بعضی از این الگوهای معماری نرم افزار در ادامه ی مقاله توضیح داده خواهند شد. الگوی میکرو سرویس بعد از اینکه توسط آمازون و نتفلیکس (Netflix) بکار گرفته شد، اعتبار خوبی بدست آورد و تأثیر عالی خود را نشان داد. حالا بیایید الگوی های معماری نرم افزار را عمیق تر بررسی کنیم.

نکته: لطفاً الگوهای طراحی مثل الگوهای کارخانه (Factory) یا وفق دهنده (adaptor) را با الگوهای معماری نرم افزار اشتباه نکنید. این موارد نیز در ادامه توضیح داده خواهند شد.

معماری سرورلس

معماری سرورلس بر خدمات شخص ثالث تکیه می کند تا پیچیدگی سرورها و مدیریت پشتیبان را اداره کند. معماری سرورلس به دو دسته اصلی تقسیم می شود. دسته اول «پشتیبان گیری به عنوان یک سرویس (BaaS)» و دسته دوم «توابع به عنوان یک سرویس (FaaS)» است. معماری سرورلس به شما کمک می کند مدت زمان زیادی را در مراقبت و تعمیر باگ های متفرقه و کارهای معمولی سرورها ذخیره کنید.

معماری رویداد محور

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

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

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

معماری میکرو سرویس

معماری میکرو سرویس تبدیل به مشهورترین معماری نرم افزار در طی چند سال گذشته شده است. این معماری نرم افزار به توسعه سرویس های مستقل کوچک بستگی دارد که هر سرویس یک مشکل خاص را حل می کند یا یک کار خاص انجام می دهد. این ماژول ها از طریق یک API (API مخفف Application Programming Interface است که به معنی رابط برنامه نویسی نرم افزار می باشد) خوب تعریف شده با یکدیگر ارتباط برقرار می کنند تا در جهت هدف کسب و کار خدمت کنند. نیازی نیست بیشتر از این توضیح دهم، فقط کافی است به این تصویر نگاه کنید.

طراحی نرم افزار

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

اگر شما یک توسعه دهنده هستید، مهم است که بدانید قاعده کلی SOLID چیست و اینکه چطور یک الگوی طراحی باید مشکلات معین را حل کند.

SOLID به Single Responsibility، Open Closed، Liskov substitution، Interface Segregation و Dependency Inversion Principles اشاره می کند.

Single Responsibility Principle یا اصل تک مسئولیتی: به این معنی است که هر کلاس باید یک هدف واحد، یک مسئولیت و یک دلیل برای تغییر داشته باشد.

Open Closed Principle یا OCP: یک کلاس باید به گونه ای باشد که قابل گسترش باشد اما نیازی به اصلاح یا تغییر نداشته باشد. به عبارت ساده تر، شما باید بتوانید عاملیت بیشتری به کلاس اضافه کنید اما تابع های فعلی را طوری ادیت نکنید که کدهای موجودی که از آن استفاده می کند را از بین ببرد.

Liskov substitution principle یا LSP: این اصل، توسعه دهنده را به گونه ای به استفاده از وراثت راهنمایی می کند که منطق برنامه تحت هیچ شرایطی نمی شکند. از این رو، اگر یک کلاس بچه به نام «XyClass» دارید که از یک کلاس والد «AbClass» ارث بری می کند، کلاس بچه نباید عاملیت کلاس والد را طوری تکرار کند که رفتار کلاس والد را تغییر دهد. بنابراین شما می توانید بدون اینکه منطق برنامه را از بین ببرید، به راحتی از CyClass به جای AbClass استفاده کنید.

Interface Segregation Principle یا اصل جدایی اینترفیس: از آنجایی که یک کلاس می تواند چندین اینترفیس را اجرا کند، کد خود را به گونه ای سازمان دهی کنید که یک کلاس هیچ وقت مجبور نباشد تابعی را اجرا کند که برای هدف آن مهم نیست. بنابراین، اینترفیس های خود را دسته بندی کنید.

 Dependency Inversion Principle یا اصل معکوس سازی وابستگی ها:  اگر تا به حال طراحی تست محور یا TDD را برای توسعه برنامه خود دنبال کرده باشید، می دانید که چه قدر جداسازی کد شما برای قابلیت تست و پیمانه ای بودن مهم است. هدف از این اصل استفاده درست و معنادار از اینترفیس ها است.

الگوهای طراحی

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

تصور کنید که می خواهید یک (Users () Model Class) را معرفی کنید، دو راه برای انجام آن وجود دارد:

1 — $users = new Users(); 
2 — $users = DataFactory::get(‘Users’);

من دومی را به دو دلیل ترجیح می دهم. اولاً، تغییر نام کلاس از «Users» به «UsersData» فقط نیازمند یک تغییر در یک محل «داخل کارخانه داده» است و بقیه ی کد شما همان خواهد بود. دوماً اگر کلاس Users شروع به اتخاذ پارامترهایی مانند Users ($connection) کند؛ آن وقت شما باید آن را در یک محل، نه در هر تابعی که نیازمند موضوع Users است تغییر دهید. بنابراین اگر فکر می کنید که شیوه اول بهتر است، بیشتر فکر کنید.

الگو تطبیق دهنده یا آداپتور: الگو تطبیق دهنده یکی از الگوهای طراحی ساختاری است. از نام آن، انتظار خواهید داشت که کاربرد غیرمنتظره کلاس را به یک مورد پیش بینی شده تغییر دهد.

تصور کنید که برنامه شما با API یوتیوب سر و کار دارد و برای اینکه نشان دسترسی را بدست آورید، باید از یک تابع به نام getYoutubeToken()استفاده کنید.

بنابراین شما این تابع را در 20 محل مختلف در برنامه خود فرا می خوانید.

سپس، گوگل ورژن جدید API یوتیوب را انتشار می دهد و نام آن را به getAccessToken() تغییر می دهد؛

حال شما باید نام تابع را در سرتاسر برنامه ی خود پیدا و جایگزین کنید یا می توانید یک کلاس تطبیق دهنده مانند مثال زیر ایجاد کنید:

در این شرایط، شما فقط باید یک خط را تغییر دهید و بقیه ی برنامه ی شما مثل همیشه کار خواهد کرد.

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