หนึ่งในวิธีที่จะทำให้เรา dev ได้สะดวกขึ้นคือการทำให้พฤติกรรมของ app เราที่ run บนเครื่องมีความเหมือนกับที่ run บน production ให้ได้มากที่สุด ซึ่งหนึ่งในเรื่องนี้ก็คือการ load ค่า configurations ซึ่งความคุ้นเคยในอดีต หลายๆคนจะชินกับการใช้ config file ต่างๆ ไม่ว่าจะเป็น yaml, tomal หรืออื่นๆก็ตาม
แต่พอเอาขึ้น production จริงส่วนใหญ่เราก็ใช้ค่าใน env ซึ่งเป็นคำแนะนำจาก 12factors นั่นเอง
ยกตัวอย่างเวลาผมเขียน Go ในอดีตก็เคยใช้ viper เข้ามาช่วยอยู่พักหนึ่ง เพราะมันยืดหยุ่น ให้สามารถใช้ค่า config จาก file ก็ได้ หรือใช้จาก env ก็ได้ใน code ชุดเดียวกัน แต่ เอาเข้าจริง พฤติกรรมมันก็ต่างกันโดยสิ้นเชิง เพราะถ้าเราไป copy example ของ viper มาใช้ตรงๆ ก็จะพบว่า ถ้าเราไม่โยน config file เข้าไปใน dockerfile มันจะ run ไม่ขึ้น เรามาดู code ตัวอย่างกัน
viper.SetConfigName("config") // name of config file (without extension)
viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name
viper.AddConfigPath("/etc/appname/") // path to look for the config file in
viper.AddConfigPath("$HOME/.appname") // call multiple times to add many search paths
viper.AddConfigPath(".") // optionally look for config in the working directory
err := viper.ReadInConfig() // Find and read the config file
if err != nil { // Handle errors reading the config file
panic(fmt.Errorf("fatal error config file: %w", err))
}
code นี้มันจะ panic เมื่อไม่เจอ config file ซึ่งถ้าเราอ่านมันเข้าใจ เราก็แค่แก้มัน ไม่ให้มัน panic ก็ได้ แต่อย่างไรก็ดีมันก็จะทำให้ พฤติกรรมของ code ที่ทำงานบนเครื่องเรา กับที่ทำงานบน production จริงต่างกันอยู่ดี
วันนี้ก็เลยอยากชวนมาใช้ .env file แทน ซึ่งจำเป็นจะต้องใช้คู่กับ direnv
เริ่มต้นเราก็ install ตามคู่มือกันก่อน และผมก็เลือกใช้ HomeBrew เนื่องจากผมใช้ Mac
brew install direnv
จากนั้นก็ไป hook ตามที่คู่มือบอก ซึ่งผมใช้ zsh ก็เอาบรรทัดนี้ไปวางใน .zshrc
eval "$(direnv hook zsh)"
ทีนี้โดยปกติ direnv
จะทำงานคู่กับไฟล์ .envrc
โดยเมื่อวางไว้ที่ directory ใดก็ตาม เราก็จะต้องทำการ allow ให้ direnv ยอมโหลดค่าจากไฟล์นี้ก่อนด้วยคำสั่ง
direnv allow
แต่เนื่องจากโดยปกติเรามักจะคุ้นกับการใช้ไฟล์ .env
กันมากกว่า แต่ถ้าจะให้ direnv
รู้ว่าเราจะใช้ .env
แทน ก็จำเป็นจะต้องทำ config กันก่อน โดยเราจะทำไว้ที่ระดับ global กันไปเลย จะได้ไม่ต้องมาทำมันบ่อยๆ
ให้สร้างไฟล์ไว้ที่ .config/direnv/direnv.toml
แล้วใส่เนื้อหานี้ลงไป
[global]
load_dotenv = true
เมื่อทำครบทุกขั้นตอนแล้ว หลังจากนี้ เวลาเราจะ dev อะไรก็ตาม แล้วต้องการใช้ค่า env เป็น configurations เราก็เพียงแค่สร้างไฟล์ .env วางไว้ใน directory นั้น เช่น
PORT=8080
LOG_LEVEL=INFO
และเมื่อมีการแก้ไขไฟล์นี้ หรือสร้างไฟล์นี้ขึ้นมาใหม่ เราก็ต้องทำการ allow มันด้วยคำสั่ง
direnv allow
หลังจาก allow มันแล้ว ตราบเท่าที่ไฟล์นี้ไม่มีการแก้ไขใดใด มันก็จะ auto load ค่าใน .env มาให้เราทุกครั้งที่เราเข้าไปทำงานใน directory นั้นๆ ทีนี้ใน code ของเรา ก็แค่เรียกค่า config มาจาก env ได้โดยตรง แล้วก็จะทำให้ code ที่รันบนเครื่องเรา กับบน prodution ทำงานแบบเดียวกันได้แล้ว
Top comments (0)