DEV Community

Cover image for Project Layout ของ Golang EP.1
Rungsikorn Rungsikavanich
Rungsikorn Rungsikavanich

Posted on

Project Layout ของ Golang EP.1

วันนี้จะมาเล่าเรื่อง Project Layout ครับ เรียกได้ว่าเป็นหนึ่งในสิ่งสำคัญที่จะทำให้เราพัฒนา application ด้วยภาษา Golang ได้ตรงตามที่ผู้พัฒนาต้องการให้เราทำ ( หรือ Idiomatic ที่แปลว่า ลักษณะจำเพาะ ) เพื่อให้โปรเจคเรา ใกล้เคียงความเป็น Gopher project มากที่สุดกันครับ

✨ TL;DR อีกแล้ว

Golang ไม่มี layout standard เป็นตัวเป็นตนจาก Go Core Dev team ที่มีอยู่ตอนนี้ก็คือ ตั้งแต่ Go 1.4 เป็นต้นไป folder internal จะไม่สามารถถูกเรียกใช้จากนอก package หลักได้

release note เรื่อง internal folder

นอกนั้นก็ตามแล้วแต่ผู้ดูแลโปรเจคจะเป็นคนกำหนด convention ของ layout ตัวเอง

ส่วนทางด้าน community และ open source ก็มีตัวอย่างที่ใช้กันบ่อยๆ ฮิตๆก็ดูได้จาก Repository นี้ (และ open source ของ Golang อื่นๆ)

https://github.com/golang-standards/project-layout

หลักๆคือ

  • cmd ใช้สำหรับเก็บ package ที่เป็น entry point ของ application (ส่วนใหญ่ก็คือ package main) โดยจะไม่นำ code มาเขียนตรงนี้เยอะ โดย package ใน cmd จะไปเรียกใช้ code ที่อยู่ในส่วนของ interal และ pkg

  • internal เก็บ package ที่เป็น implementation หลักของ application (หรือ library) ซึ่งไม่ต้องการให้มีการ import จากนอก package

  • pkg ใช้เก็บ package ที่เหมือนกัน internal แต่สามารถ import ไปใช้งานได้นอก application (หรือ library) เหมาะสำหรับใช้ reuse package ไปที่ project อื่นๆ

และนอกจากนี้ เรายังสามารถศึกษาได้จาก Open Source Project อื่นๆที่พัฒนาด้วย Golang (ดูต่อที่ Reference)

แต่ยังไงก็ตาม การทำงานที่มีประสิทธิภาพที่สุด ก็คือการทำงานบน convention ที่เราสามารถสร้าง productivity ได้มากที่สุด เพราะฉะนั้น ก็ไม่จำเป็นจะต้องทำตามสิ่งเหล่านี้ทั้งหมดครับ เราอาจจะใช้ layout ของ NodeJS หรือ Java ก็ไม่เป็นอะไร ถ้าเราสามารถ deliver งานได้ตามที่ business ต้องการ


เริ่มเนื้อหาแบบยาว...

Project Layout คืออะไร?

ในการพัฒนาแอพพลิเคชั่นแต่ละภาษา ก็จะมี Project Layout แตกต่างกันออกไปครับ เพื่อการ organize code ที่ดี แต่ละภาษาก็มี convention แตกต่างกันออกไปตาม design pattern ของภาษา

เช่นเมื่อ New Project ใน ​Java, C#, Swift หรือ NodeJS รวมไปถึงระดับ Framework เช่น Laravel หรือ Angular เราก็จะได้ project layout แตกต่างกันออกไป แต่ก็เพื่อให้สามารถจัดการ Code ง่ายที่สุด ตามที่ผู้พัฒนาภาษาคิดมาซึ่งส่วนใหญ่ หนีไม่พ้น ทุกแบบก็จะประกอบไปด้วย

  • Dependencies and Information
  • Implementation
  • Testing
  • Build
  • Distributed

เช่น Swift เราก็จะมี Podfile, xcodeproj หรือ NodeJS เราจะมี package.json, src folder

Dependencies and Project Information

สำหรับ Golang แล้ว ก่อนที่จะมี go mod เราบันทึก dependencies ไว้ภายในตัว code เอง (ใน import) แต่หลังจากนั้นก็มี tools เพื่อควบคุม version เช่น glider หรือ godeps

