AllIsHackedOff

Just a memo, just a progress

net/http触り直し(1)

GolangでWAFを使わなくても問題ない的な話が年末上がっていたのと(advent calendar界隈で)自分的にもそう思ったので RequestのBodyやらHeaderやらを適当にParseする方法を復習がてらメモ。

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/davecgh/go-spew/spew"
    "github.com/julienschmidt/httprouter"
)

func main() {
    router := httprouter.New()
    router.GET("/test", testFuncGET)
    router.POST("/test", testFuncPost)
    log.Fatal(http.ListenAndServe(":9999", router))
}

func testFuncGET(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    h := r.Header
    spew.Dump(h)
    val := h.Get("Hoge")
    fmt.Println("=======")
    fmt.Println(val)
    fmt.Println("=======")

    q := r.URL.Query()
    spew.Dump(q)
}

func testFuncPost(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    r.ParseForm()
    f := r.Form
    spew.Dump(f)
}

httprouterくらいは使わないとさすがにアレなコードになる気はしている。

curl "http://localhost:9999/test" -H "Hoge:Fugaaa" -XPOST -d "a=1" -d "a=2" -d "a=3" -d "vals=[{'key':'value1'},{'key':'value2']"
 (string) (len=1) "v": ([]string) (len=1 cap=1) {
  (string) (len=5) "1,2,3"
 }
}
(url.Values) (len=2) {
 (string) (len=4) "vals": ([]string) (len=1 cap=1) {
  (string) (len=34) "[{'key':'value1'},{'key':'value2']"
 },
 (string) (len=1) "a": ([]string) (len=3 cap=4) {
  (string) (len=1) "1",
  (string) (len=1) "2",
  (string) (len=1) "3"
 }
}
-d "a=1" -d "a=2" -d "a=3"

この送り方で配列になるのは意外だった。RFCにでもそう書いてあるのだろうか(調べるか)

Goでgitリポジトリを操作しようと軽くトライした話

はじめに

PerlRubyで色々ツールを作っていた頃
Git::Repository - search.cpan.org
GitHub - schacon/ruby-git: Ruby/Git is a Ruby library that can be used to create, read and manipulate Git repositories by wrapping system calls to the git binary.

この辺りを使って、差分を見てよしなに本番作業の手順書を自動生成したりしたのを思い出して、今でも個人プロジェクトではRubyとかPerlで描いてしまうことが多いのですが、Goでそのあたりを書くためにはどうすればいいか試行錯誤した話を書きます。

使用できるライブラリ

go git などでぐぐると下記ライブラリがヒットします。サンプルコードを動かすなどしてとりあえず触ってみることに (私のローカルの環境はgo1.6.3かgo1.7を使っています)

src-d/go-gitを試す

READMEには

go get -u gopkg.in/src-d/go-git.v4/...

と v4を go get して利用するように記載されているのですが、READMEに書かれたコードが動かず、出鼻をくじかれました。

% go run main.go                                                                                                                                 (git)-[master]
# gopkg.in/src-d/go-git.v4/plumbing/format/packfile
../../../../../../gopkg.in/src-d/go-git.v4/plumbing/format/packfile/scanner.go:158: undefined: io.SeekCurrent
../../../../../../gopkg.in/src-d/go-git.v4/plumbing/format/packfile/scanner.go:314: undefined: io.SeekCurrent

problems install v4 · Issue #107 · src-d/go-git · GitHub こちらに書かれている通り

Hahaha, yes, we only support 1.7, とのことです。goのversionを変えたら正常に動作しました。

go1.6でも、

go get -u gopkg.in/src-d/go-git.v3/...

v3を go get してくれば無事に動く模様です。 (しかしインターフェースが若干異なるようです)

用例

用例をつらつら書こうと思ったのですが、下記公式の example がよく整理されています。 go-git/examples at 78516127590ef4a8157f8850be007966b142c1ca · src-d/go-git · GitHub

git pull でデプロイしている個人プロジェクトがあるので、それらのdeploy用の簡単なツールなど書いてみました。 (shellとかansibleで事足りるんじゃないかという話はあります)

複数の開発用サーバ(ホストに番号が振られている)などに一斉に変更を反映したい場合のツール作りなどに使えそうです (適当に全サーバにはいってgit pullなど)

libgit2/git2goを触る

lib2git自体が必要なので、Macで利用する場合はにhomebrewでdownloadします。

brew install lib2git

