در این مقاله اقدام به ماژول‌بندی پروژه چند پلتفرمی کاتلین به صورت یک مبدل ارزی برای iOS و اندروید می‌کنیم که دارای چند ماژول مشترک است. توجه کنید که پروژه‌های چند پلتفرمی کاتلین در کاتلین 1.2 و 1.3 هنوز در مرحله آزمایشی قرار دارند و خالی از اشکال نیستند. استفاده از آن‌ها برای اپلیکیشن‌های پروداکشن توصیه نمی‌شود.

مقدمه‌ای بر پروژه‌های چند پلتفرمی کاتلین

Kotlin Multiplatform امکان اشتراک کد را بین پلتفرم‌های مختلف فراهم می‌سازد. تفاوت کلیدی آن با دیگر ابزارهای چند پلتفرمی ‌این است که همه کدها را به صورت کد خاص پلتفرم کامپایل نمی‌کند. به جای آن کنترل کاملی روی آن چه که به اشتراک گذاشته خواهد شد و آن چه که native خواهد بود به دست می‌آوریم. به طور کلی عموماً منطق تجاری به اشتراک درمی‌آید و UI به صورت native پلتفرم عرضه می‌شود تا تجربه کاربری طبیعی‌تری به دست آید. بدین ترتیب می‌توانیم از مزیت نوشتن اپلیکیشن‌های چند پلتفرمی بهره‌مند شویم و همزمان از محدودیت‌هایی که معمولاً در این مسیر وجود دارد، مانند فقدان انعطاف‌پذیری در نوشتن کد خاص پلتفرم نیز اجتناب کنیم.

این قابلیت به وسیله کتابخانه استاندارد کاتلین (+) برای نوشتن ماژول و سپس کامپایل کردن کد به پلتفرم‌های مقصد مختلف مانند JVM ،JS و Native فراهم شده است. این بدان معنی است که Kotlin/JVM یا هر کد جاوا یا جاوا اسکریپت دیگر نمی‌تواند برای نوشتن کد مشترک مورد استفاده قرار گیرد. دسترسی به API پلتفرم با استفاده از مکانیسم expect/actual (+) انجام می‌شود.

ماژول‌بندی

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

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

ما می‌توانیم اپلیکیشن‌های خود را بر اساس قابلیت‌هایش ماژول‌بندی کنیم. در مثالی که در ادامه آمده است، مبدل ارز یک قابلیت در سیستمی بسیار بزرگ‌تر است که به صورت مستقل از کامپوننت‌های دیگر مانند analytics یا مدیریت کاربر توسعه یافته است. ما می‌توانیم با تجرید وابستگی‌ها به منابع و زیرساخت‌های بیرونی، مبدل ارز را بیشتر توسعه دهیم و بدین ترتیب می‌توانیم برای نمونه به سادگی بین سرورها سوئیچ کنیم یا از کلاینت‌های HTTP مختلف روی پلتفرم‌های متفاوت بهره بگیریم.

معماری خاصی که در این مثال دنبال می‌کنیم، «معماری شش‌گوشه» (Hexagonal architecture) نام دارد که گاهی به صورت «پورت و آداپتر» نیز نامیده می‌شود. معماری شش‌گوشه با قرار دادن ورودی‌ها و خروجی در لبه طراحی، منطق اصلی اپلیکیشن را از دغدغه‌های بیرونی جدا می‌کند. بدین ترتیب می‌توانیم به سادگی پیاده‌سازی آن‌ها را بدون تغییر دادن منطق مرکزی تغییر دهیم.

مبدل ارز

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

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

مدخل اصلی برای استفاده از مبدل کامپوننتی به نام CurrencyConverter است. این مبدل به صورت درونی از ExchangeRateProvider استفاده می‌کند که داده‌های نرخ مبادله را واکشی می‌کند و در ادامه کامپوننت RateCalculator عمل تبدیل را اجرا می‌نماید.

زمانی که مبدل را می‌سازیم، لازم است که کلاینت‌ها یک پیاده‌سازی ExchangeRateProvider را نصب کنند تا کاملاً عملیاتی شود. طرز کار سفارشی‌سازی قابلیت ما به این صورت است. برای مشاهده کد منبع این مثال به این ریپوی گیت‌هاب (+) مراجعه کنید.

