CloudyGo – Telegram
CloudyGo
190 subscribers
9 photos
1 video
1 file
42 links
Software Engineering & Development Best Practices, Especially in Golang!


https://cloudygo.ir

@rezakhademix
Download Telegram
Channel created
یکی از مهمترین مفاهیم در دنیای امروز داکر هستش.

اگر هنوز حوصله نکردین که شروع کنین و داکر رو یاد بگیرین یا شروع کردین ولی منبع درست و حسابی برای Best Practice داکر ندارین،
ریپازیتوری awesome docker یکی از بهترین‌هاست.

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

#docker
#awesome
1👍1
#گولنگ

اگر یک struct گولنگی تعریف کردین که داخلش از mutex استفاده می‌کنید، حتما باید متدهایی که روی این استراکت تعریف میشن به‌صورت پوینتر باشن. اگر این موضوع فراموش بشه، یک نسخه کپی از mutex رو استفاده می‌کنید و در موقعیت‌های همزمانی دچار مشکل میشین.


نمونه کد بد:
type User struct {
sync.Mutex

data map[string]string
}

func NewUser() User {
return User{
data: make(map[string]string),
}
}

func (m User) Get(k string) string {
m.Lock()
defer m.Unlock()

return m.data[k]
}

نمونه کد خوب:
type User struct {
mu sync.Mutex

data map[string]string
}

func NewUser() *User {
return &User{
data: make(map[string]string),
}
}

func (m *User) Get(k string) string {
m.mu.Lock()
defer m.mu.Unlock()

return m.data[k]
}

#tip
#golang
👍2🔥1
#گولنگ

معمولا گولنگ دولوپرها تفاوت و کاربرد اسلایس‌های empty و nil رو باهم اشتباه میگیرن.
به کد زیر دقت کنید:

‍‍
// #1
var s []string

// #2
s = []string(nil)

// #3
s = []string{}

// #4
s = make([]string, 0)

کافیه برای اسلایس‌های بالا کد زیر رو اجرا کنید تا تفاوت nil و empty بودن رو متوجه بشین:

‍‍
// In Golang "\t" means tab character "\n" means new line

fmt.Printf("IsEmpty=%v \t IsNil=%v \n", len(s) == 0, s == nil)

نتیجه میشه:

#1
IsEmpty=true IsNil=true

#2
IsEmpty=true IsNil=true

#3
IsEmpty=true IsNil=false

#4
IsEmpty=true IsNil=false


خب هرچهار مورد به‌عنوان empty در نظر گرفته میشن یعنی اگر len اونارو بگیرین برابر با صفر میشه اما فقط دو مورد اول nil هستن.

دقت کنید:
۱) اسلایس‌های nil در واقع empty هم هستن
۲) اسلایس‌های nil در حافظه allocation ایجاد نمی‌کنن
۳) برای هردو نوع اسلایس‌های nil و empty میتونیم از تابع append استفاده کنیم


خب پس کاربرد اسلایس nil چیه؟
فرض کنید تابعی دارین که داره یک یا چند اسلایس برمیگردونه، خب دیگه با گولنگ نیازی نیست که مثل زبان‌های دیگه یک مقدار allocate شده برگردونید و با برگردوندن nil یا یک اسلایس nil حافظه کمتری مصرف میشه.

func scores() []int {
s, err := apiCall();
if err != nil {
return nil
}

return s
}



#golang
#tip
👏2
#گولنگ

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

گوروتین‌ها در گولنگ توسط grabage collector پاکسازی نمیشن و با وجود سبک بودنشون هنوز هم میتونن باعث ایجاد مموری لیک (memory leak) در برنامه‌تون بشن یا برای همیشه در پس‌زمینه در حال اجرا باقی بمونن!

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

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

#golang
#tip
👍2
#گولنگ

یکی از توصیه‌های کاربردی و مهم در تابع main برنامه‌های گولنگی اینه که بهتره نهایتا یک‌بار از log.Fatal یا os.Exit استفاده کنیم.

یعنی اگر ما در تابع main بخش‌های کلیدی و وابستگی‌های برنامه مثل دیتابیس و... رو آماده و برای چک کردن هر بخش بارها از log.Fatal استفاده کنیم، به‌طور فزاینده و غیرضروری تابع main رو طولانی‌ کردیم و حتی گاها رفتار عجیبی از یک قسمت سر میزنه که مورد انتظار ما نیست.

