萌えキャラとは何だったのか

ギークにも絵描きにもなれない者の末路

衣玖さんが好きすぎて、最近は衣玖さんの人としてチームメンバーからは認識されているようです。(衣玖さん結婚しよ)mix3です。

サンプルアプリ

社内的にgolangを使って行こうか、という流れが出来ていてその流れの中で @acidlemon さん作のWAF、rocketが出てきたので使い方の勉強もかねて早速それのサンプルアプリを作ってみました

リマインダアプリ

うちの社内IRCではお願いすると指定日時にメンションを飛ばしてくれるremember君というbotが生息してるのですが、それのメール版のようなイメージで作りました

指定アドレスにメールして登録、指定日時にメールが飛んでくるだけの簡単なwebアプリです

世の中便利なもので、指定アドレスにメールが来ると指定URLにPOSTしてくれるサービス(つまりSMTPいらない)があったり、1日10000通までメール送信出来るサービス(つまりSMTPいらない)があって、herokuとかと組み合わせることで簡単な物なら無料でメールを使ったサービスが作れてしまうようです

物はこちら go-rocket-sample-app http://secure-sierra-2582.herokuapp.com/

リマインダ登録までの流れ

一応登録されたメールアドレス以外のリマインダ登録は受け付けないようにしたかったので、

  • アドレス登録のアドレスに対して空メールすると、仮登録され本登録のURLが返信される
  • URLを踏むと本登録が完了する
  • リマインド登録のアドレスに対して、件名に日時指定、本文にリマインドの内容を書いて送ると登録される(認識する日時指定はだいたい以下の通り)
    • 12:34
    • 07-01 12:00
    • 2014-07-01 23:59

な感じで動く様になっています アドレス登録後はリマインド登録用のアドレスを保存しておいて使うことを想定しています

ということで

rocketのサンプルアプリでした

最近p5-Ikusanを作ったり、それで衣玖さんのIRCボット作ったりして衣玖さんへのロマンティックが止まらないmix3です

github.com/mix3/go-ikusangithub.com/mix3/go-irc

最近golangを触ってる事が多いのですが(絶賛開発中の社内アプリがgolangだけどそっちにはあんまり関わってなかったりする)

適当になんか作りたいなぁと思っていたところに最近衣玖さんへの愛が溢れ出してきてたので、そりゃ「go版ikachan作ろう」となるのは自然な事ですよね

でgoでircってどう触るんだろうとgithubを漁ったところ

辺りがirc触るためのライブラリとして有名どころなのかなぁということが分かって、その辺り使って作ろうとしたのですが、

とか

とかでなんか微妙に使いづらいなぁとなってしまい、じゃあいっそそっから作るかということで両方の間の子みたなの作ったりしました。github.com/mix3/go-irc

出来るだけ薄くしておきたかったのと、IRCについて知識はまるでないので難しいことはしないようにしたかったので

  • ircサーバへのリクエストが出来る
  • ircサーバからのレスポンスを受け取れる
  • ircサーバからのレスポンスを元にコールバックを呼ぶがディスパッチャみたいなことはしない
  • ircサーバからのレスポンスのtimeoutを待たずに落ちる事が出来る
  • 落ちたタイミングで何かしたいこともあるだろうから、別途落ちたタイミングでコールバックを呼ぶようにする
  • flagは使わない
  • loggerはデフォルトでgithub.com/umisama/gologを使うけどinterfaceが定義されてるので差し替え出来るハズ

ぐらいを満たすような感じでgithub.com/thoj/go-irceventgithub.com/fluffle/goircからコピペしたりしなかったりしました

たまに落ちるときにWaitしたまま帰ってこないみたいなことがある感じなので、明らかにここマズいとかあったらプルリクあると嬉しいです

で、これを元にgo版ikachanことgo-ikusannを作りましたとさ

とってもキュートな衣玖さんがお出迎えしてくれるwebインタフェースも作ってやはり衣玖さんは最高だなって思いました

なおAAの画像は「衣玖 AA」で検索して見繕ったAAなので著作権的に問題あったら非常に心苦しいですが消します

テンプレートは気に入っていて変えたくないのでその辺りは出来るだけそのままを保ちつつ、レスポンシブデザインってどうやるんだろうなと思いながらいじいじしてて数ヶ月経ってしまいこのままだともう日の目を見る事が無さそうな感じしたのでえいやで更新してしまいました

それにともない記事のhtmlを一カ所にまとめる様に変更(記事生成後再生成でゴミが残るので面倒になった)それにともないパーマリンクが変更になるという鬼畜ぶりに我ながら身震いしたけどどうせブクマしてる人も全然いないし自分のブログだし好きにすることにした 404のカスタムhtmlでjs使って多少の誘導ぐらいは出来る様にしたいとは思ってるけどやらないかも

ということで気分も新たにブログたまには書いて行きたい

コートレビューされると毎回マサカリが飛んできて自分はやはり糞コード製造機だなぁと改めて実感しててまた死にたい感じになってます。mix3です。

golangのWAF調査の一環として

goによる社内アプリ(?)を後輩らと共同でマサカリを一身に受けて血反吐吐きながら書いていたのですが

Revel使っていたけど使いこなせてない感じが半端無くて(Revelのセンスが悪いのか自分たちのセンスが悪いのか考えると多分自分たちのセンスが悪いんだろうなと思う)

あらかた動く様になった段階で、最終的にリライトするのも辞さない覚悟でWAF調査から再出発することに。

とググって見つかったWAFを担当振ってサンプルアプリ作ってどんなもんか調べましょうとなりました。

自分はtrafficを担当。

ただ調べるだけだとつまらないので、Travisやheroku使った事無かったというのもあり、タイトルにあるCI連携とherokuへのデプロイまでやることにしました。

作ったもの

最初はTodoMVCAngularJSを使うかと考えたがBowerが絡んできて余計な事で悩みそうだったのでやめて、AngularJSで作るToDoアプリを見てシコシコとhtml/js/cssを書いてからtrafficを書いてみた

最終的に出来たのが以下

CI連携

最初にTravisを試して、werckerなるものを後で見つけて追加して、drone.ioなるものもあってそれも追加して、と手当たり次第試してみた

基本的にCIは専用のyml(drone.ioはいらないみたい)をコミットして go test ./... を走らせるだけだけど、genmaiのTravisのテストが賢くてナルホドなってなった

https://github.com/naoina/genmai/blob/master/genmai_test.go#L110

func testDB(dsn ...string) (*DB, error) {
    switch os.Getenv("DB") {
    case "mysql":
        return New(&MySQLDialect{}, "travis@/genmai_test")
    case "postgres":
        return New(&PostgresDialect{}, "user=postgres dbname=genmai_test sslmode=disable")
    default:
        var DSN string
        switch len(dsn) {
        case 0:
            DSN = ":memory:"
        case 1:
            DSN = dsn[0]
        default:
            panic(fmt.Errorf("too many arguments"))
        }
        return New(&SQLite3Dialect{}, DSN)
    }
}

https://github.com/naoina/genmai/blob/master/.travis.yml

language: go
go:
 - 1.2
 - 1.2.1
 - tip
install:
 - go get -v github.com/mattn/go-sqlite3
 - go get -v github.com/go-sql-driver/mysql
 - go get -v github.com/lib/pq
 - go get -v github.com/naoina/genmai
env:
 - DB=sqlite3
 - DB=mysql
 - DB=postgres
before_script:
 - sh -c "if [ '$DB' = 'postgres' ]; then psql -c 'DROP DATABASE IF EXISTS genmai_test;' -U postgres; fi"
 - sh -c "if [ '$DB' = 'postgres' ]; then psql -c 'CREATE DATABASE genmai_test;' -U postgres; fi"
 - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'CREATE DATABASE IF NOT EXISTS genmai_test;'; fi"
script:
 - go test ./...

.travis.ymlでenvを複数指定するとそれぞれの環境変数でテストが走るので、テストの方で環境変数で使うDBを変える様にしておくことでいい感じにDB別のテストが走っていてとても賢い

order byしてないせいでsqlite,mysqlでは通るがpostgresでは通らないみたいなことがあったので、DB限定しない作りのアプリのテストはこのやり方を真似しておくと良いなと思った

設定に環境変数を使うというのはThe Twelve-Factor Appで推奨されてて環境に合わせて柔軟に設定出来るのは確かに良いなぁと思った

heroku

元々herokuまでやるつもりはなかったけど、作ったものを見える状態にするのも大事だなと思ってCIまでは割とサクサク行ったのでheroku使った事無かったし試してみた

最初 git push heroku master しても全然うまくいかず泣きそうになっていたのだが、最終的には

  • godepを使わない
  • .godirはgithub.com/mix3/go-traffic-sampleじゃなくてgo-traffic-sampleで
  • src以下にきちんと配置(最初はシンボリックリンク使って別の場所で開発してた)
    • pushが通らなかった一番の理由が多分これ

という感じでやるとなんとかpush出来た

ググったりgithubで「golang heroku」とかで検索掛けたりするとgodep使ってたり、srcをリポジトリに含めたり含めなかったりしてどうするのが良いのかいまいち分からなくて非常に困った(し、今も良くわかっていない)

結局traffic作者のブログ記事How to deploy Go with Traffic on Herokuをそのままやってうまく行ったので今はそれに合わせている。godepとbuildpack-goは大分トラウマになった気がする。

デプロイしてから静的ファイルが配信出来ていないことに気づいてHow to deploy Go with Traffic on Herokuをよく見るとproductionでも静的ファイルをアプリ側で返す様に弄るよう指示されていたので修正した。

が、herokuにも静的ファイルの配信は出来るハズなので、workerをアプリにしてwebをgoremにしてやればいけるんじゃないかと思ったが、portが不定なのでjsonにport記述できないし、goremはコマンドだからherokuの場合にどうしたらいいのかサッパリ分からなかったのでそこまでは出来なかった。

テスト

revelのときはテスト書いてなかったのでテスト書く場合はどうなるのかなということでCRUDを確認する簡単なモデルテストを書いてみたが、時間が絡むテストが非常に書きにくくて困る(し、今も困っている)

DBから取ってきたデータの比較でreflect.DeepEqualを使ってデータをまるまる比較したのだがdatetime型があるとそれが出来なくて困る。time.Now()をモックできないかとググるも良い情報が無くて詰んでいる。

多分標準パッケージのtimeをどうこうすることは出来ないので、別の時間管理用モジュールを作るか見繕ってきてそれをモックするようにするのが良いのかなと思っている。例えばこれとか?https://github.com/101loops/clock

gvm

goの開発環境を綺麗に保つときにgvmを使うと良さそうなことに気づいた

gvm install go1.*.*
gvm use go1.*.*

とかして、簡単に好きなバージョンのgoが使えるし、

gvm pkgset use global

とかするとインストールしたgo専用のGOPATHが設定されるし、

gvm pkgset create hoge
gvm pkgset use hoge

とかすると、さらにGOPATHが設定される(GOPATH=/path/to/hoge:/pagh/to/global になるのでhoge優先)

ので、適当にgvm installして適当にgvm pkgset create hogeしてglobal以下で開発、依存パッケージをhogeに入れるようにすると環境を何も汚さない感じで開発出来てよいと思う

ひとつ残念なのはgvmは[GVM](the Groovy enVironment Manager)とコマンド名がバッティングしていてそれだけは勘弁してほしいなってなってる

なお

この記事は5/13に書いたのだが、いつのまにか6/15である 時間が経つのは早い

人生の迷子の行き着く先は富士の樹海ではないかと最近良く考えています。mix3です。

p5-IkuSan

IRCボットいい加減今のプロジェクトに欲しくなったので、自分がIRCボット作ったらこうするなというのを以前書いたのだが、今回は実際にそれを作ったという話です。

ただ単に作るだけだと別にUnazuSanで良いじゃないってなっちゃうので、以下の機能を盛り込みました

Getopt::Longの引数が取れる

以前の記事参照

並列にタスク処理が出来る

最初Gearman使って頑張ってたのだけれど @karupanerura さん作、AnyEvent::ForkManagerというのがあるのを見つたのでそれを使うように。worker数を指定出来る様にして並列に処理出来る様にしました

あんまり気にしなくても良いとは思うけれども処理中だからってボットが無反応になるのはなんとなく嫌だったので

タスク処理中、dieしたら共通処理出来る様に

Try::Tinyを使って囲ってるだけなので別にいらないと言えばいらない(自前でtry catchするのでも良い)が、どうせボットが返すエラー文言なんて一律で同じように返したって全然良いと思うので、共通処理を設定出来る様にしておきました

ということで

p5-IkuSanが出来ました

一応CPANに上げるつもりだったので、今まで使ったことなかったMinillaを使ってみたり、plenvCartonを経由してdaemontoolsで起動出来るようにするというplackアプリの起動で良くある感じのアレをちゃんとやってみたり、その際にCarton経由しつつsystem perl使おうとするとCartonの方で環境変数PERL5OPTが設定されてしまうのでunsetするなりしないと読むモジュールが違って悲しい思いをするということを知ったり、perl5.19.10とか使うとNet::SSLeayあたりでpanicとかなんとか言われて動かなかったり(原因不明)forkしてる関係で子プロセスからsend_messageやらなんやらしようとして死にまくったりして、ikachanリスペクトで頑張ってみたり、衣玖さんはやっぱり可愛いんだなと再認識したりしました。CPANの方にもちゃんと画像出る様にしたい。

あと以下の発言が実現出来てワタクシ非常に満足しております。煩悩はチカラなり。