2008-02-05
目次
りんご味Ruby 第18回 藤本 尚邦
前回は、Rubyのブロック付きメソッドによる繰り返しの抽象化の効果を示しました。今回は、I/O(ファイルやソケットとの入出力)への読み書きアクセスを題材として、ブロック付きメソッドによるシステム上のリソースへのアクセスの抽象化とその効果を示します。
■ (1) I/Oの開け閉めを直接プログラムする
ファイルへの読み書きやTCPソケットによる通信では、ほとんどの場合、以下のような手順で処理が行なわれます。
(1) まずI/Oを開く
(2) I/Oを介してデータを読み書き処理する
(3) 最後にI/Oを閉じる
まず、この手順を直裁的にプログラムしてみましょう。
-----------------------------------------------
require 'socket'
require 'rss/2.0'
io = TCPSocket.open("www.mosa.gr.jp", 80) # I/Oを開く
io.write "GET /?feed=rss2 HTTP/1.0\r\n\r\n" # HTTP GET要求を送信
rss = RSS::Parser.parse(io, false) # 受信しながらRSSをパース
io.close # I/Oを閉じる
rss.items.each { |i| puts i.title } # 結果を表示
-----------------------------------------------
【編集部注:\r\n部分が『円記号』に見える場合は『バックスラッシュ』に置き換えてください。以下も同様です】
このプログラムは以下のような処理をしています。
・モサのWebサイトにTCP接続する
・HTTPプロトコルのGETを送信し、RSSデータを要求する
・RSSデータを受信しながらパースする
・接続を閉じる
・パース結果の各エントリのタイトルをプリントする
同時に開くことのできるファイルやソケットの数にはシステム上の制限がありますから、不要になった時点でそのI/Oは閉じるべきでしょう。しかし、上記のようなプログラムで I/O を閉じる部分を書き忘れてしまうというのはありがちな話だと思います。書き忘れなかったとしても、RSSパース時に例外が発生したりしたら、I/Oは開きっぱなしのままプログラムの実行は外に移ってしまいます。
■ (2) I/Oの開きっぱなしを避ける – ensure の導入
書き忘れはどうしようもありませんが、例外の発生によるI/O開きっぱなし問題には解決策があります。例えば Java の finally
try { ... } finally { ... }
のようなものを使う方法が考えられます(何が起ころうともtry節から出るときには必ずfinally節を実行する)。Rubyにも、beginとensureを使う同様の構文があります。さきほどのプログラムを改良してみましょう。
-----------------------------------------------
require 'socket'
require 'rss/2.0'
io = TCPSocket.open("www.mosa.gr.jp", 80) # I/Oを開く
begin
io.write "GET /?feed=rss2 HTTP/1.0\r\n\r\n" # HTTP GET要求を送信
rss = RSS::Parser.parse(io, false) # 受信しながらパース
ensure
io.close # I/Oを閉じる
end
rss.items.each { |i| puts i.title } # 結果を表示
-----------------------------------------------
begin節(beginとensureで挟まれた2行)の実行中に何が起きようと、ensure節(ensureとendで挟まれた1行)は必ず実行されます。つまり、ioは必ず閉じます。
I/Oが閉じられるようになって少し安心しました。このように書いている時点でI/Oを閉じることを意識しているわけですから、それを書き忘れることはおそらくないでしょう。
■ (2) I/Oの開け閉めを抽象化 – ブロック付きのopen呼出し
ところで、このプログラムは少し冗長な気がしませんか?とくに、I/Oの開閉に関する部分は、I/Oにアクセスするどんな目的のプログラムであろうとさほど変わるものではありません。言い換えると、TCPソケットで通信するプログラムには以下のようなパターンがあります。
io = TCPSocket.open(ホスト名, ポート番号)
begin
I/Oアクセス処理 ...
ensure
io.close
end
何度も同じようなパターンが出てくるときは、それを出来る限り抽象化して繰り返さないようにするのが正しいプログラマの姿勢(DRY原則-後述)。ここでブロック付きメソッド呼出しの登場です。TCPSocketクラスのクラスメソッドであるopenは、I/O(ソケット)へのアクセス処理をブロックとして渡すことにより、上記のようなパターンのI/Oの開け閉めを裏でやってくれます。この場合、ブロックの実行結果がopenメソッドの返す値となります。
TCPSocket.open(ホスト名, ポート番号) {|io| I/Oアクセス処理 … }
では、ブロック付き呼出しでさらにプログラムを書き換えてみましょう。
-----------------------------------------------
require 'socket'
require 'rss/2.0'
rss = TCPSocket.open("www.mosa.gr.jp", 80) { |io|
io.write "GET /?feed=rss2 HTTP/1.0\r\n\r\n"
RSS::Parser.parse(io, false)
}
rss.items.each { |i| puts i.title }
-----------------------------------------------
とてもすっきりした上、I/Oの閉じ忘れも書き忘れも起こりえないプログラムになりました。
ここまで、TCPSocketを実例としてI/Oへの読み書きアクセスの抽象化を説明しましたが、これはIOクラス(TCPSocketの上位クラス)でサポートしている機能です。ファイルI/Oに関しても同様に使うことができます。もちろん、このような抽象化をサポートするブロック付きメソッドをプログラマが定義することもできます。
■ [補足] HTTPアクセスについて
今回、説明の都合からTCPSocketを直接使いましたが、実際のRubyプログラムでHTTPプロトコルを使う場合には、Rubyに付属しているライブラリの net/httpあるいは単純な GET だけであれば open-uri (RSSリーダで使っているもの)を使うのが手軽かつ安全で良いでしょう。
■ [補足] DRY原則
DRY = Don’t Repeat Yourself の略。「同じコードの繰り返しは抽象化してひとまとめにしよう」というプログラミング上の原則のこと。「達人プログラマ」(ISBN-13: 978-4894712744)という本などで紹介されています。
藤本裕之のプログラミング夜話 #131
前回あんなことを書き始めたら、いきなりエルゴソフトがegword、egbridgeなどのパッケージソフト事業を終了するという発表をした(1月28日)。公式見解では「Mac OS Xにおける日本語環境の成熟などから、パッケージソフト事業を終了する時期である」としている。システムについてくる、いわば只の「ことえり」が良くなれば「egbridge」と「ATOK」が分け合うパイが小さくなるのは必然だし、Intel チップの採用、Boot Campの実現などで Windows との垣根が低くなったことも、デファクト・スタンダードとしてのMS Wordの立場を強化しこそすれ、egwordにプラスには働かない。企業としてはそういう言葉は使わないが、アリテイに言えば「事業として続けていても将来の展望がない」ということなんだろう。
egwordに限ったことではない。ここ数年、iPodのおかげでアップルのブランドイメージは向上、Macintoshにも波及してプラットフォームとしてのシェアは上向いているにも関わらず、Macintosh用のパッケージソフトの売り上げは伸びていない。いやWindows用のソフトだって、品数こそ多いが我が世の春を謳歌してるわけではないようだ。早い話がどこでも「マシンは普及したがソフトは売れない」という状況。まるでケーザイ評論家が言う「大企業の景気の良さが、中小企業や被雇用者にまで波及してこない」という話のインスタンスのようである。こんな感じ?
我らが現状 = [[NS日本の経済状況 alloc] initWithソフトウエア業界];
オレはこういう話を大所高所からするのが苦手なので(だって大所高所にいたことがないんだからしょうがねぇよな)、ごく私的な実体験を元にしての話しかできないのだが、考えてみればオレ自身がここ数年、ずっと使っているもののバージョンアップを除いて新たに購入したソフトウエアは数えるほどなのである。いや具体的に行こうか。全く新規にソフトウエアを買ったのは、一昨年3月の Yojimbo(Bare Bones Software, Inc.)が最後だと思う。なんで買わないのかな、と考えてみると、まぁビンボーなのはデフォルトとして、欲しくなるようなソフトがないんだよね。
昔話をしよう。おじいさんが山に芝刈りに、おばあさんが川に洗濯に行き、ワタシが足繁く秋葉原に通っていた(今は年に一度くらいだが)ころの話である。1986年に自分にとって最初のMacintosh(個人用としては最初のパソコンでもあった)であるMac Plusを買ったとき、その購入価格は「Macintosh Plus+ ImageWriterII + External FD Drive に3.5インチのフロッピーディスク10枚とソフトウエア10万円分をセットにして998,000円というものだった。MacPlus 本体がカタログ価格で898,000円だったからずいぶんオトクなセットだと思った(2ヶ月後本体は648,000円に値下げされたんだけどね)。
このときオレが本体と一緒に手に入れた「10万円分のソフト」の内訳は、MacWrite、MacPascal、FullPaint、それに Super Studio Session だった。いや信じられないと言うかも知れぬがこれで10万円になってしまったんですよ、奥さん。よく覚えていないが千数百円は負けてもらったかも知らん。はい? Super Studio Session て何だって? その話は長くなるので別の機会に譲るけど、何が言いたいかというと当時のソフト(ハードも)はとっても高かった……ということではなくて、これら4本のソフトウエアを選ぶのにオレがどんだけ悩んだか、他にも買ってみたいソフトがどれほどあったか、それも
Macintosh用ソフトウエアの市場なんて今と比べ物にならないくらい小さかったのに、ということなんである。
(以下次回 2008_02_01)
高橋真人の「プログラミング指南」第129回
コミュニケーション能力を高めよう(2)
皆さんこんにちは、高橋真人です。さっそく続けます。
前回のお話は、「本として出版されている時点で作者側の“変換作業”は終わってしまっているので、重要なのはどのように本を選ぶかだ」というところまででした。
本を選ぶのは、普通は自分の必要とするテーマに沿って書かれた本の中からより自分に適した本を選び出すというやり方になるでしょうか。選び出す判断基準としては価格、ページ数、知り合いの推薦やWebの書評などといろいろあげられます。ですが、他人から得た情報はあくまで参考でしかありません。人によって“ふさわしい”の判断基準は変わってきますから、自分自身で見極められるようになることも必要です。
かといって、いくら経験を積んでも完璧な本選び(つまり自分に必要な本のみを的確に選び出すこと)ができるようになるわけではありません。ただ、経験を積めばいろんな勘も身に付き、本選びの確度は確実に上がってくるのではないかと思います。
自分にふさわしい本が選べたら、次は読む作業です。これは前回の話に当てはめると「D/A変換」となります。人間は機械ではないので、本を読んで得られる情報は一定ではありません。読む時の心身のコンディションのせいで単に文字を目で追っているだけになったり、筆者の文体とか、本のレイアウトが気に入らないなどの理由で読む気が失せてしまうなどということが起こり得るのは、人間ならではのことだと言えるでしょう。
ところで、この連載の初期のころに「翻訳本は、それだけ多くの選抜を経ているのでヒット率が高い」というようなことを書いた記憶があります。ですがこれをデジタルとアナログの話で考えると、少し違った要素も考慮する必要が出てきます。
それは、著者と読者の間に翻訳者という存在が介在するということです。翻訳者が原書を読むD/A変換作業と、訳した内容を日本語で書き記すA/D変換作業が一連の情報伝達の過程に加わるために、情報の劣化がさらに進む可能性があるのです。例えばAmazonの書評を読んでいて「翻訳の質が悪いので、原書を読むことを勧める」などという記述を見かけることも多く、原書を自在に読むことのできない私のような人間にとっては残念でなりません。
もっとも、翻訳者という存在が介入することは悪いばかりではありません。時には翻訳者がかえって情報の質を高めてくれることもあったりします。例えば、訳している最中に原書の誤記と思われる部分に気付き、わざわざ原著者に問い合わせて確認をした上で原著にはない注記を付けてくれたり、原著のサンプルコードのバグを修正してくれていたりする例も私は経験しています。
質の低い翻訳本に当たって、さらにそれが原書に比べてかなり高価であった場合には「人の文章を翻訳するだけで儲けやがって…」と苦々しく思うこともありますが、逆に原書に負けないクオリティを保った上に、原書を買うよりも安い価格で発売してくれている翻訳本に当たったときには、とても得をした気持ちになるものです。
このような“良い翻訳”である時にポイントなのは、翻訳者が単なる仲介者ではなく、まず訳者自身が原著の“良い読者”であることです。よく言われることですが、良い翻訳者の条件は、英語力よりもその本のジャンルに通じていることなのです。
さて、今の翻訳者の話には読者としての重要なポイントも含まれています。つまり、読者として本を読む場合にも、その本に書かれている分野の知識が多ければ、それだけ本から多くのものを得ることができるということです。
一言で言えば、予備知識などということになるのでしょうが、これから読もうとする本の分野に通じていれば、それだけその本から得られる情報も多くなります。時には“行間を読む”などといって、文章に書かれていないことまで読み取れることがあるわけです。
行間を読めるようになるためには、背景知識・経験が多ければ多いほどよいわけですが、実は、プログラマという仕事には、行間を読む能力が資質として要求されるのです。
プログラマは、ソースコードを書くのが役目ですが、そのためには当然ソースコードを読む作業も発生します。人間が日常会話で使う言語に比べますと、プログラミング言語というのは極端に表現力が低いので、“どうするのか”しか表現できません。実際にコードで表現されている処理が具体的には何を意味しているのか、それを読み取れないと、ソースコードを読むということにはならないわけです。(言ってみれば、行間を読めないプログラマは、まだ一人前だとは言えないということです)
プログラマとして行間を読む力が鍛えられてくると、さらなる力を発揮できます。例えば、ドキュメントも充分でなく、サンプルすら存在しないAPIでも、ヘッダファイルに記述されている情報を頼りに、試行錯誤で使えるようにしてしまうなんてことも、プロとして活躍されているプログラマであれば珍しいことではないと思います。
見てきましたように、人間というD/A変換機は、時にデジタルの入力からあまり多くの情報を引き出せないこともあれば、逆に入力された以上の変換結果を生み出すこともできるという特徴を持っているわけです。
「『経験を積んで、行間を読め』と言われても、そもそもその力がないから困っているんじゃないか」ですって? ごもっとも。
まだ行間を読む力のない皆さんが、本からより多くのものを得られるにはどうしたらよいのでしょうか?
私の経験上、最も効果のある方法は“繰り返し”です。
先ほども言いましたように、本を一回読んだだけでそこからすべてを吸収できるなんてことはまず無理で、書かれている内容が今の自分のレベルから離れていればいるほど、いくら頑張って読んでも中身は全然頭に入ってきません。
まあ、書かれている内容が全く理解できない場合には、その本はあなたに必要のない本であるか、まだ今のあなたには早過ぎる本なのでしょう。ですが、全部がスッキリ理解できるまで待っていては、時間がいくらあっても足りません。少し分からない部分があるぐらいの段階で、どんどん挑戦していく方が、力が付くのも早まるでしょう。
もし、通して読むのは厳しいと思っても、ところどころ拾い読みできそうな場合には、ざっと目を通してみましょう。これはほとんど“読んでいる”ということにはならないかもしれませんが、とりあえず行けるところまでページをめくってみて、何か印象が残ればよしとします。
次は、忘れる作業です。
どうも、日本の学校教育で育ってくると(最近は違うのかも分かりませんが)、学習というのは記憶することだというふうに考えてしまう傾向があります。ですが、私はあえて「プログラミングの学習は記憶ではない」と申し上げておきます。
暗記することには、大した価値はありません。忘れることなど気にせずに、何度でもしつこく調べましょう。そのうち、調べなくても自然に頭から出てくるようになってしまいます。
で、パラパラと眺めるなりして一通り目を通した本は、とりあえず本棚にでもしまっておきます。まあ、できれば常に目に付くところに置いておくといいでしょう。そして、その本のことはとりあえず放っておいて、別の勉強をします(関連のあるジャンルのことだとよりベターですが、プログラミング関連であればよしとします)。しばらくすると、ふと「今なら、あの本をもう少し読めるもしれない」と思う時が来るかもしれません。その時さらにその本を読みたいという気持ちになっていたら最高です。迷わず手に取ってみましょう。あくまで、初めて読む本のように読み始めるのがポイントです。
読み進めてみて(それが無理なら、再び拾い読みでもいい)、「あれ、こんなこと書いてあったっけ?」と思ったら、ラッキーです。間違っても、「この部分は前に読んだから、適当に読んでおけばいいや」とは思わないでください。もし、「あれ、ここ、前にも読んだぞ」と感じて、一ページまるごと読んでも、一つも新しく読んだ気がしないとしたら、それはちょっと本棚に寝かす時間が少なすぎたのかもしれませんね。もう少し忘れるまでしまっておきましょう。
こんな形で、何度も繰り返して「読んでは、寝かせる」というサイクルを行っていると、そのうちその本が「まともに」読めるようになってきます。さらに面白いのは、ある程度「読めるようになった」と感じても、時間を空けて再度読み返すと、少なからず「あれ、こんなこと書いてあったっけ?」という部分が見つかることです。こういうことを繰り返していると次第に“行間も読める”ようになってきます。
まあ、以上は私のやってきた経験のお話ですので、必ずしもこの通り忠実にやる必要はないのかもしれません。ですが、私自身はこんなやり方で、最初は全く歯の立たなかった本を何冊も読めるようになりました。正直、「読んでは、寝かせて、また読んで…」という繰り返しを何度したかすら分かりませんが、本は大切に読むタイプの私であっても、その本が読めるようになった時には、手あかがついて、カバーの隅が切れかかるぐらいになったほどですから。
何より、「読めるようになった」ことの充足感は何ものにも代え難いものだったということは申し上げておきます。皆さんが、皆さんご自身の本や筆者とのコミュニケーション能力を磨いていく上で、私の経験談が参考になれば嬉しい限りです。
開発ツールよもやま話 Xcode3のスナップショット機能
高橋 政明
スナップショットはXcode3のファイルメニューにある簡易ソースコード管理機能です。
「スナップショットを作成」を選ぶだけでその時点のプロジェクトの状態を文字通りスナップショットとして保存します。スナップショットを作成するとファイルメニュー「スナップショット」項目が有効になり、スナップショットパネルを表示できます。パネルで作成したスナップショットにコメントをつけることができます。もちろん日本語入力もまったく問題なしです。
ソースを修正したあと区切りの良い時点でいつでもスナップショットパネルの「作成」アイコンクリックでスナップショットを作成できます。
通常の開発ではsubversionなど本格的なソースコード管理をおすすめしますが、実験コードやファイル数が少なく変更回数も少ないプロジェクトにはスナップショットが手軽です。
スナップショットの保存先はホーム直下のライブラリフォルダでパスは
~/Library/Application Support/Developer/Shared/SnapshotRepository.sparseimage
です。ディスクイメージファイルに圧縮されています。
このディスクイメージファイルはXcodeを終了すると開く事ができます。開くとArchivedDirectoriesフォルダとSnapshotArchive.plistがありす。plistに圧縮ファイル別のコメント情報などがあり、ArchivedDirectoriesの中に各プロジェクトがあります。ArchivedDirectoriesフォルダ内の各プロジェクトのパスはXcodeでスナップショットパネル内の『アーカイブ:』に表示されています。
ディスクイメージには変更の有無に関係なくすべてのファイルが保存されているようです。この点は変更のあったファイルの差分だけを保存して行く本格的なソースコード管理とは違います。ただしスナップショットパネルではスナップショットと現在の状態の差分を見る事ができます。
差分を見るにはスナップショットパネルのツールバー「ファイルを表示」アイコンをクリックします。ファイル名欄にはソースヘッダ以外にもXcodeのバンドル内部の開発には直接関係しないものも表示されるようです。ソースやヘッダファイルを選択すると違いを示す表示になります。右側が現在の内容で、左側が選択したスナップショットの内容になります。
差分表示はFileMergeなどでもおなじみの変更(追加/削除)部分の対応を明示した見やすいものです。この部分(スナップショットパネルの差分表示)では編集はできませんが、コピーはできますので、部分的にスナップショットの状態に手作業で戻すことは可能です。
全体をスナップショットに戻すにはツールバー「復元」アイコンをクリックします。復元操作もスナップショットに記憶されます。
スナップショットは手軽ですが、やはり長期で大規模な作業の必要なプロジェクトには本格的なソースコード管理が適します。ファイル別にコミットできるソースコード管理は運用しやすく便利です。
◆本日のまとめ
Xcode3のスナップショット機能は、本格的なリポジトリを用意するほどではない小規模なプロジェクトには手軽で便利。
スナップショットパネルには追加変更があったファイルだけ表示しているが全部を保存している。
ニュース解説 MOSAic
★★★ 開発関連のニュースはwebに掲載中 ★★★
http://www.mosa.gr.jp/?page_id=1017
・12月のニュース
http://www.mosa.gr.jp/?p=1476
◇MOSAからのお知らせと編集後記は割愛します◇