@kyanny's blog

My thoughts, my life. Views/opinions are my own.

最近思ったこと

ユニットテストの話題読んだ。

テストを書くか書かないかの判断の話 · GitHub

フロントエンドに秩序を取り戻す方法 // Speaker Deck

仕事でよくコード書くアプリケーションが五個か六個くらいあって、三個は CoffeeScript と Marionette.js でフロントエンドをほぼ全部書いてるシングルページアプリケーションみたいなやつで、二個はフロントエンド部分と JSON API 部分が一個の Rails アプリケーションのリポジトリ内にそれぞれ同居してて、残りの一個はフロントエンドのみで JSON API は別アプリケーションになってる。

シングルページアプリケーションみたいなやつはユニットテストけっこう頑張って書いてて、フロントエンドのみのやつが 2152 passing (54s) 1 pending 1 failing で、 Rails と同居してるやつが 1866 examples, 2 failed, 0 pending と 873 examples, 0 failures, 1 pending だった(失敗してるやつはタイムゾーン絡みでイギリス人の手元だと成功するけど日本人の手元だと日付が変わって一日の半分で落ちる、みたいなやつ)

コードの意味ある行数とかカバレッジとか測ってないけど、体感で C0 70% くらいはいってると思う。ただテスト書くときにいつも迷いがあって、イベントハンドラとして実行される関数に三行実装があるとその一行の副作用ごとに一個ずつテストケース分けて書いたりしてて、詳細すぎる気がする。いちステップごとにテストしていく感じなので、なんか自分がデバッガか何かになってソースコードを一行ずつ検査してるような気持ちになってくる。

ソースコードを一行ずつ検査すること自体はよいと思うけど、人間がそんなローレベルな仕事してはいけないと思う。ハイレベルな表現で記述したらソフトウェアがローレベルな処理に翻訳・展開してソースコードを細かい粒度で検査してくれるべきだと思う。テストフレームワークの語彙とかでうまく吸収して欲しいし、たぶんできるはずなんだけど、なぜか自分(たち)がテスト書いてると職人が丹精込めて手打ちしたローレベルな検査コードです、みたいになってしまってる気がする。

CoffeeScript で書いたものを JavaScript にコンパイルしてさらに圧縮してるからものすごく読みづらいけど、サーバサイドと違ってフロントエンドは基本的に動いてるソフトウェアのソースコード全部読める。本体のソースコードが読み放題なんだからそれのテストコードも読み放題でもいいのではと思う。そうしたらテストコードを社外の識者に自由に読んでもらって、この書き方いけてないですよとか、こういうテストはこういう考え方で書けば記述量少なくても意味ある内容にできるとか、アドバイスもらえる。そういうアドバイスが欲しい。いまの自分(たち)はこういうやり方に慣れすぎてあんまり疑問もなくて、それはいいことではないと思うけど、斬新な考え方とか思いつける気がしない。

就職まではしないけどちょっとソースコード読んだり会社とチームの雰囲気知ったりするのにインターンとかいいと思うけど、あんまりインターンで短期に週二とかで働ける人いないと思う。日本だとだいたい実力あってソースコード読んでみて欲しい人はフルタイムの会社員だったりして、こっちはインターンで来てくれたら嬉しいけど相手にあんまりメリットがない。仕事辞めて次探してる無職のときとかは便利かもしれないけど、普通に働きながらインターンもやるのは厳しいと思う。インターンにすらならなくていいからソースコードだけ読んで気が向いたらコメントしてもらえるようになると、ソースコード読みたい人は楽しみが増えるし、アドバイス欲しい側は助かるので一石二鳥だと思う。

テストの話、 Ruby とかだとユニットテストは書くのが当たり前で、エンドツーエンドテストもだいたい多少は書くものと思われていて、テストの質とか、一歩進んだ内容について議論していると思う。フロントエンドの場合だとそもそもテスト書くのがまだ当たり前じゃなくて、書いたほうがいいとわかってるけど難しくてうまくいかない、みんな知見がたまってないのでそれ以上の議論にならない、みたいなところが多いと思う。十年前のウェブアプリケーションがそういう感じだったので十年後くらいにはフロントエンドでも知見がたまって踏み込んだ内容の議論が出てきて今の悩みも解決しそうだけど、十年も悩みながらテスト書きたくないので困る。

