OKRと評価について

speakerdeck.com

OKRと評価について読んだものの中では一番納得感あった。

  • OKRを人事評価に使わない
  • 健康・健全性指標について
  • 給与は結局のところ、ざっくり決めるしかない云々のくだり

OKRの達成度で評価するのではなく、OKRをベースにどれだけ(大胆に)打ち手を打てたかで評価するのはどうだろうか?

Goならわかるシステムプログラミング:第3章(練習問題)

Q3.1 ファイルのコピー

package main

import (
    "io"
    "os"
)

func main() {
    file, err := os.Open("old.txt")
    if err != nil {
        panic(err)
    }
    defer file.Close()

    newFile, err := os.Create("new.txt")
    if err != nil {
        panic(err)
    }
    defer newFile.Close()
    io.Copy(newFile, file)
}

テスト

package main

import (
    "bytes"
    "io/ioutil"
    "os"
    "testing"
)

func exists(filename string)bool {
    _, err := os.Stat(filename)
    return err == nil
}

func TestMainSuccess(t *testing.T){
    if exists("new.txt") {
        os.Remove("new.txt")
    }

    main()
    oldFile, err := os.Open("old.txt")
    if err != nil {
        t.Fatalf("failed to open old file: %#v", err)
    }
    newFile, err := os.Open("new.txt")
    if err != nil {
        t.Fatalf("failed to open new file: %#v", err)
    }
    oldBuffer, err := ioutil.ReadAll(oldFile)
    if err != nil {
        t.Fatalf("failed to read content: %#v", err)
    }
    newBuffer, err := ioutil.ReadAll(newFile)
    if err != nil {
        t.Fatalf("failed to read content: %#v", err)
    }
    if bytes.Compare(oldBuffer, newBuffer) != 0 {
        t.Fatalf("each contents of files are different.")
    }

    os.Remove("new.txt")
}

テストはもうちょっとスッキリかける気がする。

Q3.2 テスト用の適切なサイズのファイルを生成

package main

import (
    "crypto/rand"
    "io"
    "os"
)

func main() {
    file, err := os.Create("samplefile")
    if err != nil {
        panic(err)
    }
    defer file.Close()
    r := io.LimitedReader{R: rand.Reader, N: 1024}
    io.Copy(file, &r)
}

io.Copyを使わないように」と問題には書いてあったが、LimitReaderを使って読み出しているので問題ない?

テスト

package main

import (
    "os"
    "testing"
)

func TestMainSuccess(t *testing.T) {
    main()
    info, err := os.Stat("samplefile")
    if err != nil {
        t.Fatalf("could not open file.")
    }
    if info.Size() != 1024 {
        t.Fatal("size was not 1024 byte.")
    }
    defer os.Remove("samplefile")
}

ファイルサイズはos.Stat()で取れる。

Q3.4 zipファイルをウェブサーバーからダウンロード

package main

import (
    "io"
    "net/http"
    "os"
)

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8081", nil)
}

func handler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/zip")
    w.Header().Set("Content-Disposition", "attachment; filename=ascii_sample.zip")
    file, err := os.Open("./chap3/test.zip")
    if err != nil {
        panic(err)
    }
    defer file.Close()
    io.Copy(w, file)
}

Q3.5 CopyN

package main

import (
    "io"
    "os"
    "strings"
)

func main() {
    r := strings.NewReader("strings reader example")
    CopyN(os.Stdout, r, 5)
}

func CopyN(dst io.Writer, src io.Reader, n int64) (written int64, err error) {
    written, err = io.Copy(dst, io.LimitReader(src, n))
    if written == n {
        return n, nil
    }
    if written < n && err == nil {
        // src stopped early; must have been EOF.
        err = io.EOF
    }
    return
}

実装はこちらのコピー。 https://golang.org/src/io/io.go?s=11939:12009#L329

Q3.6 ストリーム総集編

package main

import (
    "io"
    "os"
    "strings"
)