Github側にはドキュメントが少ないので godoc をせっせと読みながら使う感じになります。 git - GoDoc

使い方としてはgit側の使いたい機能を godoclib2git のドキュメとから引いて対応させていく感じです。 st

package main

import (
    "fmt"

    "github.com/libgit2/git2go"
)

func main() {
    repoPath := "path_to_git_repo"
    r, err := git.OpenRepository(repoPath)

    if err != nil {
        panic(r)
    }

    // conf := r.Config
    st, err := r.StatusFile(repoPath)
    fmt.Printf("%v", st)

    stlist, err := r.StatusList(&git.StatusOptions{
        Flags: git.StatusOptIncludeUntracked,
        Show:  git.StatusShowIndexAndWorkdir,
    })
    if err != nil {
        panic(err)
    }
    fmt.Println("%v", stlist)
}

まとめ

lib2gitに依存しないという意味では src-d/go-git はそれなりに使いやすそうだという感想です。 lib2gitを利用する方がAPIは色々提供されているし(各種バインディングがすでにあることで枯れている)ため、痒いところに手が届かないということはなさそうに見えました。

【翻訳】【Golang】標準的なパッケージのレイアウト

Golangレベルアップしたいので色々な記事を翻訳して整理してみようと思った(会社でもそういう試みをやっているので真似っこです)

Standard Package Layout — Medium

vendoring、Generics。Goコミュニティではこれらは大きな問題とみなされてきた。そしてほとんど言及されることのないもう一つの問題がある。アプリケーションのパッケージのレイアウトだ。

私がこれまで開発してきたGoアプリケーションは、「自らのコードをどう構造化すればよいのか?」という問題に対してそれぞれ異なる答えを出してきた。すべてを1つのパッケージに押し込めたアプリケーションもあれば、型やモジュールごとにグループ化したアプリケーションもある。チーム全体で一貫した良い戦略がなければ、コードはアプリケーションの種々のパッケージにとっちらかってしまうだろう。われわれは、Goアプリケーションの設計のためにより良い基準を必要としている。

よく普及している欠点のあるアプローチ

Goのアプリケーションの構造化へのよく普及しているアプローチはそんなに多くないように見える。そして、それぞれ特有の欠陥がある。

アプローチ1: モノリシックなパッケージ

すべてのコードを1つのパッケージに投げ込むアプローチは実際問題、小さなアプリケーションに対してはうまくいく。アプリケーションの内部に限れば、何の依存性もないのだから、循環参照の可能性が全く取り除かれるのだ。

アプローチ2: Rails方式のレイアウト

もう一つのアプローチは機能的な型ごとにコードをグルーピングすることである。 例えば、すべてのハンドラを1つのパッケージに、すべてのコントローラを別のパッケージに、モデルをさらに別のパッケージにと言った具合だ。このアプローチは元Rails開発者(私自身を含む)が書くコードに多々見られる。

しかし、このアプローチには2つの問題がある。第一に、名前が嫌な感じだ。結局最後にはcontroller.UserControllerみたいな型名に落ち着くことになり、パッケージ名と型名が重複するのだ。 私は命名にはこだわる癖がある。コーディングに困った時、命名が一番よいドキュメントであると私は考えている。命名は品質の目安にすることができる。誰かがコードを読むときに、名前を最初に知ることができる。 しかし、より大きな問題は、循環参照である。機能ごとの異なる型がお互いに参照しあう必要があることがあるだろう。このレイアウトアプローチは、一方向の依存関係を持っている場合にだけうまく働くが、多くの場合は、アプリケーションはそう単純ではない。

アプローチ3: モジュールごとのグループ化

このアプローチはRails方式のレイアウトと機能ごとにまとめる代わりにモジュールごとにグルーピングすることを以外は似通っている。例えば、usersパッケージとaccountsパッケージを持つことになるだろう。

より良いアプローチ

私が自分のプロジェクトに用いているパッケージ戦略は4つの教義から成っている。

  1. ルートパッケージはドメインタイプのために存在する
  2. 依存関係毎にサブパッケージをグルーピングする
  3. 共有された「モック」サブパッケージを用いる
  4. メインパッケージは依存関係を結びつける
ルートパッケージはドメインタイプのために存在する

アプリケーションはどのようにしてデータと処理が相互作用するかを記述する論理的な工事の言語を持っている。その言語はドメインである。Eコマースのアプリケーションであれば、ドメインは顧客と口座と、クレジットカード、そして在庫管理を含む。もしFacebookならば、ドメインはユーザ、いいね、そして関係性である。ドメインは、背後にある技術要素に依存しない物事のことである。

私はドメインタイプをルートパッケージに配置する。このパッケージは、ユーザのデータを保持するUser構造体や、ユーザのデータをフェッチしたり保存したりするためのUserServiceインターフェイスなどの単純なデータ型のみで構成される。

下記のような感じである。

これにより、ルートパッケージは非常にシンプルになる。アクションを形成する型を含めても良いが、それはそれらの方が他のドメインタイプに依存している時のみ許可される。例えば、定期的にUserServiceを呼び出す方を持つこともあるかもしれない、しかしながら、その型は外部サービスを呼び出したり、でデータベースへ保存するべきではない。それらは実装の詳細である。 ルートパッケージはアプリケーションの他のどのパッケージにも依存するべきではない。

依存関係毎にサブパッケージをグルーピングする

ルートパッケージが外部への依存性を持つことを許可されないとしよう、そのとき、われわれはそれらの依存関係をサブパッケージに押しめなければならない。パッケージレイアウトに対するこのアプローチでは、サブパッケージはドメインと実装をつなぐアダプターとして存在する。

例えば、UserServiceはPostgreSQLをは背後に持つかもしれない。postgres.UserServiceの実装を提供するpostgresのサブパッケージをアプリケーションに導入することができる。

この方法でPostgreSQLの依存関係を分離することができ、テストをシンプルにし、将来的な別のデータベースへの移行の簡単な方法が提供される。BoltDBのようなほかのデータベースの実装をサポートすることを決める場合、プラガブルなアーキテクチャとして利用することもできる。 このアプローチはレイヤー化実装の方法を提供する。もしかすると、postgreSQLの前段にインメモリのLRUキャッシュを持ちたいかもしれない。PostgreSQL実装をラップすることのできるUserServiceを実装したUserCacheを追加することができる:

われわれはこのアプローチを標準ライブラリにも見ることができる。io.Readerはバイトを読み込むためのドメインタイプであり、その実装は依存関係毎にグルーピングされている。つまり、tar.Reader, gzip.Reader, multipart.Readerである。これらは同様にレイヤー化可能である。os.Fileはbufio.Reade にラップされ、bufio.Readerはgzip.Readerにラップされ、gzip.Readerはtar.Readerにラップされる。

依存関係の間の依存関係

依存関係は孤立して存在しているわけではない。ユーザデータをPostgreSQLに保存するかもしれないが、金銭にまつわるトランザクションのデータはStripeのようなサードパーティーに存在しているかもしれない。この場合、われわれはストライプの依存関係を論理的なドメインタイプを持ってラップし、それをTransactionServiceと呼ぼう。

type UserService struct {
        DB *sql.DB
        TransactionService myapp.TransactionService
}

今、われわれの依存関係は共通のドメイン言語を通じてのみつながっている。

サードパーティに依存関係にだけ制限しないこと

奇妙に聞こえるかもしれないが、私は同じ方法論で私の標準ライブラリの依存関係を分離している。例えば、net/httpパッケージもただの1つの依存にすぎない。我々はhttpサブパッケージを我々のアプリケーションに含めることで、同様に依存関係を分離することができる。 ラップしている依存関係と同じ名前のパッケージを持つことは奇妙に見えるかもしれないが、意図的である。net/httpをアプリケーションの他の場所で使うことを許さないかぎり、パッケージ名の衝突は起こりえない。すべてのHTTPのコードをhttpパッケージへ分離することが要求されることが、名前を重複させることの恩恵である。

いま、http.HandlerはドメインとHTTPプロトコルのアダプターとして振る舞う。

共有された「モック」サブパッケージを用いる

われわれの依存関係は他の依存関係からドメインインターフェイスによって分離されているから、われわれは接続点を持っく実装を差し込むために使うことができる。 GoMockのようなモックをするためのライブラリはいくつか存在するが、私は個人的にはそれらを自分自身で書くことを好む。多くのモックのためのツールが過度に複雑であると感じている。 私が用いるモックはとてもシンプルである。例えば、UserServiceのモックは下記のような感じである。

このモックにより、引数をバリデーションする目的や、期待されたデータを返すため、機能不全を差し込むためにmyapp.UserServiceインターフェイスを使用しているあらゆる箇所に関数を差し込むことができる。 例えば、われわれは上で定めたhttp.Handlerをテストしたいとする。

メインパッケージは依存関係を結びつける

