kなんとかの日記 このページをアンテナに追加

2010-06-12

Rails の select() 系ヘルパーはイケてないと声を大にして言いたい

| 09:15 |  Rails の select() 系ヘルパーはイケてないと声を大にして言いたいを含むブックマーク

背景

いつも思うが、Rails の select() 系ヘルパーメソッドってわかりにくい。

初心者泣かせ。


具体例(1)

参考文献: マニュアル

select() の例:

### eRuby
<%= select("post", "person_id",
           Person.all.collect {|p| [ p.name, p.id ] },
           { :include_blank => true }) %>

### HTML
<select name="post[person_id]">
  <option value=""></option>
  <option value="1" selected="selected">David</option>
  <option value="2">Sam</option>
  <option value="3">Tobias</option>
</select>

( select() では [p.name, p.id] の順番なのに )

具体例(2)

collection_select() の例:

### eRuby
<%= collection_select("post", "person_id",
                      Person.all, :id, :name,
                      {:prompt => true}) %>

### HTML
<select name="post[person_id]">
  <option value="">Please select</option>
  <option value="1" selected="selected">David</option>
  <option value="2">Sam</option>
  <option value="3">Tobias</option>
</select>

( collection_select() では :id, :name の順番になってる! 紛らわしい! )


問題点

  • 使い方がわかりにくい
  • よく似たメソッドが複数存在
    • ちょっとずつ異なる用途ごとに別々のメソッドが用意されているため

改善案

<%= select(....) do |t|
      @items.each {|x| t.option(....) }
    end %>

改善例(1)

### 改善前
<%= select("post", "person_id",
           Person.all.collect {|p| [ p.name, p.id ] },
           { :include_blank => true }) %>

### 改善後
<%= select("post", "person_id") do |t|
      t.option(nil, '-')
      Person.all.each {|p| t.option(p.id, p.name) }
    end %>

(:include_blank とか覚える必要なし)


改善例(2)

### 改善前
<%= collection_select("post", "person_id",
                      Person.all, :id, :name,
                      {:prompt => true}) %>

### 改善後
<%= select("post", "person_id") do |t|
      t.option(nil, 'Please select')
      Person.all.each {|p| t.option(p.id, p.name) }
    end %>

(:prompt とか覚える必要なし)


効果

  • 使い方がわかりやすい
    • select() の引数とブロックとで役割を分担するため
    • select() の引数の数が減るため
  • 1 つのメソッドに統一できる
    • 用途が少しずつ異なっても、ブロックの記述で吸収できる
    • 少しだけ異なる用途ごとにメソッドを用意する必要がない

今後の課題

  • optgroupタグのサポート Done
  • HTMLエスケープ
    • Rails3の仕様にあわせるべき?
  • Rails plugin 化
    • めんどいなー
    • 正直、Rails には疲れた

まとめ

  • Rails の select() 系ヘルパーはイケてない
    • 使い方がわかりにくい
    • よく似たメソッドが複数存在する
  • select() がブロックを取るように改善
    • 使い方がわかりやすくなる
    • 1 つのヘルパーメソッドだけで済む
    • ブロック万歳!

2010-06-11

Java屋さんのコメントがレベル高すぎて困る

| 08:09 |  Java屋さんのコメントがレベル高すぎて困るを含むブックマーク

Velocity/JSPが遅い件について、Java屋さんからびっくりするようなコメントをもらった。


最初のコメントは、よく意味がわからなかった。

はなこ 2010/06/04 14:37

JSP 勘違いしてない?

JSP を初めて読み込むと、開発サーバーによって Java ソース コードに変換され、その Java ソースが Java バイトコードコンパイルされます。Java ソースとコンパイル済みのクラスは、一時ディレクトリに保存されます。元の JSP ファイルに変更を加えると、JSP が自動的に再生成されてコンパイルされます。

JSP の使用 - Google App Engine - Google Code

http://code.google.com/intl/ja/appengine/docs/java/gettingstarted/usingjsps.html

JSPが遅い理由をJava屋さんはまるでわかってないらしい - kなんとかの日記