کد معمولی:

package main

func main() {
args := os.Args[1:]
if len(args) != 1 {
log.Fatal("file is missing")
}
name := args[0]

f, err := os.Open(name)
if err != nil {
log.Fatal(err)
}
defer f.Close()

// If we call log.Fatal after this line,
// f.Close will not be called.

b, err := io.ReadAll(f)
if err != nil {
log.Fatal(err)
}

db, err := db.New()
if err != nil {
log.Fatal(err)
}
defer db.Close()

// Again, if we call log.Fatal after
// this line, db.Close will not be called.

// ...
}

کد بهتر:

package main

func main() {
if err := run(); err != nil {
log.Fatal(err)
}
}

func run() error {
args := os.Args[1:]
if len(args) != 1 {
return errors.New("file is missing")
}
name := args[0]

f, err := os.Open(name)
if err != nil {
return err
}
defer f.Close()

b, err := io.ReadAll(f)
if err != nil {
return err
}

db, err := db.New()
if err != nil {
return err
}
defer db.close()

// ...
}

#golang
#tip
👍1
Indexing Beyond the Basics -- Tobias Petry -- 2023.pdf
11.4 MB
Indexing Beyond The Basics - Book

این کتاب دید شفافی در رابطه با نحوه ایندکس گذاری‌ها در دیتابیس و اینکه‌ چطور استفاده بهتری از ایندکس‌ها داشته باشیم به ما میده.

#book
👍1
شاید براتون جالب باشه که وب‌سایت‌هایی مثل توییتر چطور دائما فید کاربر رو به‌روز می‌کنن؟
یا چطور میشه خیلی سبک و بدون رکوئست‌های متعدد برای کاربر نوتیفیکیشن ارسال کرد؟

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

راه‌حل در چنین مواری استفاده از SSE هستش. در واقع Server-Sent Events برای شما یک کانکشن realtime یک طرفه از سرور به کلاینت ایجاد می‌کنه که روی HTTP هستش، این کانکشن overhead کمتری داره و به هر مدت زمانی‌که سرور مشخص میکنه باز میمونه و اطلاعات رو به کلاینت میفرسته.

ویژگی‌ها:
۱. سادگی پیاده‌سازی
۲. مرورگرها از این ارتباط پشتیبانی میکنن
۳. اتصال مجدد خودکار در صورت قطع شدن کانکشن
۴. کاهش overhead و استفاده از یک کانکشن



#tip
نمونه کد اجرای یک کانکشن SSE در گولنگ:


import (
"fmt"
"net/http"
"time"
)

func sseHandler(w http.ResponseWriter, r *http.Request) {
// set SSE http headers
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")

// create a channel for client disconnection
clientIsGone := r.Context().Done()

rc := http.NewResponseController(w)

t := time.NewTicker(time.Second)
defer t.Stop()

for {
select {
case <-clientIsGone:
fmt.Println("client disconnected")
return

case <-t.C:
// send event to the client
_, err := fmt.Fprintf(w, "data: the time is %s\n\n", time.Now().Format(time.UnixDate))
if err != nil {
return
}

err = rc.Flush()
if err != nil {
return
}
}
}
}


#tip
#golang
داکرایز کردن الستیک 🫎 نکات ریز خودش رو داره اما ریپازیتوری docker elk میتونه در این پروسه کمک‌تون کنه تا راحت‌تر به هدف‌تون برسید.


#docker
#elk
👍1
این مقاله دید جالبی درباره استفاده از ORM داره وخوندنش خالی از لطف نیست.


#tip
#blog
👏1🤔1
دائما به فکر راه‌حل‌های پیچیده نباشید!

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


#tip
#blog
👍3
این مقاله دید جالبی در رابطه با دیپلوی کردن سرویس‌های داکری مطرح میکنه و دوباره موضوع مهم تگ زدن رو برامون یادآوری می‌کنه تا راحت‌تر بتونیم رول‌بک و از مشکلات احتمالی جلوگیری کنیم

#blog
👏2👍1
#فان

یه مایگریشن نوشتم، ۱۱۵ خط شده، به نظرم خیلی عالیه! :)
1😱1