نمای سطح بالای این راه‌حل به صورت زیر است:

 پروژه چند پلتفرمی کاتلین

ماژول‌ها

در این اپلیکیشن از ماژول‌های زیر استفاده شده است.

  • currency-converter-core – ماژول اصلی است که تنها شامل منطق دامنه است و پیاده‌سازی ندارد.
  • rate-provider-mock – یک پیاده‌سازی ساختگی از ارائه‌دهنده نرخ است که نرخ‌های مبادله آن جعلی است و روی همه پلتفرم‌ها کار می‌کند.
  • rate-provider-api-ktor – (TBD) پیاده‌سازی Ktor از یک ارائه‌دهنده نرخ است. Ktor یک کلاینت Http چند پلتفرمی است و از این رو می‌توانیم از این ماژول روی همه پلتفرم‌های مقصد استفاده کنیم.
  • rate-provider-api-retrofit – (TBD) پیاده‌سازی Retrofit از یک ارائه‌دهنده نرخ است. این یک کتابخانه عالی است، اما مقاصد آن صرفاً جاوا و اندروید است. این بدان معنی است که برای پلتفرم‌های مقصد دیگر نمی‌توانیم از این ماژول استفاده کنیم.
  • ios-configuration – در این نسخه (کاتلین 1.3) پشتیبانی از اپلیکیشن iOS تنها یک ماژول K/MPP است. برای دور زدن این وضعیت و دستیابی به یک اپلیکیشن چند پلتفرمی باید همه ماژول‌ها را برای اپلیکیشن iOS در این ماژول جای بدهیم و به اپلیکیشن iOS اضافه کنیم.

کاربرد در اپلیکیشن‌های کلاینت:

تصاویر اپلیکیشن

 پروژه چند پلتفرمی کاتلین

محدودیت‌های پروژه‌های چند پلتفرمی کاتلین

هنوز هیچ IDE منفردی ارائه نشده است که در آن بتوان یک اپلیکیشن چند پلتفرمی مورد پشتیبانی Kotlin Multiplatform نوشت. بنابراین در این مسیر باید به صورت مداوم از IDEA به اندروید استودیو، به Xcode و غیره جابجا شوید. پیکربندی gradle برای ماژول‌های مشترک چندان سرراست نیست و برخی بخش‌ها باید به صورت دستی انجام شود. عیب بزرگ‌تر این است که Kotlin Multiplatform هنوز یک محصول تمام نشده محسوب نمی‌شود و تا آن زمان می‌توان تصور کرد که issue-های build دیگری در نسخه‌های بعدی ظاهر شوند. با این حال بررسی آن جهت آماده شدن برای آینده در حالت آزمایشی ارزشش را دارد.

فریمورک‌های چندگانه K/MPP برای iOS

ماژول iOS به صورت یک فریمورک پکیج شده است و در حال حاضر نمی‌توان بیش از یک فریمورک Kotlin Multiplatform در پروژه iOS ایمپورت کرد. این وضعیت با رویکرد چند ماژول که در این مقاله مطرح کردیم چندان سازگار نیست. به عنوان راه‌حل می‌توان یک ماژول ios-configuration module جدید اضافه کرد تا وابستگی‌های iOS در آن قرار گیرند.

در حال حاضر gradle هیچ پشتیبانی برای ساخت پروژه‌های iOS ندارد و از این رو راه‌اندازی یک فریمورک خودکار برای پیوند دادن به پروژه iOS به خصوص در مورد ماژول‌های چندگانه مشترک نیاز به اندکی تلاش دارد. این مانعی است که باید از سر راه برداریم و این کار نیز بی‌فایده نیست، زیرا امکان تغییر ماژول‌های مشترک برای ایمپورت خودکار در پروژه‌های iOS را فراهم می‌سازد.

پروژه چند ماژولی Gradle

Gradle به عنوان یک ابزار اتوماسیون build استفاده می‌شود، زیرا از پلتفرم‌های مورد استفاده کنونی به استثنای iOS پشتیبانی می‌کند. در این مثال یک پروژه خالی Gradle ایجاد شد و ماژول‌ها به تدریج چنان که در این راهنما (+) توضیح داده شده است به آن اضافه شدند.

سخن پایانی

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

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

میثم لطفی (+)

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

آیا این مطلب برای شما مفید بود؟

نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *