2011年12月20日火曜日

いまさらRails その0

年初からRailsな仕事になるので、ちと予習。はるか昔、Rails1.0ぐらいのタイミングで調べたことはあるけど、プロセス立てられない環境にデプロイする可能性もあったので、その時は採用出来なかったし。

とりあえずWindows上に環境を構築。DBはsqliteでお茶を濁す。

pik
普段はASRの1.9.3を使っているけど、Redmineも試してみたいので1.8.7上に構築する。
pikで複数環境を切り替えられるように。Ruby+gemが入っていれば簡単。
gem install pik
pik_install [pikを置くパス]
pik install ruby -v 1.8.7-p352
pik use 187
ruby -v


rails
上記のようにRedmineも考えてるので2.3系の最新版である2.3.14を使用。
これもgemがあれば一発。

gem install rails -v 2.3.14 -r

動くことを確認。
rails sample
cd sample
ruby script/server
Windowsのコマンドプロンプトはserverスクリプトが実行ファイルだと認識しないので、rubyから起動してやる必要がある。

これでhttp://localhost:3000をブラウザで開くと、Welcomeページが見えている。

楽になってるなぁ。前調べたときは、ここまで来るだけでも一苦労だったのに。

2011年10月9日日曜日

「Blogに書くまでがTDDBCです」

というわけで、10/8に行われたTDD BootCamp 1.6 for C++に参加してきたので、復習も兼ねて感想などを。

TDDBCには半年ぐらい前から興味を持っていたけれど、1.5は定員オーバー、1.6は開催に気づかず、1.6 for PHPは言語の問題で無理。今回ようやく参加できたんだったりする。

TDD自体はファウラーの「リファクタリング」→XPの流れの中で知っていて、何度か実践しようとしてみたことはあった。でも当時のコードではUI部分のStateMachineが多く、初期化が難しかったり動作や確認に手作業/目視がどーしても必要で、自動テストの導入の所で挫折してたりする。
現職だとお客さんの流儀に合わせないとならないから、なおさら。

まず最初に、@kaorun55さんの講演「TDDBCへようこそ」
TDDBCと、TDD自体の説明。
印象に残ったのは、バージョン管理、タスク管理、自動化テストは開発者にとっては「躾」レベルの基本的なスキルである、という点。
この歳になると人を教える立場につくことが多いけれど、技術的なこと(そこ自体わりと問題だったりするが)の次に教えることとして、そのあたりを抑えると良さそうで、参考になった。

それからペアに分かれて、運営側から小出しに出される課題について、ペアプロでTDDを実践。
課題は鉄道路線の経路探索。課題1、2あたりは駅数も少ないので、GoogleTestの練習を兼ねてベタなコードで片付ける。が、最終的にグラフの探索を行わなければならない予感はしていて、どのタイミングでクラスを作るなどRichな構造に直すか、ペアの方と相談を始めてたりする。

次にレビュー。まず隣のペアと実装を見せあってから、全体で2~3ペアを選んでコードを発表してもらう。最初から構造を作り込んでるペア、課題を分析して簡単な条件を導き出し最低限の実装で行ってるペアなど、それぞれ特色があって面白い。

昼食の後、@goyokiさんの講演「テスト駆動開発入門 ネクストステップ」
TDDを理解した後で、どのように実践し、またどのように理解を深めていくかの指針。
まず実践にあたっては、テストコード自体の保守の重要性が強調され、そのための様々なテクニックを紹介していただけた。
今の案件でもテストコードの保守には手を焼いていて、大変参考になった。
学習についても、読まなきゃとAmazonのカートには入れたものの後回しになっている本がいくつも紹介されて、精進が必要だと改めて認識。

そして課題の続き。課題3がGreenになった所でデータ構造のクラス化に踏み切る。この時間違えたのは、新規にクラスを起こすところのコードについてTDDを行わなかったことで、案の定バグを作り込んで解決にかなり時間を使ってしまった。結局、課題4の途中で時間切れ。
バグの主因はデータの実体と参照の混同(というか分けて考えていなかった)で、ナビゲータをしながら嫌な予感はしていたのだが、介入せずにそのまま流してしまったのは反省点だった。boostを入れてあれば、せめてshared_ptr+仮想コンストラクタで実装して影響を出にくくできたのに。少なくともTR1なら入っているはずなので、その時気づいていれば。

