ساختار Folder per feature MVVM

نرم افزار ها نقش حیاتی برای یک کسب و کار رو دارن و یک اپلیکشن بد میتونه آینده یک کسب و کار رو تحت تاثیر قرار بده و برعکس این موضوع هم صادقِ هرچه نرم افزار توسعه پذیر تر باشه و هزینه نگهداری کمتری داشته باشه احتمال موفقیت اون کسب و کار بیشتر میشه!

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

چند نمونه از چالش های پیش رو

  • امکان اسکیل کردن پروژه (به صورت ماژولار یا مایکرو فرانت اند)
  • امکان نوشتن تست برای پروژه
  • قابلیت نوشتن چند UI مختلف
  • قابلیت استفاده مجدد از کامپوننت ها
  • یادگیری ساده برای اعضای جدید تیم
  • امکان داکیومنت کردن پروژه
  • و....

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

  • معماری Clean
  • معماری پیازی
  • معماری MVC
  • معماری MVVM

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

  • معماری Group by file types
  • معماری Group by Features

و در نهایت تصمیم گرفتم معماری فولدر های مختلف رو با استفاده از مزیت های ذکر شده در معماری های بالا و شبیه به معماری Group by Features پیاده سازی و متناسب به نیاز های پروژه شخصی سازیش کنم


folder per feature mvvm
folder per feature mvvm


پوشه Assets:

در این پوشه تمامی فایل های مورد نیاز توسعه مانند فایل های SVG تصاویر آیکون ها فونت ها و... قرار میگیرد.


پوشه API:

یکی از چالش هایی که ممکنه داشته باشیم بحث ارتباط با سرور هستش و ممکنه یکسری از دیتا هایی که از سمت سرور برگردانده میشود به هر دلیلی نیاز به بررسی مجدد و تغییر یا تبدیل داشته باشن. در این فولدر طبق استاندارد RESTful API برای هر اند پوینت یک CRUD در نظر میگیریم.

پوشه Utility:

− پوشه Helpers:

در پوشه Helpers میتوان تابع هایی که در طول زمان توسعه نرم افزار چندین بار مورد استفاده قرار میگیرند را قرار داد

− پوشه Hooks:

در این پوشه میتوان کاستوم هوک هایی نوشت که در توسعه برنامه چندین بار مورد استفاده قرار گیرند

− پوشه Consts:

همانطور که از نام این پوشه مشخص است میتوان یک یا چندین فایل مختلف در این پوشه برای نگهداری ثابت های پروژه استفاده کرد
مثلا میتوان تمامی متن های استفاده شده در برنامه و... را در این پوشه قرار داد


پوشه Components:

در این فولدر سه بخش مختلف داریم که در ادامه بررسی میکنیم

- پوشه UIKit:

در این پوشه تمامی کامپوننت های جزئی ولی پر تکرار پروژه قرار داده می شود برای مثال ما در پروژه ۵ نوع دکمه مختلف داریم که کاربرد های تقریبا مشابه دارند ولی دیزاین های متفاوتی دارند و برای همین یک کامپوننت به اسم Button در این پوشه ایجاد میکنیم.


- پوشه Shared:

بصورت پیشفرض این پوشه خالی میباشد و در تیم این قرارداد را رعایت میکنیم که هر سکشنی از صفحات باید به صورت Local components در نظر گرفته بشه ولی هر کامپوننتی در دیزاین که بیشتر از یکبار استفاده بشه باید به این پوشه انتقال پیدا کنه.

پوشه Pages

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

کامپوننت هایی که در این صفحه به قسمت های کوچک تبدیل میشن به عنوان Local components در نظر گرفته میشن و در صورتی که در چندین جای پروژه استفاده بشن به Components/Shared انتقال پیدا میکنن.


پیاده سازی

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

صفحه جزییات معامله
صفحه جزییات معامله


مرحله اول: باید به ازای این صفحه یک پوشه جدید به اسم DealDetails در پوشه Pages ایجاد کنیم

جدا سازی هدر و فوتر
جدا سازی هدر و فوتر


مرحله دوم: قسمت هایی مثل هدر و فوتر صفحه که با صفحات دیگر مشترک است باید در پوشه Components/Shared پیاده سازی شود

folder per feature components
folder per feature components


مرحله سوم: در این مرحله باید هر قسمت صفحه به کامپوننت های معنادار تقسیم شود.

ابتدا یک پوشه کامپوننت محلی برای جزییات معامله در نظر میگیریم. سپس این کامپوننت را به

سه قسمت وضعیت معامله، جزییات و موارد معامله (رنگ آبی) تقسیم میکنیم

این روند را برای تک تک این کامپوننت ها نیز مجدد اجرا میکنیم و کامپوننت وضعیت معامله نیز به دو قسمت قیمت و تایم لاین (رنگ قرمز) شکسته میشود

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

در نهایت باید خروجی فولدر ها مشابه تصویر زیر باشد

folder per feature MVVM
folder per feature MVVM


در تصویر بالا بعد از این که هر بخش رو به کامپوننت های کوچکتر تقسیم کردیم به ازای هر کامپوننت باید چند فایل ساخته شود که در ادامه در مورد هر کدام توضیح میدم

فایل item.js:

در این فایل فقط لایه view کامپوننت پیاده سازی میشه و قسمت منطق کامپوننت نباید در این لایه قرار بگیره و هر قسمتی که نیاز به لاجیک داشتیم باید از کاستوم هوک هایی و توابعی که در useItem.js پیاده شده استفاده کنیم

فایل useItem.js:

در این فایل باید تمامی منطق های کامپوننت پیاده سازی بشه همچنین تمام استیت ها در این فایل قرار میگیره و تمامی این تابع ها میتوانند توسط items.js استفاده شوند

فایل item.style.js:

در صورتی که برای استایل دهی فایل ها از styled-components یا ابزار های مشابه استفاده کنیم بهتر است استایل ها را جدا کرده و در این فایل قرار دهیم

فایل item.test.js:

در صورتی که برای پروژه تست بنویسیم تست ها در این فایل قرار می گیرد


چند نمونه از مزیت های جداسازی منطق و رابط کاربری

  • منطق برنامه به تنهایی قابل تست میباشد
  • میتوان با یک منطق چندین UI متفاوت پیاده سازی کرد (مثلا دو نسخه متفاوت برای موبایل و وب توسعه داد)
  • میتوان به راحتی لایه view پروژه را ریدیزاین کرد
  • یادگیری و تسلط نیرو جدید با این استراکچر بیشتر است
سخن پایانی
استفاده از این استراکچر یا هر معماری دیگه ای در هر پروژه ای ضروری نیست و تا حدود زیادی به عواملی همچون سایز پروژه و ظرفیت تیم و نوع دیزاین بستگی دارد.
این معماری بیشتر در پروژه هایی که پیش بینی میشود نیاز به اسکیل شدن پیدا میکنند پیشنهاد میشود و در پروژه های کوچک باعث ایجاد پیچیدگی بی دلیل میشود