1. اصول مدیریت بسته‌ها و ماژول‌ها در Go

Go Modules سیستم مدیریت بسته و کنترل نسخه وابستگی‌ها برای زبان Go است. این سیستم از نسخه Go 1.11 معرفی شد و از نسخه 1.13 به بعد به عنوان مکانیزم مدیریت وابستگی‌ها به صورت پیش‌فرض استفاده می‌شود. Go Modules هر پروژه را به عنوان یک ماژول مدیریت می‌کند که شامل کد Go در پروژه و تمامی بسته‌هایی که به آن وابسته هستند می‌شود.

اصول عملکرد

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

هنگامی که دستوراتی مانند ساخت یا اجرای دیگر دستورها صادر می‌شود، اگر فایل go.mod در دایرکتوری فعلی وجود نداشته باشد، ابزار Go به دنبال فایل go.mod در دایرکتوری فعلی و دایرکتوری‌های والد خود می‌گردد تا ماژول موضوع برای عملیات فعلی را تعیین کند. در صورت یافتن، از اطلاعات وابستگی موجود در آن فایل برای بازیابی و ساخت بسته‌ها استفاده می‌شود؛ در غیر این صورت، از روش مدیریت وابستگی در حالت GOPATH استفاده خواهد کرد.

نقش در زبان Go

  • کنترل نسخه: Go Modules به توسعه‌دهندگان اجازه می‌دهد تا استفاده از نسخه‌های خاص کتابخانه‌های شخص ثالث را مشخص کنند و تضمین می‌کند که امکان بازتولید کد وجود دارد.
  • مدیریت بسته: مدیریت آسان وابستگی‌های پروژه و نسخه‌های آن‌ها.
  • جدایی ماژول: پروژه‌های مختلف می‌توانند بر روی نسخه‌های مختلف یک بسته وابسته داشته باشند بدون تداخل، زیرا هر پروژه فایل go.mod مخصوص به خود را برای مدیریت وابستگی‌ها دارد.

مدیریت بسته و ماژول، یک جنبه مهم برای هر زبان برنامه‌نویسی مدرن است، زیرا وظایفی مانند مدیریت وابستگی، ارتقاء نسخه بسته‌ها و ساخت بازتولیدی برای کاربران بسته‌های downstream را آسان‌تر می‌کند. در زبان Go، هنگامی که اندازه پروژه و وابستگی‌ها ادامه می‌یابد، Go Modules یک مکانیزم ضروری برای به طور موثر روی کارهای مدیریت وابستگی واقعی می‌شود.

2. مقدمه‌ای برای ایجاد ماژول Go خود

ایجاد یک ماژول Go جدید بسیار ساده است. می‌توانید دستور زیر را در دایرکتوری اصلی پروژه خود اجرا کنید:

go mod init <نام-ماژول>

در اینجا، <نام-ماژول> معمولاً آدرس مخزن کد مانند github.com/username/repo است.

هدف فایل go.mod

هنگامی که دستور go mod init با موفقیت اجرا می‌شود، یک فایل go.mod در دایرکتوری فعلی ایجاد می‌شود. این فایل شامل موارد زیر به ترتیب تعریف می‌کند:

  • نام ماژول فعلی.
  • نسخه Go.
  • اطلاعات ضروری در مورد تمامی وابستگی‌های مستقیم، از جمله نسخه مناسب برای هر بسته.

فایل go.mod مهم‌ترین مولفه در مکانیزم Go Modules است و به طور خودکار به‌روزرسانی می‌شود زمانی که وابستگی‌ها اضافه یا حذف می‌شوند.

3. ایجاد و ساختاردهی بسته‌های Go

3.1 مبانی ایجاد بسته‌ها

در زبان Go، یک بسته شامل چندین فایل منبع Go است که معمولاً در یک دایرکتوری قرار دارند و دارای یک مجموعه خاص از قابلیت‌ها می‌باشند. هر فایل Go نشان می‌دهد که با کدام بسته در ارتباط است با استفاده از کلمه کلیدی package.

برای ایجاد یک بسته جدید، باید:

  1. یک پوشه برای نمایان‌گر دایرکتوری بسته ایجاد کنید.
  2. فایل‌های .go را در پوشه ایجاد کرده و package <نام-بسته> را در خط اول فایل مشخص کنید.

نام بسته معمولاً مرتبط با نام دایرکتوری است، اما الزامی به یکسان بودن آن نیست. نام بسته باید کوتاه، واضح و بهتر است از استفاده از زیرخط خودداری شود.

3.2 ساختار بسته

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

  • ساختار دایرکتوری: دایرکتوری‌ها براساس عملکرد تقسیم بندی شده‌اند، جایی که هر دایرکتوری یک بسته را نمایندگی می‌کند.
  • تصاویر اقدامات: دایرکتوری‌هایی مانند _test معمولاً حاوی فایل‌های آزمایشی هستند، دایرکتوری cmd معمولی برای برنامه‌های خط فرمان استفاده می‌شود و دایرکتوری internal کد‌های خصوصی استفاده برای استفاده خارجی نیست.
/directory-ریشه
    /pkg
        /زیربسته-۱
            زیربسته-۱.go
        /زیربسته-۲
            زیربسته-۲.go
    /cmd
        main.go  // دایرکتوری cmd برای برنامه‌های خط فرمان
    /internal
        helper.go

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

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

