Activityها در اندروید عناصر UI محسوب نمی شوند

پنج شنبه ۲۰ اردیبهشت ۹۷ توسط یوسف رضا مختاری

در این پست Activity را از دیدگاه اصل تک مسئولیتی(Single responsibility principle) طراحی شی گرا مشاهده خواهیم کرد و تلاش برای درک تک مسئولیتی که بهترین راه ارتباط با Activity در اندروید می باشد .

Activity:

توضیحات زیر در صفحه رسمی  “Activity ها” در گوگل مشاهده میشود.

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

بعد از چنین مقدمه ای , طبیعی است که ما درباره Activity ها از لحاظ UI اپلیکیشن فکر کنیم .

امروزه وقتی که موضوع طراحی ماژولار بطور ویژه ای محبوب شد بسیاری از مخفف ها (مثل MVP) به رتبه “buzz-word” ارتقا یافتند , احساس اینکه Activity به عنوان عنصر UI میباشد به خصوص قابل توجه است.

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

من شروع به تعجب کردم که آیا , ممکن است , پس از این همه , جزئیات پیاده سازی UI  به Activity ها متعلق نباشد؟

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

 

اصل تک مسئولیتی

اصل تک مسئولیتی ,  همانطور که توسط رابرت مارتین (مهندس نرم‌افزار , مؤلف آمریکایی و رئیس موسسه مشاوره با نام "عمو باب" ) تنظیم شده است ، می گوید :

برای تغییر یک کلاس فقط باید یک دلیل وجود داشته باشد.

بمنظور بحث جاری , ما لیست "دلایل تغییر" را به دو دلیل محدود خواهیم کرد  :

  • طراحی مجدد UI که عملکرد کلی اپلیکیشن را تغییر نمی دهد . ( " چهره سازی یا facelift " )
  • تغییر در عملکرد که نیاز به هر گونه تغییری در UI اپلیکیشن ندارد .

ما تمام منطق هایی که به خاطر دلیل 1# (تغییرات UI) به طور بالقوه ای تغییر می کنند را به عنوان "منطق UI" تعیین خواهیم کرد .

ما تمام منطق هایی که به خاطر دلیل 2# (تغییرات عملکرد) به طور بالقوه ای تغییر می کنند را به عنوان "منطق business" تعیین خواهیم کرد .

به منظور پیروی از "محدود شده"  اصل  تک مسئولیتی , کلاس ها در اپلیکیشن ما نباید دارای "منطق UI " و "منطق business"  با هم  باشد.

 

چرا منطق UI و business مجزا هستند؟

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

خب ، در حالی که این درست است که منطق UI و business می توانند در کنار هم باشند . مزایای واضح برای جدایی کامل آنها وجود دارد .

برخی از این مزایا عبارتند از:

  • تغییرات UI آسان می باشد –اگر آنها از هم جدا باشند شما میتوانید UI را آپدیت و یا حتی به طور کامل جایگزین کنید در حالی که منطق business (تقریبا) دست نخورده و حفظ می ماند  .
  • منطق UI "آلوده" و منطق business "مبهم" -  هر دو منطق  business و منطق UI  اگر ازهم جدا باشند بسیار خوانا و قابل نگهداری خواهند بود .
  • تست واحد یا unit test (امکان تست هر بخش از برنامه و کد به صورت جداگانه) برای UI مشکل است – شما قطعا برای منطق business به تست واحد نیاز دارید اما اگر UI به صورت "abstract" پیاده سازی نشده نباشد برای استفاده  از منطق business خود شما نیاز به اعمال سناریو های تست روی عناصر UI دارید که در حقیقت بسیار مشکل و فریب دهنده می باشد. (و تست های شما هر بار با تغییر UI تغییر خواهد کرد)

لیست فوق از مزایا نه کامل است و نه موارد ذکر شده لزوما مزایای اصلی می باشند ، اما نشان می دهد که جدایی UI و منطق business چیزی است که ما قطعا می خواهیم در برنامه های خود داشته باشیم.

 

