طراحی SDK نقشه با زبان برنامه‌نویسی گولنگ در اسنپ!

مقدمه

تو این مقاله می‌خوام در مورد فرآیند طراحی و پیاده‌سازی SDK سرویس‌های مبتنی بر نقشه در اسنپ توضیح بدم.

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

طراحی SDK نقشه با زبان برنامه‌نویسی گولنگ در اسنپ!
طراحی SDK نقشه با زبان برنامه‌نویسی گولنگ در اسنپ!


تعریف SDK

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

معمولا یک SDK برای اجرا،‌ وابسته به یک یا چند API است. این API ها می‌تونن تحت وب باشند یا کاملا آفلاین. نکته‌ی مهم دیگه که تو SDK ها وجود دارند اینه که اکثرا فقط تو یک محیط خاص (مثلا زبان برنامه‌نویسی، سیستم‌عامل و یا یک سخت‌افزار خاص) اجرا میشن.

چند مثال زیر نمونه‌های از SDK های تحت وب هستند که برای زبان‌برنامه‌نویسی گولنگ طراحی شدند:

  1. AWS SDK (Golang)
  2. Google Maps SDK (Golang)
  3. Dropbox SDK (Golang)

چرا برای سرویس‌های نقشه‌ی اسنپ نیاز به SDK داشتیم؟

ما توی تیم نقشه‌ی اسنپ (خودمون اسمپ صداش می‌کنیم!) سرویس‌های مختلفی فراهم می‌کنیم. بعضی از این سرویس‌ها عبارتند از:

  1. سرویس Reverse Geocode: کارایی این سرویس، تبدیل مختصات جغرافیایی به آدرس خوانا برای انسان است.
  2. سرویس Search: برای پیدا کردن مختصات مکانی محل‌های خاص در نقشه صرفا با استفاده از متن، از این سرویس استفاده میشه.
  3. سرویس Estimated Time of Arrival یا ETA: از این سرویس برای تخمین زمان یک سفر از نقطه‌ی «آ» به نقطه‌ی «ب» استفاده میشه.
  4. و ...

این سرویس‌ها توسط خیلی از تیم‌های اسنپ، اسنپ‌باکس، اسنپ‌فود و ... استفاده می‌شن.

نحوه‌ی استفاده‌‌ی این سرویس‌ها قبلا به این شکل بود که مستندات API ها (معمولا در قالب OpenAPI) در اختیار تیم‌های استفاده کننده قرار می‌گرفت و استفاده از API ها کاملا به عهده‌ی خود تیم بود.

این تجربه‌ی توسعه زیاد جالب نبود. هر تیمی به روش خودش از API ها استفاده می‌کرد و در نتیجه کدبیس‌های متفاوتی برای پیاده‌سازی یک functionality در سازمان به وجود می‌اومد.

در نتیجه تصمیم گرفتیم برای سرویس‌های اسمپ یک SDK بسازیم و در اختیار استفاده‌کنندگان قرار بدیم.

نکات مهم در طراحی SDK

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

کاربر‌ها را غافل‌گیر نکنید!

یک SDK خوب دقیقا همون کاری رو می‌کنه که کاربرش میگه. نه بیشتر نه کمتر! پیاده‌سازی بر اساس پیش‌فرض‌های ذهنی توسعه دهنده‌ی سرویس، که لزوما با پیش‌فرض‌های کاربر‌ان یکسان نیست، ممکنه باعث بشه در برخی از مواقع کاربر غافل‌گیر بشه.

از کمترین Dependency ممکن استفاده کنید.

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

  1. حجم کتاب‌خانه برای اون پروژه بیش‌از حد زیاده.
  2. اون پروژه داره از یک نسخه‌ی دیگه‌ای از کتاب‌خانه استفاده می‌کنه و با توجه به محدودیت بعضی از زبان‌های برنامه‌نویسی نمی‌تونه دو تا نسخه‌ از یک کتاب‌خانه رو همزمان داشته باشه.
  3. در برخی شرایط ممکنه اون کتاب‌خانه با سخت‌افزار سازگار نباشه.
  4. مشکل امنیتی توی کتاب‌خانه وجود داشته باشه. (شما هم یاد log4j افتادید؟ :)) )
  5. و ...

