1. พื้นฐานของ Go Modules และการจัดการแพ็คเกจ

Go Modules เป็นระบบการจัดการแพ็คเกจและควบคุมรุ่นของ dependency สำหรับภาษา Go โดยเป็นระบบที่เป็นทางการตั้งแต่ Go 1.11 และเป็นกลไกการจัดการ dependency ที่ถูกต้อนรับและใช้โดยค่าตั้งต้นตั้งแต่ Go 1.13 เป็นต้นมา Go Modules จัดการกับแต่ละโปรเจคเป็นโมดูลซึ่งรวมถึงโค้ด Go ในโปรเจคและแพ็คเกจที่โปรเจคนั้นพึ่งอยู่

หลักการการทำงาน

Go Modules จัดการ dependency ของโปรเจคผ่านไฟล์ go.mod ไฟล์นี้จะตั้งอยู่ในโฟลเดอร์หลักของโปรเจคและระบุรายละเอียดของ dependency ตรงต่อ Dependency โมดูลสามารถมีหลายแพ็คเกจได้ แม้ว่าปกติแล้ว repository ก็คือโมดูล ในขณะทำการ build หรือ execute คำสั่งอื่นๆ หากไฟล์ go.mod ไม่ปรากฏอยู่ในโฟลเดอร์ปัจจุบัน Go toolchain จะค้นหา go.mod ในโฟลเดอร์ปัจจุบันและโฟลเดอร์หลักของมัน ถ้าพบก็จะนำข้อมูล dependency จากไฟล์นั้นมา fetch และ build แพ็คเกจ ถ้าไม่พบจะใช้วิธีการจัดการ dependency ในโหมด GOPATH

บทบาทในภาษา Go

  • การควบคุมเวอร์ชัน: Go Modules อนุญาตให้นักพัฒนาแสดงว่าต้องการใช้เวอร์ชันของไลบรารีของฝั่งที่สาม และ ใช้เพื่อใจความสามารถในการทำซ้ำโค้ด
  • การจัดการแพ็คเกจ: จัดการควบคุม dependency และเวอร์ชันของโปรเจค
  • การแยกโมดูล: โปรเจคต่างก็ณอาจพึงใช้งานแพ็คเกจเวอร์ชันที่ต่างกันของแพ็คเกจเดียวกันโดยไม่ทำให้เกิดข้อแตกต่าง เพราะทุกโปรเจคมีไฟล์ go.mod ของตัวเองเพื่อจัดการ dependency

การจัดการแพ็คเกจและโมดูลเป็นส่วนสำคัญสำหรับภาษาโปรแกรมที่ทันสมัย เนื่องจากรับหน้าที่ทั่วไปอย่างการจัดการ dependency, การอัพเกรดเวอร์ชันของแพ็คเกจ และการสร้างโค้ดที่สามารถทำซ้ำได้อย่างมีประสิทธิภาพสำราญลงหล่เมื่อพัฒนาภาษา Go โดยที่โปรเจคและในมหายนก continue การเพียพโมดูลทำให้ Go Modules เหรี่ยมที่ไม่ควรจำเป็นต่อการจัดการ dependency

2. การเริ่มกำหนดโมดูล Go ของคุณเอง

ขั้นตอนการเริ่มต้นโมดูล Go ใหม่นั้นง่ายมาก คุณสามารถดำเนินการดังนี้ในโฟลเดอร์หลักของโปรเจคของคุณ:

go mod init <ชื่อโมดูล>

ที่นี้ <ชื่อโมดูล> โดยทั่วไปจะเป็นที่อยู่ของโค้ดที่จัดเก็บ เช่น github.com/username/repo

วัตถุประสงค์ของไฟล์ go.mod

เมื่อคำสั่ง go mod init ถูกดำเนินการอย่างสำเร็จไป go.mod ไฟล์จะถูกสร้างขึ้นในไดเร็กทอรี่ปัจจุบัน ไฟล์นี้กำหนดการเหล่านี้:

  • ชื่อของโมดูลปัจจุบัน
  • เวอร์ชันของ Go
  • ข้อมูลที่จำเป็นเกี่ยวกับ dependency ตรงต่อแพ็คเกจแต่ละตัวรวมถึงเวอร์ชันที่ถูกเลือกสำหรับแต่ละแพ็คเกจ

ไฟล์ go.mod เป็นส่วนสำคัญสุดในกลไกของ Go Modules และกำลังถูดัพเดทโดยอัตโนมัติเหมือนกันเมื่อ dependency ถูกเพิ่มหรือถูกลบ