あちらこちらのパッケージのあらゆる依存関係を分離したので、どのようにしてすべてを一緒にするのか悩ましくなるでしょう。そしてそれは、mainパッケージの役割です。

メインパッケージのレイアウト

アプリケーションは複数のバイナリを生成することがありえるため、われわれはcmdパッケージのサブディレクトリとしてメインパッケージを配置するというGoの規約を用います。例えば、われわれのプロジェクトはmyappサーバのバイナリをもつが、それと同時にサーバをターミナルから制御するためmyappctlクライアントのバイナリを持つかもしれません。

myapp/
    cmd/
        myapp/
            main.go
        myappctl/
            main.go
コンパイル時に依存関係を注入する

「依存性の注入」という用語はいわれのない避難を受けている。 しかし、オブジェクトをビルドすることや依存関係それ自体を発見することを要求する代わりに、オブジェクトに依存関係を渡すことこそが、用語の真に意味するところです。 メインパッケージはどの依存関係をどのオブジェクトに注入するかを選択するものです。メインパッケージは部品を単純に組み合わせているから、とても小さく自明なコードになる傾向があります。

メインパッケージもまた1つのアダプタであることは需要です。メインパッケージはターミナルとドメインを接続します。

結論

アプリケーションの設計は難しい問題です。設計上決めなければいけないことは大量jに有り、ソリッドな原理がないことには問題はより悪い方向に行くでしょう。われわれはいくつかのGoアプリケーションの設計に対する現行のアプローチを見て、多くの欠陥を見てきました。

依存関係の観点で設計にアプローチすることでコードの構造化を論理的に考えることがよりシンプルで簡単になると考えています。まずはじめに、われわれはドメイン言語を設計します。それから、依存関係を分離し、その次にテストを分離するためにモックを導入しました。そして最後に、われわれはメインパッケージの中にすべてを結びつけるのです。

これらの原理原則を次にアプリケーションを設計するときに考慮してみてください。設計に関して議論や疑問がある場合は、Twitterの @benbjohnsonにコンタクトをとるか、Gopherのslackで私を見つけてみてください。

suで少し戸惑ったのでメモ