さいごに@t_wadaさんによる総括の講演。
問題を扱いやすい粒度に分割することが重要、という点と、実際にTDDを適用した結果の工数変化が参考になった。

実際に手を動かせて、また参加者が比較的バラエティに富んでいて違う業種の方とコミュニケートでき、有意義な勉強会だった。
今後も機会があれば参加したいし、それだけではなく自社内でなり客先の人を巻き込むなりして、なんか出来ればなぁと思った。

2011年10月3日月曜日

IO#unpack!

String#unpack!の続き。 普通はStringが処理できれば問題ないんだけど、時にはIO(と言うかファイル)を直接パースしたい時がある。特にファイルだとサイズが巨大で、事前に全部読み込んでおくのが現実的でないこともあるし。
ここで問題になるのが、pack文字列の中には読んでみないとデータ長が確定しない場合があること。なので、事前にpack文字列をパースして、判るならば読み込み長を事前に計算する実装にしてみた。以下ソース。 長さがわからなったら、packして実際のデータ長を求め直してからseekするという富豪設計。ちなみにSTDINとかのtellやseekがエラーになるストリームでは使えないので注意。

本来unpackで消費するバイト数が取得できたり、unpack時に1バイト取ってくる動作をカスタマイズできたりすれば、こんなゴマカシは必要ないわけで。この辺はRubyの入出力周り、とくにIOが安易にunixのファイルに準拠した仕様になっている弊害だと思う。

2011年9月30日金曜日

Rubyと型と割れ窓

Rubyは動的型付けの言語だからエラーが予防しづらいとか、大規模開発に向かない、とかよく言われる。有名なところではこの辺とかだろうか。
確かに自分でも身に覚えのある話で、凡ミスで変数にあらぬ型の値が入って謎のエラー発生とか、実際わりとある。構造体とか作らずArrayやHashに突っ込んどくのが悪いんだけど。
にもかかわらず、だから開発しづらいという印象が、不思議なことに無かったりする。これまでは好みや嗜好、あるいは腕の問題かなぁとか漠然と考えていたのだが、もうちょっと説得力のある理由を思いついた。

先に上げたリンク先でも、こんなことが言われている。
ちょっとした脳内のアイディアをコードに落とすのはRuby(やRails)が最速であると胸を張って言える
でもって「ちょっとした脳内のアイディア」には、ささいな修正とか可読性の向上も含まれる。コストが掛かるんだったらわざわざやらないような小さな改良でも、Rubyだったらやっておこうか、となる。小さくても改良されれば開発効率は上がる。上がった効率で小改良はますます安価になり、さらなる改良が行われる。何のことはない、いわゆる割れ窓理論だ。

動的型付けがエラーを呼び込みやすいのは、おそらく事実だと思う。しかしコード変更が十分に安価でメンテナンスが頻繁に行われるなら、その効果は型付けのマイナスを補うこともあるのかもしれない。

2011年9月14日水曜日

String#unpack!

VC++とWindowsで遊ぼうかと思ったら、VC2010のSP1インストールで盛大にトラブってまだ終わらないので、Rubyの小ネタで場をつなぐ。

Rubyでフォーマットのあるバイナリを読み込む場合、String#unpackを使うのがよくあるパターン。とはいえ使いづらい点もあって

  1. フォーマット文字列が長さ情報を持っているのに、何バイト読んだかの情報が取れない
  2. unpack自体はデータを消費しないので、次のデータを読もうとすると自分で進めないといけない

これで、例えばデータ自体の内容によってフォーマットが切り替わるようなデータを処理しようとすると、フォーマットから長さを計算して固定長切り出してフォーマットに従ってunpackして……という鉄板コードが並ぶことに。

やってられないので、こんなのを考えてみた。



unpackした結果をpackし直して長さを求めるという手抜きかつ富豪な実装だけど、これだけでデータ処理コード自体の見通しはだいぶ良くなったりする。

2011年9月5日月曜日

エラーハンドリング勉強会

に参加してきた。復習も兼ねて覚え書きやら思ったことやら。

  • エラーハンドリングモデルの考察(@wraith13さん)