ปัจจุบัน Golang มี dependency management เองแล้วชื่อ go mod ซึ่งประกอบด้วย go.mod และ go.sum ภายในบ่งบอกถึง dependencies ต่างๆที่เราจะใช้งาน

ส่วน Project Information ต้องบอกก่อนว่า Golang เราทำ document ด้วยการ comment เป็นหลัก (เรื่องการทำ godoc จะเอาไว้เขียนบทความหน้า) เพราะฉะนั้น Information ของ package ต่างๆก็เลยถูกเขียนไว้ใน comment ทั้งหมด

Implementation

ส่วนที่เราเก็บ code ที่เราเขียนไว้จะประกอบด้วย 4 packages หลักๆ (จริงๆมีมากกว่านั้น แต่ผู้เขียนเลือกอันที่ใช้ และเจอบ่อยมาเพื่อความเรียบง่าย ลองดูใน Go Standard Layout เพิ่มเติมครับ)

1. cmd Folder

Folder หลักที่ใช้เก็บ Entry point package ต่างๆของ application โดยส่วนมากจะเป็น Package main โดย package ภายใต้ folder นี้ไม่จำเป็นจะต้องมี implementation ที่ซับซ้อนมากมาย ทำแค่เพียงเป็น entry point เรียก implementation อื่นๆจาก package ใน folder internal, web และ pkg

ตัวอย่างจาก Ethereum Golang
Etereum cmd

ตัวอย่างจาก Go Pkgsite
gopkgsite


2. internal Folder

Folder นี้น่าจะเป็น folder ที่มี source code เก็บอยู่มากที่สุด (ถ้าเป็น application) เพราะประกอบด้วย implementation หลักของ Project ที่ไม่สามารถ import ผ่าน package อื่นๆนอกจาก Project นี้ได้ (หรือภายใต้ go module เดียวกัน)

ตัวอย่างจาก Go Pkgsite ซึ่ง package แน่นมาก
gopkg internal

ถึงใน standard project layout จะบอกว่าเป็น folder ที่อยู่ด้านนอกสุด (workspace root) แต่ก็ไม่จำเป็น เพราะ Golang จะ recognize folder internal ให้ตลอด เพราะฉะนั้นไม่จำเป็นที่จะต้องอยู่ที่ workspace root ก็ได้

เช่นตัวอย่างจาก Golang source code เองก็มีการวาง folder internal ไว้ภายใน src folder ( ซึ่ง src folder ไม่ได้มีใน Standard Project Layout )

gosource internal

3. pkg Folder ( หรืออยู่ที่ root ไปเลย )

คล้ายๆกันกับ internal (อ่าว พูดเหมือนใน TL;DR เลย) แต่ในนี้จะประกอบด้วย code ที่สามารถนำไป reuse ใช้งานภายนอก package หลักได้

หรือบาง repository ก็ไม่ใช้เลย โดยนำเอา package ต่างๆมาไว้ที่ workspace root (ที่เดียวกับ go.mod ไปเลย) โดยมีการเถียงกันที่ issue นี้ 555555
https://github.com/golang-standards/project-layout/issues/10

ถ้าดูตัวอย่าง ส่วนใหญ่จะเป็น Library หรือ Opensource tools ต่างๆ เช่น
ตัวอย่างจาก Moby (container engine ของ docker)

moby pkg

ตัวอย่างจาก Kubernetes
kube pkg

ตัวอย่างจาก Gorilla Mux ที่ไม่ใส่ folder อะไรเลย เอาไว้มันโต้งๆนี่แหล่ะ

mux pkg

4. web Folder

Folder นี้จะประกอบด้วย source code ของ frontend ซะส่วนใหญ่ (ถ้าเป็น web base application) โดยเราจะเอา html template, static asset ต่างๆมาเก็บไว้ในนี้ หรือถ้าเป็น Javascript framework อย่าง Angular ก็นำมาเก็บไว้ในนี้ได้ (ในกรณี Monorepository)

ตัวอย่างจาก traefik (http engine ที่เขียนด้วย golang (คล้ายๆ nginx)
Alt Text

go pkgsite นั้นเอาไว้ใน content folder แทน go pkgsit repository


จบแล้วสำหรับ part แรก เดี๋ยวส่วนอื่นๆที่เหลือ จะเขียนต่อใน part ต่อไปครับ

Happy Christmas and coding!
🎄 🤖

Reference

Discussion (0)