CloudyGo
212 subscribers
8 photos
1 video
1 file
41 links
Software Engineering & Development Best Practices, Especially in Golang!


https://cloudygo.ir

@rezakhademix
Download Telegram
#blog
#tip

این مقاله از techblog تیندر در مورد نحوه طراحی API‌های خودشون صحبت می‌کنه و سناریوهایی رو میگه که هممون تجربه کردیم. مثلا همیشه میدونیم واکشی اطلاعات با متد GET انجام میشه اما در برخی اوقات نیاز داریم از متد POST استفاده کنیم. اگه وقت کردین بخونیدش نکات ریز جالبی داره و خالی از لطف نیست.

https://medium.com/tinder/tinder-api-style-guide-part-1-081804a7ef40
2👏1
#golang
#tip

مشکل کد زیر کجاست؟

‍‍‍
func main() {

names := make([]string, 0, 10)

names[0] = "reza"

fmt.Println(names)
}

خب این برنامه در ظاهر مشکلی نداره، یک اسلایس تعریف و در خط بعدی ایندکس صفرم دارای مقدار شده، اما نکته مهم اینجاست برای متغیر names یک اسلایس با ظرفیت (capacity) 10، اما طول (length) حقیقی صفر ایجاد شده و هنگامی ‌که در خط بعدی تصمیم به مقداردهی یکی از ایندکس‌های اسلایس می‌کنیم برنامه با خطای ران‌تایم مواجه میشه و نتیجه چنین کدی مساوی با خطای زیر است:

‍‍‍
panic: runtime error: index out of range [0]  with length 0


اگر می‌خواهید به اسلایسی که طول آن صفر است مقداری را اضافه کنید باید با استفاده از تابع ()append به شکل زیر این کار را انجام دهید.

names = append(names, "reza")


اما اگر نیاز داریم حتما مقادیر در ایندکس‌های مشخص در این اسلایس قرار بگیرند باید تعریف متغیر names را به‌ روش درست زیر انجام دهیم:

 names := make([]string, 10)


در این نوع تعریف علاوه‌بر تعیین ظرفیت، طول حقیقی اسلایس نیز معین میشه تا از خطای ران‌تایم جلوگیری شود.
دقت کنید تعریف اسلایس با کلمه کلیدی var و تکرار روند بالا بازهم برنامه را با خطای index out of range روبرو خواهد کرد.

var ages []int
ages[1] = 29 // this line will fail with runtime error: index out of range [1] with length 0



#tip
#golang
1🔥1😱1
یک راهنمای خوب در خصوص نحوه افزایش Observability و Tracing
در برنامه‌های گولنگ با بررسی بررسی مموری، گوروتین‌ها، تردها و...

https://github.com/DataDog/go-profiler-notes/blob/main/guide/README.md

#blog
#tip
👍5
گولنگ ۱.۲۴ در ماه فوریه ۲۰۲۵ ارائه میشه و بالاخره توسعه‌هندگان تصمیم گرفتن تگ omitzero رو برای پکیج encoding/json فعال کنن و از این به بعد با نوشتن این تگ علاوه بر مقادیر پیش‌فرض، استراکچرهای خالی هم حذف میشن!

در ورژن‌های فعلی گولنگ تگ‌ omitempty رو داشتیم اما تنها فیلدهای با مقادیر پیش فرض رو حذف میکرد.

یه نگاه به نمونه کد زیر بندازین تا بیشتر موضوع روشن بشه:

type Blog struct {
Name string `json:"omitempty"`
Tags []string `json:"omitempty"`
Posts Posts `json:"omitempty"`
}

تگ‌ omitempty استراکچر درونی Posts رو حذف نمیکنه و فقط فیلدهای Name و Tags رو به شرطی حذف می‌کنه که مقدار پیش‌فرض گولنگی خودشون رو داشته باشن.

برای اینکه این مقادیر رو حذف کنید باید اینترفیس marshaler رو خودتون برای استراکت پیاده‌سازی کنید اما با ورژن ۱.۲۴ با تگ omitzero استراکت‌های خالی به شکل خودکار حذف میشن.

type Blog struct {
Name string `json:"omitzero"`
Tags []string `json:"omitzero"`
Posts Posts `json:"omitzero"`
}


لینک ریلیز ۱.۲۴ گولنگ برای جزییات بیشتر:
https://tip.golang.org/doc/go1.24


#tip
#golang
👏5
یکی از جالب‌ترین مباحث در Golang استفاده از errgroup است.


