1. Understanding Naming Conventions

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

1.1. اهمیت نام‌گذاری

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

1.2. قوانین عمومی نام‌گذاری

قوانین نام‌گذاری در Go ساده ولی قدرت‌مند هستند:

  • استفاده از نام‌های کوتاه و مختصر: Go به نام‌های کوتاه تشویق می‌کند، به‌ویژه برای متغیرهایی که دارای محدوده کوچکی هستند. به عنوان مثال، i ممکن است برای شمارنده‌ی حلقه استفاده شود، اما اگر وضوح بیشتری لازم باشد، می‌توان از index یا counter استفاده کرد.

  • استفاده از CamelCase برای نام‌های چند واژه‌ای: وقتی یک نام از چند واژه تشکیل شده است، از نمادگذاری CamelCase استفاده کنید. نام‌های صادرشده (آن‌هایی که باید از خارج از بسته قابل دسترسی باشند) باید با حرف بزرگ شروع شوند (MyFunction)، در حالی‌که نام‌های داخلی باید با حرف کوچک شروع شوند (myFunction).

  • استفاده از نام‌های معنی‌دار: نام‌ها باید به اندازه کافی توصیفی باشند تا هدف یا استفاده آن‌ها را بیان کنند، بدون این‌که خیلی طولانی و پرساپرس باشند. به عنوان مثال، CalculateNetIncome بهتر از CNI است.

  • اجتناب از زیرخط: بر خلاف برخی زبان‌ها، در Go از استفاده از زیرخط در نام‌ها خودداری می‌شود. به‌جای record_count، شما باید از recordCount استفاده کنید.

  • استفاده یکنواخت از کلمات اختصاری: وقتی از کلمات اختصاری در نام‌ها استفاده می‌شود، آن‌ها را به‌صورت یکنواخت نگه دارید. برای نام‌های صادرشده، از همه حروف بزرگ (HTTPServer) استفاده کنید و برای نام‌های داخلی، استفاده از حروف کوچک (httpServer) عملی است.

  • نام بسته باید ساده باشد: نام‌های بسته در Go ساده و حروف کوچک باشند، بدون زیرخط یا ترکیب‌های حروف بزرگ و کوچک. آن‌ها باید یک کلمه باشند که بازنمایی مناسبی از هدف بسته را داشته باشد (net، os، json).

  • نام‌گذاری متغیر براساس نوع: برای متغیرهایی که نماینده‌ی نمونه‌های ساختارها هستند، معمول استفاده از نام ساختار به‌عنوان نام متغیر به صورت حالت کوچک (var user User) باشد.

اینجا یک مثال از کد Go با توضیحات درباره‌ی انتخاب‌های نام‌گذاری آمده است:

package main

import "fmt"

type User struct {
    FirstName string
    LastName  string
    Age       int
}

func main() {
    var currentUser User // استفاده از نام ساختار با حروف کوچک به عنوان نام متغیر.
    currentUser.FirstName = "John"
    currentUser.LastName = "Doe"
    currentUser.Age = 30

    fmt.Println(formatUserDetails(currentUser))
}

// formatUserDetails یک ساختار کاربر را به عنوان ورودی می‌گیرد و یک رشته قالب‌بندی شده را برمی‌گرداند.
// نام تابع با یک حرف کوچک شروع می‌شود زیرا از بیرون قابل دسترسی نیست (ناخصوصی).
func formatUserDetails(u User) string {
    return fmt.Sprintf("Name: %s %s, Age: %d", u.FirstName, u.LastName, u.Age)
}

رعایت این نام‌گذاری‌ها به‌طور چشمگیری کیفیت کد Go شما را بهبود می‌بخشد، زیرا کد را خواناتر و قابل نگهداری‌تر می‌کند.

2. شناسه‌ها در Go

هنگامی که با Go آغاز می‌کنید، درک نقش شناسه‌ها امری ضروری است. شناسه‌ها نام‌هایی هستند که به اجزای مختلف کد شما مانند متغیرها، توابع و ثابت‌ها اختصاص می‌دهید. انتخاب نام‌های معنی‌دار و یکنواخت به کد شما کمک می‌کند تا خواناتر و قابل نگهداری‌تر شود.

2.1. نام‌گذاری متغیرها

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

روش‌های بهتر:

  • استفاده از نام‌های کوتاه و توصیفی.
  • برای دامنه‌ی بسته، با یک حرف کوچک شروع کنید.
  • برای نام‌های چند واژه‌ای از CamelCase استفاده کنید (برای مثال، totalAmount).
  • برای متغیرهای صادرشده (قابل دسترسی خارج از بسته) با یک حرف بزرگ شروع کنید.

مثال:

var userName string // متغیر ناخصوصی
var UserAge int     // متغیر صادرشده

توضیحات در کد، تفاوت بین متغیرهای صادرشده و ناخصوصی را روشن می‌کنند.

2.2. توافق‌های نام‌گذاری توابع

توابع در Go باید طبق قوانین مشابه متغیرها نامگذاری شوند. نام باید منعکس کننده هدف تابع باشد و دامنه آن تعیین‌کننده‌ی حالت حرف اول است.

روش‌های بهتر:

  • از نام‌های توصیفی استفاده کنید که هدف تابع را منعکس کنند.
  • برای توابع داخلی با حرف کوچک شروع کنید.
  • از PascalCase (شروع با حرف بزرگ) برای توابع صادرشده استفاده کنید.
  • نام توابع را مختصر اما معنادار نگه دارید.

مثال:

func calculateTotal(price int, quantity int) int { // تابع داخلی
    return price * quantity
}

func CalculateDiscount(totalPrice int) float64 { // تابع صادرشده
    return totalPrice * 0.1
}

نظرات در مورد دسترسی تابع بر اساس حالت آن است و یک بررسی اجمالی از هدف آن را فراهم می‌کند.

2.3. توافق‌های نام‌گذاری ثابت‌ها

ثابت‌ها مقادیری ثابت‌هستند که بعد از تعریف، قابل تغییر نیستند. در Go، از کلمه const برای تعریف آن‌ها استفاده می‌شود و می‌توانند مقادیر کاراکتری، رشته، بولی، یا عددی باشند.

روش‌های بهتر:

  • از حروف بزرگ و زیرخط برای جداکردن استفاده کنید (مانند MAX_LIMIT).
  • برای ثابت‌های معدود، از شمارنده iota استفاده کنید.
  • ثابت‌های صادرشده باید با حرف بزرگ شروع شوند.

مثال:

const MAX_RETRY_COUNT int = 3 // ثابت صادرشده

type ByteSize float64
const (
    _           = iota // اولین مقدار را با اختصاص به شناسه خالی نادیده بگیرید
    KB ByteSize = 1 << (10 * iota)
    MB
    GB
    TB
)

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

3. توافق‌های نام‌گذاری برای انواع

این فصل بر استانداردهای نام‌گذاری انواع مختلف مانند struct و interface تمرکز دارد.

3.1. راهنمای نام‌گذاری برای Struct‌ها

مروری: Structs در Go نوع‌های داده‌ای ترکیبی را که متغیرها را گروه‌بندی می‌کنند، نمایان می‌کنند. هنگام نامگذاری struct‌ها، از نام‌های توصیفی در PascalCase که با حرف بزرگ شروع می‌شوند، استفاده کنید.

  • روش خوب: Struct‌ها را با اسم‌های اسمی یا عبارت‌های اسمی که به وضوح آنچه که نمایان می‌کنند را شرح دهند، نام‌گذاری کنید. به عنوان مثال:
// خوب
type Employee struct {
    ID        int
    FirstName string
    LastName  string
    Position  string
}
  • اجتناب از: استفاده از نام‌های دو پهن یا سراسری که هدف struct را منتقل نمی‌کنند.
// اجتناب از
type Data struct {
    ID        int
    FirstName string
    LastName  string
    Position  string
}

3.2. راهنمای نام‌گذاری برای Interface‌ها

مروری: Interface‌ها در Go مجموعه‌های روش‌ها را مشخص می‌کنند و از اسم‌های توصیفی با پایان با پسوند 'er' استفاده می‌کنند اگر منطقی باشد.

  • روش خوب: اینترفیس‌ها را بر اساس رفتاری که انتزاع کرده‌اند نام گذاری کنید. معمولاً اگر یک interface فقط شامل یک متد باشد، نام باید اقدام متد به همراه پسوند '-er' را منعکس کند.
// خوب
type Reader interface {
    Read(p []byte) (n int, err error)
}
  • نام‌گذاری مجموعه از رفتارها: اگر یک interface مجموعه‌ای از رفتارها را نمایش دهد، یک اسم برای آن انتخاب کنید که بدون پسوند 'er' هدفش را به درستی منعکس کند.
// مثالی از مجموعه‌ای از رفتارها
type Filesystem interface {
    ReadFile(path string) ([]byte, error)
    WriteFile(path string, data []byte) error
}

4. حساسیت حروف کوچک و بزرگ و شناسه‌های صادرشده

4.1. نام‌های صادرشده در مقایسه با نام‌های غیرصادرشده

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

مثال:

package geometry

// شناسه صادرشده
type Rectangle struct {
    Length, Width float64
}

// شناسه غیرصادرشده
type point struct {
    x, y float64
}

در این مثال، Rectangle یک نوع صادرشده است چون با حرف بزرگ شروع می‌شود و می‌تواند توسط بسته‌های دیگری که بسته geometry را import کرده‌اند، استفاده شود. به طور مشابه، نوع point غیرصادرشده است و فقط در داخل بسته geometry قابل استفاده است.

4.2. بهترین روش‌ها برای نام‌گذاری شناسه‌های صادرشده

در هنگام نام‌گذاری شناسه‌های صادرشده، ضروری است که از برخی از بهترین روش‌ها پیروی شود تا اطمینان حاصل شود که کد شما توسط دیگران قابل خواندن و قابل فهم است:

  • وضوح بر کوتاهی: بجای نام‌های کوتاه و رمزآلود، نام‌های واضح و توصیفی انتخاب کنید. به عنوان مثال، انتخاب محاسبه‌مساحت نسبت به محاسبه_م ترجیح داده می‌شود.
  • یکپارچگی: در سراسر پروژه کد خود، باید همیشه با استانداردهای نام‌گذاری یکپارچه باشید. اگر شما نامگذاری موجودیت‌های مشابه را با الگوهای خاصی شروع کرده‌اید، باید به آنها پایبند بمانید.
  • اجتناب از تکرار: در نام‌های شناسه‌ها، نام‌های بسته را تکرار نکنید. به عنوان مثال، از geometry.Rectangle به جای geometry.GeometryRectangle استفاده کنید.
  • متناسب با زمینه: نام‌های شناسه‌ها باید در زمینه‌ای که استفاده می‌شوند معنی داشته باشند. از نام‌هایی که ممکن است گمراه‌کننده یا دو پهلو باشند، خودداری کنید.
  • نظرات مستند: از نظرات مستند برای توضیح شناسه‌های صادرشده استفاده کنید و توضیح دهید که آنها چه کار می‌کنند و چطور باید استفاده شوند.

مثال:

package geometry

// CalculateArea مساحت یک مستطیل را برمی‌گرداند.
func (r Rectangle) CalculateArea() float64 {
    return r.Length * r.Width
}

در این مثال، محاسبه_مساحت یک تابع صادرشده با یک نام روشن و توصیفی است که شامل یک نظر مستند است که هدف آن شرح داده شده است.

5. عادات نام‌گذاری در عمل

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

5.1. مشکلات رایج و چگونگی اجتناب از آنها

نام‌گذاری متغیرها، توابع و سایر شناسه‌ها اغلب در اهمیت آن نادیده گرفته می‌شود. اشتباهات رایج شامل:

  • استفاده از نام‌های عمومی: نام‌هایی مانند داده یا اطلاعات توصیفی نیستند و می‌توانند منجر به ابهام شوند.
  • نام‌های بسیار طولانی: در حالی که نام‌های توصیفی خوب هستند، نام‌های بسیار طولانی می‌توانند سنگین باشند. توازن بین دو نکته مهم است.
  • زیرخط در شناسه‌های چند کلمه‌ای: Go از camelCase برای نام‌گذاری متغیرها و PascalCase برای توابع صادرشده و انواع استفاده می‌کند.
  • الگوهای نام‌گذاری نامناسب: یکپارچگی در استانداردهای نام‌گذاری کمک می‌کند در درک سریع ساختار کد.

راهنمایی‌ها برای اجتناب از این مشکلات:

  • از نام‌های مختصر و توصیفی استفاده کنید. به عنوان مثال، به جای داده، از داده‌کاربر استفاده کنید اگر شامل اطلاعات کاربران است.
  • استفاده از استاندارد Go برای کلمات مخفف؛ آنها را با حروف بزرگ نوشته شوند، مانند HTTPServer به جای HttpServer.
  • برای متغیرها و ثابت‌های سطح پکیج غیرصادرشده، نام‌ها را کوتاه نگه دارید چون دامنه‌شان محدود است.

5.2. باز‌نامگذاری برای نام‌گذاری بهتر

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

  1. استفاده از نام‌های توصیفی: نام‌ها را به‌طور روشن به‌خاطر بسپارید که آنها چه چیزی را نماینده می‌کنند یا چه کاری انجام می‌دهند. به عنوان مثال، یک تابع را از پردازش به پردازش_ورودی_کاربر تغییر دهید اگر این کار را انجام می‌دهد.
  2. استفاده از ابزارها: از ابزارهایی مانند gorename استفاده کنید که امکان بازنامگذاری ایمن با تجزیه و تحلیل معنایی کد Go را فراهم می‌کند.
  3. بررسی با همکاران: گاهاً آنچه برای شما منطقی است، ممکن است برای دیگران واضح نباشد. بررسی‌های همتا می‌توانند در شناسایی نام‌های مبهم کمک کنند.
  4. تکرار بر اساس بازخورد: پس از انجام تغییرات، بازخورد از کاربران پایگاه کد جمع‌آوری کرده و در صورت لزوم در بازنامگذاری تکرار کنید.

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