:= "{\"key\":\"" + value + "\"}" b := "{" + "\"key\":\"" + value + "\"" + "}" c := `{"key":"` + value + `"}` println(a == c && b == c) println(c) } // true // {"key":"ʕ◔ϖ◔ʔ"} Strings should be human readable
} type helloResponse struct { Message string `json:"message"` } func helloHandler(...) { // process helloRequest/helloResponse } type confirmRequest struct { ... } type confirmResponse struct { ... } func confirmHandler(...) { ... } Just a HTTP handler The obvious way to declare req/resp :(
Name string `json:"name"` Toke string `json:"token"` } type response struct { Message string `json:"message"` } var req request var resp response // process request/response } But we can do better :)
string `json:"name"` Toke string `json:"token"` } // process request var response = struct { Message string `json:"message"` }{ Message: “yo, GoGoConf”, } // process request } or with an anonymous type :D
foo() interface{} { mu.Lock() defer mu.Unlock() if !flag { return nil } // do some stuff // huh… everything is fine return value } And suddenly we have… no problems
func() { var i int64 for { ch <- i i++ } }() return ch } func foo() { ch := out() for c := range ch { ... } } Simple code, huh How to shoot yourself into the foot
func() { var i int64 for { ch <- i // *BANG* i++ } }() return ch } func foo() { ch := out() // read from ch a bit and... close(ch) // and make a panic, probably } Don't close in-channel *BANG*
func() { var i int64 for { ch <- i // just send, right? i++ } }() return ch } func foo() { ch := out() // read from ch a bit and... close(ch) // hah, compilation error // invalid operation: close(ch) // (cannot close receive-only channel) } Specify a channel direction One small arrow for developer One giant leap for safety
:= range [10]struct{}{} { println(i) greetOnce.Do(func() { print("hey, there!") }) } } // 0hey, there!123456789 Do something once with sync.Once No comments
{ return keyValue[k] } func Set(k string, v []byte) { keyValue[k] = v } package service func foo() { cache.Set(“conf”, “GoGoConf”) } Avoid a global state Yeah, it works
*redis.Client func Get(k string) ([]byte, bool) { switch CacheType { case “inmemory”: return keyValue[k] case “redis”: return redisClient.Get(k) ... } } But how to make it different? Oh..that’s hard
New() *Cache {...} func (c*Cache) Get(k string) ([]byte, bool) {...} func (c*Cache) Set(k string, value []byte) {...} package service func foo() { c := inmemory.New() c.Set(“best conf”, “GoGoConf”) } Let’s make it simpler And it’s Easy to test
{ “oh_please_stop”: [{ ... }] }, “tet_another”: {...}, } }` var m map[string]interface{} json.Unmarshal([]byte(body), &m) // slow :( // and we need only id & timestamp Unmarshal JSON JSON from a production
int `json:”timestamp”` Data json.RawMessage `json:”data”` } // encoding/json.go // type RawMessage []byte var m Body json.Unmarshal([]byte(body), &m) // fast :) timestamp := m.Timestamp We can make it type-safe
every test like that package service_test var iTests = flag.Bool("integration", false, "<docs>") func TestSomething(t *testing.T) { if !*iTests { t.Skip(“skipping test because of”) } if service.IsMeaningful() != 42 { t.Errorf(“oh no!”) } } // And run: go test ./... -args integration