JSPServletに変換されて実行されるくらい、ワシでも知っとる。このコメントだけでは、ワシのどの文章が『JSPを勘違いしている』と思ったのかわからない。


2つ目のコメントから、雲行きが怪しくなる。

はなこ 2010/06/04 19:00

書いてる通りですけど、JSP や Velocity は実行前にはすでにサーブレットに変換され、コンパイルされており、インタプリタ言語のように JSP の構文を解析しながら実行されるものではありません。

コンパイルするのでこの時点で構文エラーもチェックされており、

ここで仰っている動的、静的で言うならば、静的だと思います。

JSPが遅い理由をJava屋さんはまるでわかってないらしい - kなんとかの日記

まず、『インタプリタ言語のように JSP の構文を解析しながら実行されるものではありません』という文章から、インタプリタ構文解析をしながら実行していると勘違いしている。しかしシェルスクリプトならともかく、今ドキのインタプリタ (Ruby/Python/Perl/PHP/...) は構文解析してから実行するので、『構文解析しながら実行』というのは間違い。

また『コンパイルするのでこの時点で構文エラーもチェックされており、ここで仰っている動的、静的で言うならば、静的だと思います。』という文章から、明らかに動的言語・静的言語を誤解していることがわかる。コンパイルする・しないことと、言語が動的・静的ということは、別に関係はない。Pythonは動的な言語だが事前にコンパイル可能だし、Rubyならコンパイルできるかどうかは処理系に依存する (RubiniusはできるがMatz Rubyではできない)。

さらに、『Velocity は実行前にはすでにサーブレットに変換され』ると書いてあるが、そんな事実はない。確かにVelocityではVelocityServletというクラスが用意されているが、それはVelocityをサーブレットに変換するわけでもないし、変換されたものでもない。まあさすがにこの間違いは自分で気づいたようで、次のコメントで訂正している。

はなこ 2010/06/04 19:16

Velocity はコンパイルされないようですね。

JSPが遅い理由をJava屋さんはまるでわかってないらしい - kなんとかの日記

つうかそのくらい知っとこうぜ、Java屋さんなら。Velocityは歴史ある有名ライブラリなんだから。


次のコメントもボロがでてる。

はなこ 2010/06/04 20:29

先に

> Velocity はコンパイルされないようですね。

と書いてます。Velocity のしくみはおっしゃる通りのようですが、

Velocity と JSP はしくみが違います。

Velocity - You make the decision - Generation?

http://www.jajakarta.org/velocity/velocity-1.2/docs-ja/ymtd/ymtd-generation.html

> Perl/PHP/Python/Ruby/JavaScriptといった現代のインタプリタはどれも、実行に先立って構文解析を済ませてから実行されます。

承知しています。

言いたかったのは、

"JSP は実行前にサーブレットに変換されスタンバイしてます。" っていうことです。

JSP が遅いということは、サーブレットが遅いと言っていることと同じに思えたのでコメントしました。

JSPが遅い理由をJava屋さんはまるでわかってないらしい - kなんとかの日記

『承知しています』なんて書いてあるけど、理解してたら『インタプリタ言語のように JSP の構文を解析しながら実行されるものではありません。』などど書くわけがない。明らかに理解しているふりをしてるだけ。

また『JSP が遅いということは、サーブレットが遅いと言っていることと同じに思えた』と書いてあるのだが、この人は元記事を読んだのだろうか。JSPが遅いのは動的な言語を導入したからだと元記事に書いてあるのに、なぜServletのことを持ち出すのだろうか。関係ないだろうに。


ここまできてようやく気づいたのだが、どうもこのJava屋さんは「動的な言語」というのを勘違いしているようだ。恐らく、事前にコンパイルするのが「静的な言語」で、そうでないのを「動的な言語」と思い込んでいるらしい。だから「JSPは動的な言語を導入したから遅い」という主張に対し、「JSPは事前にコンパイルするから静的である。JSPを勘違いしてない?」というアサッテな反論をしているわけだ。

いやいやいや、勘違いしているのはそちらですから。


はなこ 2010/06/06 01:00