var (
    computer = strings.NewReader("COMPUTER")
    system = strings.NewReader("SYSTEM")
    programming = strings.NewReader("PROGRAMMING")

)
func main() {
    var stream io.Reader

    charA := io.NewSectionReader(programming, 5, 1)
    charS := io.NewSectionReader(system, 0, 1)
    charC := io.NewSectionReader(computer, 0, 1)
    charI, pw := io.Pipe()
    w := io.MultiWriter(pw, pw)
    go func() {
        io.Copy(w, io.NewSectionReader(programming, 8, 1))
        pw.Close()
    }()
    stream = io.MultiReader(charA, charS, charC, charI)
    io.Copy(os.Stdout, stream)
}

同じwriterに2回書けるということに気づかず、時間を使ってしまった。 答えは下記のリンクにある(上記のものとは少し違う)

ASCII.jp:低レベルアクセスへの入り口(3):io.Reader後編 (2/2)|Goならわかるシステムプログラミング

同じ振る舞いが想像以上に威圧的にとられてしまう懸念

エンジニアを育てる環境と、コミュニティのありかたについて - 滞舎路日記

自分自身は、率直に物事を指摘する、勢いのある若手のつもりでいても、在籍年数を重ねるうちに、同じ振る舞いが想像以上に威圧的にとられてしまうこともあるので、みなさん注意しましょう。

これがすごい金言で、ありがちな状況を的確に言語化していると思う。他人がそういうふうであることを見かけることもままあるし、自分が他人からそう見えていないかどうか不安だ。本人は悪意が無いかつ無自覚なので

DockerfileからビルドしたDockerイメージをDocker Hubにアップする

個人的によく使うDockerイメージをpublicに置いておきたかったので初めてやってみた。

今回実際に上げたのはこちら。 https://hub.docker.com/r/chokkoy/redis_trib/

Docker Hubのアカウントを取る

https://hub.docker.com/ から、画面に沿って行う。

Dockerfileを書いて、イメージをビルド

下記のような状態で、

~/Documents/docker/image ᐅ ls
Dockerfile
~/Documents/docker/image ᐅ cat Dockerfile
FROM ubuntu:16.04

RUN apt-get update
RUN apt-get install -y ruby vim wget redis-tools
RUN gem install redis
RUN wget http://download.redis.io/redis-stable/src/redis-trib.rb

下記のコマンドでビルドする

docker build -t chokkoy/redis_trib:1.0 ./

できている

~/Documents/docker/image ᐅ docker images | grep redis_trib                                                                                    
chokkoy/redis_trib                                            1.0                 8a146f5d717b        About an hour ago   245MB
  • docker loginでログインする

  • docker push chokkoy/redis_tribでイメージをPush

これでOK

不合理だからうまくいく:行動経済学で「人を動かす」

Docker for Macに同梱のKubernetesを使う(minikubeの代替?)

Docker for MacKubernetesが同梱されるようになったことはなんとなく知っていたが、どのように使うのかは分かっていなかったので試してみた。

現時点でのDocker for MacのバージョンはVersion 18.06.0-ce-mac70 (26399)

f:id:road288:20180810161026p:plain

Preferenceをみると、Kubernetesというタブができているので、それを開いてEnable Kubernetesにチェックを入れる。

f:id:road288:20180810161116p:plain

Defaultのオーケストレーションツールを選択する。SwarmはつかったことないのでKubernetesにする(デフォルトはSwarmになっていた)。

f:id:road288:20180810161212p:plain

画面に沿ってインストールする。インストールは数分かかった。 f:id:road288:20180810161220p:plain

インストールが終わると、docker for desktopというコンテキストが用意されていて、ターミナル上もそれに切り替わっている。

ᐅ kubectl config current-context                                                                                              
docker-for-desktop

defaultのネームスペースにはpodがないが、他のネームスペースにはpodがいくつか起動済みになっている。

~ ᐅ kubectl get pods

No resources found.
~ ᐅ kubectl get namespace

NAME          STATUS    AGE
default       Active    3m
docker        Active    3m
kube-public   Active    3m
kube-system   Active    3m
~ ᐅ kubectl get pods --namespace docker

NAME                           READY     STATUS    RESTARTS   AGE
compose-7447646cf5-bk579       1/1       Running   0          3m
compose-api-6fbc44c575-jg2dp   1/1       Running   0          3m
~ ᐅ kubectl get pods --namespace kube-public