رفتار ثابتی در SDK طراحی نکنید!

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

چند مثال:

  1. کاربر باید بتونه آدرس سرویس‌هایی که درخواست‌ها بهشون ارسال میشه رو شخصی‌سازی بکنه. کاربر می‌تونه از این ویژگی برای Mock کردن تست‌ها و یا بهره‌برداری از سرویس‌های دیگه به عنوان fallback استفاده بکنه.
  2. کاربر باید بتونه تنظیمات مربوط به کلاینت شبکه رو با توجه به نیاز‌ها و وضعیت شبکه‌ی خودش شخصی‌سازی بکنه. برای مثال توی گولنگ باید بشه http.Transport کلاینت‌های http رو override بکنه.

تمام اطلاعات رو در اختیار کاربر بگذارید.

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

یا قابلیت لاگ‌کردن به صورت Verbose رو به صورت اختیاری برای SDK خودتون پیاده‌سازی کنید. در این صورت کاربر می‌تونه تمام اتفاقاتی که داخل SDK می‌افته رو مشاهده بکنه.

سعی کنید SDK شما قابل mock کردن باشه.

احتمالا از اهمیت تست‌نوشتن برای برنامه‌هایی که می‌نویسید با خبر هستید. پس از اونجا که تست‌کردن برای ما پسندیده است، برای کاربران SDK ما هم پسندیده‌است :)

برای این منظور می‌تونید از interface ها در گولنگ استفاده کنید.

ما تو اسمپ یک ورژن ماک‌شده‌ی آماده هم از SDK مون در اختیار کاربر قرار می‌دیم که کمتر زحمت بکشه. این کار رو با استفاده از mockgen انجام دادیم.

اگر امکانش رو دارید کد‌های SDK رو generate کنید.

معمولا کاربران از تکنولوژی‌های مختلفی برای استفاده‌از سرویس‌های ما به کار می‌گیرند. به خاطر همین موضوع بهتره رفتار‌ها و ویژگی‌های یک SDK رو با یک زبان میانی توصیف کنید و در نهایت از روی این توصیفات، SDK مربوط به زبان‌های برنامه‌نویسی مد نظرتون رو generate بکنید.

قاعدتا این کار می‌تونه خیلی پیچیده و زمان‌بر باشه. پس زمانی سراغش برید که شرایط تیمتون مناسب باشه.

نحوه‌ی پیاده‌سازی SDK نقشه اسنپ با در زبان گولنگ

ساختار کد SDK پیاده‌سازی‌شده‌ی ما در دیاگرام زیر خلاصه شده:

نمودار UML ساختار SDK
نمودار UML ساختار SDK


اطلاعات پراستفاده و مشترک بین کلاینت‌های سرویس‌های مختلف در پکیج config نگه داری شده است.

نکته: لازم به ذکر است که برای راحتی کاربران SDK می‌توان قابلیت خواندن کانفیگ از فایل، Environment variable و راه‌های دیگر را پیاده‌سازی کرد.

برای هر سرویس یک پکیج جدا در نظر گرفته شده است. برای مثال در نمودار بالا پکیج ETA را مشاهده می‌کنید.

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

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

پیاده‌سازی دیگر جهت استفاده در Unit test های کاربران SDK و Mock کردن هرچه‌ راحت‌تر تست‌هاست.

نکته‌ی بسیار مهم در طراحی interface هر سرویس، استفاده از context.Context گولنگ بوده. این امر باعث شده کنترل بیشتر و گسترش‌پذیری بسیار بالاتری داشته باشیم.

پایان

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

در ضمن، اگه حس می‌کنین از پروژه‌هایی شبیه به این خوشتون میاد و در نتیجه علاقه دارید به تیم ما ملحق بشید، خوشحال می‌شیم که رزومه‌هاتون رو از طریق آدرس engineering@snapp.cab برای ما ارسال کنید. مراقب خودتون باشید!