4. وارد کردن و استفاده از بسته‌ها

4.1 وارد کردن بسته‌های داخلی

فرض کنید که ساختار پروژه شما به صورت زیر است:

├── src
│   ├── main.go
│   └── mypackage
│       └── mymodule.go

در این مثال، mypackage یک بسته داخلی است که شما ایجاد کرده‌اید و شامل یک فایل به نام mymodule.go می‌باشد. ابتدا اطمینان حاصل کنید که فایل mymodule.go نام بسته صحیح را اعلام می‌کند:

// mymodule.go
package mypackage

// SomeFunction یک تابع عمومی در mypackage است
func SomeFunction() {
    // پیاده‌سازی تابع
}

حالا، اگر بخواهیم از SomeFunction از بسته mypackage در فایل main.go استفاده کنیم، باید آن را وارد کنیم:

// main.go
package main

import (
    "fmt"
    "project/src/mypackage"
)

func main() {
    mypackage.SomeFunction()
    fmt.Println("تابع فراخوانی شده است")
}

دستور import بالا بسته mypackage را به فایل main.go وارد می‌کند و به ما امکان می‌دهد تا از طریق mypackage.SomeFunction توابع این بسته را فراخوانی کنیم.

4.2 استفاده از بسته‌های خارجی

هنگام نیاز به پیاده‌سازی قابلیت‌های پیچیده‌تر، ما معمولاً به بسته‌های خارجی وابسته هستیم. بسته‌های خارجی توسط توسعه‌دهندگان دیگر نوشته می‌شوند و به صورت عمومی در دسترس است، که ما می‌توانیم به راحتی آنها را در پروژه‌های خود یکپارچه کنیم. برای پیدا کردن بسته‌های خارجی، می‌توانید به وب‌سایت‌هایی مانند godoc.org مراجعه کنید یا در GitHub جستجو کنید.

فرض کنید که می‌خواهید از gorilla/mux در پروژه‌تان استفاده کنید که یک کتابخانه محبوب مسیریابی درخواست‌های HTTP است. می‌توانید آن را به صورت زیر وارد کرده و استفاده کنید:

ابتدا، بسته را با استفاده از دستور go get نصب کنید:

go get -u github.com/gorilla/mux

سپس، آن را وارد کرده و در کد خود استفاده کنید:

package main

import (
    "net/http"
    "github.com/gorilla/mux"
)

func main() {
    r := mux.NewRouter() // ایجاد نمونه مسیریاب
    // افزودن قوانین مسیر
    r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){
        w.Write([]byte("به gorilla/mux خوش آمدید!"))
    })
    
    // شروع سرور HTTP
    http.ListenAndServe(":8000", r)
}

در کد بالا، ما gorilla/mux را وارد کرده و یک مسیریاب HTTP ایجاد می‌کنیم، یک تابع دستگیرنده برای مسیر ریشه تعریف می‌کنیم و در نهایت سرور را در پورت 8000 با استفاده از http.ListenAndServe راه‌اندازی می‌کنیم.

5. مدیریت وابستگی‌های ماژول

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

5.1 به‌روزرسانی وابستگی‌ها با go get

دستور go get نه تنها می‌تواند وابستگی‌های بسته را اضافه کند، بلکه می‌تواند وابستگی‌های موجود را نیز به‌روز کند. گزینه‌های معمول زیر برای go get وجود دارند:

  • به‌روزرسانی یک بسته تکی:
  go get -u github.com/some/package
  • به‌روزرسانی همه وابستگی‌های این بسته:
  go get -u github.com/some/package/...
  • به‌روزرسانی همه وابستگی‌ها در پروژه:
  go get -u ./...
  • دانلود اما نصب نکن:
  go get -d github.com/some/package

هنگام انجام عملیات به‌روزرسانی، Go وابستگی‌ها را به آخرین نسخه‌های دقیق یا تجدید نسخه خواهد کرد (براساس ورژن‌بندی نشانه‌ای) و تغییرات همچنین در فایل go.mod نیز قابل مشاهده خواهد بود.

کنترل نسخه 5.2 و go.mod

از نسخه 1.11 به بعد، Go یک سیستم مدیریت وابستگی جدید به نام Go Modules ارائه داده است. در دایرکتوری اصلی پروژه، فایل go.mod وابستگی‌های بسته‌ها را ثبت می‌کند.

فایل go.mod شامل بخش‌های زیر است:

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

یک نمونه از یک فایل go.mod ممکن است به این شکل باشد:

module github.com/my/awesome-project

go 1.14

require (
    github.com/gorilla/mux v1.7.4
    golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975
)

replace (
    github.com/old/dependency => github.com/new/dependency v1.2.3
)

exclude (
    github.com/old/dependency v1.1.4
)

هنگام اجرای دستورات مانند go build یا go test در پروژه، Go به طور خودکار فایل go.mod را تولید یا به‌روزرسانی می‌کند تا تمام وابستگی‌های مورد نیاز برای پروژه را تعیین کند. بهترین روش در کنترل نسخه، این است که به طور منظم فایل‌های go.mod و go.sum (که هش‌های رمزنگاری مورد انتظار وابستگی‌ها را ثبت می‌کند) را commit کنید.

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