Golang config profile với Toml

Hi Vtitans,
Hôm nay mình lộ bí mật đen tối là đôi khi mình blog trong bực bội đó.

Nguyên là thấy code kì cục mà chưa được khách cho sửa, dev nào mà chẳng ấm ức. Tuy mình không biết code, mình cũng chẳng biết golang với toml gì sất, nhưng mà đọc đoạn code sau vẫn cứ bực giùm ông khách á.

Vào vấn đề nhé, hẳn bạn đã quen thuộc với cách viết file config có profile kiểu local - staging - production rổi phải không. Syntax sau dù là ini, yml hay gì thì nó cũng rất phổ biến rồi, nên toml thì ý tưởng cũng vậy thôi. Có thể có chút khác biệt về chuyện toml sử dụng dấu "=", và string thì phải quote như vầy nè:

[local]
host    = "SOME HOST"
[staging]
host    = "STAGING HOST"

Để decode đoạn toml trên, cha dev struct đại khái như sau:

type Config struct {
    HOST        string `toml:"host"`
}

type ConfToml struct {
    Production Config `toml:"production"`
    Staging    Config `toml:"staging"`
    Local      Config `toml:"local"`
}

Wth? Cái struct thứ 2 vả vào định kiến của mình là môi trường deploy có thể là bất cứ cái gì từ abc đến xyz. Nếu bây giờ tôi có thêm Demo 1, Staging Feature 1, Staging Feature 2 hay Customer Mới thì tôi đi sửa cái struct này á ạ?

Định kiến 1:

  • Khi có thêm một profile với name bất kì, tôi sẽ chỉ sửa file config chứ không sửa code.

Làm gì có chuyện một vấn đề đơn giản mà giải pháp lại kì cục thế kia. Thế là lại đành code thử vậy, và nó đúng như mình nghĩ.

Bỏ struct thứ hai đi, chỉ cần struct Config thôi. Dưới đây là toàn bộ code:

package main

import (
    "github.com/BurntSushi/toml"
    "log"
    "os"
)

func main() {
    in, errOpenFile := os.Open("./config.toml")
    if errOpenFile != nil {
        log.Fatal(errOpenFile)
    }
    defer in.Close()
    c := make(map[string]Config)
    if _, errDecodeToml := toml.DecodeReader(in, &c); errDecodeToml != nil {
        log.Fatal(errDecodeToml)
    }
    // Trong code thật, profile sẽ được truyền vào từ ... ừm, thôi tự hiểu nha. Ở đây mình hard code cho nhanh.
    println(c["local"].HOST) //expect "SOME HOST"
    println(c["staging"].HOST) //expect "STAGING HOST"
}

//Config toml
type Config struct {
    HOST string `toml:"host"`
}

Tất nhiên còn có rule 2:

  • Một config có thể vắng mặt trong [profileA], khi đó value của nó sẽ được lấy từ profile [default]. Nói cách khác, các config mà giá trị của chúng không phụ thuộc môi trường thì không cần thiết phải copy vào mọi profile.

Nhưng mà cái này lúc nào khách bằng lòng yêu thì đệ mình mới code nha. Bực chứ có ngu đâu =))))

Thân, from Châu D9

Leave a Reply

Your email address will not be published. Required fields are marked *