ข้ามไปยังเนื้อหา

โครงสร้างโปรเจกต์ Go

ถ้ามาจากสาย Node.js/TypeScript คุณคงคุ้นกับ package.json, tsconfig.json, โฟลเดอร์ src/ และ node_modules โปรเจกต์ Go วางโครงสร้างต่างออกไป แต่ก็เป็นระเบียบไม่แพ้กัน เข้าใจโครงสร้างนี้ตั้งแต่ต้นช่วยประหยัดเวลาไปได้หลายชั่วโมง

go mod init เป็นคนสร้าง go.mod ขึ้นมาเป็น root manifest ของ Go module ในไฟล์นี้จะประกาศชื่อ module (prefix ของ import path ของคุณ) และ Go version ขั้นต่ำที่ต้องใช้

TypeScript
// package.json
{
"name": "my-app",
"version": "1.0.0",
"scripts": { "build": "tsc", "start": "node dist/index.js" },
"dependencies": { "express": "^4.18.2" },
"devDependencies": { "typescript": "^5.0.0" }
}
Go
// go.mod
module github.com/yourname/myapp
go 1.22
require (
github.com/gin-gonic/gin v1.9.1
)
// go.sum คือ lockfile (เหมือน package-lock.json)
// จัดการอัตโนมัติ — ไม่ควรแก้ด้วยตัวเอง

ชื่อ module (github.com/yourname/myapp) ไม่ใช่แค่ชื่อ — แต่คือ import path prefix ที่ใช้ทั่วทั้งโค้ดของคุณ โดย convention มักตั้งให้ตรงกับ URL ของ source repository

ใน Go package คือ directory ที่รวมไฟล์ .go ซึ่งประกาศ package name เดียวกันทั้งหมด เข้มงวดกว่า TypeScript/ESM ที่ทุกไฟล์เป็น module ของตัวเอง เพราะใน Go คุณ import ที่ระดับ package ไม่ใช่ระดับไฟล์

TypeScript
// TypeScript: imports ระดับไฟล์
import { UserService } from './services/user.service';
import type { User } from './models/user.model';
import * as utils from '../shared/utils';
Go
// Go: imports ระดับ package
import (
"github.com/yourname/myapp/internal/services"
"github.com/yourname/myapp/internal/models"
"github.com/yourname/myapp/pkg/utils"
)
// แล้วใช้: services.NewUserService(...)
// models.User{...}
// utils.SomeHelper(...)

ชุมชน Go ลงตัวกับ layout มาตรฐานสำหรับ service และ CLI มาแล้ว ลองมาเทียบกับโปรเจกต์ Node/TypeScript ทั่วไปดู:

TypeScript
// TypeScript / Node.js project
my-app/
src/
controllers/ # route handler
services/ # business logic
models/ # TypeScript interface/type
middleware/ # Express middleware
index.ts # entry point
dist/ # compiled output
package.json
tsconfig.json
.env
Go
// Go project (idiomatic layout)
myapp/
cmd/
myapp/
main.go # entry point (package main)
internal/
handlers/ # HTTP handler
services/ # business logic
models/ # struct definition
middleware/ # HTTP middleware
pkg/ # package ที่นำกลับมาใช้ได้ (public API)
go.mod
go.sum
.env

กฎสำคัญ:

  • cmd/ เก็บ entry point (main package) — หนึ่ง subdirectory ต่อหนึ่ง binary
  • internal/ คือโค้ด private ที่ Go บังคับให้ — package ในนี้ module ภายนอก import ไม่ได้
  • pkg/ เก็บ package ที่คุณตั้งใจเปิดให้ภายนอกเรียกใช้

ใน TypeScript คุณใช้ export กับ import ส่วนใน Go ตัวอักษรแรกของชื่อ identifier เป็นตัวกำหนด visibility — ไม่ต้องมี keyword export

TypeScript
// TypeScript: export แบบ explicit
export interface User { id: string; name: string; }
export function greet(name: string): string {
return `Hello, ${name}!`;
}
// helper ภายใน (ไม่มี export)
function formatName(n: string): string { return n.trim(); }
Go
// Go: ตัวพิมพ์ใหญ่ = exported, ตัวพิมพ์เล็ก = unexported
type User struct { // exported (U ตัวใหญ่)
ID string
Name string
}
func Greet(name string) string { // exported (G ตัวใหญ่)
return "Hello, " + formatName(name) + "!"
}
func formatName(n string) string { // unexported (lowercase)
return strings.TrimSpace(n)
}
package main
import (
"fmt"
"strings"
)
// Exported function — ตัวพิมพ์ใหญ่
func Greet(name string) string {
return "Hello, " + formatName(name) + "!"
}
// unexported helper — ตัวพิมพ์เล็ก
func formatName(n string) string {
return strings.ToUpper(n[:1]) + n[1:]
}
func main() {
fmt.Println(Greet("gopher"))
fmt.Println(Greet("world"))
// Standard library import โดย path
// "strings" -> the strings package
fmt.Println(strings.ToUpper("go is great"))
}
ใน Go อะไรกำหนดว่า identifier ถูก export (public) หรือไม่?
directory `internal/` enforce อะไรใน Go?
ใน Go scope ของ import คืออะไร? (เช่น import "fmt")
go.sum เทียบเท่ากับอะไรใน Node.js ecosystem?