jsp遅延評価使わなければ静的では。jsp 使う時 el 必須とは思ってない。el 限定の話ならタイトル変えて欲しい。最初から読まないから。

JSPが遅い理由をJava屋さんはまるでわかってないらしい - kなんとかの日記

遅延評価』などと言っているが、これも明らかに勘違いだわな。遅延評価をバリバリ使っているHaskellが静的なのに『遅延評価使わなければ静的』とかアホか。聞きかじった用語でコメントされても困る。いや違うな、聞きかじった用語で*エラそうに*コメントされても困る。

他のJava屋さんは誰も見てないのかなあ。こんなコメントするやつを放置するなんて、身内には甘いよね。

しかしなあ、『el 限定の話ならタイトル変えて欲しい。最初から読まないから。』と言い出すとか、逆切れだろ。Java屋さんのほうが勝手に勘違いしてただけのくせに、そこを謝ることは一切しない。自分の間違いや勘違いは正そうとせず、相手のせいにするんだから、まあマスゴミモンスターペアレントの類いと一緒だわな。


やっぱこんな国は一度バルスされちゃったほうがいいよ。まじで。


#「はなこ」なんて名乗ってるけどこれで男だったら笑える

forth83forth83 2010/06/11 09:31 Javaメインでやってるけれど、Java素人のSI屋みたくJava屋なんて呼ばれて面白いわけないだろ?

payopayo54payopayo54 2010/06/11 09:42 Javaは一時はやちゃったから、いろんなレベルの人がいるよね。Javaのレベルで言えば、漏れも底辺だけど。。。SIerではメイン言語でやっているところが多いけど、そういうところのエンジニアってあんまり奥まで勉強してなさそう、SIするのに必死で。
Javaの利点はあくまで、静的な言語で、EclipseなどのIDE環境が整っているため、開発(導入)コストが低いところにあるんじゃないかなー。元ネタのベンチマーク(?)はすごい参考になった。PHPの隠された実力にちょっと使ってみようかなと思った。(私的レベルで)
ただ、Javaメインでやっていると、他の言語を勉強しようとしても、それJavaでできるよなー的に挫折を繰り返している毎日です orz

payopayo54payopayo54 2010/06/11 09:48 続きですいません。JSPとか、確かに動的な言語になっちゃっているよね。自分は開発する上でこれが嫌です。MCは静的なのに、Vが動的でデバッグが面倒。自分がよい開発方法を知らないだけかもしれないけど、ただ、これも、WicketとかGWTみたいなものも出てきて解消されてくのかなーと期待しています。

superaraisuperarai 2010/06/11 12:58 いつも勉強させてもらってます。
私もそのように深い知識を得たいと思っているのですが、そのような知識はどのように収集しているか伺ってもよろしいでしょうか?

kwatchkwatch 2010/06/11 22:06 forth83さん:
> Javaメインでやってるけれど、Java素人のSI屋みたくJava屋なんて呼ばれて面白いわけないだろ?

これまたレベル高いコメント。自分たちのことは省みず他人のせいにしてる。
ところで『Java屋』ってのは気に障るんですか?「PHPer」「コボラー」「Rubyist」と同じでは?

payopayo54さん:
> JSPとか、確かに動的な言語になっちゃっているよね。自分は開発する上でこれが嫌です。
> MCは静的なのに、Vが動的でデバッグが面倒。

同意します。ふうつにJavaをそのまま使えばいいのに、わざわざ静的言語のメリットを捨ててまで動的言語を導入し、物事を複雑にしているんだからあきれます。そのくせ他のスクリプト言語は大いにdisってるし。

superaraiさん:
> そのような知識はどのように収集しているか

単に年寄りなだけです。別に深い知識なんてもってません。相手が無知すぎただけ。
今は若い子のほうがよく勉強して知識を身につけてますよ。

forth83forth83 2010/06/12 00:18 kwatchさんの書く記事は技術的に面白い。特にここ一連の記事の特にVelocity や JSP のイケテ無さには激しく同意するし、的確な分析だと思いました。
だけど、かように幼稚な挑発をする人とは議論を交えたいとは思わなかったってこと。

