Ansible を使ってみた感想
ここ数日 Ansible を触ってみてた。 MoinMoin Wiki のセットアップとか試しにやってみた。
tototoshi/ansible-playbook-moinmoin · GitHub
Chef の代替というよりも Chef + Capistrano/Fabric という感じ。
- インストールが楽。設定ファイルもほとんどなし。
- デフォルトでできることが多い。Apache の Basic 認証設定とか PostgreSQL のユーザー作成とかまで最初っから使えるのが良い。
- ドキュメントが充実しているしサンプルも併記してくれていて親切。
- あまりハマらない。
シンプルで良いツールだと思った。
yaml なので簡単なことは簡単にかけるけれど、手続きっぽいことを書くのは当然つらい。 そこは仕方ないかというところ。まあ数日使った程度ではそこまで困ることはなかった。
シェルスクリプトでは手続きを書くのに対し、 こういうツールでは冪等性うんぬんってやつでどんな状態に収束するかを書くので、 yaml で宣言的に書くほうが向いている(という都合の良い見方)。
あと一つ一つの記述は宣言的だけど、 それでいて処理は上からべたーっと順番に行われるのはわかりやすい。
うまく動いてくれないなーって思ったのが handlers。 難しいものではないんだけれど、試行錯誤しているうちに間接的な原因で意図通りに発火してくれないことがある。notify 書き忘れとかもあるし普通に最後に明示的に reload,restart とかしたほうがシンプルかも。
Chef はいろいろめんどくせーと思ってやらなかったけど Ansible ならイケると思ったし、 おいしいところだけ使うで十分得られるものが多そう。 簡単なのでまだ試してない人も一度触ってみると良いんじゃないかな。
IntelliJ IDEA を無料で使う方法
IntelliJ IDEA は Community Edition であれば無料で使えますが、 Ultimate Edition になると大体初期2万+維持費1万/年くらいの課金をする必要があります。
これをどう見るかは人によると思いますが、自分は Scala はほとんど Emacs で書いてしまって、たまに気分で IntelliJ IDEA を使うくらいのノリなので少し高く感じています。
しかし、実は Ultimate Edition をタダで使う方法が存在します。Open Source License というヤツです。
IntelliJ IDEA 14.x Open Source License
Open Source License はオープンソースのプロジェクトの開発に使用できるライセンスです。ライセンスの発行には審査が必要です。 条件は、
- プロジェクトのリーダー、または常にコミットしていること
- プロジェクトがオープンソースの定義を満たしていること
- 資金援助などを受けていないこと
- アクティブに開発されていること
- コミュニティがアクティブであること
- ウェブサイトを持っていること
- 定期的にリリースがされていること
と、一見厳しそうですが、コミュニティとかウェブサイトがどうとかは GitHub のリポジトリや issues がその役目を果たしますし、規模とかはあまり関係なく、真面目に開発してる感さえあれば大丈夫だと思います。
というわけで、今回は tototoshi/scala-csv で申請してライセンスを発行してもらえました。ライセンスの発行には大体数日必要らしいですが、以前 PhpStorm のライセンスを tototoshi/staticmock に対して発行してもらったときは1ヶ月くらいかかった(絶対忘れてただろ)ので気長に待ちましょう。
Open Source License の有効期間は1年で、更新のときは期限切れの直前にメールでお願いする必要があるようです。
というわけで、自信のない人もとりあえず申請してみればよいと思います。JetBrains もそれなりに儲けてそうだし皆さんがタダで使っても潰れないでしょう。
追記: はてぶコメントで補足してくれてる方がいますが、仕事には使えないので会社に Commercial License を買ってもらいましょう
build.sbt の変更を検知する sbt プラグインを作りました
git でブランチを切り替えたらうまくビルドできなくなって困ったけど、build.sbt が変わっているのに sbt の reload をするのを忘れていただけだった、ということがたまに起こります。これを防ぐために、.sbt や project/.scala が変更されていたら警告を表示する sbt プラグインを作りました。
tototoshi/sbt-build-files-watcher
作りました、というかよしださんの https://gist.github.com/xuwei-k/6278769 をだいたいパクった感じです。
インストールはプロジェクトごとに設定するよりはグローバルの設定にすると便利だと思います。
~/.sbt/0.13/plugins/build.sbt
addSbtPlugin("com.github.tototoshi" % "sbt-build-files-watcher" % "0.1.1")
~/.sbt/0.13/build.sbt
showMessageOnBuildFilesChanged
sbt-git などを使っている場合は showMessageOnBuildFilesChanged
が sbt-git のshowCurrentGitBranch
とぶつかるので messageOnBuildFilesChanged
という関数を使って shellPrompt
キーを設定します。
shellPrompt := { state => messageOnBuildFilesChanged(state) + GitCommand.prompt(state) }
これで .sbt や project/.scala を編集すると reload しろという警告が出るようになります。めでたし。
Flyway は複数人での開発に向かないという誤解について
“データベースマイグレーションについて考えないといけないことや諦めないといけないことが結構あるでよ”
http://t.co/BYna6w5luj
期待して記事見たが、複数人開発時におけるバージョン番号の衝突について説明がなかったのが残念。紙面が限られてるししゃあない。
— 早すぎる最適化オジサン (@makotokuwata) 2014, 12月 29
flyway って、V1_ みたいな prefix をつけるけど、integer を increment するのって、ブランチきって平行で開発してる場合どうなるの?という気がしている
— tokuhirom (@tokuhirom) 2014, 7月 30
flywayのマイグレーションについて見てたけど、これ、バージョン番号をファイル名につける感じなのですかね。まだよく見てないが。Railsのマイグレーションと比べて複数人開発に強くないですねぇ。
— でこくん (@dekokun) 2013, 3月 26
というように、Flyway は複数人開発に向かないという噂をたまに聞くのですが、多分誤解です。
誤解が生まれるのは公式ドキュメントで Flyway のマイグレーションスクリプトのファイル名として、V1__Add_new_table.sql
みたいなファイル名が例に出されており、これが V2__
、V3__
のような名前をつける必要があるという印象を与えるためかと思われます。
ドキュメントを良く読むと、バージョンのルールは
- One or more numeric parts
- Separated by a dot (.) or an underscore (_)
- Underscores are replaced by dots at runtime
- Leading zeroes are ignored in each part
なので、もう少し柔軟です。だから rails のようにタイムスタンプベースのファイル名付けちゃえば良いです。
sql ├── V20150127114055__create_user_table.sql ├── V20150127114322__add_country_column.sql └── V20150127114323__add_age_column.sql
このようにタイムスタンプベースのバージョン付けを行うとブランチをマージしたときなどに順番が狂うという問題が発生しますが、 outOfOrder
という設定があるのでこいつを on にしてやれば OK です。
WEB+DB PRESS VOL.84 の Flyway の記事にもなかったので書いてみました。
play-json で snake_case な json を camelCase な case class にマッピングする
play-json を使えば json を case class にマッピングすることは簡単にできますが、json のキーがそのまま case class のフィールドに対応するため、snake_case な json API を case class にマッピングするためには、case class のフィールドも snake_case にする必要があります。Scala は camelCase にするのが主流ですから少し気持ち悪いですね。
snake_case な json を camelCase な case class にマッピングするためには、いつも使っている Json.format[T]
のラッパーを作る必要があります。作りました。
tototoshi/play-json-naming · GitHub
build.sbt に
libraryDependencies += "com.github.tototoshi" %% "play-json-naming" % "0.1.0"
して使ってください。
使い方は、JsonNaming.snakecase
を呼び出すだけの単機能ライブラリです。
import com.github.tototoshi.play.json.JsonNaming case class Name(firstName: String, lastName: String) case class User(id: Int, nameData: Name) // Json.format[T] をラップする implicit val nameFormat = JsonNaming.snakecase(Json.format[Name]) implicit val userFormat = JsonNaming.snakecase(Json.format[User]) val jsonString = """{"id":1,"name_data":{"first_name":"Toshiyuki","last_name":"Takahashi"}}""" Json.parse(jsonString).validate[User] Json.toJson(User(1, Name("Toshiyuki", "Takahashi")))
イメージとしては
+---------------+ | json string | +---------------+ ⇅ +---------------+ | JsValue | +---------------+ ⇅ JsonNaming.snakecase +---------------+ | JsValue | +---------------+ ⇅ +---------------+ | case class | +---------------+
こんなかんじで、json の内部表現である JsValue に対して変換をかけています。
snake_case 以外にもよくある規則があれば取り込みますので pull-req ください。
PHP のトレイトに気をつける
普段 Scala でトレイトを使いまくってるけれども PHP にも 5.4 からトレイトが入った。
trait の良いところは多重継承のできない言語で多重継承っぽいことができることだ。 use, use とつけていけば、いくらでも追加できる。DRY に書けてよいことだ。
対して悪いところはいとも簡単に複雑で暗黙的な依存関係が生まれることだ。
例えばこんなの
<?php trait Greeting { public function say() { if ($this->location == 'ja') { echo 'こんにちは' . PHP_EOL; } else { echo 'Hello' . PHP_EOL; } } } class Location { } class US extends Location { use Greeting; private $location = 'us'; } class Japan extends Location { use Greeting; private $location = 'ja'; } $us = new US(); $us->say(); $ja = new Japan(); $ja->say();
US、Japan ともに Location クラスを継承している。 それぞれに挨拶をするメソッドを追加したいけれどもこれは継承で実装するのが適切だろうか? よくわからない。よし、トレイトを作ろう。という経緯で上のコードは書かれた、という設定。
このコードのどこが微妙か。それは Greeting トレイト が US, Japan クラスのフィールドに依存していることだ。しかも暗黙的に。
こういうコードは読みにくい。Greeting トレイト だけを読んでも $this->location
ってなに?という気持ちになるし、US、Japan クラスだけを読んでも、まさかその private フィールドに Greeting トレイトが依存しているとは思うまい。
これだけでもひどいが、もう少しやりすぎ感を出してみよう。
<?php trait Greeting { public function say() { if ($this->location == 'ja') { echo 'こんにちは' . PHP_EOL; } else { echo 'Hello' . PHP_EOL; } } } trait JapanLocation { private $location = 'ja'; } class Japan { use JapanLocation; use Greeting; } $ja = new Japan(); $ja->say();
Japan クラスは実装を持っていない。Greeting と JapanLocation を mix-in してやることでオブジェクトを合成している。Greeting は Japan に mix-in されているが、それだけでは動作しない、JapanLocation も一緒に mix-in してやることで初めて動作する。わかりづらい。Greeting トレイトを使うきは Location トレイトも mix-in してくださいね!ということはドキュメントにしっかり書こう。あと JapanLocation の $location
は PhpStorm が未使用の変数として警告してくるけど消しちゃだめだよ、これは一見意味のない変数に見えるけれど、実は Greeting メソッドと一緒に mix-in するときに使われるんだ、ってこともドキュメントにちゃんと書いておかなきゃね。
とまあ、そんなのはやりすぎに見えて説得力がないけれど、 trait を使いまくるとこういうところに行き着くだろう。 それに実を言うとこれは Scala ではよく見るパターンだ。
trait Location { val location: String } trait JapanLocation extends Location { val location: String = "ja" } trait Greeting { self: Location => def say(): Unit = { if (location == "ja") { println("こんにちは") } else { println("Hello") } } } object Japan extends JapanLocation with Greeting
このコードの何が PHP と違うのかと言うと、次の1行にある。
trait Greeting { self: Location =>
self: Location =>
という記述は self-type annotation
と呼ばれ、
この Greeting トレイトは Location 型でもありますよ。つまり Location 型のクラスやトレイトにのみ mix-in できますよ、という意味になる。使いかたを間違えるとコンパイルエラーになる。
このように Scala ではクラス間の関係を明示することができるし、しなければコンパイルが通らない。ドキュメントなどではなく、コードとして表現できる。Scala 最高だった。
Scala ではこのように小さな trait を組み合わせて大きなオブジェクトを合成するパターンは、ケーキ作りになぞらえて、Cake Pattern と呼ばれる。Cake Pattern を使うと実装の一部となっている trait を差し替えることができるのでコンパイル時 DI のような使われ方もしている。
とは言え、いくら型の制約があると言っても、やりすぎると当然コードは読みづらくなるし、コンパイルが遅くなるとか、パス依存型が絡んでややこしくなるなどといった問題はあるので、最近では「Cake Patternはアンチパターンだ」とする流れもある。
話がずれた。Scala の話じゃない。PHP ではどうすれば良いか。そんなのは簡単、というか今まで(<PHP5.3)どおりやれば良い。
<?php class Greeting { public static function say($location) { if ($location == 'ja') { echo 'こんにちは' . PHP_EOL; } else { echo 'Hello' . PHP_EOL; } } }
結局これだけでよかった。この実装はシンプルだ。 このファイルだけ見れば良いし、呼び出し元から見ても say は場所に依存するんだな、ということがわかる。 このクラス単体で動作し、テストも書きやすい。リファクタリングも PhpStorm で自動的にできる。
トレイトの使いどころ
フレームワーク側で便利な trait を提供したりするのはそこまで悪くはないと思う。ドキュメントなりサンプルコードなりがしっかりあって、ユーザーの前提知識となっていれば良い。(例えば Ruby の Enumerable みたいなの)
それから古いフレームワークのコードを見ていて、継承関係がやたら複雑で、トレイトがあったらもっとマシになるなあと思うことはあるので、多重継承がない言語で多重継承っぽいことをやりたい、というところでは使えば良い。そういうものなので。
それ以外の、今までスタティックメソッドやら委譲・集約とかで済んでたものをトレイトにする、というのはやらないほうがよい。
まとめ
トレイトは柔軟で便利ではあるけれども、特に PHP のように型の制約のない言語で使用すると、 複雑で暗黙的なオブジェクト間の関係を生み出しコードはひどく読みづらくなる。 密結合で壊れやすく、変更が難しいコードになる。
トレイトはどうしても多重継承したい、という場面で使う。しかしそもそもを言えば「継承より委譲・集約を選ぶ」べきである。
暗黙的な知識を要求するトレイトを使うときはきちんとドキュメントを書くなり知識の共有を行うなどする。
結局は trait が悪いというよりは書き方の問題であるけれども、trait が意図せずにクラス間の結合を生み出す危険性が高いことは確か。話がややこしくなるから Ruby の module には触れなかったけど、同じような辛い場面には遭遇する。trait をたくさん使いたかったら Scala を書けば良い。
漏水工事した
9月、入院エンジョイしてたら漏水が発覚して引っ張りだされました。
自宅が漏水してるらしく一時外出…
— Toshiyuki Takahashi (@tototoshi) September 9, 2014
うち(3階)からの漏水で2階の部屋の天井が落ち、1階の駐車場まで雨漏りしていました。
自分だけでなく家まで内視鏡検査することになってしまった…
— Toshiyuki Takahashi (@tototoshi) September 9, 2014
内視鏡検査の結果、引っ越し前のリフォームのときに床下の配管の締めが甘く、それからずっと漏水していたらしいことがわかりました。どうしてこんなになるまで...早く言おうよ2階の人... (リフォーム業者の不手際なので私は無実です)
うちも少しやられてしまったので、修理しました。
以下、修理の手順です。
穴を開けて床下のパイプを直します。 どこがおかしいのかわからないので、とりあえず穴を開けます。 当たりが出れば直せます。
良くみたら壁が床から水を吸い上げてカビてきてたのではがしました。
手頃な穴を開けて、一週間くらい空気を送りこんで床下を乾かします。 乾かしたあとで消毒もします。
工事の途中でインターネットの線を破壊されちゃって辛かった。
穴をふさぎ、壁を貼りました。
壁紙をはりました。
以上です。
だいたい3ヶ月くらいかかります。みなさんも是非漏水してみてくださいね!