این نمونه کد از آقای matt boyle به‌خوبی یک مثال ساده از این مفهوم رو به نمایش می‌گذارد.


#tip
👍3🙏2
تفسیر کردن آبجکت‌های json در همه زبان‌های برنامه‌نویسی می‌تونه مثل حرکت کردن در یک میدان مین باشه! 💣

اگر تا حالا در این حوزه عمیق نشدین حتما یه سر به مقاله زیر بزنید که در مورد موضوعات بسیار جالبی در خصوص parse کردن آبجکت‌های json صحبت می‌کنه.

Parsing Json Is A Minefield


#blog
#tip
#deep
2👍2
این داستان: وقتی خودمون با دست خودمون N+1 می‌سازیم!


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

SELECT
posts.id,
posts.caption,
posts.content_url,
COALESCE(
(
SELECT COUNT(*)
FROM post_reactions
WHERE post_reactions.post_id = posts.id
),
0
) AS reactions_count
FROM
posts LEFT JOIN post_reactions ON post_reactions.post_id = posts.id

اگر با بعضی واژه‌ها در کوئری بالا آشنا نیستید مهم نیست، هدف ما بررسی ساب‌کوئری:

 SELECT COUNT(*)
FROM post_reactions
WHERE post_reactions.post_id = posts.id

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

اما باید دقت کنیم که این ساب‌کوئری‌ها در دل خودشون یک N+1 ایجاد میکنن و به‌ ازای تک‌تک ریف‌هایی که فراخوانی کردیم، تکرار میشن و به‌راحتی ما رو در رکوردهای بالا دچار مشکل میکنن!

راه‌حل چنین موضوعاتی استفاده از pre aggregating و CTE هستش.
بهتره در چنین مواقعی با استفاده از WITH در PostgreSQL یا MySQL یا MariaDB از تکرار کوئری‌ها به‌صورت پنهان در Joinها جلوگیری کنیم. نسخه اصلاح شده کوئری:

WITH
reaction_counts AS (
SELECT post_id, COUNT(*) AS reactions_count
FROM post_reactions
GROUP BY
post_id
),
SELECT
posts.id,
posts.caption,
posts.content_url,
reaction_counts.reactions_count
FROM
LEFT JOIN reaction_counts ON reaction_counts.post_id = posts.id



کوئری بالا هم خوانایی بیشتری داره و هم پرفورمنس بهتری! کاری که هیچ ORM درکی از انجامش نداره!


#episode_0
#story
#tip
🔥31
یکی از بهترین رو‌ش‌ها برای اینکه عملکرد کدهاتون رو بهتر کنید اینه که بنچمارک‌های مختلفی روی کد مورد نظرتون اجرا کنید تا مشخص بشه چه قسمت‌هایی باید بهبود پیدا کنن.
مقاله زیر توضیحات کاملی در خصوص بنچمارک کدهای گولنگی بیان کرده و هر بخش رو با مثال شفاف‌تر کرده!

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

https://stackademic.com/blog/profiling-go-applications-in-the-right-way-with-examples

#tip
#bench
👍4
اگر در اپلیکیشنی که دارید زیاد از time.Time استفاده می‌کنید می‌تونید با استفاده از ایجاد یک تایپ دلخواه و استفاده int64 میزان مصرف مموری رو تا حد قابل قبولی کاهش بدید و پرفورمنس رو بهتر کنید. به مثال زیر دقت کنید:

‍‍‍‍
type Timestamp int64

func (t Timestamp) Time() time.Time {
return time.Unix(int64(t), 0)
}

#tip
#golang
👍3
مقاله زیر به ما آموزش میده چطور 1,000,000 رکورد دیتا رو در 4 ثانیه در PostgreSQL ذخیره کنیم!

https://www.timescale.com/learn/testing-postgres-ingest-insert-vs-batch-insert-vs-copy?ref=timescale.com


#tip
#postgresql
#database
👏5
تمام تغییرات زبان گولنگ در نسخه 1.24 رو در لینک زیر مشاهده و اجرا کنید!

لینک زیر یک محیط تعاملی برای درک بهتر قابلیت‌های Golang در ورژن 1.24 است.

https://antonz.org/go-1-24/


#golang
#tip
👏21
همانطور که می‌دونید، همه ما می‌تونیم براساس نیازمون یک یا چند extension روی دیتابیس پوستگرس نصب کنیم. افزونه‌هایی برای ایندکس کردن، mask کردن دیتاهای حساس و... اما خب همین افزونه‌ها ممکنه در آینده باعث سردرد بشن. پکیج Pig با زبان گولنگ نوشته شده و یک extension manager خیلی ساده و خوب برای نصب و به‌روزرسانی و مدیریت افزونه‌های PostgreSQL هست.