kwatchkwatch 2010/06/12 09:28 forth83さん:
> かように幼稚な挑発をする人とは議論を交えたいとは思わなかったってこと。

どこまで相手のせいにすれば気が済むんだろう。相手を尊重しているように見せかけて、やっぱり自分たちのことは省みないですね。
今回は「はなこ」さんが「動的な言語」を勘違いしたうえに逆ギレしていることが原因なんだから、まずは身内を反省することが先じゃないでしょうか。
『Java屋』と言われて機嫌悪くしたりとか、ここにコメントするJava屋さんは感情的になって議論ができない人が多いですね。

forth83forth83 2010/06/12 16:42 やはり議論に参加するためには、まずははなこ某さん達に対する責任を果たさなきゃならないんだ。
身内って何ですか?同じ言語使っていたら同じ立場だとでも思っているのでしょうか?

kwatchkwatch 2010/06/13 00:11 『議論に参加』って、何か議論したいことがあったのでしょうか。『議論を交えたいとは思わなかった』と書いているんだから、議論なんかしたくないのでは?

kwatchkwatch 2016/10/01 04:52 全体的にイラっとする.

2010-06-10

Rubyでライブラリのrequireにかかる時間を計測するスクリプト

| 08:33 |  Rubyでライブラリのrequireにかかる時間を計測するスクリプトを含むブックマーク

## usage: ruby -s invoke.rb [-n=1000] [command]

require 'benchmark'

n = ($n || 1000).to_i
puts "*** n=#{n}"
commands = ARGV.collect {|lib| "ruby -e nil -r #{lib}" }
commands.unshift("ruby -e nil")

Benchmark.bm(30) do |job|
  commands.each do |command|
    title = command
    job.report(title) do
      (n/10).times do
        system command; system command
        system command; system command
        system command; system command
        system command; system command
        system command; system command
      end
    end
  end
end

実行例 (MacOS X 10.6)。見れば分かるけど、ミリ秒単位はうまく計測できないようだ。

$ ruby -v
ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-darwin10.2.0]
$ ruby -s invoke2.rb -n=1000 erb cgi openssl yaml rexml/document
*** n=1000
                                    user     system      total        real
ruby -e nil                     0.040000   0.380000   5.080000 (  5.388027)
ruby -e nil -r erb              0.050000   0.390000   7.930000 (  8.334806)
ruby -e nil -r cgi              0.040000   0.440000  15.960000 ( 16.603249)
ruby -e nil -r openssl          0.050000   0.400000  18.750000 ( 19.486394)
ruby -e nil -r yaml             0.060000   0.460000  30.750000 ( 31.581488)
ruby -e nil -r rexml/document   0.050000   0.460000  38.750000 ( 39.970713)

opensslがかなり重いと思ってたけど、yamlやrexmlはそれよりも重いのか。yamlはextentionのくせになぜ重いんだろう?

2010-06-09

Windows では Ruby の require が遅いらしい

| 08:44 |  Windows では Ruby の require が遅いらしいを含むブックマーク

Ruby の require が Windows では遅いという話。

このような現象が起こるのは一体なぜなのでしょうか?理由は、read_class_onefile_binmodeを見るとすぐに分かります。バイナリモードでは、Windowsの1.8.7と1.9.1は違いがないのです。バイナリモードとテキストモードの違いは、文字列のエンコード関係の処理を行うか否かですので、これにより、Windowsではファイル読み込み時のエンコード処理に時間がかかることがわかります。

require高速化:基準となるベンチマーク - ashelの日記

(強調はワシによる)

これって、File.open('file.rb', 'r') と File.open('file.rb', 'rb') の違いを言っているんだよね。だったらエンコードじゃなくて改行文字の変換 ("\r\n" → "\n") をするかどうかじゃないのかな。

あと requrie のベンチマークは、1 回の require だけで計測してるけど、これだと時間が短すぎて計測誤差が大きいように思うけど、そんなことない?複数回 require して計測できればそのほうがいい。