روش "استاندارد" پیاده سازی Activity :

حالا که ما  با تفیک منطق UI  و منطق business موافقت کردیم که یک ویژیگی مطلوب سیستم است , ما می توانیم به Activity ها بازگردیم .

آیا ممکن است راهی که معمولا Activity ها رو پیش از این پیاده سازی میکردیم در حال حاضر نتیجه مطلوب را تولید کند؟

من فکر نمی کنم . اجازه دهید به یک مثال ساده نگاه کنیم .

دو مسئولیت زیر میتواند در یک Activity در تقریبا هر برنامه ای یافت شود :

  1. Register listeners یا ثبت شنونده برای تعامل کاربران با UI اپلیکیشن
  2. انجام اقداماتی در واکنش به تعامل کاربران با UI اپلیکیشن

 این طبیعی است که Activity هم registers listener ها و هم تعامل با کاربر را مدیریت می کند ؟ این درسته ؟

اما بیایید از زاویه ای متفاوت نگاه کنیم . برای register listener با اجزای UI اکتیویتی باید از ID آن ها (*.R.id) آگاه باشد .

این یک وابستگی واضح به جزئیات پیاده سازی UI است  - Activity نام اجزای UI  را "می داند" . (و معمولا، نوع شان را هم می داند: TextView، Button و غیره)

بنابراین، مسئولیت 1# از لیست فوق به "سبد منطق UI" می افتد .

در پاسخ به تعامل کاربر با UI برنامه ، Activity می تواند دستکاری های مختلف در UI انجام دهد (به عنوان مثال تغییر رنگ ها و شکل ها)

اما معمولا،اقداماتی را اعمال میکند که ارزش اضافی برای کاربر فراهم می کنند

(به عنوان مثال توجه داشته باشید که برنامه ی یادداشت برداری با کلیک روی دکمه ذخیره یادداشت را ذخیره می کنند)

این اقدامات دستکاری UI نیست و به هیچ وجه به UI بستگی ندارد - آنها از تعریف جهانی  "عملکرد" برنامه اخذ شده .

این برنامه ها "قوانین business " هستند .

بنابراین، در مورد معمول ترین، مسئولیت شماره 2# از لیست فوق به "سبد منطق business "  میافتد.

آنچه که مشاهده کردیم این است که حتی  در ساده ترین شیوه register listener با اجزای UI و مدیریت تعامل با این اجزا در یک کلاس باعث می شود UI و منطق business به هم پیوسته شوند.

و هر توسعه دهنده ای که تا به حال تجربه debug اکتیویتی هایی که دارای 500+ خط کد هستند , که بسیاری از آن ها دستکاری UI می باشد که با چند خط از منطق business جاسازی شده، رنج تلاش برای کشف مشکل و نحوه رفع آن را می داند (بدون شکستن هر چیز دیگری).

 

چرا Activity ها عناصر UI نیستند

برای پیوستن به اصل "محدود شده" تک مسئولیت ما، Activity ها در اپلیکیشن ما باید شامل تنها منطق UI یا فقط تنها business باشد. کدام رویکرد بهتر است؟

به نظر می رسد که تیم پلتفرم Android قبلا برای ما تصمیم گرفته است. فهرست زیر وابستگی های Activity است که جداسازی منطق business از Activity به طور عملی غیر ممکن است :

  • Activity ارث میبرد از Context

فهرست کامل از تمام ویژگیهایی که Activity را غیرقابل جداسازی از منطق business برنامه می کند خیلی طولانی تر است (برای مثال runtime permission، ادغام با LoaderManager و غیره)، اما این یکی به تنهایی کافی می باشد. ممکن است شگفت آور باشد که چنین واقعیتی اساسی که همه ما به آن عادت کرده ایم اهمیت زیادی دارد، اما واقعا ساده است.

 

عملا، اشیاء Context دسترسی به اکثر ویژگی های پلت فرم را فراهم میکند که برنامه های شخص ثالث می توانند استفاده کنند. این یک  چیز کلی است ، اما در این پست ما نیاز به توضیحات بیشتری دراین باره نداریم.