No resources found.
~ ᐅ kubectl get pods --namespace kube-system

NAME                                         READY     STATUS    RESTARTS   AGE
etcd-docker-for-desktop                      1/1       Running   0          2m
kube-apiserver-docker-for-desktop            1/1       Running   0          3m
kube-controller-manager-docker-for-desktop   1/1       Running   0          2m
kube-dns-86f4d74b45-kddhh                    3/3       Running   0          3m
kube-proxy-nnsx8                             1/1       Running   0          3m
kube-scheduler-docker-for-desktop            1/1       Running   0          2m

nodeが1つなのは当然として、kubernetesというserviceがすでに存在している。このへんはkubernetesのデフォのものなのか、docker for macならではの設定なのかは調べてない。

~ ᐅ kubectl get nodes             
NAME                 STATUS    ROLES     AGE       VERSION
docker-for-desktop   Ready     master    16m       v1.10.3
~ ᐅ kubectl get services         
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   16m
~ ᐅ kubectl describe service kubernetes 
Name:              kubernetes
Namespace:         default
Labels:            component=apiserver
                   provider=kubernetes
Annotations:       <none>
Selector:          <none>
Type:              ClusterIP
IP:                10.96.0.1
Port:              https  443/TCP
TargetPort:        6443/TCP
Endpoints:         192.168.65.3:6443
Session Affinity:  ClientIP
Events:            <none>

というか、get all --all-namespacesという便利なコマンドがあった。

~ ᐅ kubectl get all --all-namespaces   
NAMESPACE     NAME            DESIRED   CURRENT   READY     UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
kube-system   ds/kube-proxy   1         1         1         1            1           <none>          4m

NAMESPACE     NAME                 DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
docker        deploy/compose       1         1         1            1           4m
docker        deploy/compose-api   1         1         1            1           4m
kube-system   deploy/kube-dns      1         1         1            1           4m

NAMESPACE     NAME                        DESIRED   CURRENT   READY     AGE
docker        rs/compose-7447646cf5       1         1         1         4m
docker        rs/compose-api-6fbc44c575   1         1         1         4m
kube-system   rs/kube-dns-86f4d74b45      1         1         1         4m

NAMESPACE     NAME                                            READY     STATUS    RESTARTS   AGE
docker        po/compose-7447646cf5-fn2ft                     1/1       Running   0          4m
docker        po/compose-api-6fbc44c575-bcg82                 1/1       Running   0          4m
kube-system   po/etcd-docker-for-desktop                      1/1       Running   0          3m
kube-system   po/kube-apiserver-docker-for-desktop            1/1       Running   0          3m
kube-system   po/kube-controller-manager-docker-for-desktop   1/1       Running   0          3m
kube-system   po/kube-dns-86f4d74b45-ggqq4                    3/3       Running   0          4m
kube-system   po/kube-proxy-z9886                             1/1       Running   0          4m
kube-system   po/kube-scheduler-docker-for-desktop            1/1       Running   0          3m

NAMESPACE     NAME              TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)         AGE
default       svc/kubernetes    ClusterIP   10.96.0.1      <none>        443/TCP         4m
docker        svc/compose-api   ClusterIP   10.102.8.163   <none>        443/TCP         4m
kube-system   svc/kube-dns      ClusterIP   10.96.0.10     <none>        53/UDP,53/TCP   4m

このdocker for desktopをリセットしたいとき

docker for macのPreferenceにResetという項目があり、そこでKubernetesのリセットもできるようになっている。

docker composeの設定ファイルを使う

docker stackコマンドでdocker-compose.ymlもKubernetesへデプロイできると書いてあって試してみたが、docker composeのversion1や2には対応していない。version 3のサンプルを使ったら動作した。

ᐅ docker stack deploy --compose-file docker-compose.yml words                                                                        
unsupported Compose file version: 1.0

参考

[和訳] デスクトップ向けDockerでのDocker ComposeとKubernetes #docker #kubernetes #k8s - クリエーションライン株式会社

Compose file version 3 reference | Docker Documentation