su - [% user_name %] # 環境変数を[% user name %]の$HOME/.bashrcから読む
su                   # 環境変数には特に触らない
serviceユーザでrailsをインストールしている
ec2-userとかからserviceにsu => bundleが入ってないって怒られる(汗
で発覚

Bandit

とりあえずε-greedy

import random
import numpy as np

class Arm:
    def __init__(self, prob, no):
        self.probability = prob
        self.no = no
        self.hit_count = 0
        self.total_count = 0

    # retrun boolean value
    def lot(self):
        random_float = random.random()
        self.increment_total_count()

        if random_float < self.probability:
            self.increment_hit_count()
            return True

        return False

    def increment_total_count(self):
        self.total_count += 1
        return

    def increment_hit_count(self):
        self.hit_count += 1
        return

    def observable_expected_hit(self):
        if self.total_count == 0:
            return 0

        return self.hit_count / self.total_count
        return

class Recorder:
    def __init__(self):
        self.trial_count = 0
        self.probability_list = []
        self.arm_no_list      = []
        self.hit_count   = 0
        return

    def increment_hit_count(self):
        self.hit_count += 1
        return

    def increment_trial_count(self):
        self.trial_count += 1
        return

    def push_probability(self, prob):
        self.probability_list.append(prob)
        return

    def push_arm_no(self, arm_no):
        self.arm_no_list.append(arm_no)
        return

    def output(self):
        print "trial_count : %d" % self.trial_count
        print "hit_count   : %d" % self.hit_count

        return

class Bandit:
    def __init__(self, recorder):
        self.counter = {}
        return
    # have to override
    def explore(self, arms):
        return
    def exploit(self, arms):
        return
    def execute(self, arms):
        return
    def lot_arm(self,arm):
        return

class EpsilonGreedyBandit(Bandit):
    def __init__(self, recorder, init_epsilon):
        self.recorder = recorder
        self.epsilon  = init_epsilon
        return

    def explore(self, arms):
        number_of_arms = len(arms)
        selected_index = int(number_of_arms * random.random()) - 1
        selected_arm   = arms[selected_index]

        self.lot_arm(selected_arm)

        return

    def exploit(self, arms):
        expected_hit_list = [ arm.observable_expected_hit() for arm in arms ]
        max_index = np.argmax(expected_hit_list)

        selected_arm = arms[max_index]
        self.lot_arm(selected_arm)

        return

    def lot_arm(self, arm):
        is_hit = arm.lot()
        self.recorder.increment_trial_count()
        self.recorder.push_arm_no(arm.no)
        self.recorder.push_probability(arm.probability)

        if is_hit:
            self.recorder.increment_hit_count()

    def execute(self, arms):
        epsilon = self.epsilon
        if epsilon < random.random():
            self.exploit(arms)
        else:
            self.explore(arms)

arm_attributes = [
    (0.1, 1),
    (0.2, 2),
    (0.4, 3),
]

arms = [ Arm(attribute[0], attribute[1]) for attribute in arm_attributes ]

recorder = Recorder()
EPSILON   = 0.1
TRIAL_NUM = 100
epsilon_greedy_bandit = EpsilonGreedyBandit(recorder, EPSILON)

counter = 0
for _ in range(0, TRIAL_NUM):
    counter += 1
    epsilon_greedy_bandit.execute(arms)

recorder.output()

print recorder.arm_no_list
print counter

今日やったこと/Reactの復習とか/行儀の良い書き方とか

今日やったこと

PythonとかScikit-learnにもすこし飽きて、動きがあるものを作りたいなと思ったので javascriptを触ることに

React流行っているし4月に本も出るようなので今更キャッチアップした

React Tutorial チュートリをひと通りおわらせた。 やっぱコードを写経すると理解度が上がりますね。 感想としては、JSXが混ざるのが若干気持ち悪いものの、データの流れがすんなり整理されるのでなかなか使いやすそうなフレームワーク(ライブラリ)

Virtual DOMの利点とかその辺も深くわかるようになりたいっすね。

最近の行儀の良い書き方

最近の行儀のよい JavaScript の書き方

(function(global){
  "use strict;"
  // Class
  function Hoge() {
  };
  //Header
  Hoge["prototype"]["constructor"] = Hoge;
  Hoge["prototype"]["methodHoge"]  = methodHoge;
  Hoge["prototype"]["methodPlus"]  = methodPlus;
  
  // implementation
  function methodHoge(arg) {
    console.log("fugafuga");
  };
  
  function methodPlus(a, b) {
    var c = a + b;
    console.log(a + " + " + b + " = " + c);
  };
  
  // Exports
  if ("process" in global) {
    module["exports"] = Hoge;
  };
  global["Hoge"] = Hoge;

})((this || 0).self || global); //ブラウザだったらthis == windowになる

(function(globa){
  hogeInstance = new global.Hoge();
  console.log(hogeInstance);
  
  //call function
  hogeInstance.methodHoge();
  hogeInstance.methodPlus(1, 2);
  
})((this || 0).self || global);

話題になっていたのでexaをインストール

話題になっていたのでexaをインストール

公式

exa公式

exa is a modern replacement for ls. It uses colours for information by default, helping you distinguish between many types of files, such as whether you are the owner, or in the owning group. It also has extra features not present in the original ls, such as viewing the Git status for a directory, or recursing into directories with a tree view. exa is written in Rust, so it's small, fast, and portable.

gitの情報も表示してくれるlsの代用品だとな。 Rustで書かれているらしい。

Install

Rustが当然入っていないのでRustを入れる Homebrew対応してないのかなー

curl -s https://static.rust-lang.org/rustup.sh | sudo sh

必要らしいのでlibgit2とcmakeをintall

brew install cmake libgit2

Rustのインストールに少し時間かかる

使用感

ls にあるオプションは大抵ありそう -hをつければヘッダ行もわかって意味がわかりやすいし、tree表示も良さそう -tオプションだけ何故か動かないのは僕だけなんでしょうか manがないので慣れるまではREADMEを参照しつつですかね

memo

-1, --oneline: display one entry per line
-a, --all: show dot files
-b, --binary: use binary (power of two) file sizes
-B, --bytes: list file sizes in bytes, without prefixes
-d, --list-dirs: list directories as regular files
-g, --group: show group as well as user
-h, --header: show a header row
-H, --links: show number of hard links column
-i, --inode: show inode number column
-l, --long: display extended details and attributes
-r, --reverse: reverse sort order
-R, --recurse: recurse into subdirectories
-s, --sort=(field): field to sort by
-S, --blocks: show number of file system blocks
-t, --time: which timestamp to show for a file
-T, --tree: recurse into subdirectories in a tree view
-x, --across: sort multi-column view entries across