از آنجا که Activity یک زیر کلاس context است، برنامه های ما از API آن برای کنترل زیر مجموعه ای از ویژگی ها  استفاده می کنند  و منابع پلتفرم را کنترل کند.

این منطق که این ویژگی ها و منابع را "هماهنگ" می کند منطق business می باشد. بنابراین، صرف نظر از اینکه چقدر سعی کنیم، ما نخواهیم توانست منطق business را از Activity ها کاملا جدا کنیم.

از آنجایی که ما نمی توانیم منطق business را از Activity ها جدا کنیم، باید تمام منطق UI را از آن جدا کنیم. این کاری بی اهمیت نیست، در دراز مدت ارزش زیادی دارد .

 

آزمون آلودگی:

برای اینکه بتوانیم در مورد جدایی UI و منطق business کمی بحث کنیم، باید نوعی "معیار کثیفی"  یا “dirtiness metric” را تعریف کنیم - یک مقدار قابل اندازه گیری که می تواند به عنوان نشانه ای از  چگونگی «کثیفی» منطق ما باشد. در واقع، ما دو معیار را تعریف می کنیم: یکی برای منطق business و یکی برای منطق UI.

آزمون آلودگی منطق business (برای Activity ها) :

هر رخداد از یکی از موارد زیر در Activity های شما یک "نقطه ضعف" یا " آلودگی "است:

  1. مراجعه به *.R.layout  (فایل های layout)
  2. مراجعه به *.R.Id) ID های View)
  3. وابستگی به هر class یا interface که ویژیگی های 1 و 2 را داراست .

 

توجه داشته باشید که این تست "انتقالی" است - نه تنها Activity های شما نباید از جزئیات پیاده سازی UI  آگاهی داشته باشند، بلکه کلاس هایی که در Activity ها ارجاع داده اید، نمی توانند این اطلاعات را نیز داشته باشند.

بنابراین، شما «کد کثیفی» که در برخی از کلاسهای «کمکی» که در Activity بکار میبرید وجود دارد را نمیتوانید قرار دهید .(مگر اینکه  هدف شما از آزمون آلودگی 0 نباشد)

 

آزمون آلودگی منطق UI (برای کلاس هایی که منطق UI را encapsulate می کنند):

رخداد یکی از موارد زیر در کلاس هایی که منطق UI را کپسوله می کند، یک "نقطه ضعف" است :

  1. وابستگی به Activity
  2. وابستگی به هر class یا interface که ویژیگی 1 را داراست .

توجه داشته باشید که این آزمون نیز "انتقالی" است - نباید "سلسه وابستگی" از کلاسهایی باشد که منطق UI را نسب به Activity ها کپسوله میکنند . متاسفانه، من نمی توانم وابستگی به Context را به عنوان "نقطه ضعف" تعریف کنم - شما باید یک Context برای کپسوله کردن محتویات کلاس های UI ایجاد کنید ، زیرا هیچ راهی برای پر کردن یک View بدون  اشاره به یک Context وجود ندارد(Context یک God  برای Object ها می باشد یادتون هست؟)

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

نتیجه:

در این پست ما بحث کردیم که چرا Activity ها در اندروید نباید شامل منطق UI باشد. ما با پذیرش این که جدایی منطق UI از منطق business یک ویژگی مطلوب است، نشان دادیم که تفکیک منطق business و  Activity  غیر ممکن می باشد به دلیل اتصال بسیار محکم Activity به بخش های مختلف framework اندروید. ما همچنین "معیارهای آلودگی" را برای منطق business و UI تعریف کردیم تا بتوانیم "آلودگی" را در برنامه های خود اندازه گیری کنیم.

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

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

 

امیدوارم این مطلب برای شما مفید بوده باشد .

 
 

 

 
 
 
 

کلیدواژه: اصل تک مسئولیتی Single responsibility principle منطق UI منطق business روش استاندارد پیاده سازی Activity Dirtiness test

منابع: www.techyourchance.com

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