Rack::Proxy でプロキシ認証が必要な forward proxy の習作

習作なので RFC を読んでいません。実用しないほうがよいです(僕も実用してないです) Squid などを使いましょう。

https://github.com/kyanny/playground/tree/gh-pages/rack-proxy-auth

仕事で IP アドレス制限のかかった API と HTTP でやり取りするために forward proxy を使う必要がありそうで、 curl の -x オプションと -U オプションを使うことを知り、実際それでうまく動いたのだが、プロキシ認証というものを初めて使ったのでいろいろ気になることがでてきて、 Squid の設定とかせずにプロキシ認証の動作検証(主にクライアント側が正しくプロキシサーバを利用できているかの検証)ができないかと思って Rack で書いてみた。

Rack::Proxy はこの記事で書いたようにリクエストとレスポンスを加工するのが目的なので、プロキシ認証の機構は組み込まれてない。そこで call を上書きして、クライアントが送ってきたプロキシ認証の情報をリクエストヘッダから取り出し、正しい認証情報でなかったら 407 Proxy Authentication Required を返す、としてみた。実験用なのでいろいろ決め打ち実装。

最初は何を思ったのか rewrite_env の中で認証情報のチェックをし、 NG だったら Rack::Proxy がリクエストを送り直す処理をする perform_request メソッドを差し替える、という変なことをしていた 6404fe2b1c7ad93302f032d61d86b74df8d9012c 差し替えちゃうと一度でも認証失敗した場合に以後正しい認証情報つきでリクエストしてもずっと 407 を返してしまうので差し戻したりと、謎に謎を重ねる感じになっていた。

これと直接関係ないが、 Ruby プログラムから子プロセスとして Rack アプリケーションを起動し、その HTTP サーバに対してリクエストを送ったりしたあとちゃんと kill して自分自身も終了する、というのがなかなかうまく書けなくて苦労したが、そのおかげで Ruby でのプロセス操作についていい復習になった。 Working With Unix Processes 読んだけど身についてなかったみたいでちょっと悲しい。

プログラム内から起動した外部プロセスが利用可能になるまで TCPSocket.open で待つ

https://github.com/kyanny/playground/blob/gh-pages/tcpsocket-open/wait_port_open_close.rb

プログラム内から子プロセスとして Rack アプリケーションを起動し HTTP リクエストを送りたい、という場合に、 Rack アプリケーションが起動し終わって localhost:9292 への HTTP リクエストを受け付けられるようになるまでには少し時間がかかる。適切なウェイトをはさまないと Rack アプリケーションがまだ起動してないのにプログラム本体の処理が進んでしまって HTTP リクエストを送ってしまう。

だいたい sleep で適当に三秒くらい待ってたけど、もっと効率よく最短の時間だけ待つようにできないかと思って TCPSocket.open でポートが利用可能になったか調べる方法を思いついたので試してみたらいい感じだった。

# wait until rack server launch
loop do
  begin
    TCPSocket.open('localhost', 9292)
    break
  rescue
  end
end

これはポートが利用可能になるまで待つほう。ポートに繋がらないと例外が出るので rescue で無視する。ポートに繋がったら break して無限ループを抜ける。

# wait until rack server shutdown
loop do
  begin
    TCPSocket.open('localhost', 9292)
  rescue
    break
  end
end

これは逆にポートが利用できなくなるまで待つほう。 Rack アプリケーションを kill するとシャットダウンにも少し時間がかかる。シグナルを送れていれば Rack アプリケーションのシャットダウンより前にプログラム本体が終了しても問題ないけど、シェルに戻ってからプロンプトに Stopping ... とか表示されるとかっこわるい。シャットダウンを待ってからプログラム終了するほうがかっこいい気がする。