crystalでyamlなど触ってみた
crystal-langが少し流行りだしそうなので触ってみた。
timeの扱い
t = "2011-10-11 11:00:00" t = Time.parse(t_str, "%F %T") puts t
yaml(読み込んだyamlの特定のキーに対応する部分を別の変数に代入したい RubyならばHashでよしなにできるのだけれど、crystal-langには空ハッシュがないので空のYAML::Anyを定義してあげる必要がある。
file_path = "hoge.yaml" y_data = YAML.parse_all(File.read(file_path)) y_data = banner_yaml[0] empty_yaml = YAML::Any.new("")
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リポジトリを操作しようと軽くトライした話
はじめに
PerlやRubyで色々ツールを作っていた頃
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を使っています)
GitHub - src-d/go-git: A low level and highly extensible git client library
- source{d}社が作っている
- ライブラリを用いてGitHubのリポジトリを解析しているとのこと
- [Topic Modeling of GitHub Repositories · source{d}](https://blog.sourced.tech/post/github_topic_modeling/
- 解析してトピックモデルLDAなどやっている
GitHub - libgit2/git2go: Git to Go. Like McDonald's but tastier.
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側の使いたい機能を godoc
と lib2git
のドキュメとから引いて対応させていく感じです。
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つの教義から成っている。
- ルートパッケージはドメインタイプのために存在する
- 依存関係毎にサブパッケージをグルーピングする
- 共有された「モック」サブパッケージを用いる
- メインパッケージは依存関係を結びつける
ルートパッケージはドメインタイプのために存在する
アプリケーションはどのようにしてデータと処理が相互作用するかを記述する論理的な工事の言語を持っている。その言語はドメインである。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で私を見つけてみてください。
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の利点とかその辺も深くわかるようになりたいっすね。
最近の行儀の良い書き方
(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);