3. การสร้างและจัดโครงสร้างแพ็คเกจ Go

3.1 พื้นฐานของการสร้างแพ็คเกจ

ในภาษา Go แพ็คเกจคือคณะของหลายไฟล์ต้นฉบับ Go ที่อยู่ในโฟลเดอร์เดียวกันและมีความสามารถเฉพาะแต่ละแพ็คเกจดังกล่าวจะระบุข้างบนไฟล์แรกของแพ็คเกจในทางปฏิบัติคุณต้อง:

  1. สร้างโฟลเดอร์ซึ่งแทนไดเร็กทอรี่ของแพ็คเกจ
  2. สร้างไฟล์ .go ในโฟลเดอร์ และระบุ package <ชื่อแพ็คเกจ> บนบรรทัดแรกของไฟล์

ชื่อแพ็คเกจส่วนใหญ่จะเกี่ยวข้องกับชื่อของโฟลเดอร์ แต่ก็ไม่จำเป็นที่จะเป็นเช่นนั้น ชื่อแพ็คเกจควรสั้น ชัดเจน และควรหลีกเลี่ยงการใช้ underscore

3.2 โครงสร้างแพ็คเกจ

การสร้างโครงสร้างแพ็คเกจ Go อย่างมีระเบียบนั้นสำคัญสำหรับการมุ่งหน้าถึงความสามารถในการอ่านโค้ดรวมถึงการซ่ำใช้จนรุ่งเรือในการจัดการทดสอบตรวจสอบและคอมไพล์ แบบโครงสร้างแพ็คเกจที่ถูกวางอย่างชัดเจนตัวย่อจะสามารถ import และใช้ต่อไปได้อย่างง่ายโดยไม่เสียเวลา

ศันยะตามกฎและการตั้งชื่อตามข้างต้นจะช่วยให้นักพัฒนาพึ่งเนื้อหาโค้ดเก่าอย่างรวดเร็ว ซึ่งสามารถทำให้การจัดการแพ็คเกจและการแก้ไขโค้ดมีประสิทธิภาพมากยิ่งขึ้น

4. การ import และใช้แพ็คเกจ

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 การใช้แพ็คเกจภายนอก

เมื่อต้องการสร้างความสามารถที่ซับซ้อนมากขึ้น เรามักจะพึ่งพาที่แพ็คเกจภายนอก แพ็คเกจภายนอกเขียนขึ้นและเปิดเผยโดยนักพัฒนาอื่น ๆ ซึ่งเราสามารถผสานเข้ากับโปรเจกต์ของเราได้โดยง่าย

ถ้าคุณต้องการใช้ gorilla/mux ในโปรเจกต์ของคุณ ซึ่งเป็นไลบรารีเสถียรที่จัดการเรื่องการเรียก HTTP request คุณสามรถนำเข้าและใช้ได้ดังนี้:

ก่อนอื่น ติดตั้งแพ็คเกจโดยใช้คำสั่ง go get:

go get -u github.com/gorilla/mux

จากนั้น นำเข้าและใช้ 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 ระบบ Version Control และ go.mod

ตั้งแต่เวอร์ชัน 1.11 เป็นต้นมา Go ได้มีระบบการจัดการ dependencies ใหม่ที่เรียกว่า Go Modules อยู่ในไดเรกทอรีหลักของโปรเจค ไฟล์ go.mod จะบันทึก dependencies ของแพ็กเกจทั้งหมด

ไฟล์ go.mod ประกอบด้วยส่วนต่อไปนี้:

  • Module กำหนดเส้นทางโมดูลสำหรับโปรเจคปัจจุบัน
  • Require กำหนด dependencies และเวอร์ชันที่แน่นอนของพวกมัน
  • Replace สามารถระบุเส้นทางและเวอร์ชันทดแทน
  • Exclude ใช้สำหรับการยกเว้นเวอร์ชันที่เฉพาะเจาะจง

ตัวอย่างของไฟล์ 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 โดยอัตโนมัติเพื่อกำหนด dependencies ที่ต้องใช้สำหรับโปรเจค การทำ version control ที่ดีคือการคอมมิตไฟล์ go.mod และ go.sum (ซึ่งบันทึกการคาดหวังของ cryptographic hashes ของ dependencies)

การจัดการผ่านไฟล์ go.mod ทำให้แน่ใจว่าทุกโปรแกรมเมอร์ในทีมใช้เวอร์ชัน dependencies เดียวกัน ทำให้ไม่เกิด "แต่ที่เครื่องของฉันยังทำงานได้" อันไม่สะดวก