エラーの定義とエラー記録のモデルについて列挙する感じで。
エラーって何かというのは考えだすと難しい話で、分類とか対処法とかきっちり決まっていたら、それって仕様通りの動作なんちゃうの? って話にもなる。
結局どこかで人間の価値判断が入ってくるわけで、そのためにも通知/記録はしっかりと。
エラー時の動作も発生即終了とは限らず、エラー状態のまましばらく走ることも(例外がcatchされるまでスタックをunwindしつつ呼び出し階層を戻っていくとか)あり、その過程でさらなるエラーが起こったりとかも考えうるので、エラー値の持ち方も色々と。


  • エラーハンドリングとアプリケーションの運用(@super_rtiさん)
運用も絡めた話。エラーハンドリングは問題を特定し、可及的速やかに正常な状態にするため。時間の浪費を防ぎ運用コストも低減する。
その観点から、エラーは不正の起こった状況を正確に記録することが重要。何が起こったかだけでなく、何故起きたかも記録すべき。そういう意味では、assertマクロみたいな仕組みも有効なのかなぁ。
またエラーの回収方法も大事。ユーザの作業が必要だったりサイズが大きすぎたりすると、エラー取得そのものが上手くいかない場合もあるので、考えておく必要がある、と。


  • ドキュメントとエラーハンドリング(@cpp_akiraさん)

ドキュメントにはチュートリアルがついてくるけど、そのレベルではエラーハンドリングは省略されていることが多い。ドキュメントまでちゃんと読まないと、想定外のエラーの温床になってしまう。
ソースにあって有用だけどドキュメントに記載のない機能があった場合、勝手に使ってしまうのは良くなくて、作者に確認を取るべき。単なる記載漏れだとしても、それは「ドキュメントのバグ」なので。


  • スタート例外(@ranhaさん)

Exceptional C++の例題(スタックの実装)をHaskellで書いてみて、エラーへの対処戦略を比較。
Optional型や例外送出だとエラーの影響を局在化することが困難なので、スタック操作関数の戻り値型にスタックの状態も持たせることによって、そもそもエラーが発生しないようにして解決。
Haskellがそういう言語だとはいえ、それエラーハンドリングちゃうやん、という話もあるけど、事前に対処に漏れがないようしておくは、どんな場合でも有効なわけで。


  • Actorとエラーハンドリング(@cooldaemonさん

ErlangやScalaでActorモデルを使った場合の、エラーハンドリングのパターンについて。
Erlangではリンクと呼ばれるエラー伝搬の仕組みがあって、1つのActorがエラーで停止すると、リンクしている他のActorも連鎖的に止めることができる。エラーが発生するようなActorは何かが根本的におかしい可能性もあるので、その場でジタバタせずになるべく早く止めて上位で回復動作を行ったほうがいい、というポリシーらしい。
SupervisorのActorはリンクしてても通知されるだけで一緒に死なないが、そういうActorはworker Actorの起動/停止のみで他の処理は」やらない方がいい。
Scalaはまた違う感じだけど、Erlangではこれらはパターンとしてあるだけで、それを強制するシステムはないような感じを受けた。
個人的には並行処理の実装方法の本命はActorモデルだと思っているので、いろいろ参考になった。


  • exception_ptr(@__gfx__さん

C++11で加わった、exception_ptrの話。これまでのC++では、例外オブジェクトはスタック上にできるし、型情報が失われてしまうので自由に持ち運びできなかったけれど、C++11ではcurrent_exception()でexception_ptrを作成すれば一時的に記録できるし、rethrow_exception()に渡せばrethrowできる。
昔、Fiberの中から投げた例外が外に出ていけなくて(スタック切り替えるから当然なんだけど)困ったことがあったけど、これを使えば出来るのかなぁ。そのうち試してみよう。


  • LD_PRELOAD(@egtraさん

勉強会中に作られたとか。テストとして失敗するclose()が欲しいよねという話から、では作ってみましたというLT。LinuxならLD_PRELOADなんだけれど、MacOSなので相当する別のものでやってみたそうで。
エラーハンドリングというか、ユニットテストでは地味に必要な機能なんだよね。このへんで考えてることもあるので、早く形にしてみよう。

といった感じでした。最初にも書いたけどエラーハンドリングは難しくて、みんな試行錯誤している最中かな、という印象。
実装の話に限っても、エラー値は対処漏れがあるし、チェック例外はやってられない、その他の例外も近距離ならいいけれど、throwとcatchが離れるとラベル付きgotoと同じ問題をはらんでしまう、とまだ決定打がない状態だし。

といったところ。