ویرگول
ورودثبت نام
SAJAD noroozi
SAJAD norooziکمی اندروید دولوپر کمی کنجکاو
SAJAD noroozi
SAJAD noroozi
خواندن ۵ دقیقه·۶ ماه پیش

Orchestrator Class

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

پیش فرض:
ما یه اپلیکیشن Clean Architect داریم
اپ ما لاجیک نسبتا زیادی تو هر قسمت داره به شکلی که چند یوزکیس مختلف میتونن درگیر یک فلوی بیزنسی بشن

چی شد که به این جا رسیدم؟

درگیر یه مشکل معماری تو ذهنم بودم من یک فلو دارم تو پروژه ام که چندتا یوزکیس درگیرش میشن! تو ویو مدل مدیریتش کنم ؟ به نظرم نه
بریم یه یوزکیس براش بسازیم ولی آخه این یوزکیسه واقعا؟؟ آره هست ولی مگه بست پرکتیس های ما همیشه نمیگن که یوزکیس باید اتمیک باشه حس میکنم هم هست هم نیست !
کلی هم گشتم و چرخیدم که ببینم ساختار دامین ماژول ها و ترکیب و تفکیک شون چطوری میتونه بهترین حالت رو تو پروژه های بزرگ ایجاد کنه چون حس میکردم یه چیزی هست که نمیدونم ! یا یادم رفته
بعداز کلی سر و کله زدن با ai بهم گفت که ترکیب ماژول مشترک دامین و لوکال دامین ها راه حل خوبیه برای چیزی که تو ذهنته حالا برای مشکلت بهتره بعد با Orchestrator ترکیبش کنی و این ترکیب برنده ایه که توی UBER و SPOTIFY داره استفاده میشه و من اینجوری بودم که فععععک نکنم ولی بگو ببینم داستان این Orchestrator Layer چیه ؟؟
یکم توضیح داد منم شروع کردم چرخیدن تو مدیوم و اینور اونور ببینم داستان چیه ! که خروجیش شد این پست حالا بریم سراغ اصل داستان

مشکل چیه ؟

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

  • ماژول login شامل LoginUseCase
  • ماژول SharedDomains شامل GetUserProfileUseCase
  • ماژول settings شامل ApplyUserPreferencesUseCase
  • حالا یه نیاز بیزینسی داریم: «بعد از لاگین، پروفایل کاربر رو بگیر، تنظیماتش رو نگه دار و بعد بفرستش به Home.»
    اگر این فلو رو تو LoginUseCase انجام بدی باید به SharedDomains و settings دسترسی داشته باشی اولی اوکی ولی دومی وابستگی نابجا ایجاد میکرد یعنی login به همه چی وابسته می‌شه و از طرفی فقط لاگین رو مدیریت نمیکنه(Violation of Separation of Concerns)

    خب من میخوام در لایه دامین بتونم این رو مدیریت کنم و انجامش بدم (چون به نظرم بیزنس لاجیکه) بدون اینکه لقمه رو دور سرم بچرخونم و باانتقالش به لایه های بالاتر بیزنس لاجیک رو در ویو مدل ویو یا جاهای دیگه دخیل کنم !

    اژدها وارد میشود :
اژدها وارد میشود
اژدها وارد میشود

اژدها که بود و چه کرد؟
Orchestrator یه لایه یا کلاس واسطه که از UseCaseهای مختلف (از ماژول‌های مختلف) استفاده می‌کنه و اون‌ها رو طبق یک (business flow) با هم هماهنگ می‌کنه بدون اینکه این UseCaseها مستقیماً از وجود همدیگه خبر داشته باشن. بهش Composite UseCase یا Flow-Level UseCase هم میگن در اصل تو همیشه نیاز خواهی داشت که ترکیبی از عملکرد یوزکیس ها رو تو یه فلو داشته باشی و تجربه من میگه اکثرا این لاجیک رو بدون توجه به جنس بیزنسیش میارن لایه های بالاتر مدیریت میکنن ! مثلا ویو مدل !! در حالی که وظیفه ویو مدل باید محدود به مدیریت state باشه نه منیج کردن ارتباط یوزکیس ها برای پیاده سازی بیزنس فلو
اینجا بود که فهمیدم بله کامپوزیت یوزکیس رو قبلا دیدم !
چجوری هست حالا ؟مثلا اینجوری :

class LoginFlowOrchestrator @Inject constructor( private val loginUseCase: LoginUseCase, private val fetchProfileUseCase: FetchProfileUseCase, private val applyUserSettingsUseCase: ApplyUserSettingsUseCase) { suspend fun execute(email: String, password: String): Result<Unit> { val loginResult = loginUseCase(email, password) if (loginResult.isFailure) return Result.failure(loginResult.exceptionOrNull()!!) val profile = fetchProfileUseCase() applyUserSettingsUseCase(profile.preferences) return Result.success(Unit) } }

خب حالا این هماهنگ کننده جاش کجاست در معماری کلین معمولا بین لایه دامین و UI قرار میگیره
پس میشه Ui به Orchestrator به Domain
یه چیزی شبیه همون شوخی معروف باقرزاده تو اون فیلمه ! بهرحال راه درست بردن این لاجیک تو ویو مدل نیست و کار خوبی هم نیست
در اصل ما تو این حالت میایم Composite UseCase یا Flow-Level UseCase یا همون Orchestrator هامون رو از یوزکیس های ساده مون جدا میکنیم و تبدیلشون میکنیم به یه لایه جدید که در سطح بالاتری از یوزکیس هامون جا میگیرن تا بتونیم فلو ها رو کنترل کنیم و کنترل فلو های مربوط به بیزنس لاجیک رو نبرین تو لایه های بالاتر ! هرچند میشه تو خود دامین هم انجامش داد ولی اگر پروژه از یه حدی بزرگتر باشه و تعداد فلوی های پیچیده مون از یه اندازه ای بیشتر بشه منطقی تر اینه که لایه جداگانه ای داشته باشه
به دلیل اینکه به نظر نمیرسه همیشه تو تمام ماژول هامون یک فلوی پیچیده رو تکرار کنیم ! ترجیحم این بود که لایه Orchestrator بیاد و بخشی از ماژول هامون بشه نه بخشی از دامین ماژول مشترک اپ که شامل یوزکیس های پر تکراره در نتیجه تو هر فیچر ماژولم از لایه دامین شروع کردم ( یوز کیس هایی اختصاصی فیچر ) و بعد تو لایه Orchestrator میتونستم ترکیبی از یوز کیس های اشتراکی و اختصاصی رو باهم ترکیب کنم !

در نهایت یه نکته راجع‌به اسم Orchestrator:

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

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



۲
۰
SAJAD noroozi
SAJAD noroozi
کمی اندروید دولوپر کمی کنجکاو
شاید از این پست‌ها خوشتان بیاید