oinume journal

Scratchpad of what I learned

Arguments to defered functions are evaluated when the defer executes

The arguments to the deferred function (which include the receiver if the function is a method) are evaluated when the defer executes, not when the call executes.

Effective Go - The Go Programming Language

I sometimes make a mistake that defered functions are evaluated when the function is called but it’s wrong. Here is an example.

package main

import (
        "fmt"
        "time"
)

type wrapped func()

func main() {
        wrapper(func () {
                time.Sleep(time.Second * 3)
                fmt.Println("Hello")
        })
}

func wrapper(f wrapped) {
        fmt.Println("wrapper() start: ", time.Now().UTC())
        defer instrument(time.Now().UTC())
        f()
        fmt.Println("wrapper()   end: ", time.Now().UTC())
}

func instrument(start time.Time) {
        fmt.Println("instrument():    ", start)
}
$ go run defer.go
wrapper() start:  2016-05-23 07:28:37.474091714 +0000 UTC
Hello
wrapper()   end:  2016-05-23 07:28:40.474272645 +0000 UTC
instrument():     2016-05-23 07:28:37.474139821 +0000 UTC

If defer functions are evaluated at call time, instrument() time must be 3 seconds later.

会社のITシステムで良かったところまとめてみた

今まで勤めてきた会社で良かった社内のITシステム(?)を思い出してみた。

BYOD (Bring Your Own Device)

会社用の携帯を別途支給されるのは携帯の2台持ちになってしまってつらい。2台持ちのつらいところは

  • 単純に邪魔
  • 2台あると紛失するリスクも2倍
  • 2台あると端末の設定が面倒

あたりだろうか。BYODなら普段自分が使っている端末をそのまま使えるので便利だった。業務で使う電話については、モバチョというアプリを使うと、業務用の番号で電話がかけられる。

ただ、BYODにも問題があって、「iPhoneを探す」の設定をちゃんとやっているかを事前に確認しておかないと、端末をなくした時に色々問題が発生するので、情シス的にはその辺が課題かもしれない。

シングルサインオン

経費精算や人事関連の社内のシステムへのログインが全部バラバラだと辛いので、やっぱりシングルサインオン大事。月に1回しか使わない経費精算システムのパスワードとかメモしておくの辛いし。情シス的にも認証の口は一つにしておいたほうがアカウントをロックするにも楽なはず。

Google Apps

もう説明する必要はないでしょう。Google DriveとHangoutがいい。Google Calendarは人数が多いと辛い気がする。

セキュリティカードがSUICA/PASMO

オフィスに入るためのセキュリティカード、別途配られると財布の中にまた新しいカードが増えて嫌な感じになるけど、SUICAPASMOに登録して使えるようになってるのがけっこう良かった。もっといいのはSmartNewsのような顔認証システムだとは思う。

まともなドキュメント管理システム

数百人規模の会社だともはやConfluence一択な気がするけど、ドキュメント管理システムはないとつらい。Google Docsでもいいかもしれないけど、Word感が強くて個人的にはあまり好きじゃなかった。Qiita Teamは人数が多くて部署が多いとつらそう。

Go Tip: Don't take the address of loop variable

stackoverflow.com

If you take the address of loop variable, it may cause a bug which all values are same. You might expect following program prints 5 10 15 but it prints 15 15 15. That’s because loop variable v is initialized just once.

package main

import "fmt"

func main() {
    coll := []int{5, 10, 15}
    for _, v := range toPointers(coll) {
        fmt.Printf("%v ", *v)
    }
}

func toPointers(ints []int) []*int {
    pointers := make([]*int, len(ints))
    for i, v := range ints {
        pointers[i] = &v // XXX: mistake
    }
    return pointers
}

You can get expected result if you write like this:

package main

import "fmt"

func main() {
    coll := []int{5, 10, 15}
    for _, v := range toPointers(coll) {
        fmt.Printf("%v ", *v)
    }
}

func toPointers(ints []int) []*int {
    pointers := make([]*int, len(ints))
    for i, _ := range ints {
        pointers[i] = &ints[i]
    }
    return pointers
}

First loaded configuration becomes default_server in nginx

How nginx processes a request

server {
    listen      80;
    server_name example.org www.example.org;
    ...
}

server {
    listen      80;
    server_name example.net www.example.net;
    ...
}

server {
    listen      80;
    server_name example.com www.example.com;
    ...
}
In this configuration nginx tests only the request’s header field “Host” to determine which server the request should be routed to. If its value does not match any server name, or the request does not contain this header field at all, then nginx will route the request to the default server for this port. In the configuration above, the default server is the first one — which is nginx’s standard default behaviour.

I didn't know this behaviour and I should always add default_server to prevent someone from misunderstanding like this.

server {
    listen      80 default_server;
    server_name _;
}