معماری تمیز یا "Clean Architecture" یک الگوی طراحی نرمافزاری است که به منظور جداسازی بخشهای مختلف یک سیستم و افزایش قابلیت تغییرپذیری آن، به کار میرود. در این مقاله، نگاهی به پیادهسازی Clean Architecture در قسمت Frontend یک نرمافزار خواهیم داشت. ما در این نوشته پس از آشنایی با اصول اولیه این معماری، به بررسی مزایا و معایب این رویکرد و نحوه پیادهسازی آن در برنامههای وب با یک مثال میپردازیم.
دربارهی مفهوم کلی معماری Clean صحبت خواهیم کرد و با مفاهیمی مانند لایههای domain، use case و application آشنا میشویم. سپس، به بحث در مورد اینکه چگونه این مفاهیم در فرانتاند پیادهسازی میشوند و آیا اصلاً ارزش آن را دارند، بحث خواهیم کرد.
بعد، برای یک فروشگاه آنلاین شیرینی فروشی، طراحی Frontend را با رعایت قوانین Clean Architecture شروع خواهیم کرد. در نهایت، یک use case را از ابتدا پیادهسازی کرده و مشاهده خواهیم کرد که آیا قابل استفاده است یا خیر.
برای پیاده سازی رابط کاربری این فروشگاه از React به عنوان چارچوب رابط کاربری خود استفاده خواهد شد. اگرچه استفاده از React ضروری نیست، شما میتوانید از هر کتابخانه یا چارچوب دیگری برای رابط کاربری نیز استفاده کنید.
در این نوشته کمی از TypeScript در کد استفاده خواهد شد، اما فقط برای نشان دادن اینکه چگونه از نوعها و رابطها برای توصیف شیها استفاده کنیم. هر کدی که در این نوشته بررسی خواهیم کرد، میتواند بدون استفاده از TypeScript نوشته شود.
و در نهایت، این نوشته بیشتر درباره فهم مفهوم معماری تمیز است. مثالهای ارائه شده در نوشته، سادهسازی شدهاند، بنابراین این نوشته دستورالعمل صریحی در مورد نحوه نوشتن کد نیست. ایده را درک کرده و به این فکر کنید که چگونه میتوانید این اصول را در پروژههای خود به کار ببندید.
حالا، بیایید شروع کنیم!
معماری و طراحی در اصل به معنای جداسازی چیزها به نحوی است که بتوان آنها را دوباره به هم وصل کرد. از بین بردن چیزها به بخشهایی که میتوانند به هم پیوند داده شوند، همان چیزی است که معماری را تشکیل میدهد.
Rich Hickey
مطابق این گفته طراحی سیستم، جداسازی سیستم به گونهای است که بتوان بعداً آن را ترکیب کرد و بیشتر از همه، این ترکیب باید به راحتی و بدون کار زیادی انجام پذیرد.
اما فقط این نیست. میتوانیم یک هدف دیگر برای استفاده از معماری مد نظر داشته باشیم و آن گسترشپذیری سیستم است. نیازهای برنامه همیشه در حال تغییر هستند. ما همیشه میخواهیم برنامه را به راحتی به روز کنیم و به دنبال نیازهای جدید، آن را تغییر دهیم. معماری تمیز دستیابی به این هدف را ممکن میکند.
معماری تمیز یک روش برای جداسازی مسئولیتها و بخشهای عملکردی بر اساس فاصله آنها از domain برنامه است. منظور از domain قسمتی از جهان واقعی است که با یک برنامه مدلسازی میکنیم.
معماری Clean به عنوان یک معماری سه لایهای شناخته میشود، زیرا عملکرد در آن به لایههای مختلفی تقسیم شده است. مقاله مرجع درباره معماری Clean یک نمودار با لایههای مشخص شده زیر را ارائه میدهد:
در مرکز لایه دامنه قرار دارد. این لایه شامل انتیتیها و دادههایی است که حوزه موضوعی برنامه را توصیف میکنند، همچنین کدهایی برای تغییر این دادهها نیز در این لایه قرار دارد. دامنه، هستهای است که یک برنامه را از برنامه دیگر متمایز میکند.
میتوانید از دامنه به عنوان چیزی یاد کنید که اگر از React به Angular حرکت کنیم تغییر نخواهد کرد. در واقع این قسمت مستقل از چارچوب مورد استفاده خواهد بو. در صورتی که در مورد domain یک فروشگاه صحبت کنیم، شامل محصولات، سفارشات، کاربران، سبد خرید و توابع برای به روزرسانی دادههای آنها است.
ساختار دادههای موجود در دامنه و ماهیت تغییرات آنها، مستقل از جهان بیرون است. رویدادهای خارجی تغییر دادههای دامنه را آغاز میکنند، اما نحوه وقوع آنها را تعیین نمیکنند.
برای مثال تابع اضافه کردن آیتم به سبد خرید، اصلا اهمیتی نمیدهد که این آیتم به چه صورتی به سبد خرید اضافه شده است: از طریق لمس دکمه "خرید" توسط خود کاربر یا به صورت خودکار با یک کد تبلیغاتی. در هر دو حالت، آن آیتم را به عنوان یک ورودی قبول میکند و یک سبد خرید به روز شده با آیتم اضافه شده را برمیگرداند.
در اطراف لایه دامنه، لایه اپلیکیشن وجود دارد. این لایه شامل use caseهایی است که به عنوان سناریوهای کاربر مشخص شدهاند و مسئول آنچه بعد از وقوع یک رویداد اتفاق میافتد میباشد.
به عنوان مثال، سناریو «افزودن به سبد خرید» یک use case است. این سناریو، اقداماتی که باید بعد از کلیک دکمه انجام شود را توصیف میکند. این سناریو میگوید:
در همین لایه، پورتها نیز وجود دارند که توصیفکنندهی نحوهی ارتباط برنامهی ما با جهان خارجی هستند. معمولاً پورت، یک interface یا به عبارتی قرارداد رفتاری است. پورتها به عنوان یک «buffer zone» بین خواستههای برنامه ما و واقعیت عمل میکنند.
پورتهای ورودی به ما میگویند که برنامه چگونه با جهان خارج باید ارتباط برقرار کند. پورتهای خروجی هم میگویند که برنامه چگونه با جهان خارج برای آماده شدن باید ارتباط برقرار کند.
در ادامه در مورد پورتها بیشتر صحبت خواهیم کرد.
این لایه از نرمافزار مجموعهای از آداپتورهاست که دادهها را از فرمتی که بیشترین سازگاری با use caseها و موجودیتهای سیستم دارند به فرمتی که برای یک سازمان خارجی مانند پایگاه داده یا وب بیشترین سازگاری را دارد تبدیل میکنند. به عنوان مثال، این لایه معمولاً کل معماری MVC رابط کاربری گرافیکی را در بر میگیرد. مدلها، ویوها و کنترلکنندهها (model-view-controller) همه در این لایه قرار دارند. مدلها احتمالاً فقط ساختار دادهای هستند که از کنترلکنندهها به use caseها منتقل میشوند و سپس از use caseها به مدلها و ویوها بازمیگردند.
این ساختار سه لایه دارای یک قانون وابستگی است: فقط لایه های بیرونی می توانند به لایه های درونی وابسته باشند.
این بدان معناست که:
گاهی اوقات ممکن است این قانون نقض شود، اما بهتر است از آن سوء استفاده نشود. به عنوان مثال، گاهی اوقات استفاده از کدی شبیه به کتابخانه در دامنه، هرچند این لایه نباید وابستگی داشته باشد، راحتتر است. در قسمتهای بعد، به یک مثال از این موضوع میپردازیم.
یک جهت کنترل نشده از وابستگیها میتواند منجر به کدی پیچیده و گیجکننده شود. به عنوان مثال، نقض قانون وابستگی میتواند منجر به ایجاد وابستگیهای چرخهای شود که در آن ماژول A به B، B به C و C به A وابسته است. همچنین، این موضوع میتواند منجر به کاهش قابلیت تست، افزایش ارتباطات بین ماژولها و در نتیجه، برهمکنش شکننده بین ماژولها شود.
شروع هر کاری سخت است، اما به یاد داشته باشید هر روز کمی آسانتر خواهد شد :)
بازنشر و نظر شما با ارزش و باعث دلگرمی است ❤︎