https://github.com/pgsty/pig

#tip
#database
#PostgreSQL
👍2👏1
یکی از مسائلی که هنگام scale کردن دیتابیس برای تیم توسعه می‌تونه اتفاق بیفته ایجاد Replication دیتابیس و جداسازی کوئری‌های Read و Write است.

بدین معنی که شما یک/چند دیتابیس Main و به تعداد نیاز دیتابیس Replica خواهید داشت که هر کوئری که از جنس نوشتن، سمت دیتابیس Main و هر کوئری که هدفش خواندن اطلاعات باشد در یکی از instanceهای رپلیکا اجرا می‌شود.

در گولنگ نوشتن چنین امکانی بسیار ساده است اما باید استراتژی‌های مناسبی برای لود بالانس دیتابیس‌ها، به‌درستی Sync کردن دیتا (Data Consistency)، مدیریت I/O و جلوگیری از ایجاد Nework Overhead درنظر داشت.

شخصا یک‌مرتبه از پکیج زیر برای ایجاد دیتابیس‌های Read/Write استفاده کردم که در ابتدای مسیر تا حد مناسبی نیازهای اصلی پروژه را پوشش می‌داد.
https://github.com/bxcodec/dbresolver

احتمالا در طول مسیر برای کنترل صحیح‌تر مجبور می‌شوید پکیج اختصاصی خودتان را ایجاد کنید.

در این مسیر حتما به پترن CQRS توجه کنید. علاوه‌بر این، الگوریتم‌هایی مثل Raft و Paxos می‌توانند برای ایجاد Eventual Consistency کاربردی باشند.

در پست‌های بعدی با راه‌حل چالش‌ها آشنا خواهیم شد

#tip
👍6
به نظرتون اینستاگرام یا توییتر چطور به ‌این سرعت تعداد لایک‌ها یا بازدیدهای یک پست رو نمایش میدن؟

آیا در این حجم داده یک کوئری دیتابیسی و cache یا روشهایی مثل distribution کافیه؟
خب Google Analytics‌‌ چطور می‌تونه این حجم داده از جنس بازدید یکتا، تعداد کلیک یا... رو محاسبه کنه؟

یک الگوریتم بسیار زیبا وجود داره به اسم
HyperLogLog
که به ما اجازه میده با تقریب بسیار خوبی و فقط با مصرف چند کیلوبایت RAM تعداد المان‌های یکتا رو از مجموعه دیتا استخراج کنیم.

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

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

https://www.geeksforgeeks.org/hyperloglog-algorithm-in-system-design/


- در دوره صفر تا صد گولنگ کلودی‌گو یک نمونه از این الگوریتم رو پیاده‌سازی خواهیم کرد.

#tip
#systemdesign
👍51🔥1
اگر دوست‌دارین best practiceها و نکات ریزی که حین استفاده از defer در گولنگ بهش برخورد می‌کنید رو بدونید و از اشتباهات رایج جلوگیری کنید، مقاله زیر بهتون کمک می‌کنه.


https://rezakhademix.medium.com/defer-functions-in-golang-common-mistakes-and-best-practices-96eacdb551f0



#tip
#golang
👍4🙏1
مقاله زیر با زبان خیلی ساده به ما میگه که چطور از اشتباهات پیش‌پا افتاده جلوگیری کنیم و بتونیم اپلیکیشن گولنگی که داریم به برای تعداد رکوئست بالا آماده کنیم.


https://dev.to/rikenshah/scaling-backend-to-1m-requests-with-just-2gb-ram-4m0c


#tip
#golang
👍4🔥1
اگر دوست‌دارین best practiceها و نکات ریزی که حین استفاده از sliceها در گولنگ بهش برخورد می‌کنید رو بدونید و از اشتباهات رایج جلوگیری کنید، مقاله زیر بهتون کمک می‌کنه.


https://rezakhademix.medium.com/slices-in-golang-common-mistakes-and-best-practices-76c30857d4e4


#tip
#golang
👍4👨‍💻1
اگر دوست‌دارین best practiceها و نکات ریزی که حین استفاده از stringها در گولنگ بهش برخورد می‌کنید رو بدونید و از اشتباهات رایج جلوگیری کنید، مقاله زیر بهتون کمک می‌کنه.


https://rezakhademix.medium.com/strings-in-golang-common-mistakes-and-best-practices-1250045051f8

#tip
#golang
2👍2