انتخاب Go هنگام ساخت Lambdas

بنابراین شما تصمیم گرفته اید که اولین یا پانصدمین تابع Lambda خود را با AWS بسازید. تبریک می گویم! این به خودی خود یک تصمیم عالی است که شما را بر پایه ای محکم برای تعالی عملیاتی، سهولت نگهداری، انعطاف پذیری برای گسترش و مجموعه ای از نکات مثبت دیگر که همراه با سرور بدون سرور است، قرار می دهد. حال، میخواهید این لامبدا جدید را به چه زبانی توسعه دهید؟ من طرفدار فوق العاده ای برای انتخاب Go در هنگام ساختن Lambdas بوده ام و می خواهم دلیل آن را توضیح دهم.
انتخاب یک زمان اجرا لامبدا
وقتی شروع به ساخت اولین Lambda خود می کنید، این تصمیم زمان اجرا باید یکی از اولین چیزهایی باشد که تصمیم می گیرید. در حال حاضر، AWS از مجموعه ای از گزینه های مختلف پشتیبانی می کند که می توانند در صفحه AWS Runtimes Lambda بررسی شوند. یکی از بهترین چیزها در مورد ساخت با Lambdas این است که از آنجایی که دامنه مشکل شما تقریباً در سطح “نانو” ایزوله است، می توانید خود را از قفل شدن در یک مجموعه فناوری رها کنید.
منظور من از آن این است که زبانها و چارچوبهای خاصی برای حل مشکلات خاص مناسبتر هستند و شما میتوانید آن راهحلها را با آن مجموعه از قابلیتها بررسی کنید و در عین حال به ساخت عملکردهای دیگر در مجموعهای کاملاً متفاوت از فناوریها و چارچوبها ادامه دهید. و اگر متوجه شدید که این لامبدا به هر دلیلی مطابق انتظار شما عمل نمی کند، سرمایه گذاری در زمان و انرژی باید به اندازه ای کم باشد که انتقال به چیز دیگری پایان جهان نباشد. من این اتفاق را چندین بار در سرتاسر ساختمان بدون سرور خود دیده ام.
هر زبان و فریم ورک بر نمایه عملکرد شما تأثیر می گذارد. مواردی مانند:
- شروع سرد – زمان استقرار لامبدا و اجرای اولیه آن
- هزینه – قیمت هر گیگابایت ثانیه اساسا حافظه اختصاص داده شده و جزء زمان
- حافظه – عملکرد شما به چه مقدار حافظه نیاز دارد تا به خوبی اجرا شود
- اندازه بسته – هر چه بسته نرم افزاری بزرگتر استقرار بیشتری داشته باشد و زمان شروع آن طولانی تر است
انتخاب Go هنگام ساخت Lambdas
اول از همه، این صرفاً فهرستی از دلایل بر اساس تجربیات و نظرات من است. من Lambdas را در Go، Node، NET Core، Java، Python و Rust مستقر کرده ام. اما در زیر دلایلی وجود دارد که من در هنگام ساختن عملکردهای خود ابتدا به سراغ گوفر می روم.
تجربه توسعه دهنده
متوجه شدم، این موضوع ذهنی است، اما دوباره این یک نظر است. برای من، ابزارهای داخلی Go و وسعت کتابخانه استاندارد برای من کافی است. بسیاری از جزئیات کوچک مراقبت شده است.
آزمایش کردن
برای اجرای تستهای Go Unit خود نیازی به انتخاب Mocha، Jest، jUnit، nUnit یا سایر کتابخانههای بیرونی ندارم. در پشته تعبیه شده است
package sample
import "testing"
func Test_Should_Do_Something(t *testing.T) {
if someCondition {
t.Fail()
}
}
سپس قادر به دویدن go test
و بس
کتابخانه استاندارد
دوست داشته باشید یا نخواهید، دنیای API روی JSON اجرا می شود. و Go دارای پشتیبانی بومی با یک کتابخانه داخلی برای مقابله با JSON است. آن encoding
بسته جامع است و همه Marshalling
و Unmarshalling
به نظر می رسد اشیاء روی سیم و خارج از آن به همین ترتیب عمل می کنند
package sample
import "encoding/json"
// unmarhsall
i := SomeStruct{}
err := json.Unmarshal(bytes, &i)
// marshall
i := SomeStruct{}
out, err := json.Marshal(&i)
این قابلیت بومی هنگام کار با SQS، Step Functions، DynamoDB و سایر سرویسها در اکوسیستم AWS، هنگام تجزیه و تحلیل ورودیها و قالببندی خروجیها مفید خواهد بود.
ساختمان برو
روند ساخت Go سریع است. چرا این موضوع هنگام توسعه توابع اهمیت دارد؟ بازخورد. مطمئنا، IDE ها و VSCode ها در شناسایی مشکلات عالی هستند، اما اگر مشکلات زمان کامپایل ندارید و فقط می خواهید کد خود را شروع کنید، سرعت اهمیت دارد. چند ده بار در روز بسازید و آزمایش کنید و پساندازی که به دست میآورید به شما این امکان را میدهد که فقط چند چرخه بیشتر از آنچه در غیر این صورت انجام میدادید انجام دهید.
به نظر من این در زبان های مدرن کم گفته شده است و از همان ابتدا شروع به ساختن زبانی کرد که به سرعت کامپایل شد. این همچنین در توسعه محلی و ساخت و استقرار هنگام استفاده از CDK یا SAM در صورتی که مثلاً 10 یا 15 عملکرد در یک API دارید، بازی می کند. داشتن سریع کامپایل قبل از راهاندازی API به صورت محلی برای آزمایش، باعث صرفهجویی در زمان ارزشمندی میشود که میتوانید صرف کد کنید.
قالب بندی کد
برو fmt من تقریباً می توانم این را با بیان آن رها کنم. اما برای توضیح کمی، من دیدهام که قالببندی پایگاههای کد یا چیزی است که به شدت بحث میشود یا چیزی به هر کسی واگذار میشود، بنابراین پایگاه کد هرگز قالببندی نمیشود. با Go fmt شما یک روش پشتیبانی شده توسط جامعه برای قالب بندی کد خود دارید تا همیشه یکسان به نظر برسد، صرف نظر از اینکه از کجا آمده است. IDE شما پشتیبانی دارد و خط فرمان ابزاری برای آن دارد، بنابراین لازم نیست به آن فکر کنید. این یک معامله بزرگتر از آن چیزی است که فکر می کنید.
نحو تمیز و در عین حال پرمخاطب
Go یک سینتکس به ظاهر آشنا دارد. متوجه مواردی از این قبیل خواهید شد {}
، ()
علاوه بر تمام ساختارهای حلقه و کنترل معمولی. نظرات شبیه C و C++ هستند. این زبان گاهی اوقات میتواند به صورت لمسی پرمخاطب باشد، اما وقتی به آن عادت کنید، بسیار منطقی به نظر میرسد. به طور خاص وقتی صحبت از مدیریت خطا می شود.
Go فاقد وراثت است، اما با طراحی رابط قوی و همچنین استفاده از ترکیب بندی ساختارها، آن را جبران می کند که دوباره، زمانی که در اطراف الگوها پیچیده می شوید، کدهای تمیز و قدرتمندی ایجاد می شود.
امکان برگرداندن چندین مقدار این ممکن است در ابتدا عجیب به نظر برسد، اما من آن را واضح تر می دانم که چیست func
به جای ساختن کلاسی که شی بازگشتی من را نگه می دارد، انجام می دهد. این کد را بگیرید:
public class SomeClass {
public String theString;
public Integer theInteger
}
function SomeFunction() SomeClass {
return new SomeClass() {
theString: "ABC",
theInteger 123
};
}
برای من، این تقریباً به اندازه این کد قابل خواندن نیست
func SomeFunction() (string, int) {
return "ABC", 123
}
واضح است که تابع چه چیزی را برمی گرداند و من را از پناه گرفتن برای ایجاد یک “حامل داده” جداگانه برای برگرداندن خروجی نجات می دهد. یا بدتر از آن، داشتن نوعی “ref” است که مقدار ورودی تغییر می کند و حالتی را که از مشتری پنهان است تغییر می دهد.
پشتیبانی CDK
اگر با CDK آشنایی ندارید، در اینجا یک مقاله مقدماتی خوب برای شروع شما وجود دارد.
ایجاد زیرساخت به عنوان کد دارای مزایای بسیار زیادی است و استفاده از CDK این کار را تقریبا لذت بخش می کند. خوشبختانه، پشتیبانی Go برای CDK در حال حاضر ساخته شده است. با استفاده از ساختار GoFunction میتوانید تابعی را اعلام کنید که برای معماری لامبدا درست ساخته میشود.
new GoFunction(this, "TheFunc", {
entry: path.join(__dirname, "some-path"),
functionName: "func-name",
});
برای گزینه های CDK بیشتر به مستندات نگاهی بیندازید.
موارد بالا فقط چند دلیل هستند که من دوست دارم با Go حتی خارج از Lambdas کار کنم.
تجربه عملیاتی
اندازه بسته نرم افزاری
بیایید به اندازه باندل برگردیم. این به چند دلیل اهمیت دارد.
- زمان استقرار هرچه بسته نرم افزاری کوچکتر باشد، ساخت و استقرار سریعتر است. اگر بسته شما 540 مگابایت است در مقابل مثلا 13 مگابایت، زمان بسیار کمتری برای انتقال بایگانی خود به محیط لامبدا است.
- شروع سرد. باز هم، بستهبندی کوچکتر و وابستگیهای کمتر، راه طولانیای برای راهاندازی زمان اجرا شما خواهد داشت. Go بسیار سریع با همه چیزهایی که در باینری کامپایل شده است راه اندازی می شود تا شروع های سرد خوب و سریعی داشته باشید.
در زیر نمونهای از لامبدا وجود دارد که دارای چند مورد از جمله وابستگی به AWS SDK برای کار با DynamoDB و ذخیره پارامتر است، اما اندازه باندل تنها 13 مگابایت است. من آن را دوست دارم!
شروع سرد
این یک موضوع داغ در دنیای بدون سرور است. من 6 سال است که Lambdas را در حال تولید استقرار می دهم و می توانم بگویم که در ابتدا، با استفاده از NET Core، 2 تا 4 ثانیه شروع سرد دریافت می کردم. برای عملیات نوع async، این پایان دنیا نیست. اما اگر رویداد شما به یک API Gateway متصل است، آیا کاربران میخواهند تا این مدت برای اولین پاسخ شما منتظر بمانند؟ احتمالا نه.
سالهای پیش رو به سرعت و صادقانه هر زبانی شاهد پیشرفتهایی بوده است و با معرفی SnapStart، جاوا اکنون برای این نوع موارد استفاده لذتبخش است. من همچنان ترجیح میدهم از Go استفاده کنم، اگرچه نمودار زیر تأخیرهای 4 روزه شروع سرد را در نقطه پایانی API نشان میدهد. میانگین فقط یک لمس بیش از 500 میلیثانیه است که برای من 100٪ قابل قبول است زیرا چرخه زندگی کامل با API Gateway کمتر از 1 ثانیه خواهد بود که هدف شخصی من برای بازگشت چیزها از نقطه پایانی API در کمتر از آن آستانه 1 ثانیه را برآورده میکند.
من این را به ماهیت Go نسبت میدهم، زیرا بسته نرمافزاری کوچک است، وابستگیها در آن کامپایل شدهاند و راهاندازی برنامه فقط “snappy” است. من یکی از اولین کسانی خواهم بود که با ارائه پشتیبانی Go به قطار SnapStart میپرم، اما در حال حاضر، به اندازه کافی از این کار راضی هستم.
پیچیدگی زمان اجرا
این فوقالعاده ذهنی است و من درباره قرار دادن آن بحث کردم، اما چیز دیگری که در مورد Lambdas دوست دارم اما دوست ندارم Layers است. لایه ها راه بسیار خوبی برای به اشتراک گذاشتن منطق بین توابعی هستند که هدف مشابهی دارند. اما از طرف دیگر، متوجه شدم که آنها می توانند چیزهایی را از من پنهان کنند و آزمایش آنها کمی دشوار است.
با استفاده از Go، وابستگیهایم را در آن کامپایل میکنم، بنابراین متوجه میشوم که کد قابل استفاده مجدد از طریق یک بسته بسته به اشتراک گذاشته میشود که میتوانم زمانی که ساختمان خود را انجام میدهم به صورت محلی آزمایش کنم. باز هم، این بزرگترین چیز در جهان نیست، اما در هنگام ساخت توابع برای من کمی آشناتر احساس می شود.
قابلیت مشاهده
این منحصر به فرد Go نیست، اما در اینجا مقاله ای است که من در مورد استفاده از Go with Datadog نوشتم که نشان می دهد چقدر تمیز و ساده است که قابلیت مشاهده مستقیماً در عملکردهای شما ایجاد شود.
بسته شدن
کدنویسی و استقرار Lambdas سفری پر ارزش است که نیازی به تمرکز بر چیزهایی نیست که برای مشتریان و کاربران نهایی شما ارزشی ندارد. با تمرکز بر آنچه مهم است، میتوانید ایدههای خود را نوآوری و تکرار کنید و زمانی را صرف کارهایی مانند زیرساختهای عملیاتی یا تلاش برای کشف چگونگی ساخت ویژگیها در شاید نه ایدهآلترین پشته فناوری نکنید.
لامبداها و توابع کوچکترین سطح ایزوله را به شما می دهند تا بتوانید روی آن مشکل تمرکز کنید و بهترین فناوری را برای اجرای مجموعه ای از ویژگی ها انتخاب کنید. به طور پیش فرض، من به دلایلی که در بالا به شما نشان دادم، Go را انتخاب می کنم. من میدانم که هنگام انتخاب نحوه استقرار لامبدا، محبوبترین زمان اجرا نیست، اما امیدوارم دفعه بعد که یک عملکرد جدید را شروع میکنید، این مقاله نکاتی را در اختیار شما قرار دهد که باید درباره آن فکر کنید.