ashelashel 2010/06/10 01:15 突っ込みありがとうございます、確かにバイナリモードとテキストモードの違いは、1.8系においては改行の扱いだけなのですが、1.9系においては読み出した文字列をシステム標準のエンコードにエンコードするか(例えばWindowsではWINDOWS-31Jになります)、エンコード処理を行わずにASCII-8BITにするかという違いがあります。改行コードの処理は1.8系でもやっているはずですので、1.9系で違いが出るというのはエンコード処理かな…という推測でした。もう少し調べてみようと思います。
計測誤差に関しては、確かにあります。ただ、大きくて10%くらいでそれほど大きくなかったので、今回はぱっと見で平均に近い値を選びました。そのくらいの精度の計測だと思っていただけたらと思います。将来的には平均を取るような計測をしてみたいと思います。

kwatchkwatch 2010/06/10 07:59 元記事では『read_class_onefile_windows31jでMacでファイルをWindows-31Jとして読み込むベンチマークを行ってみたのですが、特に遅くありませんでした。』という説明があり、かつ改行文字の変換については触れていないことから、改行文字の変換が原因かなと推測しました。
計測誤差については、そもそもミリ秒以下のタイムが正しく計測できるのかを心配してます。

ちなみに文字コードとも改行コードとも関係ありませんが、require 'openssl' はすごい遅いです。

2010-06-07

形式的な仕様記述がすごいらしい

| 05:28 |  形式的な仕様記述がすごいらしいを含むブックマーク

 早速,メルコ・パワー・システムズの開発部門が原因究明に乗り出す。しかし,いくらデバッグしてみても不具合の原因が分からない。それどころか,現象が非常にまれにしか起きないため,不具合の再現すらおぼつかない状況だった。

 開発作業に暗雲が立ち始めたちょうどその時,社内でモデル検査技術の試験適用を進めていた早水公二氏が現れる。新技術の調査・導入を担当する技術統括部 ビジネスチーム2に所属するモデル検査の専門家だ。既に何件かのプロジェクトでモデル検査の効果に手応えを感じ始めていた同氏は,この不具合の原因究明にもモデル検査技術が使えないかと思い立ち,作業に取り掛かる。そして,モデルの作成やツールによる探索作業などを経た13時間後,見事,不具合の原因を見つけ出したのだった(図2,図3,図4)。

no title

形式的手法を用いることで、再現性が非常に低いバグの原因をわずか13時間で見つけたとな。すごすぎる。

 今回の不具合の要因は結局,境界値に起因する条件判断文の単純な実装ミスだった(図3)。バグというのは,大概が思いも寄らない部分に潜むからこそ,発見できずに不具合となる。レビューやテストの観点を増やせば検出できるという正論だけでは限界がある。「コンピュータルーチンワークとしてプログラム中を探索するモデル検査は,人力に頼るテストの限界を別の観点から補足してくれるもの」(星野氏)といえる。

no title

形式的な仕様記述は、プログラミング言語とは独立して利用できるのかな。だとしたら、動的な言語においてテストを補完するものになるのだろうか。

 自然言語の仕様であれば,人により解釈は千差万別。一度きりの片方向のやりとりであれば,目立たない仕様解釈の誤差も,仕様精査や実装のサイクルが回る中で蓄積され増幅されてしまうのだった。サイクルを経ても,解釈の誤差が入り込まないような方法論,それが形式的手法だったのだ。「10万行もの仕様をVDMで書いたと言うと,『ほとんど実装に近いですね』などと言われるが,仕様策定者が実装を書いて何が悪いのか。そのくらいの詳細度が本当に必要な立場であれば,実装並みに厳密な仕様でも,ためらいなく書くべきだ」(同社の栗田氏)。

 栗田氏によると,形式的手法による仕様記述を経験すると,仕様を厳密に書く発想が根付くため「今は日本語に戻っても十分厳密に仕様を書く自信がある。形式的仕様記述言語がソフトウエア技術者の共通言語になれば望ましいのでは」とする。

no title

かっこえー!

英語の勉強やめて、仕様記述言語を勉強しようかな。