<?xml version="1.0" encoding="UTF-8"?>

<rdf:RDF
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:admin="http://webns.net/mvcb/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns="http://purl.org/rss/1.0/"
>

<channel rdf:about="http://articles.shibu.jp/">
<title>shibu.jp</title>
<link>http://articles.shibu.jp/</link>
<description>翻訳記事集</description>
<dc:language>ja</dc:language>
<admin:errorReportsTo rdf:resource="mailto:info@blog.sakura.ne.jp" />
<admin:generatorAgent rdf:resource="http://blog.sakura.ne.jp" />
<items>
<rdf:Seq>
<rdf:li rdf:resource="http://articles.shibu.jp/article/35008957.html" />
<rdf:li rdf:resource="http://articles.shibu.jp/article/34840060.html" />
<rdf:li rdf:resource="http://articles.shibu.jp/article/30833304.html" />
<rdf:li rdf:resource="http://articles.shibu.jp/article/30612137.html" />
<rdf:li rdf:resource="http://articles.shibu.jp/article/30549316.html" />
<rdf:li rdf:resource="http://articles.shibu.jp/article/30008337.html" />
<rdf:li rdf:resource="http://articles.shibu.jp/article/29464661.html" />
<rdf:li rdf:resource="http://articles.shibu.jp/article/29464627.html" />
<rdf:li rdf:resource="http://articles.shibu.jp/article/29464593.html" />
<rdf:li rdf:resource="http://articles.shibu.jp/article/29464527.html" />
<rdf:li rdf:resource="http://articles.shibu.jp/article/29464404.html" />
</rdf:Seq>
</items>
</channel>

<item rdf:about="http://articles.shibu.jp/article/35008957.html">
<title>iPadがKindleに勝てない10の理由</title>
<link>http://articles.shibu.jp/article/35008957.html</link>
<description>原著者： Arun 原題：Private Clouds Are Not The Future原文：http://arunshroff.com/2010/01/28/top-10-reasons-why-ipad-will-not-kill-kindle/原文公開日：JAN 28, 2010今日、TechCrunchに"iPadがAmazonのKindleを叩き潰す10の理由"という記事が投稿されました。確かに、iPad、特に$489のモデルは、Kindleに対抗しえるものをい...</description>
<dc:subject>EBook</dc:subject>
<dc:creator>しぶかわ</dc:creator>
<dc:date>2010-01-30T00:52:10+09:00</dc:date>
<content:encoded><![CDATA[
<p><b>原著者：</b> Arun <br/>
<b>原題：</b>Private Clouds Are Not The Future<br/>
<b>原文：</b><a href="http://arunshroff.com/2010/01/28/top-10-reasons-why-ipad-will-not-kill-kindle/">http://arunshroff.com/2010/01/28/top-10-reasons-why-ipad-will-not-kill-kindle/</a><br/>
<b>原文公開日：</b>JAN 28, 2010</p>

<p>今日、TechCrunchに"<a href="http://jp.techcrunch.com/archives/20100128top-10-reasons-ipad-kindle/">iPadがAmazonのKindleを叩き潰す10の理由</a>"という記事が投稿されました。</p>

<p>確かに、iPad、特に$489のモデルは、Kindleに対抗しえるものをいくつか持っています。しかし、たたきつぶせるのか？というと、私はそうは思えません。私が考える、iPadがKindleを倒せない10の理由を列挙します。</p>

<p>1) <b>価格:</b> 比較対象となる値段は、$269のKindleと、$499のiPadです。$269のKindleは、本を読むという目的では非常に良くできています。もしもAmazonがKindleの値段を$199に落としてきたら・・・勝ち目はありません。</p>

<p>2) <b>電子インク:</b> 読む楽しみを与えてくれます。これ以上言う必要はありませんよね？</p>

<p>3) <b>グレア:</b> iPadにはバックライトがあるので、長時間読書をする場合、目にやさしくありません。それに加えて、Kindleは直射日光下での読書もまったく問題ありません。ぜひiPadでもやってみてください。</p>

<p>4) <b>3G接続:</b> Kindleには3G機能が内蔵されていて無料で使えます。月々の支払はずっと 無料です！しかも世界中で、です。まず、iPadの3Gオプションを選択すると、$130のコストが余計にかかります。さらに、その3Gを使用する場合には、AT&Tに毎月$30(あるいは$15)のお金を支払い続ける必要があります。iPadにはさらに３つのネガティブな要素、申し込みの苦労、コスト、AT&Tの接続性の悪さもかかってきます。</p>

<p>5) <b>Amazon対iTunes:</b> Amazonから多くの本をダウンロードすることができます。それはApple/iTunesという監獄につながれるということは永遠にありません。Appleはなんでもコントロールしたがります。そして、しばらくはその姿勢は変わらないでしょう。</p>

<p>6) <b>サイズ:</b> KindleはiPadよりも小さく、携帯性にすぐれています。ちょうど本を持ち運ぶような感覚で、簡単に持ち運びできます。iPadはポータブルではありますが、タブレットかラップトップを持ち運んでいる感覚でしょう。</p>

<p>7) <b>重さ:</b> Kindleの0.6ポンド(292g)と比べて、iPadは1.5ポンド(680g)です。大抵、これに持ち運びやすさのための重さが追加されます(訳注：ケースとかのこと？)。そのため、Kindleは片手で疲れずに長時間持ち続けることができます。ぜひiPadで挑戦してみてください。</p>

<p>8) <b>バッテリーの持続時間:</b> Kindleは一回充電すると、軽々と2週間は使い続けることができます。これがKindleを長時間の飛行機の移動や、旅行などで本を読むには完璧なデバイスにしています。iPadのバッテリーは10時間持つとしていますが・・・ご存知の通り、実際のバッテリーはその半分ぐらいしか持たないでしょう。</p>

<p>9) <b>タッチ:</b> iPadはタッチデバイスです。そのため、読書をして、ページをめくる度に付く指の脂を常に掃除しなければならないでしょう。そのような問題はKindleにはありません。</p>

<p>10) <b>耐久性:</b> 最後にになりますが、私は落としてスクリーンが壊れるような心配をすることなく、Kindleを5歳と10歳の子供に与えることができました。iPadの高価でもろいパネルではそうはいかないでしょう。実際、Kindleは、子どもたちが毎日持ち運ばなければならないような、重い教科書の代わりを完璧に努めてくれるでしょう。</p>

<p>どのように思われましたか？コメントとフィードバックをお待ちしています。</p>

<div class="category_articles">
<a href="http://articles.shibu.jp/article/35008957.html">iPadがKindleに勝てない10の理由</a></div>
]]></content:encoded>
</item>
<item rdf:about="http://articles.shibu.jp/article/34840060.html">
<title>プライベートクラウドに未来はない</title>
<link>http://articles.shibu.jp/article/34840060.html</link>
<description>原著者：James Hamilton原題：Private Clouds Are Not The Future原文：http://perspectives.mvdirona.com/2010/01/17/PrivateCloudsAreNotTheFuture.aspx原文公開日：JAN 17, 2010クラウドコンピューティングは、エンタープライズのITの経済性を大幅に向上させるチャンスです。私たちは、より少ない投資で、本当に数多くのことができるようになります。私は、エンター...</description>
<dc:subject>Cloud Computing</dc:subject>
<dc:creator>しぶかわ</dc:creator>
<dc:date>2010-01-20T01:05:37+09:00</dc:date>
<content:encoded><![CDATA[
<p><b>原著者：</b>James Hamilton<br/>
<b>原題：</b>Private Clouds Are Not The Future<br/>
<b>原文：</b><a href="http://perspectives.mvdirona.com/2010/01/17/PrivateCloudsAreNotTheFuture.aspx">http://perspectives.mvdirona.com/2010/01/17/PrivateCloudsAreNotTheFuture.aspx</a><br/>
<b>原文公開日：</b>JAN 17, 2010</p>

<p>クラウドコンピューティングは、エンタープライズのITの経済性を大幅に向上させるチャンスです。私たちは、より少ない投資で、本当に数多くのことができるようになります。</p>

<p>私は、エンタープライズITというのは、競争を勝ち抜くための武器であり、すべての業界において、業界のリーダーとなる企業は情報処理に対して、さらなる投資を行い続けるでしょう。それぞれの市場セグメントの中で一番となる会社は、その投
資のおかげで情報処理のエキスパートとなり、顧客についても良く理解して、サプライヤーの選択をするときにも適切な相手を選ぶことができるようになり、深い知識をもってサプライチェーンをコントロールできるようになり、驚くほど効率的な配送システムを構築するでしょう。情報処理への投資のおかげで、すべての仕事の質と効率が高められます。これらは、小売企業、金融系企業、油田開発企業、製薬業、スポーツチーム、ロジスティックスの企業などの未来の現実です。これらの現実から逃れられるセグメントはないでしょう。また、多くのセグメントは、もう現実となっています。競争相手以上のITへの投資というものが、唯一、顧客と株主へ報いる手段となっています。</p>

<p>私には、情報技術への投資こそが、すべての成功を収めた企業の未来につながる道であることは明らかです。また、現在もほぼそのような状態になっています。これに関して、朗報があります。コストをより低減し、効率的にして、環境への影響も少ない方法です。それはクラウドコンピューティングを利用することです。私たちは、より少ない投資で、本当に数多くのことができるようになります。</p>

<p>クラウドコンピューティングに関する議論は業界レベルでは承認を獲得することができています。しかし、何人かの企業とアナリストはエンタープライズのITインフラの経済性を向上させる方法として、プライベートクラウドというものにこだわっています。私の感覚では、歩き出す方向性としては正しいと思うのですが、規模の経済によって受ける恩恵は、リアルはクラウドコンピューティングよりも効果が低いと考えています。違いはなんでしょうか？スケールの面で、理想スを共有する枠組みの範囲内であれば、よりよいサービスを少ないコストで使うことができるようになります。高性能なリソースも使用ができます。コストと、リソースの利用の利点については、後ほど詳細に見て行きます。</p>

<p>大規模なスケールにおいては、配電、機械システムのエキスパートのチームを持つことが、手頃な値段と性能を獲得するための手段となります。主要なクラウドコンピューティングのプロバイダーは、これらのチームを持ち、コストを下げたり効率を上げたりして、より環境に良いと言えるように、新しい技術に投資をしています。10数メガワット未満では、スケールさせてもコスト・効率を良くして行くのは難しいです。同じような議論を他のドメインにも広げると、クラウドコンピューチングのプロバイダーは、サーバおよび記憶装置に特化したチームを持っているでしょう。彼らはネットーワークに関するハードとソフトウェアに深く投資をしています。これらはすべて、プライベートクラウドの範囲のスケールでは正当化しにくいものです。</p>

<p>クラウドコンピューティングのプロバイダーには、24時間、年中無休でサービスをモニターしたり、顧客の問題に対応するスタッフを抱えています。サービスのモニターを行うというのは、極めて難しいことです。数メガワット以下の規模で、それらをうまく行っている例を私はまだ見たことがありません。</p>

<p>クラウドコンピューティングのプロバイダーには、世界で最も優秀な、分散システムの専門家が何人も所属しています。オープンソースに関するエキスパートもいて、オープンソースと、内部で作成したソフトウェアの両方に対して、深く依存しています。このようにしている理由には２つあります: 1) 高度にスケールすると、今まで全く考えていなかった、ワクワクするような理由でシステムが失敗しますが、その際にうまく扱えるかどうかは、ハードウェアとソフトウェアの両方に関する深い知識があるかどうかにかかっていて、 2) 効率のために高度にスケール場合には、ほとんどのクラウドサービスのすばらしい経済性を達成するには、ソフトウェアのライセンスのコストとは両立しないからです。</p>

<p>リソースの活用というのは、未だに、高度にスケールした共有のインフラ上のクラウドに移行が行われるだろう、ということに対しての、強い論拠になっています。スケールにおいては、顧客の多様性が高ければ、クラウドの素晴らしい特性である、「相互に関連のないピーク」が現れます。会社ごとに、ピークの負荷に耐え切れる能力を供給しなければなりませんが、共有されたクラウドで実行されていれば、負荷のピークと底の間で、スムーズに実行が行えます。11月の販売のピーク、4月の税金のピーク、4半期の終わりごとの金融ビジネスのピークなど、これらの多くの負荷はそれぞれ毎日、週ごと、年ごとなどのサイクルを持っていて、それらを重ねあわせになります。例えば、マイケル・ジャクソン死去のニュースは、いくつかの領域で重い負荷を与えることになりましたが、ほとんどなかった領域もあるでしょう。東海岸の巨大な嵐のニュースは、いくつかのビジネスでは大規模なピークを与えることになりますが、ほとんどなかったという企業もあるでしょう。大量の多様な負荷をまとめて考えると、少ししかスケールできない場合よりも、利用レベルが平均的に高いレベルになるという傾向があります。プライベートクラウドでは、共有クラウドで達成されているような、高い利用レベルは達成することができません。</p>

<p>先週、Alistair Croll氏は<a href="ttp://www.informationweek.com/">InformationWeek</a>に素晴らしい記事を書きました。
<blockquote>
正しいクラウドの利用者には必ずコスト面でのアドバンテージがあります。なぜな
ら、クラウドの利用者全員がいつも注目しているのはコストだからです。また、彼
らは消費者により近い位置にいます。というのも、どこにでもプログラム運用計画
(POP)があり、コンテンツ配信システムとパートナーシップを結んでいるからで
す。消費者とパートナーを結びつけるということは、エンタープライズのIT戦略に
おいて、ますます不可欠な部分になっていくでしょう。
</blockquote>
<a href="http://www.informationweek.com/news/services/saas/showArticle.jhtml?articleID=222300587&pgno=1&queryText=&isPrev">プライベートなクラウドを見ると、固定化していて、未来はありません。</a></p>

<p>プライベートクラウドへの投資は、一時的な対処法で最終目的地である、共有クラウドにたどり着くのを遅くする以上の価値はありません。プライベートクラウドで行くという決定は、利用レベルを低く使用という決定であり、多くのパワーを無駄に消費します。環境面での効果も低下し、高いコストがかかります。</p>

<div class="category_articles">
<a href="http://articles.shibu.jp/article/34840060.html">プライベートクラウドに未来はない</a></div>
]]></content:encoded>
</item>
<item rdf:about="http://articles.shibu.jp/article/30833304.html">
<title>EEP8: 型と関数の仕様定義</title>
<link>http://articles.shibu.jp/article/30833304.html</link>
<description>原文：http://www.erlang.org/eeps/eep-0008.html訳注: -compiler attributeは、プログラミングErlangに準拠して、「モジュール属性」としています。termはそのままtermとしています。EEP: 8Title: 型と関数の仕様定義Version: $Revision: 52 $Last-Modified: $Date: 2008-10-30 15:20:25 +0100 (Thu, 30 Oct 2008) $Aut...</description>
<dc:subject>EEP</dc:subject>
<dc:creator>しぶかわ</dc:creator>
<dc:date>2009-07-26T11:51:58+09:00</dc:date>
<content:encoded><![CDATA[
<p><b>原文：</b><a href="http://www.erlang.org/eeps/eep-0008.html">http://www.erlang.org/eeps/eep-0008.html</a></p>

<p>訳注: -compiler attributeは、プログラミングErlangに準拠して、「モジュール属性」と
しています。termはそのままtermとしています。</p>

<hr/>

<pre>EEP: 8
Title: 型と関数の仕様定義
Version: $Revision: 52 $
Last-Modified: $Date: 2008-10-30 15:20:25 +0100 (Thu, 30 Oct 2008) $
Author: Tobias Lindahl [tobias(dot)lindahl(at)it(dot)uu(dot)se], Kostis
Sagonas [kostis(at)it(dot)uu(dot)se]
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 2-Dec-2007
Erlang-Version: R12B
Post-History:</pre>

<h3>目次</h3>
<ul>
  <li><a href="#sec1">概要</a></li>
  <li><a href="#sec2">論拠</a></li>
  <li><a href="#sec3">仕様</a></li>
  <ul>
    <li><a href="#sec3_1">型とシンタックス</a></li>
    <li><a href="#sec3_2">ユーザ定義型の型宣言</a></li>
    <li><a href="#sec3_3">レコード宣言の中の型情報</a></li>
    <li><a href="#sec3_4">関数の仕様(契約)</a></li>
    <li><a href="#sec3_5">現在の仕様の制限</a></li>
  </ul>
  <li><a href="#sec4">著作権</a></li>
</ul>

<a name="sec1"><h3>概要</h3></a>

<p>このEEPは、ある型や、効率的にすべてのErlangの語彙(term)のサブタイプを
宣言するためのErlang言語拡張について説明します。これらの型は、レコードの
フィールドや、関数の引数、返り値で使用することができます。</p>

<a name="sec2"><h3>論拠</h3></a>

<p>型情報を利用することで、関数のインタフェースを説明したり、
Dialyzerなどのバグ検出ツールに対してより詳しい状況説明を提供したり、
Edocなどのさまざまな形式でプログラムのドキュメントを生成することができる、
ドキュメンテーションツールが詳しい情報を取得できるようになります。
このドキュメントで説明している型システムに期待されることは、Edocで使用されている、
@typeや@specなどのコメントベースの説明よりも使われるようになって、置き換わることです。</p>

<a name="sec3"><h3>仕様</h3></a>

<a name="sec3_1"><h4>型とシンタックス</h4></a>

<p>型はErlangのtermのセットに対して説明します。型は、既定の型の集合で構成され、
組み立てられます。既定の型というのは、<tt>integer()</tt>,
<tt>atom()</tt>, <tt>pid()</tt>などになります。これについては、後ほど説明します。
既定の型は、これらの型に属す、Erlangのtermの集合によって表現されます。
たとえば、<tt>atom()</tt>はアトムの集合を意味します。</p>

<p>数値とアトムのシングルトン型としては、数値の<tt>-1</tt>, <tt>42</tt>、あるいはアトム
の<tt>'foo'</tt>, <tt>'bar'</tt>が該当します。</p>

<p>他のすべての型は、既定の型、もしくはシングルトン型の集合を使って組み立てていきます。
もし、あるタイプと、そのサブタイプの両方を構成要素とする型があったとすると、
サブタイプは吸収されてなくなり、そのサブタイプは、
集合の要素として最初から定義されていなかったかのように扱われます。
例えば以下のような集合があったとします。

<pre>   atom() | 'bar' | integer() | 42</pre>

<p>これは以下のtermのセットで定義された型集合と同じ意味になります。</p>

<pre>   atom() | integer()</pre>

<p>型同士の間にあるサブタイプの関係により、
すべてのErlangのtermを含む最上位要素の<tt>any()</tt>から、
termの空集合を表す最下層の要素の``none()``との間で、
すべての型はラティス構造を形成します。(訳注：完全な木構造にはならない、という意味だと思われる)</p>

<p>以下に示されているが、既定の型の集合です。また、
型に関するシンタックスについても示します。</p>

<pre>   Type :: any()            %% トップの型。すべてのErlangのtermを含む
         | none()           %% 最下層の方。termを含まない
         | pid()
         | port()
         | ref()
         | []               %% nil
         | Atom
         | Binary
         | float()
         | Fun
         | Integer
         | List
         | Tuple
         | Union
         | UserDefined      %% <a href="#sec3_2">ユーザ定義型</a>の項で説明する

   Union :: Type1 | Type2

   Atom :: atom()
         | Erlang_Atom      %% 'foo', 'bar', ...

   Binary :: binary()                        %% <<_:_ * 8>>
           | <<>>
           | <<_:Erlang_Integer>>            %% 基数(Base size)
           | <<_:_*Erlang_Integer>>          %% 単位サイズ(Unit size)
           | <<_:Erlang_Integer, _:_*Erlang_Integer>>

   Fun :: fun()                              %% あらゆる関数
        | fun((...) -> Type)                 %% あらゆる引数と返り値のタイプ
        | fun(() -> Type)
        | fun((TList) -> Type)

   Integer :: integer()
            | Erlang_Integer                 %% ..., -1, 0, 1, ... 42 ...
            | Erlang_Integer..Erlang_Integer %% 整数の範囲を示したもの


   List :: list(Type)                        %% Proper list ([]-終端)
         | improper_list(Type1, Type2)       %% Type1=中身, Type2=終端
         | maybe_improper_list(Type1, Type2) %% Type1とType2は↑と同様

   Tuple :: tuple()                          %% あらゆるサイズのタプルに適合
          | {}
          | {TList}

   TList :: Type
          | Type, TList</pre>

<p>リストは一般的によく使用されるため、リストには短縮型表記法がいくつか設定されています。
<tt>list(T)</tt> は短縮して、 <tt>[T]</tt> と書くことができます。 
<tt>[T,...]</tt> という短縮形は<tt>T</tt>型の要素を持つ、空でないリストを表します。
<tt>[T]</tt>と<tt>[T,...]</tt>の唯一の違いは、
<tt>[T]</tt>は空のリストになる可能性があるが、
<tt>[T,...]</tt>は空になることはないという点だけです。</p>

<p>注意して欲しいのは、 <tt>list()</tt> の短縮形、
つまり未知の型を要素に持つリストの短縮形は
<tt>[_]</tt>(あるいは<tt>[any()]</tt>)になります。<tt>[]</tt>ではありません。
<tt>[]</tt>という表記は、空のリストに対するシングルトン型を表します。</p>

<p>表記を便利にするために、以下のような型も組み込みで定義されています。
表の中の型の集合に対する、定義済みの別名として、見ることができます。
いくつかの型の集合は、これからの説明の中で頻繁に使います。</p>

<table>
<tr><th>組み込み型</th><th>同値の定義</th></tr>
<tr><td><tt>term()</tt></td><td><tt>any()</tt></td></tr>
<tr><td><tt>bool()</tt></td><td><tt>'false' | 'true'</tt></td></tr>
<tr><td><tt>byte()</tt></td><td><tt>0..255</tt></td></tr>
<tr><td><tt>char()</tt></td><td><tt>0..16#10ffff</tt></td></tr>
<tr><td><tt>non_neg_integer()</tt></td><td><tt>0..</tt></td></tr>
<tr><td><tt>pos_integer()</tt></td><td><tt>1..</tt></td></tr>
<tr><td><tt>neg_integer()</tt></td><td><tt>..-1</tt></td></tr>
<tr><td><tt>number()</tt></td><td><tt>integer() | float()</tt></td></tr>
<tr><td><tt>list()</tt></td><td><tt>[any()]</tt></td></tr>
<tr><td><tt>maybe_improper_list()</tt></td>
    <td><tt>maybe_improper_list(any(), any())</tt></td></tr>
<tr><td><tt>maybe_improper_list(T)</tt></td>
    <td><tt>maybe_improper_list(T, any())</tt></td></tr>
<tr><td><tt>string()</tt></td><td><tt>[char()]</tt></td></tr>
<tr><td><tt>nonempty_string()</tt></td><td><tt>[char(),...]</tt></td></tr>
<tr><td><tt>iolist()</tt></td><td><tt>maybe_improper_list(<br/>
            char() | binary() | <br/>
            iolist(), binary() | [])</tt></td></tr>
<tr><td><tt>module()</tt></td><td><tt>atom()</tt></td></tr>
<tr><td><tt>mfa()</tt></td><td><tt>{atom(), atom(), byte()}</tt></td></tr>
<tr><td><tt>node()</tt></td><td><tt>atom()</tt></td></tr>
<tr><td><tt>timeout()</tt></td>
    <td><tt>'infinity' | non_neg_integer()</tt></td></tr>
<tr><td><tt>no_return()</tt></td><td><tt>none()</tt></td></tr>
</table>

<p>既定の型、および、組み込み型と同じ名前の型をユーザが定義することはできません。
これはコンパイラによってチェックされ、問題があれば、
コンパイルエラーとして結果が通知されます。
最初に説明した目的のために、もし組み込み型に対して同様のことを行った場合には、
警告が発生します。</p>

<blockquote><p><b>NOTE</b>: 以下のような組み込みのリスト型も存在しますが、
ほとんど使われないことを想定しています。そのために長い名前がついています。</p>
<pre>nonempty_maybe_improper_list(Type) :: nonempty_maybe_improper_list(Type, any())
nonempty_maybe_improper_list() :: nonempty_maybe_improper_list(any())</pre>
<p>以下の二つのは型は期待されるErlangのtermのセットを定義するのに使用されます(訳不安)。
<pre>nonempty_improper_list(Type1, Type2)
nonempty_maybe_improper_list(Type1, Type2)</pre>
</blockquote>

また、便利に使うために、レコード記法も使用できるようになっています。
レコードは対応するタプルを短く書く記法になります。

<pre>   Record :: #Erlang_Atom{}
           | #Erlang_Atom{Fields}</pre>

<p>レコードは型情報も入れることができるように拡張されました。これについての詳
細は<a href="#sec3_3">レコード宣言の中の型情報</a>にて説明していきます。</p>

<a name="sec3_2"><h4>ユーザ定義型の型宣言</h4></a>

<p>今までに見てきたように、型の基本的なシンタックスは丸括弧が後ろについたアトムになります。
<tt>'type'</tt>コンパイラ属性を利用して新しい型を宣言する方法は以下のようになります。

<pre>   -type my_type() :: Type.</pre>

<p>型名は、後ろに丸括弧のついたアトム(この例では <tt>'my_type'</tt>)になります。
Typeは今までのセクションで説明してきたような型です。現在の制限としては、
Typeに指定できるのは、既定の型、もしくはそれまでに出てきたユーザ定義型
のみになります。この制限に引っかかると、コンパイルエラーとして通知されます。
同様の制限がレコードに関しても存在します。</p>

<p>この制約があるために、現在では、再帰的な型の定義を一般的に行うことはできません。
この制約をどのようにはずしていくか、ということに関しては今後の課題になります。</p>

<p>型宣言では、型変数を丸括弧の中に含めることによりパラメータ化することもできます。
型変数を使うための文法は、Erlangの変数と同じで、最初の文字を大文字から開始します。
当然、これらの変数は、宣言の右側に書くことができますし、書かなければなりません。
具体的なサンプルを以下に示します。</p>

<pre>   -type orddict(Key, Val) :: [{Key, Val}].</pre>

<a name="sec3_3"><h4>レコード宣言の中の型情報</h4></a>

<p>レコードに含まれる、フィールドの型についても、レコード宣言の中で定義するこ
とができます。</p>

<pre>   -record(rec, {field1 :: Type1, field2, field3 :: Type3}).</pre>

<p>型の指定がないフィールドは、デフォルトでは<tt>any()</tt>の型であるという扱いになります。上記のサンプルは以下の書き方を省略したのと同じになります。</p>

<pre>   -record(rec, {field1 :: Type1, field2 :: any(), field3 :: Type3}).</pre>

<p>フィールドの初期値がある場合には、以下のように初期化が終わった後に型宣言を
置く必要があります。</p>

<pre>   -record(rec, {field1 = [] :: Type1, field2, field3 = 42 :: Type3}).</pre>

<p>当然のことながら、フィールドの初期値は、指定された型(複数選択肢がある場合はそのひとつに)
に準拠した値である必要があります。これはコンパイラによってチェックされ、
問題があれば、コンパイルエラーになります。初期値が存在しないフィールドについては、
<tt>'undefined'</tt>というシングルトン型がすべての型宣言に対して追加されます。
実際の例で説明すると、次に説明する２つのレコードは、処理系の中では、
まったく同じものとして扱われます。</p>

<pre>   -record(rec, {f1 = 42 :: integer(),
                 f2      :: float(),
                 f3      :: 'a' | 'b').

   -record(rec, {f1 = 42 :: integer(),
                 f2      :: 'undefined' | float(),
                 f3      :: 'undefined' | 'a' | 'b').</pre>

<p>これらの理由から、可能な場合には常に、レコードの初期化を行うことをお勧めします。</p>

<p>あらゆるレコードは、型情報を持つか持たないか、のどちらかになります。一度定義すると、
下記のようなシンプルなシンタックスで型を使用することができます。</p>

<pre>   #rec{}</pre>

<p>さらに、レコードのフィールドは使用時にも仕様を設定することができます。
レコード型を使用するときに、以下のようにフィールドに関する型情報
を足すことで、指定することができます。</p>

<pre>   #rec{some_field :: Type}</pre>

<p>この場合、型情報が設定されなかったフィールドに関しては、オリジナルの
レコード宣言の情報が設定されているものとして実行します。</p>

<a name="sec3_4"><h4>関数の仕様(契約)</h4></a>

<p>新しいモジュール属性の ``'spec'`` を使用することで、関数の契約(あるいは仕様)
を記述することができます。基本的な書き方のルールは以下のようになります。</p>

<pre>   -spec Module:Function(ArgType1, ..., ArgTypeN) -> ReturnType.</pre>

<p>関数の引数の数は、実際の関数と、使用の宣言で一致している必要があります。
もし一致しない場合には、コンパイラエラーになります。</p>

<p>この形式の書き方はヘッダファイル(.hrl)の中で、エクスポートされた関数の型情報
を宣言するのにも使用することができます。これらの情報が書かれたヘッダファイル
をインクルードすると、これらの関数がインポートされて(場合によっては暗黙的に
インポートされる場合もあります)使用できるようになります。</p>

<p>モジュール内部だけで使用する場合には、ほとんどの場合は下記のような、モジュール名を
省略した短縮系で使用されます。</p>

<pre>   -spec Function(ArgType1, ..., ArgTypeN) -> ReturnType.</pre>

<p>また、ドキュメント化する目的で、引数に名前を設定することもできます。</p>

<pre>   -spec Function(ArgName1 :: Type1, ..., ArgNameN :: TypeN) -> RT.</pre>

<p>関数定義は、オーバーロードさせて、複数のタイプを持たせることができます。
その場合は、セミコロン(;)を使用して、それぞれのパターンを区切って指定します。</p>

<pre>   -spec foo(T1, T2) -> T3
          ; (T4, T5) -> T6.</pre>


<p>現在の制限としては、引数の型がオーバーラップしていると、コンパイラが
警告を発します。エラーにはなりません。例えば、以下のような仕様定義を
すると警告が発生します。</p>

<pre>   -spec foo(pos_integer()) -> pos_integer()
          ; (integer()) -> integer().
</pre>


<p>型の変数を使って、関数の入出力の引数関係の定義を行うことができます。
以下のサンプルでは、ポリモーフィックな識別を行う関数の定義を行っています。</p>

<pre>   -spec id(X) -> X.</pre>

<p>しかし、上記の定義では入力と出力の型について制約を与えることはできません。
ガードのように、特定の型のサブタイプであるという制約をかけるやり方を使用することができます。
</p>

<pre>   -spec id(X) -> X when is_subtype(X, tuple()).</pre>

<p>数量の境界に関しても、制約をかけることができます。現在は、
<tt>is_subtype/2</tt>ガードは、<tt>'spec'</tt>属性中でのみ使用することができます。</p>

<p><tt>is_subtype/2</tt>制約のスコープは、それが適用された後の
<tt>(...) -> RetType</tt>定義までになります。混乱を避けるために、
以下のような引数のオーバーロードがある場合には、それぞれの制約の定義では、
それぞれ別の変数を使用することをおすすめします。</p>

<pre>   -spec foo({X, integer()}) -> X when is_subtype(X, atom())
          ; ([Y]) -> Y when is_subtype(Y, number()).
</pre>

<p>Erlangの関数の中には値を返さない物もあります。サーバを定義するものであったり、
以下のように例外を投げるのに使用される関数であったり、というのが主要なケースです。</p>

<pre>   my_error(Err) -> erlang:throw({error, Err}).</pre>

<p>このような関数においては、<tt>no_return()</tt>という<b>特殊な返り値</b>を返すものとして、定義することをおすすめします。</p>

<pre>   -spec my_error(term()) -> no_return().</pre>

<a name="sec3_5"><h4>現在の仕様の制限</h4></a>

<p>現在の使用の一番大きな制約は、再帰を用いた型の定義ができないことです。</p>

<a name="sec4"><h3>著作権</h3></a>

<p>このドキュメントはパブリックドメインです。</p>

<div class="category_articles">
<a href="http://articles.shibu.jp/article/30833304.html">EEP8: 型と関数の仕様定義</a><br/>
</div>
]]></content:encoded>
</item>
<item rdf:about="http://articles.shibu.jp/article/30612137.html">
<title>Erlang用の軽量ユニットテストフレームワーク</title>
<link>http://articles.shibu.jp/article/30612137.html</link>
<description>原著者：Copyright 2004-2009 Mikael Remond, Richard Carlsson原文：http://erlang.org/doc/apps/eunit/ 原文更新：2009 EUnitはErlang用のユニットテストフレームワークです。とてもパワフルで柔軟かつ、使用するのが簡単であり、構文上のオーバーヘッド(書かなければいけないもの)が少ないのが特徴です。 EUnitは、ケント・ベックと、エリック・ガンマが作成したJUnit(と、ケント・ベックが...</description>
<dc:subject>EUnitユーザーズガイド</dc:subject>
<dc:creator>しぶかわ</dc:creator>
<dc:date>2009-07-17T17:17:29+09:00</dc:date>
<content:encoded><![CDATA[
<a name="top"></a>
<p><b>原著者：</b>Copyright 2004-2009 Mikael Remond, Richard Carlsson<br/>
<b>原文：</b><a href="http://erlang.org/doc/apps/eunit/">http://erlang.org/doc/apps/eunit/</a><br/> 
<b>原文更新：</b>2009</p> 

<p>EUnitはErlang用のユニットテストフレームワークです。とてもパワフルで柔軟かつ、使用するのが簡単であり、構文上のオーバーヘッド(書かなければいけないもの)が少ないのが特徴です。</p> 

<p>EUnitは、ケント・ベックと、エリック・ガンマが作成したJUnit(と、ケント・ベックがそれ以前に作成した、Smalltalk用のSUnit)を起源とする、オブジェクト指向言語用のユニットテストフレームワーク群から来たアイディアを元に開発されています。しかし、EUnitは、より関数型プログラミングと、並列プログラミングに適応するような技術が使用されています。また、関連するフレームワーク群よりも、言葉数が少なくて済むことが多いです。</p> <p>EUnitは多くのプリプロセッサマクロを使用しますが、利用者にできるだけ負担をかけないように設計されています。また、既存のコードと衝突を起こさないように設計されています。モジュールにEUnitのテストを追加する際には、通常は既存のコードに変更を加える必要がありません。これに加え、モジュールのエクスポートされた関数をテストするだけであれば、いつでも、完全に分割したモジュールにテストをおくことができます。何らかの衝突が起きることはありません。</p> 

<a name="1_1"><h3>1.1 ユニットテスト</h3></a>

<p>ユニットテストは、お互いに分離されている「ユニット」という単位で個別にテストを行う方法です。ユニットは特定のサイズにしなければならない、ということはありません。ユニットが一つの関数であることもあるし、モジュールを示すこともあります。またプロセスはアプリケーション全体を一つのユニットと呼ぶこともあります。が、多くのケースにおいては、テストを行うユニットは、複数の関数、もしくはモジュールであることが多いです。ユニットをテストするためには、個別のテストをいくつか用意したり、これらのテストを実行するのに必要な最小限の環境を作るためのセットアップ(通常、設定が必要でないケースがほとんどですが)を行ったり、テストを実行して結果を収集したり、後でテストを再実行するために最後に必要となる片付けを行ったりします。ユニットテストのフレームワークを使用することで、これらのプロセスのそれぞれの段階の作業を軽減することができて、テストを書くのがラクになります。そしてテストを実行するのも簡単になり、どのテストが失敗したかが簡単に確認できるようになり、バグを修正することができるようになります。</p> 

<h4>1.1.1 ユニットテストのメリット</h4> 

<h5>プログラム変更のリスクを削減する</h5> 

<p>ほとんどのプログラムは、作成されてから破棄されるまでの間に変更されるでしょう。バグがあれば修正され、機能が追加され、必要になれば最適化が行われ、また、リファクタリングやコードの整理が必要となれば、同じ機能を達成するやり方の別の方法に修正されます。しかし、動作しているプログラムに対して、これらの変更を加えることは、新しいバグや、既に修正済みのバグを再び入れ込んでしまうリスクを常に孕んでいます。少ない手間ですぐに実行できるユニットテスト群があれば、簡単にコードが期待通りに動作するかどうかを知ることができます。このようなテストをリグレッションテストあるいは、<b>回帰テスト</b>(<a href="#1_2">用語集</a>を参照)と呼ばれます。これは、コードの変更や、リファクタリングをする抵抗を減らすのに役に立ちます。</p> 

<h5>開発プロセスの遵守とスピードアップ</h5> 

<p>テストをパスするコードを開発するのにフォーカスするため、プログラマはより生産的になります。仕様以上に作り込んでしまうこともなくなりますし、不必要な最適化をしてしまうことも防げます。最初から正しいコードを作成することができるようになります。これは<b>テスト駆動開発</b>と呼ばれます(<a href="#1_2">用語集</a>を参照)。</p>
<h5>インタフェースと実装の分離に役立つ</h5>

<p>テストを書いている時に、テストの実行とは関係のない、そこにあるべきではない依存関係があるのを見つけるかもしれません。よりクリーンな設計をするためにこのような依存関係は取り除く必要があります。早めにこのような依存関係を切っていくことで、コード中に悪い依存関係が広がっていくのを未然に防ぐことができます。</p>

<h5>部品の統合を簡単に</h5>

<p>ボトムアップでテストをしていくことで、小さいプログラムのユニットから開発を開始することができ、期待通りに動作するという信頼性も生まれます。これにより、テスト済みのユニットを組み合わせて作る、上位のレベルの部品が仕様通りに動作するかのテストも簡単になります。これは<b>統合テスト</b>(<a href="#1_2">用語集</a>参照)と呼ばれます。</p>

<h5>ドキュメントになる</h5>

<p>テストはドキュメントとしても読むことができます。テストを見れば、正しい使用法と、正しくない使用方法、そして期待される結果が分かります。</p>

<a name="1_2"><h3>1.2 用語集</h3></a>

<h4>ユニットテスト</h4>

<p>プログラムユニットが、仕様に従って、期待通りに動作するかどうかのテストになります。ユニットテストは、リグレッションテストを書く場合にも重要な構成要素となります。リグレッションテストというのは、何らかの理由でコードが変更された場合に、仕様通りの動作を保っているかどうかをチェックするものになります。</p>

<h4>リグレッションテスト(回帰テスト)</h4>

<p>プログラムに変更を加えたあとにテストを実行し、以前と同じようにプログラムが動作するかどうかチェックすることです。もちろん、意図して変更した振る舞いは除きます。ユニットテストはリグレッションテストとして重要ですが、リグレッションテストは単にユニットテストの範疇に収まるものではありません。バグや互換性など、テストの振る舞いは通常の仕様とは異なるものです。</p>

<h4>統合テスト</h4>

<p>個別に開発されたプログラムのユニット(それぞれのユニットは個別にユニットテストされているものとします)を統合したときに、期待通りに動作するかどうかをテストすることを指します。システムの開発された方法により、統合テストは単に「階層の違うユニットテスト」と同等の場合もありますが、他の種類のテストも含みます。<b>システムテスト</b>との違いを確認してください。</p>

<h4>システムテスト</h4>

<p>すべてのユニットを組み合わせた完全なシステムが、仕様通りに動作するかどうか検証します。具体的には、システムテストでは実装の詳細の知識が要求されるようなものであってはいけません。システムテストには、基本的な機能性とは別に、様々な異なる側面から見たシステムの振る舞いに関するテストを含みます。例えば、パフォーマンスや、ユーザビリティ、信頼性などになります。</p>

<h4>テスト駆動開発</h4>

<p>テストを実装コードよりも<b>先に書いて</b>、その後にテストをパスする最小の実装を行うことによりソフトウェアを開発していくという、プログラム開発テクニックです。この方法を使うと、正しい問題を解決することにのみフォーカスします。そして、ユニットテストによって、そのプログラムが完了した後の姿を決定することで、必要以上に実装が複雑になることを防ぎます。もしテストをパスして仕様を満足したあとは、それ以上機能を追加する必要はないのですから。</p>

<h4>モックオブジェクト</h4>

<p>他のユニットB(引数として渡されるか、参照される)と何らかの連携を行う必要のある、ユニットA(例えば関数)をテストする必要があり、なおかつユニットBの実装が完了していない、というケースが時々あります。この場合に、ユニットAをテストするために、本物のBと同じような振る舞いをするニセ者を代わりに利用することがあります。これを「モックオブジェクト」と呼びます。もちろん、これは本物のユニットBを実装する方が、モックオブジェクトを作るよりも大変である場合にのみ役立ちます。</p>

<h4>テストケース</h4>

<p>明確に定義され、識別可能なテストの最小単位です。実行されると、テストケースは<b>パス</b>するか、<b>失敗</b>するかのどちらかになります。テストのレポートでは、どのテストケースが失敗したか明確に区別されなければなりません。</p>

<h4>テストスイート</h4>

<p>テストケースを集めたものになります。一般的には、とある関数や、モジュール、サブシステムなど、共通のターゲットに対するテストを集めたものになります。テストスイートは、他の小さなテストスイートを含んだ、再帰的な構造として作成することもできます。</p>

<a name="1_3"><h3>1.3 テストをはじめよう</h3></a>

<ul>
<li><a href="#1_3_1">EUnitヘッダファイルのインクルード</li>
<li><a href="#1_3_2">シンプルなテスト関数を書く</li>
<li><a href="#1_3_3">EUnitの実行</li>
<li><a href="#1_3_4">サンプル</li>
<li><a href="#1_3_5">テストを生成する関数を書く</li>
<li><a href="#1_3_6">テストの無効化</li>
<li><a href="#1_3_7">コンパイル時のEUnitへの依存を回避する</li>
</ul>

<a name="1_3_1"><h4>1.3.1 EUnitヘッダファイルのインクルード</h4></a>

<p>EUnitをErlangのモジュールで使用する、一番簡単な方法は、モジュールの先頭(-module宣言の直後で、他の関数宣言の前)に以下の行を追加するやり方になります。</p>

<pre name="code" class="python">-include_lib("eunit/include/eunit.hrl").</pre>

<p>この行を追加すると以下のような効果が現れます。</p>

<ul>
<li>エクスポートされるtest()関数が作成されます。ただし、テスト機能がオフになっていたり、モジュール内に既にtest()関数が含まれている場合を除きます。この関数は、モジュール内に定義されているユニットテストをすべて実行するのに使用することができます。</li>

<li>_test()、もしくは_test_()という名前にマッチするすべての関数をモジュールから外にエクスポートします。これも、テスト機能がオンになっているか、EUNIT_NOAUTOマクロが定義されていない場合のみ動作します。</li>
<li>テストを書くのを手助けするすべてのEUnitのプリプロセッサマクロを使用可能にします。</li>
</ul>

<p><b>Note:</b> -include_lib(...)が実行可能になるためには、Erlangのモジュールサーチパスにはeunit/ebinで終わる名前を持つディレクトリ(EUnitインストールディレクトリのebinサブディレクトリ)が含まれる<b>必要があります</b>。もし EUnitが lib/eunitのような、Erlang/OTPのシステムディレクトリにインストールされている場合には、ebinサブディレクトリはErlangの起動時に自動的にサーチパスに追加されます。そうでない場合には、erlコマンド、もしくはerlcコマンドに-paフラグを渡して、サーチパスにきちんと追加する必要があります。例えば、.erlファイルをコンパイルするアクションがMakeファイルに書かれていたとすると、以下のように書きます。</p>

<pre name="code" class="python">erlc -pa "path/to/eunit/ebin" $(ERL_COMPILE_FLAGS) -o$(EBIN) $&lt; </pre>

<p>あるいは、Erlangをインタラクティブに実行する場合に、常にEUnitを有効にしたい時には、$HOME/.erlangファイルに以下の行を追加します。</p>

<pre name="code" class="python">code:add_path("/path/to/eunit/ebin").</pre>

<a name="1_3_2"><h4>1.3.2 シンプルなテスト関数を書く</h4></a>

<p>EUnitフレームワークはErlangでユニットテストを書くのをとても簡単にしてくれます。テストを書く方法は何通りかありますが、まずは一番簡単なやり方から開始します。</p>

<p>EUnitは、名前の最後が_test()で終わる、引数のない関数をシンプルなテスト関数であると認識します。任意の値(EUnitが破棄してしまいますが)を返すとテストは成功とみなされます。また、なんらかの例外を投げる(ただし中断しない)場合には失敗したとみなされます。実行が中断すると、テストの実行自体が途中終了します。</p>

<p>以下のコードが、シンプルなテスト関数の例になります。</p>

<pre name="code" class="python">reverse_test() -> lists:reverse([1,2,3]).</pre>

<p>このテストは、[1, 2, 3]というリストに対して、lists:reverse(List)を実行するとクラッシュはしない、というテストになります。これはすばらしいテストとは言えませんが、多くの人がこのようなシンプルな関数を書き、自分のコードの基本的な機能性をテストしています。これらのテストはコードを変更しなくても、名前がマッチすればEUnitから直接使用されます。</p>

<p><b>失敗を表すためには例外を使用します</b>。そうすることで、より詳しいテストを書くことができます。もし期待していない結果が得られた場合には、クラッシュさせて例外を投げる必要があります。一番簡単な方法は = を使ったパターンマッチを使用する方法です。</p>

<pre name="code" class="python">reverse_nil_test() -> [] = lists:reverse([]).
   reverse_one_test() -> [1] = lists:reverse([1]).
   reverse_two_test() -> [2,1] = lists:reverse([1,2]).</pre>

<p>もし lists:reverse/1 に何かバグがあり、[1, 2]という入力に対して、 [2, 1]以外の結果を返した場合には、上記の最後のテストはbadmatch errorを投げます。最初の二つ(badmatchが得られなかったとすると)はそれぞれ単純に [] と [1] を返し、成功したことになります。EUnitは魔法使いではないので、比較値を書かない場合には、値を返すテストを書いて、もしそれが間違った値だったとしても、EUnitは成功したとみなします。もし返り値が仕様通りでない値を返した場合にはクラッシュするようなテストを書く必要があります。</p>

<p><b>assertマクロの使用:</b> もしBoolean演算をテストで使用したい場合には、assertマクロを使うのが手軽です(詳しくは<a href="#1_4">EUnitマクロ</a>を参照)。</p>

<pre name="code" class="python">length_test() -> ?assert(length([1,2,3]) =:= 3).</pre>

<p>?assert(Expression) というマクロは式を評価します。そして評価した結果がtrueでない場合には、例外を投げます。そうでない場合にはokを返します。上記の例では、 lengthを呼び出した結果が3を返さなかった場合に失敗します。</p>

<a name="1_3_3"><h4>1.3.3 EUnitの実行</h4></a>

<p>もし前の説明に書いたように -include_lib("eunit/include/eunit.hrl") 宣言をモジュールに付けた時には、モジュールをコンパイルするだけで大丈夫です。自動的にエクスポートされた test() 関数を実行します。例えば、m という名前のモジュールを作ったとしたら、 m:test() がEUnitを実行し、モジュールの中で定義されたすべてのテストを実行します。テストの関数に対して、 -export 宣言を付ける必要はありません。魔法によって、これらはすべて自動的に行われます。</p>

<p><a href="#test-1">eunit:test/1</a>関数を使用することで、各々のテストを実行することもできます。例えば、より進んだテストデスクリプタ( <a href="#1_5">EUnitテスト表現</a>を参照)を使用したい場合などです。例えば、eunit:test(m) を実行するのは、自動生成された m:test()を実行するとの同等です。また、 eunit:test({inparallel, m}) を実行すると、同じテストケースを実行しますが、それぞれのテストは並列で実行されます。</p>

<h5>テストを別のモジュールに分ける</h5>

<p>通常のコードと、エクスポートされた関数に対するテストコードを分けたいとします。このような場合には、もしモジュールの名前がmであったとすると、テスト関数をm_tests(m_testではなく複数形)というモジュールの中に書くことができます。EUnitにモジュールmをテストするように指示した場合、m_testsというモジュールを探しにいって、この中に定義されたテストが実行されるようになります。モジュール名に関しては<a href="#Primitives">プリミティブ</a>というところで詳しく説明します。</p>

<h5>EUnitにより標準出力を取得する</h5>

<p>もしテストコードが標準出力に何かを書き出したとすると、テストが実行されたときにコンソールに何もテキストが表示されないのを見て驚くでしょう。これはEUnitがテスト関数から出力される、すべての標準出力の結果をキャプチャーしているからです。これにはセットアップ、クリーンナップの関数も含まれますが、ジェネレータ関数は含まれません。そして、この結果は、エラーが発生した場合に、テストレポートの中に出力されます。テストの実行中にEUnitを迂回して、テキストを直接コンソールに書き出したい場合には、io:format(user, "~w", [Term])というユーザ出力ストリームを利用することができます。推奨される方法としては、EUnitの<a href="#Debugging_macros">デバッグマクロ</a>を使用することで、シンプルに書くことができます。</p>

<h4><a name="1_3_4">1.3.4 テストを生成する関数を書く</a></h4>

<p>シンプルなテストを書く際に障害となるのは、テストケースごとに別々の名前を持った、個別の関数を書く必要があるということです。テストを書くためのコンパクトで、より柔軟な方法は、テスト<b>そのもの</b>を書くのではなく、テストを<b>返す</b>関数を書くことです。</p>

<p>EUnitは、_test_()(最後のアンダースコアが大切)という名前で終了する関数を、<b>テストジェネレータ関数</b>として扱います。テストジェネレータは、EUnitで実行することができる<b>テスト群</b>の<b>の表現</b>を返します。</p>

<h5>データとしてテストの表現</h5>

<p>基本的なテスト表現は、テストは引数のない１つのfun式で表されます。例えば、以下のようなテストジェネレータを作成することができます。</p>

<pre name="code" class="python">basic_test_() ->
       fun () -> ?assert(1 + 1 =:= 2) end.</pre>

<p>このジェネレータは、以下のようなシンプルなテストと同じ結果になります。</p>

<pre name="code" class="python">simple_test() ->
    ?assert(1 + 1 =:= 2).</pre>

<p>実際には、EUnitは内部ではすべてのシンプルなテストをfun式として扱います。これらの式をリストの中に格納して、一つずつ実行します。</p>

<h5>テストを書くためのマクロを使用する</h5>

<p>テストをよりコンパクトで読みやすく書くためには_testマクロ(先頭のアンダースコアを忘れずに)を使用することができます。このマクロは、テストが書かれているソースコード内の行番号の情報を自動的に付加し、タイプ数を節約できます。</p>

<pre name="code" class="python">basic_test_() ->
    ?_test(?assert(1 + 1 =:= 2)).</pre>

<p>_testマクロは引数としてあらゆる式(テスト本体)を受け取り、それを追加の情報とともにfun式の内部に格納した状態で展開されます。本体は、シンプルなテスト内に書くように、テストを表す式なら何でも指定することができます。</p>

<h5>テストオブジェクトを作成するアンダースコアが前に付いたマクロ</h5>

<p>上記の例はもっと短くすることができます。マクロ名の前にアンダースコアがついたassertマクロ群などのほとんどのテストのためのマクロは、自動的に?_test(...)ラッパーを付加します。上記の例はもっとシンプルに以下のように書くことができます。</p>

<pre name="code" class="python">basic_test_() ->
    ?_assert(1 + 1 =:= 2).</pre>

<p>_assertマクロを、assertマクロの代わりに使用することで、まったく同じ文となります。最初にアンダースコアがついたマクロは<b>テストオブジェクト</b>を表す記号として見ても差し支えありません。</p>

<h4><a name="1_3_5">1.3.5 サンプル</a></h4>

<p>１つのサンプルは百聞にしかず。以下の小さなErlangモジュールはEUnitを実践の中でどのように使用できるのかということを示しています。</p>

<pre name="code" class="python">-module(fib).
   -export([fib/1]).
   -include_lib("eunit/include/eunit.hrl").

   fib(0) -> 1;
   fib(1) -> 1;
   fib(N) when N > 1 -> fib(N-1) + fib(N-2).

   fib_test_() ->
       [?_assert(fib(0) =:= 1),
        ?_assert(fib(1) =:= 1),
        ?_assert(fib(2) =:= 2),
        ?_assert(fib(3) =:= 3),
        ?_assert(fib(4) =:= 5),
        ?_assert(fib(5) =:= 8),
        ?_assertException(error, function_clause, fib(-1)),
        ?_assert(fib(31) =:= 2178309)
       ].</pre>

<p><b>著者のメモ:</b> 初めてこのサンプルを書いた際に、fib関数の中の+演算子の代わりに、間違って*演算子を書いてしまいました。もちろん、テストを実行したらすぐに間違ったことが分かりました。</p>

<p>EUnitでテストを定義するすべての方法を表したリストを見るためには、<a href="#1_5">EUnitテスト表現</a>を見てください。</p>

<h4><a name="1_3_6">1.3.6 テストの無効化</a></h4>

<p>コンパイル時にNOTESTマクロを定義することでテストを除外することができます。erlcのオプションとして指定するには以下のように書きます。</p>

<pre name="code" class="python">erlc -DNOTEST my_module.erl</pre>

<p>コード中に書く際は、<b>EUnitヘッダファイルをインクルードするよりも前に</b>、以下のマクロ定義を書きます。</p>

<pre name="code" class="python">-define(NOTEST, 1).</pre>

<p>定義する値は重要ではありませんが、1かtrueを良く使用します。EUNIT_NOAUTOマクロが定義されない場合には、明示的にエクスポートされているものを除いて、すべてのテスト関数を自動的に削除し、テストを無効にします。</p>

<p>実際にEUnitをアプリケーションの中に実際に使用するが、デフォルトではテスト機能をオフにしたい場合には以下のようにヘッダファイルに書きます。</p>

<pre name="code" class="python">-define(NOTEST, true).
-include_lib("eunit/include/eunit.hrl").</pre>

<p>このヘッダファイルがすべてのモジュールにインクルードされているものとします。一カ所だけを修正することで、テストのデフォルト設定を変更することができるようになります。また、NOTESTの定義はコードを修正しなくても上書きできるようになっています。一時的にテストを有効にするためには、TESTをコンパイラオプションとして定義します。</p>

<pre name="code" class="python">erlc -DTEST my_module.erl</pre>

<p>これらのマクロの詳細については、<a href="Compilation_control_macros">コンパイル制御マクロ</a>を参照してください。</p>

<h4><a name="1_3_7">1.3.7 コンパイル時のEUnitへの依存を回避する</a></h4>

<p>もし、自分で作ったソースコードを配布して、他のユーザが自分のアプリケーションに組み込み、コンパイルして実行しようとしているとしたら、EUnitが手に入らなかったとしてもコードがコンパイルできるようにしたいと思いますよね？前の方のセクションで出てきたサンプルを参考に、共通ヘッダファイルに以下のようなコードを書くことができます。</p>

<pre name="code" class="python">-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.</pre>

<p>もちろん、EUnitのマクロを使用する、すべてのテストコードは、-ifdef(TEST)、あるいは、-ifdef(EUNIT) セクションの中に書くようにします。</p>

<a name="1_4"><h3>1.4 EUnitマクロ</h3></a>

<p>EUnitのすべての機能はプリプロセッサマクロを使用しなくても使用できますが、EUnitのヘッダファイルには、ユニットテストを書くのを簡単にするためのマクロが数多く定義されています。これを使用すると、詳細まで書かなくても、可能な限り短いコードになります。</p>

<p>明確に定義されているものを除いて、EUnitのマクロを使用しても、EUnitのライブラリコードへの実行時の依存関係は発生しません。これは、コンパイル時にテストが有効になっているか、無効になっているか、というのには依存しません。</p>

<ul>
<li><a href="#Basic_macros">基本マクロ</a></li>
<li><a href="#Compilation_control_macros">コンパイル制御マクロ</a></li>
<li><a href="#Utility_macros">ユーティリティマクロ</a></li>
<li><a href="#Assert_macros">assertマクロ</a></li>
<li><a href="#Macros_for_running_external_commands">外部コマンド実行用マクロ</a></li>
<li><a href="#Debugging_macros">デバッグマクロ</a></li>
</ul>

<a name="Basic_macros"><h4>1.4.1 基本マクロ</h4></a>

<h5>_test(Expr)</h5>

<p>式をテストオブジェクトに変換します。テストオブジェクトはfun式でラップされ、ソースファイルの行番号が付加されます。技術的には、{?LINE, fun () -> (Expr) end}と書くのと同一です。</p>

<a name="Compilation_control_macros"><h4>1.4.2 コンパイル制御マクロ</h4></a>

<h5>EUNIT</h5>

<p>このマクロはコンパイル時にEUnitが有効な時にはいつでも定義されています。このマクロは、以下のようにテストコードを条件コンパイル内に置くときに使用します。</p>

<pre name="code" class="python">-ifdef(EUNIT).
    % ここにテストコードを書く
    ...
-endif.</pre>

<p>例えばテストが無効になっているときには、EUnitヘッダファイルをインクルードしないでコンパイルされることもあります。TEST, NOTESTの項目も参照してください。</p>

<h5>EUNIT_NOAUTO</h5>

<p>このマクロが定義されると、自動的にテスト関数をエクスポートする機能が無効になります。</p>

<h5>TEST</h5>

<p>このマクロは、コンパイル時にEUnitが有効になっている場合にはいつも定義されます。ユーザが自分で別の値を定義した場合を除いて、trueとして定義されます。このマクロはテストコードを条件コンパイルする際に使用することができます。NOTEST, EUNITの項目も参照してください。</h5>

<p>EUnitに依存しているテストコードについて条件コンパイルする場合には、EUNITマクロを使用する方が望ましいです。TESTマクロはもっと一般的なテスト条件に使用されます。この場合はTESTマクロの方が望ましいでしょう。</p>

<p>TESTマクロは、TOTESTマクロを上書きすることができます。NOTESTが定義されていたとしても、EUnitヘッダファイルが<b>インクルードされる前</b>にTESTが定義されていれば、EUnitは有効な状態でコンパイルされます。</p>

<h5>NOTEST</h5>

<p>このマクロは、EUnitがコンパイル時に<b>無効になっている場合に</b>はいつも定義されます。ユーザが自分で別の値を定義した場合を除き、trueとして定義されます。TESTマクロと比較してみてください。</p>

<p>このマクロは条件コンパイルにも使用することができますが、一般的にはテストを無効化用途に使用します。EUnitヘッダファイルを<b>インクルードする前</b>にNOTESTが定義されていて、なおかつTESTが定義されていない場合には、EUnitが無効の状態でコンパイルされます。<a href="#1_3_6">テストの無効化</a>も参照してください。</p>

<h5>NOASSERT</h5>

<p>このマクロは、テストが無効になっていて、assertマクロを使用しても無効になる場合に定義されます。テストが有効な場合には、このマクロは常に自動的に有効になります。無効化することはできません。<a href="#Assert_macros">assertマクロ</a>の項も参照してください。</p>

<h5>ASSERT</h5>

<p>もしこのマクロが定義されていると、NOASSERTマクロを上書きします。他の設定によらず、常にassertマクロを有効にすることができます。</p>

<h5>NODEBUG</h5>

<p>もしマクロが定義されていれば、デバッグマクロが動作しなくなります。詳しくは<a href="#Debugging_macros">デバッグマクロ</a>の説明を見てください。NODEBUGを定義するとテストが定義されていたとしても、NOASSERTが定義されます。</p>

<h5>DEBUG</h5>

<p>もしこのマクロが定義されると、NODEBUGマクロの動作が上書きされます。デバッグ用のマクロを強制的に使用可能にします。</p>

<a name="Utility_macros"><h4>1.4.3 ユーティリティマクロ</h4></a>

<p>テストをより短く、読みやすくすることができます。</p>

<h5>LET(Var,Arg,Expr)</h5>

<p>ローカルな、Expr内で、Var = Argというローカルな束縛を作成することができます。 (fun(Var)-&gt;(Expr)end)(Arg)と定義するのと同じです。この束縛はExprの外にはエクスポートされません。このVarに対する束縛は、使用されるスコープの他の束縛を邪魔することはありません。</p>

<h5>IF(Cond,TrueCase,FalseCase)</h5>

<p>もしCond式がtrueの場合にはTrueCaseが評価されます。そうでない場合はFalseCaseが評価されます。これは (case (Cond) of true-&gt;(TrueCase); false-&gt;(FalseCase) end).と同等です。Condはブーリアンの値でない場合にはエラーになります。</p>

<a name="1_4_4"><h4>1.4.4 assertマクロ</h4></a>

<p>?_assert(BoolExpr)のような、"_"アンダースコアの文字から始まる名前のマクロも存在します。この形式のマクロは、テストを実行するだけでなく、"テストオブジェクト"も作成します。これは?_test(assert(BoolExpr))のように書くのと同じ動作をします。</p>

<p>もし、EUnitヘッダファイルがインクルードされる前にNOASSERTマクロが定義されると、テストも無効化されている時に、これらのマクロも空の実装に取り替えられます。詳細については、コンパイル制御マクロを参照してください。</p>

<h5>assert(BoolExpr)</h5>

<p>テストが有効になっている場合に、BoolExpr式の評価を行います。結果がtrueでなければ、それを知らせる例外が生成されます。例外発生しなかった場合には、マクロ式の評価結果は、okというアトムになります。BoolExprの値は返されません。もしテストが無効な場合には、okアトムを返すコード以外は生成されません。BoolExprも評価されなくなります。</p>

<p>一番使用される方法は以下のようになります。</p>

<pre name="code" class="python">?assert(f(X, Y) =:= [])</pre>

<p>このassertマクロは、ユニットテストの中だけでなく、どこでも使用することができます。以下のように、DbCで行う、事前条件/事後条件/不変条件のチェックにも使用することができます。</p>

<pre name="code" class="python">some_recursive_function(X, Y, Z) -&gt;
    ?assert(X + Y &gt; Z),
    ...</pre>

<h5>assertNot(BoolExpr)</h5>

<p>assert(not (BoolExpr))と同等です。</p>

<h5>assertMatch(GuardedPattern, Expr)</h5>

<p>テストが有効になっている時に、Exprを評価し、結果がGuardedPatternに対して、マッチするかどうか検証します。もしパターンにマッチしなかった場合には、それを知らせる例外を生成します。このあたりの詳細はassertマクロの説明を見てください。GuardedPatternはcase構文の -&gt; シンボルの左側に書くことができるものであれば、なんでも書くことができます。ただし、カンマで区切られたガードテストを含むものを除きます。</p>

<p>シンプルなマッチのテストでも、= ではなくて、assertMatchを使用すると、より詳細なエラーメッセージを生成することができます。</p>

<p>サンプル:</p>

<pre name="code" class="python">?assertMatch({found, {fred, _}}, lookup(bloggs, Table))
?assertMatch([X|_] when X > 0, binary_to_list(B))</pre>

<h5>assertEqual(Expect, Expr)</h5>

<p>テストが有効な場合に、ExpectとExprの両方の式を評価して、結果が等しいかどうか比較します。もし等しくなかった場合には、情報を伝える例外を生成します。詳しくはassertマクロの説明を見てください。</p>

<p>assertEqualは、左側の期待値がパターンではなくて、計算後の値である場合には、assertMatchよりも良いでしょう。また、?assert(Expect =:= Expr)よりも、詳しい説明が得られます。</p>

<p>サンプル:</p>

<pre name="code" class="python">?assertEqual("b" ++ "a", lists:reverse("ab"))
?assertEqual(foo(X), bar(Y))</pre>

<h5>assertException(ClassPattern, TermPattern, Expr)</h5>
<h5>assertError(TermPattern, Expr)</h5>
<h5>assertExit(TermPattern, Expr)</h5>
<h5>assertThrow(TermPattern, Expr)</h5>

<p>Exprを評価して、その中で発生した例外をキャッチし、それが期待されたClassPattern, TermPatternと一致しているか検証します。マッチしないか、Exprを評価した中で例外が発生しなかった場合には、情報を伝える例外を生成します。詳しくはassertマクロの説明を参照してください。assertError, assertExit, assertThrowは、ClassPatternとしてerror, exit, throwを設定してassertExceptionを使用した場合と、それぞれ同一です。</p>

<p>サンプル:</p>

<pre name="code" class="python">?assertError(badarith, X/0)
?assertExit(normal, exit(normal))
?assertException(throw, {not_found,_}, throw({not_found,42}))</pre>

<a name="Macros_for_running_external_commands"><h4>1.4.5 外部コマンド実行用マクロ</h4></a>

<p>外部コマンドはOSに強く依存します。これらのマクロ以外にも、現在のOSに依存したテストを作成するために、標準ライブラリのos:type()をテストジェネレータ関数の中で使用することもできます。</p>

<p>注: これらのマクロはテストが有効な状態でコンパイルされると、EUnitのライブラリコードへの実行時の依存が発生します。</p>

<h5>assertCmd(CommandString)</h5>

<p>テストが有効な場合に、CommandStringを外部コマンドとして実行します。もし外部プログラムの返値がゼロでなかった場合には、それを通知する例外が生成されます。例外が発生しなかった場合には、マクロの式の結果は、okアトムになります。もしテストが無効化されている場合には、okアトムを返す以外のコードは生成されず、外部コマンドも実行されます。</p>

<p>一般的な使用法:</p>

<pre name="code" class="python">?assertCmd("mkdir foo")</pre>

<h5>assertCmdStatus(N, CommandString)</h5>

<p>assertCmd(CommandString)マクロと同様ですが、もしステータス値としてN以外の値が返されると例外を生成します。</p>

<h5>assertCmdOutput(Text, CommandString)</h5>

<p>テストが有効な時に、CommandStringを外部コマンドとして実行します。コマンドが出力したものが、指定した文字列のTextと一致しなかった場合には、違いの情報を伝える例外を出力します。どのようなプラットフォームでも、改行コードはLFに正規化されます。もし例外が発生しなかった場合には、このマクロはokアトムを返します。</p>

<h5>cmd(CommandString)</h5>

<p>CommandStringを外部文字列として実行します。返り値が0(成功を意味します)でなかった場合には、情報を伝える例外が生成されます。成功した場合には、このマクロは、コマンドが出力した物をフラットな文字列として返します。どのようなプラットフォームでも、改行コードはLFに正規化されます。</p>

<p>このマクロは、エラーが発生しても、テストをきちんと実行するために、ファイルの作成と削除、OS特有のタスクの実行などを、フィックスチャのセットアップ、片付けのセクションで使用するのが便利です。</p>

<p>UNIX環境で動作するサンプル:</p>

<pre name="code" class="python">{setup,
 fun () -> ?cmd("mktemp") end,
 fun (FileName) -> ?cmd("rm " ++ FileName) end,
 ...}</pre>

<a name="Debugging_macros"><h4>1.4.6 デバッグマクロ</h4></a>

<p>EUnitではいくつかのデバッグを補助するマクロを定義しています。これらを使うと、標準出力ではなく、直接コンソールにメッセージをひょうじすることができます。これらのマクロは同じ基本フォーマットを使用して出力されます。これにはデバッグマクロが実行されたファイル名、行番号が含まれ、開発環境(Emacsのバッファ内でErlangを実行している場合など)によっては、出力メッセージから、ソースコードの該当する行に直接ジャンプすることができます。</p>

<p>EUnitヘッダファイルがインクルードされる前にNODEBUGマクロが定義されると、これらのマクロは何もしなくなります。詳しくはコンパイル制御マクロの項目を見てください。</p>

<h5>debugHere</h5>

<p>コンソールに現在のファイルと行番号を表すマーカーを表示するだけのマクロです。このマクロは引数を取りません。結果は常にokとなります。</p>

<h5>debugMsg(Text)</h5>

<p>Textをメッセージとして出力します。Textはプレーンな文字列、IOリスト、アトムが使用可能です。実行結果は常にokとなります。</p>

<h5>debugFmt(FmtString, Args)</h5>

<p>このマクロは、テキストをio:format(FmtString, Args)と同様にテキストをフォーマットして、debugMsgと同じように出力します。結果は常にokとなります。</p>

<h5>debugVal(Expr)</h5>

<p>Exprに対するソースコードと、現在の値の両方を出力します。例えば、?debugVal(f(X))は"f(X) = 42"と表示されます。(ほとんどの単語は切り詰めて表示されます)。評価結果はExprの値となります。そのため、デバッグ機能を有効にしてコンパイルされている時には、このマクロで式(式が使える所はどこでも)をラップして、コードがコンパイルされた時の値を表示するという使い方ができます。</p>

<h5>debugTime(Text,Expr)</h5>

<p>Exprを評価したときの時間とテキストを表示します。評価結果はExprの値となります。そのため、デバッグ機能を有効にしてコンパイルされている時には、このマクロで式(式が使える所はどこでも)をラップして使用することができます。例えば、List1 = ?debugTime("sorting", lists:sort(List))を実行すると、"sorting: 0.015 s"と表示されます。</p>

<h3><a name="1_5">1.5 EUnitテスト表現</a></h3>

<p>EUnitでテストやテストセットをデータとして表現する方法は柔軟でパワフルで、簡潔です。このセクションでは、詳細の表現について説明していきます。</p>

<ul>
<li><a href="#Simple_test_objects">シンプルテストオブジェクト</a></li>
<li><a href="#Test_sets_and_deep_lists">テストセットと、深いリスト</a></li>
<li><a href="#Titles">タイトル</a></li>
<li><a href="#Primitives">プリミティブ</a></li>
<li><a href="#Control">制御</a></li>
<li><a href="#Fixtures">フィックスチャ</a></li>
<li><a href="#Lazy_generators">遅延ジェネレータ</a></li>
</ul>

<a name="Simple_test_objects"><h4>1.5.1 シンプルテストオブジェクト</h4></a>

<p><b>シンプルテストオブジェクト</b>は以下の表現のうちの１つになります。</p>

<ul>
<li>空のファンクションの値(例えば、引数を一つもとらないfunなど)。サンプル: 
<pre name="code" class="python">fun() -> ... end
fun some_function/0
fun some_module:some_function/0</pre>
</li>
<li>ModuleName:FunctionName/0 という関数を参照する、{ModuleName, FunctionName}というアトムのペア。</li>
<li>{LineNumber, SimpleTest}のペア。LineNumberは負でない整数で、SimpleTestは他のシンプルテストオブジェクト。LineNumberはテストのソースコード行数を示す。このようなペアは普段は、?_test(...)マクロを使って生成される。 詳しくは<a href="#Basic_macros">基本マクロ</a>を参照してください。</li>
</ul>

<p>まとめると、シンプルテストオブジェクトは、引数をもたない関数を一つだけ持ちます。また、行番号などの追加のメタデータをいくつか持ちます。テストの評価は、この関数が<b>成功</b>するか、<b>失敗</b>するかで行われます。成功した場合には何かの値を返します。ただし、この値は無視されます。例外が投げられると失敗と判定されます。</p>

<a name="Test_sets_and_deep_lists"><h4>1.5.2 テストセットと、深いリスト</h4></a>

<p>テストオブジェクト群をリストに入れるだけでテストセットを作成することができます。T_1, ..., T_Nというのが個別のテストオブジェクトだったとすると、[T_1, ..., T_N]はこれらのオブジェクトで構成されるテストということになります。順番もこの通りに扱われます。</p>

<p>同様の方法でテストセットをつなげることができます。S_1, ..., S_Kがテストセットだったとすると、[S_1, ..., S_K]もまたテストセットになります。テストの順番は、S_iに含まれるテストは、S_(i+1)のテストの前となるようにテストセットごとに配置されます。</p>

<p>よく使用されるテストセット表現は<b>深いリスト</b>になります。シンプルなテストオブジェクトは、一つだけのテストを含んでいるテストセットとして見えます。Tと[T]に違いはありません。</p>

<p>モジュールもテストセットの表現として利用されます。<a href="#Primitives">プリミティブ</a>のModuleNameの項目も参照してください。</p>

<a name="Titles"><h4>1.5.3 タイトル</h4></a>

<p>すべてのテストとテストセットにはタイトルを注釈でつけることができます。テストもしくはテストセットをTとすると、注釈を付けるには{タイトル、T}というペアのタプルを作ります。タイトルは文字列です。あらゆるテストは通常タプルを使用して、タイトル文字列を最初の要素として、{"タイトル", ...}という形式で作成するだけで表現できます。さらに{"タイトル", {...}}というような、余計なタプルを付ける必要はありません。</p>

<a name="Primitives"><h4>1.5.4 プリミティブ</h4></a>

<p>以下の要素がプリミティブになります。他のテストセットを引数に含むことはできません。</p>

<h5>ModuleName::atom()</h5>

<p>モジュール名を表す単独のアトム。これは{モジュール, モジュール名}と同等です。これはeunit:test(モジュール)という形式でコールされたときに良く使用されます。</p>

<h5>{module, ModuleName::atom()}</h5>

<p>これは与えられた名前のモジュール内の、エクスポートされたテスト関数からなるテストセットで構成されます。これらの関数は、引数がゼロで、名前の末尾が_testもしくは_test_で終わるものになります。..._test()という関数は、シンプルなテストで、..._test_()という関数はジェネレータになります。</p>

<p>これに加えて、EUnitは、ModuleNameというモジュールに_testsという末尾の文字列の追加された別のモジュールも探しに行きます。もし見つかれば、このモジュールに含まれるテストもすべて追加されます。ただし、ModuleNameにすでに_testsという文字が後ろについている場合は探しに行きません。 {module, mymodule}という仕様は、mymoduleと、mymodule_testsというモジュールに含まれる、すべてのテストを実行することになります。通常、_testsモジュールは、メインのモジュールの公開インタフェースに対するテストケースのみを含み、他のコードは含まないようにすべきです。</p>

<h5>{application, AppName::atom(), Info::list()}</h5>

<p>これは、.appファイルの中で見られる、通常のErlang/OTPアプリケーションのディスクプリタになります。結果となるテストセットはInfoに含まれるモジュールの中のエントリーの中のモジュールから構成されます。</p>

<h5>{application, AppName::atom()}</h5>

<p>これは、特定のアプリケーションに含まれるすべてのモジュールにあるテストセットを作成します。アプリケーションの.appファイル({file, FileName}参照)を調査するか、もしくは存在しない場合には、アプリケーションのebinディレクトリ({dir, Path}を参照)に含まれるすべてのオブジェクトファイルを調べます。もしそれでも見つけられない場兄は、code:lib_dir(AppName)ディレクトリが使用されます。</p>

<h5>Path::string()</h5>

<p>ファイルやパスを表す文字列です。これは{file, Path}もしくは{dir, Path}と同等になります。このPathは、それぞれファイルシステムの中で参照されます。</p>

<h5>{file, FileName::string()}</h5>

<p>もし、FileNameの末尾が、オブジェクトファイル(.beam)を表す拡張子がついている場合には、EUnitはそのファイルをリロードして、テストしようとします。そうでない場合には、ファイルを、テスト仕様を含むテキストファイルとみなして、標準ライブラリ関数のfile:path_consult/2を使用して読み込みます。</p>

<p>ファイル名が絶対パスでない場合には、まず現在のディレクトリからの相対パスとして検索します。その後は通常のサーチパス(code:get_path())を利用します。これにより、よく使う"app"ファイル名はパスを指定しなくても直接指定することが可能になります。例えば、"mnesia.app"のように書くことができます。</p>

<h5>{dir, Path::string()}</h5>

<p>これは、指定されたディレクトリの中のすべてのオブジェクトファイルをテストします。{file, FileName}を使用してすべてのファイルを個別に指定するのと同じように動作します。</p>

<h5>{generator, GenFun::(() -&gt; Tests)}</h5>

<p>ジェネレータ関数であるGenFunがコールされ、テストセットが生成されます。</p>

<h5>{generator, ModuleName::atom(), FunctionName::atom()}</h5>

<p>テストセットを生成するのに、ModuleName:FunctionName()が呼ばれます。</p>

<h5>{with, X::any(), [AbstractTestFun::((any()) -&gt; any())]}</h5>

<p>Xの値を、リストに含まれている単体の関数に適用し、それぞれを引数のないテスト関数に変換します。AbstractTestFunは通常のテスト用のfunとほぼ同じですが、引数をゼロ個ではなく、一つだけ受け取ります。パラメータを受け取る前の、正式なテスト関数になる前のテストは、いくつかの情報が足りない状態になります。実際、 {with, X, [F_1, ..., F_N]}は、[fun () -&gt; F_1(X) end, ..., fun () -&gt; F_N(X) end].と同等になります。これは特に、抽象的なテスト関数がすでにきちんとした関数として定義されている場合に便利です。{with, FD, [fun filetest_a/1, fun filetest_b/1, fun filetest_c/1]}は、[fun () -&gt; filetest_a(FD) end, fun () -&gt; filetest_b(FD) end, fun () -&gt; filetest_c(FD) end]と一緒ですが、よりコードが短くなります。フィックスチャの項目もご覧ください。</p>

<a name="Control"><h4>1.5.5 制御</h4></a>

<p>これから説明していく表現を使うと、どこでどのようにテストが実行されるかを制御することができます。</p>

<h5>{spawn, Tests}</h5>

<p>それぞれのテストをサブプロセスに分けてテストを行います。現在のテストプロセスはそれぞれのテストが終了するのを待ちます。これはプロセスの状態を独立した、新規のプロセスとしてテストを実行するのに役立ちます。EUnitは常に少なくとも一つのサブプロセスを自動でスタートさせます。呼び出しもとのプロセスでテストが実行されることはありません。</p>

<h5>{spawn, Node::atom(), Tests}</h5>

<p>{spawn, Tests}とほぼ同一ですが、テストを、指定されたErlangのノードで実行します。</p>

{timeout, Time::number(), Tests}

<p>指定されたタイムアウト時間の中でテストを実行します。Timeは秒で設定します。60を指定すると1分に、0.1を指定すると1/10秒になります。もしタイムアウトすると、終了していないテストは強制的に中断されます。設定されたタイムアウトの時間は、セットアップと片付けも含んだ、フィックスチャ全体の時間になります。もしタイムアウトが起動すると、片付けのコードが実行されないで、突然強制終了されることになります。</p>

<h5>{inorder, Tests}</h5>

<p>指定されたテストを、厳格な順序で実行します。{inparallel, Tests}.も参照してください。デフォルトでは、テストはinorderもinparallelも指定されていません。テストのフレームワークまかせの方法で実行されます。</p>

<h5>{inparallel, Tests}</h5>

<p>可能であれば、指定されたテストを並列で実行します。{inorder, Tests}も参照してください。</p>

<h5>{inparallel, N::integer(), Tests}</h5>

<p>{inparallel, Tests}と同様ですが、平行実行の数をN以下に設定します。</p>

<a name="Fixtures"><h4>1.5.6 フィックスチャ</h4></a>

<p>フィックスチャは、あるテストセットを実行するのに必要な状態を表します。EUnitはテストセットのためのローカルの状態を簡単に設定しやすいような機能を提供しています。また、テストの結果(success, failures, timeoutsなど)に関わらず、テストセットが終了したときに自動的にクリーンアップを行うこともできます。</p>

<p>説明を簡単にするために、まず最初に定義をリストアップします。詳細は後半で説明します。</p>

<p><b><tt>Setup() -&gt; (R::any()) SetupX(X::any()) -&gt; (R::any()) Cleanup(R::any()) -&gt; any() CleanupX(X::any(), R::any()) -&gt; any() Instantiator((R::any()) -> Tests) | {with, [AbstractTestFun::((any()) -&gt; any())]} Wherelocal | spawn | {spawn, Node::atom()} </tt></b></p>

<p>以下の表現は、テストセットを操作するためのフィックスチャを定義します。</p>

<h5>{setup, Setup, Tests | Instantiator}</h5>
<h5>{setup, Setup, Cleanup, Tests | Instantiator}</h5>
<h5>{setup, Where, Setup, Tests | Instantiator}</h5>
<h5>{setup, Where, Setup, Cleanup, Tests | Instantiator}</h5>

setupは、一つのフィックスチャをすべてのテストを実行するためにセットアップします。また、追加で片付けのためのコードを追加することもできます。引数についてはこの後で詳細に説明します。

<h5>{node, Node::atom(), Tests | Instantiator}</h5>
<h5>{node, Node::atom(), Args::string(), Tests | Instantiator}</h5>

nodeはsetupはセットアップと同様ですが、指定しない場合は、テストを実行したら終了するスレーブのノードを開始します。atomノードは"ノード名@完全なマシン名"というフォーマットを持ちます。Argsは新しいノード作成時に使用される追加の引数になります。詳しくはslave:start_link/3をご覧ください。

<h5>{foreach, Where, Setup, Cleanup, [Tests | Instantiator]}</h5>
<h5>{foreach, Setup, Cleanup, [Tests | Instantiator]}</h5>
<h5>{foreach, Where, Setup, [Tests | Instantiator]}</h5>
<h5>{foreach, Setup, [Tests | Instantiator]}</h5>

<p>foreachはフィックスチャのセットアップと追加の片付けを、指定されたテストセットの中の一つ一つのテストに対して繰り返し行う際に使用されます。</p>

<h5>{foreachx, Where, SetupX, CleanupX, Pairs::[{X::any(), ((X::any(), R::any()) -> Tests)}]}</h5>
<h5>{foreachx, SetupX, CleanupX, Pairs}</h5>
<h5>{foreachx, Where, SetupX, Pairs}</h5>
<h5>{foreachx, SetupX, Pairs}</h5>

<p>foreachxはforeachとほぼ同じですが、テストセットではなくて、追加の引数Xと、追加のインスタンス作成関数のペアのリストに対して行われます。</p>

<P>Setup関数は、指定された何かテストが実行される前に実行されます。また、Cleanup関数は、指定されたテストが(理由に関わらず)もうなくなった時点で実行されます。セットアップ関数は引数を取りません。セットアップ関数の返値はそのままCleanup関数に渡されます。Cleanup関数は必要なことを行い、okアトムなどの任意の値を返す関数でなければなりません。SetupX, CleanupXもほぼ同様ですが、追加の引数X(コンテキストに依存します)を受け取ります。もしCleanup引数が設定されなかった場合には、何もしないダミーの関数が設定されます。</p>

<p>Instantiator関数はCleanup関数と同様に、いくつかの値(Setup関数が返した値)を受け取ります。Instantiator関数はジェネレータ(<a href="#Primitives">プリミティブ</a>を参照してください)と同様に。指定された値で<b>インスタンス化</b>されたテストを持つテストセットを返さなければなりません。特別なケースとしては、{with, [AbstractTestFun]}というシンタックスは引数を一つ取る関数のリストの一つ一つに対して値を渡すインスタンス作成関数を表します(この行自信ないです)。詳しくは、<a href="#Primitives">プリミティブ</a>の{with, X, [...]}の項目を参照してください。</p>

<p>これらの用語は指定されたテストがどのように実行されるかを定義します。デフォルトではspawnが設定されていて、現在のプロセスでセットアップと片付けが行われ、テスト自体はサブプロセスで実行されます。{spawn, Node}もspawnと近いのですが、サブプロセスは指定されたノード上で実行されます。localを指定すると、セットアップ、片付けと、テストの実行のすべてを現在のプロセスで実行します。この場合、テストがタイムアウトしてプロセスが終了したときに、<b>クリーンアップ処理が実行されない</b>という問題があります。そのため、ファイル操作など、永続化に関するフィックスチャについては避けるようにしてください。以下のような場合にのみ、'local'を指定するようにしてください。</p>

<ul>
<li>セットアップ、片付けをテストと同じプロセスで実行する必要がある</li>
<li>プロセスが止められた場合には片付けをする必要がない場合。例えば、セットアップではプロセスの外に対しては状態の影響を与えていない場合など</li>
</ul>

<a name="Lazy_generators"><h4>1.5.7 遅延ジェネレータ</h4></a>

<p>テストが開始するまでは、テスト記述のセット全体を生成するのではなく、徐々に生成できたら便利なこともあります。例えば、かなり大量のテストを生成したいが、かなりのすべてを一度に生成するにはメモリをかなり消費していまう場合などです。</p>

<p>呼ばれるたびに、完了していたら空のリストを作り、そうでなければテストケースと残りのテストを生成する新しいジェネレータを含むリストを返すという、ジェネレータを作成するのが簡単です。以下のコードが基本パターンでのデモコードになります。</p>

<pre name="code" class="python">lazy_test_() ->
    lazy_gen(10000).

lazy_gen(N) ->
    {generator,
     fun () ->
         if N > 0 ->
                [?_test(...)
                 | lazy_gen(N-1)];
            true ->
                []
         end
     end}.</pre>

<p>EUnitが、テストを実行しようとこのテスト表現をトラバースしようとしたときに、新しいジェネレータは、前のテストが実行されるまでは次のテストを生成しません。</p>

<p>上記のlazy_gen/1など、補助関数を使ってこの主の再帰的なジェネレータを作成することは簡単です。名前空間を汚染するのがいやで、この種のコードを書くのが好きであれば、再帰的なfunを使っても書くことができます。</p>

<p>eunit 2.1.2</p>

<p>Copyright 2004-2009 Mikael Remond, Richard Carlsson</p>

<div class="category_articles"> 
<a href="#top">1. Erlang用の軽量ユニットテストフレームワーク</a><br/> 
<a href="#1_1">1.1 ユニットテスト</a><br/> 
<a href="#1_2">1.2 用語集</a><br/> 
<a href="#1_3">1.3 テストをはじめよう</a><br/> 
<a href="#1_4">1.4 EUnitマクロ</a><br/> 
<a href="#1_5">1.5 EUnitテスト表現</a><br/> 
</div>
]]></content:encoded>
</item>
<item rdf:about="http://articles.shibu.jp/article/30549316.html">
<title>EUnit in Practice</title>
<link>http://articles.shibu.jp/article/30549316.html</link>
<description>原著者：Richard Carlsson原文：http://www.erlang-factory.com/conference/SFBayAreaErlangFactory2009/speakers/RichardCarlsson原文更新：May 1, 2009Erlang Factory Bay Area 2009で発表された、Erlangのテスティングフレームワーク、EUnitのチュートリアルです。EUnit in Practice(Japanese)View more ...</description>
<dc:subject>EUnit in Practice</dc:subject>
<dc:creator>しぶかわ</dc:creator>
<dc:date>2009-07-15T01:54:47+09:00</dc:date>
<content:encoded><![CDATA[
<p><b>原著者：</b><a href="http://hem.bredband.net/richardc/">Richard Carlsson</a><br/>
<b>原文：</b><a href="http://www.erlang-factory.com/conference/SFBayAreaErlangFactory2009/speakers/RichardCarlsson">http://www.erlang-factory.com/conference/SFBayAreaErlangFactory2009/speakers/RichardCarlsson</a><br/>
<b>原文更新：</b>May 1, 2009</p>

<p>Erlang Factory Bay Area 2009で発表された、Erlangのテスティングフレームワーク、EUnitのチュートリアルです。</p>

<hr/>

<div style="width:425px;text-align:left" id="__ss_1720383"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/shibukawa/eunit-in-practicejapanese" title="EUnit in Practice(Japanese)">EUnit in Practice(Japanese)</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=eunitinpracticejp-090714114335-phpapp02&stripped_title=eunit-in-practicejapanese" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=eunitinpracticejp-090714114335-phpapp02&stripped_title=eunit-in-practicejapanese" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">documents</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/shibukawa">shibukawa</a>.</div></div>

<div class="category_articles">
<a href="http://articles.shibu.jp/article/30549316.html">EUnit in Practice</a><br/>
</div>
]]></content:encoded>
</item>
<item rdf:about="http://articles.shibu.jp/article/30008337.html">
<title>プロジェクト計画</title>
<link>http://articles.shibu.jp/article/30008337.html</link>
<description>原著者：Unladen Swallowプロジェクト原文：http://code.google.com/p/unladen-swallow/wiki/ProjectPlan原文更新：April 23, 2009~Python最適化計画~注意: 引用している論文はすべて、 "RelevantPapers"のページからリンクを張っている。中国語版もあるゴール概要マイルストーン2009 Q12009 Q22009 Q3以降詳細計画正規表現起動時間テストと測定パフォーマンス正確さ複雑さ...</description>
<dc:subject>Unladen Swallow</dc:subject>
<dc:creator>しぶかわ</dc:creator>
<dc:date>2009-06-23T09:18:18+09:00</dc:date>
<content:encoded><![CDATA[
<p><b>原著者：</b>Unladen Swallowプロジェクト<br/>
<b>原文：</b><a href="http://code.google.com/p/unladen-swallow/wiki/ProjectPlan">http://code.google.com/p/unladen-swallow/wiki/ProjectPlan</a><br/>
<b>原文更新：</b>April 23, 2009</p>

<p>～Python最適化計画～</p>

<p>注意: 引用している論文はすべて、 <a href="http://code.google.com/p/unladen-swallow/wiki/RelevantPapers">"RelevantPapers"</a>のページからリンクを張っている。<a href="http://danmarner.yo2.cn/unladen-swallow-project-plan/">中国語版</a>もある</p>

<ul>
<li><a href="#Goals">ゴール</a></li>
<li><a href="#Overview">概要</a></li>
<li><a href="#Milestones">マイルストーン</a></li>
<ul>
<li><a href="#2009 Q1">2009 Q1</a></li>
<li><a href="#2009 Q2">2009 Q2</a></li>
<li><a href="#2009 Q3">2009 Q3以降</a></li>
</ul>
<li><a href="#Detailed Plans">詳細計画</a></li>
<ul>
<li><a href="#Regular Expressions">正規表現</a></li>
<li><a href="#Start-up Time">起動時間</a></li>
</ul>
<li><a href="#Testing and Measurement">テストと測定</a></li>
<ul>
<li><a href="#Performance">パフォーマンス</a></li>
<li><a href="#Correctness">正確さ</a></li>
<li><a href="#Complexity">複雑さ</a></li>
</ul>
<li><a href="#Risks">リスク</a></li>
<li><a href="#Communication">コミュニケーション</a></li>
</ul>

<a name="Goals"></a>
<h3>ゴール</h3>

<p>このプロジェクトではPythonを速くしたいと思っている。また、大きくて安定しているアプリケーションをこのプロジェクト"Unladen Swallow"に切り替えて使用してもらえるようにするのもゴールの一つである。</p>

<ol>
   <li>CPythonと比べて、最低でも5倍早いバージョンのPythonを作成する</li>
   <li>Pythonアプリケーションの動作は安定していなければならない</li>
   <li>CPythonアプリケーションと、ソースレベルの互換性を維持する</li>
   <li>CPythonの拡張モジュールと、ソースレベルの互換性を維持する</li>
   <li>Pythonの実装をずっと維持し続けたくはないため、Pythonとフォークするのではなく、ブランチとして活動する</li>
</ol>

<a name="Overview"></a>
<h3>概要</h3>

<p>パフォーマンスと互換性という、二つのゴールを同時に達成するために、我々はスクラッチから作るのではなく、CPythonを改修していくという方法を取ることを決めた。具体的には、CPython 2.6.1に対して作業を始めることにした。Python 2.6が、2.4/2.5(ほとんどのアプリケーションが使用している)と、3.x(最終的に到達する未来)の、間のちょうどいい位置にあるからである。CPythonのリリースコードから開始したおかげで、我々は組み込みの関数やオブジェクト、標準ライブラリモジュールなどの重要な部品を再実装しなくて済んでいる。また、頻繁に用いられているCPythonのC言語による拡張のAPIもそのまま使用することができるのである。2.XのCPythonからスタートしているため、既存のアプリケーションからは簡単に移行することができる。もし、3.Xから始めていたら、大きなアプリケーションのメンテナンスをしている人たちにアプリケーションの移植からお願いする必要があり、私達が対象としているユーザにうまくスタートしてもらうのを難しいと思っていただろう。</p>

<p>多くの時間をPythonコードの実行速度の方にフォーカスして行う仕事がメインとなる。Pythonのランタイムライブラリに使用する時間は少なくなるだろう。我々が長期間かけて提案したいのは、<a href="http://llvm.org/">LLVM</a>上に構築された、Python用のJIT機能付きのカスタムの仮想マシンを補完することである。それ以外のPythonランタイムに関してはほとんどCPythonのままになる予定である。我々が今までに行ってきた調査によると、Pythonのアプリケーションはメインのevalループの中で多くの時間を消費しているということが分かっている。特に、opコードのディスパッチといった、VMの構成部品に比較的小さい変更を加えるだけで、Pythonアプリケーションのパフォーマンスには著しい効果がある。我々は、LLVMのJITエンジンを通じて、Pythonをマシンコードにコンパイルすと、極めて大きなパフォーマンスの向上が得られると信じている。</p>

<p>いくつか明確になっているメリット:</p>

<ul>
<li>JITを使用することで、Pythonをスタックベースマシンから、レジスタマシンにすることができる。こうすることで、過去にいくつかの似たような言語がパフォーマンスの向上を示している(Ierusalimschy et al, 2005; Shi et al, 2005)。</li>
<li>例え他に効果がなかったとしても、命令コードのフェッチとディスパッチが除去できるというだけで、十分にメリットは十分にある。<a href="http://bugs.python.org/issue4753">http://bugs.python.org/issue4753</a> で行われている議論を見ると、CPythonの命令コードのディスパッチの変更がいかに難しい問題であるかが分かるだろう。</li>
<li>現在のCPythonのVMの命令コードのフェッチ/ディスパッチのオーバーヘッドはあまりに大きいために、追加の最適化が行えない状況になっている。例えば、SELF-93(Ho"lzle, Chambers and Ungar, 1992)の型のフィードバックと、動的な再コンパイルをしようとしても、ポリモーフィズムの使えるインラインキャッシュを実装するのが容認できないほど遅いと感じている。</li>
<li>LLVMを使用しているため、さまざまなプラットフォームに対して簡単に使用できるコードジェネレータが利用できる。LLVMのコードジェネレータはC/C++を中間形式にコンパイルすることもできるが、それと同じコードをPythonから出力しようとしている。これにより、インラインでC/C++と連携したり、現在のPython/C言語間の障壁を越えたコード分析が行える。</li>
</ul>

<p>マシンコードを生成するインフラを、Pythonをコンパイルする機能に加えると、現在のバイトコード表現で行えることよりももっと多くの効果的な実装が行えるようになる。例えば以下のようなコードがあったとすると：</p>

<pre name="code" class="python">for i in range(3):
  foo(i)
</pre>

<p>現在は以下のように変換される</p>

<pre name="code" class="python">$x = range(3)
while True:
  try:
    $y = $x.next()
  except StopIteration:
    break
  i = $y
  foo(i)
</pre>

<p>もしrange()というのが組み込み関数のrange()のことであるというのを知ることができれば、我々は以下のように変換することもできるだろう。</p>

<pre name="code" class="python">for (i = 0; i < 3; i++)
  foo(i)
</pre>

<p>C言語では、数値計算のためのアンボックス型を使用することもできる。また、以下のようにループを展開することもできるだろう。</p>

<pre name="code" class="python">foo(0)
foo(1)
foo(2)</pre>

<p>我々は、Unladen Swallowの内部構造を、マルチコアが使用できることになることを想定した構造にしようと考えている。サーバにおいては、コア数は増える一方であり、より多くのタスクを並列でこなすために、性能を引き出せるようにしたいと考えている。例えば、他のコアで仕事をしつつ、より時間がかかるが性能の良い最適化を平行して行う並列コードオプティマイザを入れたいと考えている。また、<a href="http://code.google.com/p/unladen-swallow/wiki/GarbageCollector">並列ガーベジコレクション</a>も導入して、負荷のかかっていない、あまっているコアを利用できるようにしたいと考えている。今日では、ほとんどのサーバの製品は、4個から32個のコアを載せて出荷されているので、私達はこの方向性での最適化が有利であると考えている。しかし、高度に並列化されたアプリケーションの需要については敏感に察知していかねば、と考えている。盲目的にコアを消費すればいいとは考えていない。</p>

<p>なお、我々が取り組もうとしている領域の多くの部分では、他の動的言語の実装がいくつも計画されていたり、開発されていたりする。例えば、<a href="http://www.macruby.org/blog/2009/03/28/experimental-branch.html">MacRuby</a>, <a href="http://jruby.codehaus.org/">JRuby</a>, <a hre="http://rubini.us/Rubinius">, <a href="http://www.parrot.org/">Parrot</a>や、他のPython実装である、<a href="http://www.jython.org/Project/">Jython</a>, <a href="http://codespeak.net/pypy/dist/pypy/doc/">PyPy</a>, <a href="http://www.codeplex.com/Wiki/View.aspx?ProjectName=IronPython">IronPython</a>などである。我々はデバッグ情報に関するアイディアや、正規表現のパフォーマンスに関するアイディア、動的言語で一般的に使用されているパフォーマンスのためのアイディアというのを知るために、これらの他の実装を参考にさせてもらっている。これらは、すでに先人により踏み固められてきた部分であるため、一から車輪の再発明をすることは、できれば避けたいと考えている。</p>

<a name="Milestones"></a>
<h3>マイルストーン</h3>

<p>Unladen Swallowは三ヶ月ごとにリリースを行う。また、それとは別に必要に応じてその間にバグフィックスのためのリリースを行う。</p>

<a name="2009 Q1"></a>
<h4>2009 Q1</h4>

<p>Q1では、既存のCPythonの実装に対して、比較的小さな改修だけを行う。Q1で狙っているのは、標準の状態から25%から35%の高速化である。Q1の目標はできるだけ早く、既存のアプリケーションに対して、実際にパフォーマンスアップの恩恵を受けてもらうという、保守的なものである。プロジェクトの完了まで待ってもらうのは我々の望むところではない。</p>

<p>目標を達せするためのアイディア:</p>

<ul>
<li>"<a href="http://www.complang.tuwien.ac.at/anton/vmgen/">vmgen</a>の文法"の中のevalループを再実装する。</li>
<li>64bitのコンパイルオプションや、LLVMのLTOサポート、gcc4.4のFDOサポートを組み込む。</li>
<li>重要な命令コードのために、あまり使用されない命令コードを置き換える。</li>
<li>ガベージコレクションのパフォーマンスを改善する(<a href="http://bugs.python.org/issue4074">http://bugs.python.org/issue4074</a>)参照。</li>
<li>cPickleのパフォーマンスを向上させる。多くの巨大なウェブサイトでは、memcacheとしてかなりの頻度で使用しているからである。</li>
<li>フレームの割り当てと解放を高速化するために、frameオブジェクトをシンプルにする。</li>
<li>グローバルの要素と、組み込みの要素の探索のスピードを上げるために、いくつか考えているデータ構造(スキーム)の一つを組み込む。</li>
</ul>

<p>2009Q1リリースは<a href="http://code.google.com/p/unladen-swallow/source/browse/branches/release-2009Q1-maint">release-2009Q1-maint</a>というブランチで管理する。<a href="http://code.google.com/p/unladen-swallow/wiki/Releases">リリース</a>とCPython 2.6.1とを比較して我々のパフォーマンスを見て欲しい。</p>

<a name="2009 Q2"></a>
<h4>2009 Q2</h4>

<p>Q2でフォーカスするのは、LLVMの作法に従って実装した、機能的に同等のPython VMに置き換えることである。我々はいくつかのパフォーマンス向上をanticipateしているが、2009Q2リリースではそこには軸足を置くことはしない。Q2ではあくまでも、LLVM上で動作する実装を手に入れるということに注力する。subsecuent半期後には、これによって多くの速度改善が得られる見込みである。</p>

<p>目標：</p>

<ul>
<li>LLVMベースのJITを追加する。</li>
<li>JITを使用して、すべての標準ライブラリの回帰テスト群をパスする。</li>
<li>既存のアプリケーションや、C言語の拡張モジュールとソースコードレベルの互換性を維持する。</li>
<li>10%のパフォーマンスアップ。強気な目標としては25%の速度アップ。</li>
</ul>

<a name="2009 Q3"></a>
<h4>2009 Q3以降</h4>

<p>Q3以降(onward)の計画は単純に<a href="http://code.google.com/p/unladen-swallow/wiki/RelevantPapers">論文</a>に従ってイテレーションをこなしていくだけである。我々は独自の作業は行わないつもりであるが、過去30年にわたる研究成果を取り込むつもりである。 完全なリストではないが、<a href="http://code.google.com/p/unladen-swallow/wiki/RelevantPapers">RelevantPapers</a>のページにはその一部が含まれる。これらの論文の研究成果を引用して実装していくことを考えている。</p>

<p>我々は正規表現エンジンや、他のボトルネックが見つかった拡張モジュールのパフォーマンス改善についても計画をしている。しかし、正規表現はすでに、我々が改良を行っていくターゲットとしてふさわしいことは既に分かっているため、まず最初に最適化を行っていく。</p>

<p>それに加えて、我々が取り組もうと思っているは、GILの削除と、Pythonのマルチスレッドの状況の改善である。これは、IBMのRecycler(Bacon etal, 2001)のような、より"sophisticated "なガベージコレクションのシステムを実装することで可能になると信じている。</p>

<p>われわれの長期の目標は、パフォーマンス上重要なクラスと関数をCのバックエンドからPythonに持ってくることができるぐらい、Pythonを高速にすることである。</p>

<p>2009第三四半期のパフォーマンスの目標は第二四半期の終わりに決定する。</p>

<a name="Detailed Plans"></a>
<h3>詳細の計画</h3>

<p>すぐにできる改良を行って、何人かの人に我々のPythonが適用できると確信してもらったら、LLVMへの切り替え作業に入る予定である。おそらく、最初はブランチを切って作業を開始するだろう。これによって数多くの作業が行えるようになる。</p>

<ol>
<li>(完了)llvmmoduleと、llvmfunctionの２つの型をPythonに追加する。これはLLVMの<a href="http://llvm.org/docs/ProgrammersManual.html#Module">モジュール</a>と<a href="http://llvm.org/docs/ProgrammersManual.html#Function">関数型</a>へのインタフェースである。llvmmoduleに対しては、<a href="http://llvm.org/doxygen/ReaderWriter_8h.html">ビットコードファイル</a>の読み方と、それを<a href="http://llvm.org/doxygen/PrintModulePass_8h.html">整形して文字列化する機能</a>を実装する。ビットコードファイルの読み込みは次のステップの開発には必要ではないが、テストを楽にすることができる。<a href="http://code.google.com/p/llvm-py/">llvm-py</a>はこのようにラップされた型をいくつか持つが、コアインタプリタ内でPythonによって定義された型を使用するのはとても難しい。そのため、自分たちでこれらを書き直そうと考えている。llvm-py内に実装されるものは完全なラッパーとはならないが、デバッグが便利になると考えている。</li>

<li>(完了)LLVM IR(中間コード)で定義されたPython関数を実行する方法を追加する。これらの関数のコンパイルと実行にはLLVM JITを使用する予定である。この作業自体は迅速に進んだが、<a href="http://code.google.com/p/unladen-swallow/wiki/CodeLifecycle">開発の間中面倒をみる必要があると思われる問題</a>がいくつか残っている。</li>

<li>(作業中) CPythonのバイトコードに加えて、llvmmoduleやllvmfunction型としてLLVM IRを生成するコンパイラを組み込む。この作業は少しずつ進行させていくが、その間中、Pythonインタプリタとしても動作可能なまま作業を行っていく。作業の進捗は、<a href="http://code.google.com/p/unladen-swallow/source/browse/trunk/Python/ll_compile.h">Python/ll_compile.h</a>内の未実装(UNIMPLEMENTED)の命令コードで見ることができる。命令コードごとにLLVM IRのほぼ手作業で変換するという作業を行っている。作業のほとんどは、関数を分解して、これらを呼ぶという方法でできる。しかし、いくつかのPythonの構造はそう簡単には実装できない。</li>

<ul>
<li>クロージャー: クロージャーというのは、宣言された環境をパラメータとして設定された関数である。</li>
<li><a href="http://code.google.com/p/unladen-swallow/wiki/ExceptionHandling">例外のハンドリング</a> -- c版のevalの例外ハンドリング機構を変換する作業は順調とは言い難い状況である。CPythonは、ジャンプ先のバイトコードのインデックスを保存する。LLVMは命令のアドレスを保存することはできないため、例外ハンドラとして使用される基本ブロックと、適切なブロックにジャンプするswitch文を生成するようにしている。</li>
<li><a href="http://code.google.com/p/unladen-swallow/wiki/FunctionCallingConvention">関数呼び出し規則</a> -- すべての引数を含むPyFrameObjectを渡している。生成コストは我々が期待しているものよりも高価である。PyFrameObjectはスタックのように動作し、関数から戻る時にローカル変数を戻すのに使用されるが、LLVMが最適化するのを妨げてしまうのである。</li>ジェネレータ: 我々は、例外ハンドラで行ったのと同じように、yieldステートメントの数を数える予定である。そして、関数の中に、switch文を作成し、一度抜けたyield文から復帰できるポイントをブロックとして表現することを考えている。yieldの呼び出しの前後では、すべてのレジスタとローカル変数を保存する必要がある。幸いなことに、現在のCPythonのバイトコードからの変換作業の中では、スタックとローカル変数はすべて、return時にFrameObjectに保存するようにしているため、yieldからの復帰を実現するのも簡単にできる見込みである。しかし、フレーム内にローカル変数を保存するのをやめてしまうと、これを実現するのが難しくなってしまう。本来ならば、疑似レジスタの保存・復帰機能があればよかったが、残念ながら、現在のLLVMにはそのような機能は実装されていない。
</li>
</ul>
<li>おそらく、LLVM中間コードジェネレータと、CPythonコンパイラを切り離す。すべての関数に対して中間コードを生成するのは、メモリと時間の観点で見ると、かなりコストがかかる。すべてのJITコンパイラ内蔵のシステムがやっているように、使用頻度の高い関数に関してのみコンパイラすることで、よりパフォーマンスが向上するだろう。この処理を入れる前に、両方の選択肢の測定をする必要はあるだろう。</li>

<li><a href="http://code.google.com/p/unladen-swallow/wiki/PersistentIr">.pycを永続化する</a>にあたって、一番簡単に行うにはどのようにするかを理解する。今考えているのは、PythonモジュールをLLVMモジュールとしてバイトコードにして実行できる形式でディスクに保存することである。将来的(step11)には情報がぎっしり詰まったプロファイリングのデータと、最適化前のコードも追加したいと考えている。</li>

<li>Pythonに対して、高速JITと低速JITを、ある関数はどちらを適用するか、というのをどのように決定するか、というのを教える(<a href="http://llvm.org/doxygen/classllvm_1_1JIT.html#fd0a3b0d55489b96760121e3e25b7de62">JIT::create</a>にfast==Trueを渡す)。nlewycky氏は「コード生成は高速モードにおいては、おおまかに3倍は高速(計測時はリリースモードではなく、デバッグモード)」と話をしている。このタスクの中では、ただしいバランスを見つけるためには、非常に細かい調整が必要になりそうである。この時点で、我々の最初のリリースよりも早くなることが期待される。</li>

<li>追加の最適化の追加の開始<br/>
Talin氏は、Pythonの関数呼び出しが間接的であるため、事前定義の最適化に関する技術を前もって適用するのは困難であると指摘している。そのため、直接呼出しができるように、型推論に取り組みたいと考えている。</li>
</ol>

<p>8番目以降の項目は、2009の第二四半期の終わりに向けて、平行で作業を行っていく。</p>

<li>Step4の成果と関連する項目。よりよいプロファイルやコンパイル結果が得られるように、CPythonバイトコードからのLLVM中間コード生成をやり直すか、あるいはAST情報を使用して<a href="http://code.google.com/p/unladen-swallow/wiki/DirectLlvmIrGeneration">LLVM中間コードへのコンパイルを直接</a>行いたい。</li>

<li>どのようにして特定の型に対して、特別バージョンの関数を定義すればいいかを考える。これができれば、インライン化されて高速になる。Psycoのアルゴリズムを盗むことができるため、同じぐらい簡単にできるはずである。
<ol>
<li>インタプリタに対して、どの特別版を使用すればいいのかをユーザがアノテーションを使って指定できるようにする</li>
<li>メソッド呼び出しとをプロファイルし、一般的な引数の型を推測する</li>
</ol>
</li>
<li>9bと10は与えられた関数を実現するためには、複数のバージョンのコードを取得し、既存の呼び出し元に対してさかのぼってパッチを与える必要がある。我々は複数バージョンのGCが必要になるだろう。興味深くなるはずである。</li>
<li><a href="http://code.google.com/p/unladen-swallow/wiki/PersistentIr">生成されて、最適化された中間コードを、.pycファイルの代わりにディスクに保存</a>する。このとき、同時に収集済みのプロファイルデータも保存する。２回目以降の実行時には、前回の実行時に既に行われた最適化のメリットを享受することができるようになる。LLVMが約束している「一生涯にわたるプログラム分析と変換のためのコンパイルフレームワーク」という標語にも合っている。</li>

<a name="Regular Expressions"></a>
<h4>正規表現</h4>

<p>正規表現は伝統的なパフォーマンス上のホットスポットではないが、ほとんどの正規表現のユーザは、もっと早くなることを期待しているということが分かっている。また、結果として予想外のパフォーマンス劣化が発生することもある(訳不安)。このため、CPythonの正規表現エンジンの速度アップに対しても、リソースを投入するつもりである。</p>

<p>CPythonの現在の正規表現エンジンは、スタックベースのバイトコードインタプリタである。CPythonの正規表現エンジンには、命令コードのディスパッチのパフォーマンスを向上させるような、現代的な技術(Bell 1973; Ertl & Gregg, 2003; Berndl et al, 2005)の要素は取り込まれていない。その他の面では、伝統的で率直な実装のバーチャルマシンとなっている。我々は、Pythonそのものパフォーマンスの速度アップに使用される多くの技術は、同じように正規表現のパフォーマンス向上に対しても適用できると信じている。方法としては、まずはJITコンパイルされた正規表現をマシンコードに落とすことにより、命令コードのディスパッチの性能を向上させるところから始めるだろう。</p>

<p>JavaScriptのコミュニティが最近行っていることを見れば、我々が信じていたものは間違っていないということが分かる。GoogleのV8エンジンには<a href="http://blog.chromium.org/2009/02/irregexp-google-chromes-new-regexp.html">Irregexp</a>というものが組み込まれている。これはJIT正規表現コンパイラである。また、<a href="http://webkit.org/blog/214/introducing-squirrelfish-extreme/">SquirrelFish Extreme</a>には同様の原理を基にした、新規の正規表現エンジンが含まれている。JITのコンパイル時間と、実行時間のトレードをするものである。これらは両方とも、さまざまなJavaScriptのベンチマークの正規表現の項目において、驚くほどの改善を見せている。我々が行いたいのは、これらの成果を、CPython上でも実現することである。</p>

<p>我々は、これとは別にシンプルな正規表現については<a href="http://209.85.173.132/search?q=cache:XQrcPV-4kngJ:swtch.com/~rsc/regexp/regexp1.html+thompson+NFA&cd=1&hl=en&ct=clnk&gl=us">Russ Cox</a>が主張している、Thompson NFAを使用しようと考えている。これは、パターンによって最速の実装を選択できるような、複数エンジンの正規表現システムを作成するということである。V8チームも、Irregexpのワーキングではこのようなハイブリッドシステムを考えていたが、採用はされなかったという話を聞いた。以下のように<a href="http://blog.chromium.org/2009/02/irregexp-google-chromes-new-regexp.html#c4843826268005492354">述べている</a>。</p>

<blockquote>現在我々が取り掛かろうとしている問題は後方参照と、後方追跡の文脈で使用される|や*といった基本演算子である。正しい振る舞いにするためには、通常の正規表現のように、後方追跡が必要となる。Webで使用されている正規表現のデータをもとに、我々が考えている最適化が十分であるかどうか検証してみたが、この方法をとったサブセットによる利益はあまりにも小さいということがわかった。</blockquote>

<p>CPythonの正規表現エンジンに対して仕事に取り掛かる前に解決しなければならない問題のひとつは、Pythonには正規表現のベンチマーク集が存在しないというという問題である。我々は<a href="http://v8.googlecode.com/svn/data/benchmarks/v3/regexp.js">V8ベンチマークのregexp.jsコンポーネント</a>を再利用できないか、ということを考えているが、まず最初に、これらのベンチーマークがPythonのプログラムで書かれる正規表現の種類を網羅しているかどうかの検証をしなければならない。Pythonプログラムの中で使用されている正規表現が、JavaScriptやRuby, Perlなどで使用されるものと大きく違うと信じる理由は特にないが、確認が必要なことには変わりはない。</p>

<a name="Start-up Time"></a>
<h4>起動時間</h4>

<p>数多くのPythonのヘビーユーザと話をすると、Pythonの起動時間の改善に興味を持つ人は多い。これは、サーバーの再起動の時間を早くしたいと思っているような巨大なウェブサイトでもそうであるし、起動時間が減れば作業時間もそのまま減るようなコマンドラインツールの作者からも言われる。</p>

<p>特に<a href="http://bazaar-vcs.org/">Bazaar</a>のようなアプリケーションの場合、現在は起動時間はほとんどimportにかかった時間である。Pythonは、インポートを実行時まで遅延させたり、インポートがどのように動作するかをカスタマイズできるようなフックをたくさん提供したり、モジュールを読み込む場所を変更できたり、数多くの柔軟性を提供している。この柔軟性の代償としてimportが遅くなっているのである。</p>

<p>多くのユーザにとっては、特定のサーバで利用されるような柔軟性のメリットはあまりない。起動ごとにimportの動作が変える必要はないのである。そのため、我々はより厳格で動作の速いimport文の選択肢を提供しようと考えている。アイディアのひとつは、必要となるすべてのモジュールを、ひとつにまとめて自己完結したバイナリを格納するという方法である。これは、a)ファイル操作のシステムコールがimportするたびに発生するのを避ける、b)Pythonのレベルでの、<a href="http://www.airs.com/blog/archives/100">リンク時の最適化</a>が行えるようになるというメリットがある。結果として、内部モジュールのインライン化や同様の最適化が行えて、速いコードが手に入るのである。自己完結イメージは特に、サーバアプリケーションの実装をする多くのPythonユーザにとって魅力的である。ビルドとデプロイが効率的に行えるからである。</p>

<p>内部構造の変更が少ない高速化としては、<a href="http://docs.python.org/library/marshal.html">Pythonのmarshalモジュール</a>の最適化が考えられる。marshalモジュールは.pycや.pyoといったファイルの生成で使用されている。Unladen Swallowの作業の成果であるcPickleの高速化の技術を基にすることで、少ない手間でmarshalモジュールの高速化を行うことができる。</p>

<p>いくつかの設定の違いごとの、起動時間を追跡するベンチマークは手元にある。現在のCPythonの起動時間の大きな部分をimportが占めているので、このベンチマークにimportにフォーカスした小さいなベンチマークを追加しようと考えている。</p>

<a name="Testing and Measurement"></a>
<h3>テストと測定</h3>

<a name="Performance"></a>
<h4>パフォーマンス</h4>

<p>Unladen Swallowの<a href="http://code.google.com/p/unladen-swallow/source/browse/#svn/tests">tests</a>ディレクトリの中には、いくつかの面白いパフォーマンステストのディレクトリがある。pref.pyというファイルが我々が開発に利用するベンチマークの主要なインタフェースである。このファイルが、各種ベンチマークの起動の橋渡しをしたり、*.py[co]ファイルの掃除をしたり、実行結果の統計を取ったりするのである。</p>

<p>Unladen Swallowのベンチマーク集は、主要なPythonアプリケーション、特にウェブアプリケーションのホットスポットにフォーカスしている。我々が調査した主要なウェブアプリケーションでは、主にテンプレートシステムがボトルネックであると分かった。そのため、我々の初期のベンチマーク集は以下の項目に注目した。</p>

<ul>
<li><b>DjangoとSpitfireのテンプレート:</b> テンプレート言語としてはこの二つは大きく異なる方法で実装されている。</li>
<li><b>2to3:</b> Python2の文法をPython3に変換する。興味深いのは、ピュアPythonのカーネルがオブジェクトやメソッドディスパッチを多用するプログラムとなっている。</li>
<li><b>pickle化とunpickle化:</b> 大規模なアプリケーションでは、Pythonのpickleフォーマットをシリアライズに利用したmemcacheの仕組みに依存している。</li>
</li>
</ul>

<p>これとは別に、マイクロベンチマークも用意している。例えば、Nクイーン問題を解くプログラムや、覆面算を解くプログラムや、起動時間のベンチマークなどである。</p>

<p>これらとは別に、Richards, PyStone, PyBenchといったベンチマークもいくつか含んでいる。これらは、Pythonの実装の完全さを確認したり、他のPython実装と比較する目的で入れているだけである。Unladen Swallowでは、これらのベンチマークは実際のアプリケーションや、Pythonの実装方法のパフォーマンスを代表したベンチマークであるとは考えていない。そのため、デフォルトでは、これらのテストは実行されないし、この結果を持って方法を決めることもないのである。</p>

<p>プロジェクトの、長期のパフォーマンスの傾向をグラフ化するために、Unladen SwallowではGoogleの社内標準のパフォーマンス測定フレームワークを利用している。プロジェクトメンバーは定期的に、これを使用したパフォーマンスの最新情報をメーリングリストに投稿するだろう。しかし、個々の変化のテストに使用するのは、<a href="http://code.google.com/p/unladen-swallow/wiki/Benchmarks">Benchmarksのページ</a>で説明されている、perf.pyで十分である。</p>

<a name="Correctness"></a>
<h4>正確さ</h4>

<p>Unladen Swallowでは、実装の正確さを確認するために、Pythonの標準のテストスイートと、Python2.6上でよく知られているいくつかのサードパーティ製のライブラリの両方を使用する。特に、サードパーティ製のC拡張モジュールは、気づかないようなC言語レベルの変化で、すぐに動作しなくなるため、テストに使用している。</p>

<p>JITの実装が前進するにつれて、我々はファジングテストを通常のテスト実行に組み込む予定である。我々が計画しているのは、Victor Stinner氏の<a href="http://fusil.hachoir.org/svn/trunk/">Fusil</a>というPythonのファジングツールである。これはa)既に存在しており、b)Python上の本当のバグを発見するデモンストレーションを行ったことがある、というのが理由である。</p>

<p>Unladen Swallowでは--jitオプションを設定することで、JIT実行時の動作を制御することができる。例えば、--jit=neverを指定すると、JITは完全に動作停止をする。--jit=alwaysを設定すると、初回のウォームアップのインタプリタの実行をスキップし、直接ネイティブコード生成を行うようになる。--jit=onceを設定すると、再コンパイルしなくなる。これらのオプションは、状況に応じてさまざまな実行方法をテストするのに使用される予定である。我々の目標は、例えば最適化が十分に行われて初めて発生するようなバグのある機能があったとして、そのような決して出会うことのないようなJITバグを見つけることである。これはJVMで提供されているinterpreted modeと同様のものである。</p>

<p>Unladen Swallowでは上記のようなテストをコミットごとに毎回実行するために、<a href="http://buildbot.net/trac">BuildBot</a>インスタンスを整備している。</p>

<a name="Complexity"></a>
<h4>複雑さ</h4>

<p>CPythonの美徳のひとつはシンプルさである。CPythonのVMとコンパイラを変更するのも比較的シンプルで簡単であった。LLVMを組み込む作業は、必然的にCPython実装を複雑にしてしまうものである。この追加実装からくる生産的なトレードオフを測定するために、Unladen Swallowチームは定期的にpython-devとpython-ideasというメーリングリストからアイディアをもらい、実装している。もしそのアイディアを実装するのがCPythonに適用させるのよりも難しければ、それをマージする前に何かを修正しなければならないということが分かるのである。チームメンバー以外のメンバーにやってもらいたいのは、バイアスが少ない視点で実装してもらうことである。</p>

<a name="Risks"></a>
<h3>リスク</h3>

<ul>
<li><b>Pythonのメインのソースコードに対して結果をフィードバックすることがおそらくできない:</b> Pythonのコア開発コミュニティのメンバーの中には、我々が行った変更が大きすぎるということで反対する人がいる。しかし、これは正しいことである。このような状況において、変更に反対することは健全なことである。我々のパッチを公に検査を行うことは、かなりの労力をさいたとしても、CPythonのメンテナンスに長期にわたる影響を与えてしまうからである。もちろん、Pythonはオープンソースであるので、変更をチェックしようと言う人が現れるのは大歓迎である。我々は、自分達の提案は正当なものであると認めてもらうことは可能であると信じている。Guidoや他のコミュニティメンバーと緊密に協調し続けているが、我々の変更は、受け入れてもらうチャンスがある内容に限定したいと考えている。しかし、いくつかのパッチはリジェクトされる可能性もまだある。そうなると、我々はデファクトのPython実装とは別のPython実装をサポートし続けるか、あるいは妥協して、期待ほど速くない実装で我慢するかしなければならない。人生と言うのはそういうものである。</li>
<li><b>LLVMにまつわる多くの未知のもの:</b> 拡張モジュールの影響は？マルチスレッドアプリケーションにおけるJITの動作は？Pythonの起動時間に与える影響は？</li>
<li><b>Windowsサポート:</b> 現在のCPythonのWindowsサポートはすばらしいので、メインのコードに我々のパッチをマージする際にもこれは維持する必要があると考えている。Unladen SwallowのエンジニアはWindowsの経験が浅いか、ない人が多く、Windowsマシンもないが、我々の進捗を多少遅らせても大丈夫なレベル、もしくはいくつかのパフォーマンス改善コードを無効にしたとしても、windowsのサポートは維持していこうと考えている。コミュニティの貢献により、これらのことが行うことができている。</li>
<li><b>特殊なプラットフォーム:</b> CPythonは現在、巨大な鉄の塊のサーバマシンから、Nokiaのケータイ電話まで、幅広いハードウェア、ソフトウェアのプラットフォームで実行できる。このプロジェクトでは、移植性と柔軟性をできる限り維持したいと考えている。LLVM(や、手書きのJITコンパイラ)を使用することでメモリ使用量と、Pythonのバイナリファイルのサイズが大きくなることはわかっている。そのため、程度によっては、以前サポートされていたプラットフォーム上でもUnladen Swallowが実行できなくなってしまう可能性もある。このリスクを軽減するために、Unladen SwallowではLLVM統合を完全に無効にして、以前のevalループを強制的にしようさせる、./configureのフラグを導入しようと考えている。</li>
</ul>

<a name="Communication"></a>
<h3>コミュニケーション</h3>

<p>Unladen Swallowに関するすべてのコミュニケーションは、Unladen Swallowのメーリングリスト上で行われるべきである。このメーリングリストでは、設計に関する議論が行われ、ビルド結果、パフォーマンスの数値、コードレビューの結果が定期的に報告され、その他のオープンソースプロジェクトに関するすべての詳細な話も行われる。もしこのページ(Unladen Swallowのwiki)にコメントを付けたとしても、見落とすことがあるかもしれないため、申し訳ないが、<a href="http://groups.google.com/group/unladen-swallow">メーリングリスト</a>の方にメールを出してもらいたい。</p>

<div class="category_articles">
<a href="http://articles.shibu.jp/article/30008337.html">プロジェクト計画</a><br/>
</div>
]]></content:encoded>
</item>
<item rdf:about="http://articles.shibu.jp/article/29464661.html">
<title>Capabilities for Python?</title>
<link>http://articles.shibu.jp/article/29464661.html</link>
<description>原著者：Guido van Rossum原文：http://neopythonic.blogspot.com/2009/03/capabilities-for-python.html原文公開日：MARCH 6, 2009Python作者のGuidoのブログの翻訳です。一日にちょっとずつ翻訳をしていたのですが、長くて一ヶ月もかかってしまいました。読むのも大変だとは思いますがどうぞ。capabilityという言葉があったんですね。権限を与えていく方式のことをcapabilityと...</description>
<dc:subject>Guido's Blog</dc:subject>
<dc:creator>しぶかわ</dc:creator>
<dc:date>2009-05-30T08:45:27+09:00</dc:date>
<content:encoded><![CDATA[
<p><b>原著者：</b>Guido van Rossum<br/>
<b>原文：</b><a href="http://neopythonic.blogspot.com/2009/03/capabilities-for-python.html">http://neopythonic.blogspot.com/2009/03/capabilities-for-python.html</a><br/>
<b>原文公開日：</b>MARCH 6, 2009</p>

<p>Python作者のGuidoのブログの翻訳です。一日にちょっとずつ翻訳をしていたのですが、長くて一ヶ月もかかってしまいました。読むのも大変だとは思いますがどうぞ。<a href="http://ja.wikipedia.org/wiki/Capability-based_security">capability</a>という言葉があったんですね。権限を与えていく方式のことをcapabilityというらしいです。最後にGoogle App Engineのこともちょろっと触れられていますよ。</p> 
 
<p>訳がこなれていない部分もあったり、リンク先の資料とかも目は通してなかったりするので、読みにくかったり勘違いしている部分もあるかもしれません。</p> 
 
<hr/> 
 

<p>私はMark Miller氏からemailを受け取った。<a href="http://www.eros-os.org/pipermail/cap-talk/2009-March/012361.html">Zooko氏のcap-talkメーリングリスト(私は参加していない)のポスト</a>を引用したものである。Markは私に対して、<a href="http://ja.wikipedia.org/wiki/Capability-based_security">capability</a>(訳注：チケットを用いたオブジェクトの保護システム)に対する見解を明らかにして欲しいと質問をしてきた(おそらくPythonに対して) 。他のメーリングリストへの参加が必要ということもあるので、自分の意見をここに書くことにした。検索エンジンの魔法によりこの記事は関係する場所に届くことが期待される (訳注：GuidoはGoogleで働いているため検索エンジンに触れているのかも) 。</p> 
 
<p>彼がポストした内容によると、Zooko氏は、私がcapabilityについてのアイディアを敵視をしていて、Amoeba(Pythonは、もともとは、Amoeba向けに開発された)におけるパスワードを使ったcapabilityと、私の想定される態度や経験とを結び付けようとしているようである。これはいくつかの理由で奇妙だと言わざるを得ない。最初に、私が覚えている範囲内では、Amoebaのcapabilityはパスワードを利用しているわけではなく、不可逆(一方向)の関数と乱数を基にしている。それと、安全な壁に埋め込まれたイーサネットのソケット(これはおそらく流行らなかった:)も。二番目にAmoebaにおけるcapabilityの私の経験から、何年もかけて、プログラミング言語の<a href="http://www.erights.org/elang/index.html">E</a>のようなモダンな言語から、Pythonへcapabilityを組み込む提案の中に効果のあるものがあったとは思えないことである。最初の提案は確か、Ka-Ping Yee氏とBenLaurie氏のものであった。この内容はというと、足し算的なアプローチよりも、引き算的なアプローチであったが、実質的にはユーザを制限するPythonサブセットのことである。</p><a name="more"></a><p>今回の件でもっとも驚いたことは、人々が私のひとつひとつの言葉を細かく読んでいるということである。私は宗教的な権威であるローマ法王でもなんでもないのに！私は、設計上の問題について独り言を言うのが好きなハッカーでしかないのである。その独り言も、正しいとは決して言えないのである。もし、私がつぶやいた意見に同意できず、何か質問をしたいというときは、私が投稿しているフォーラム(python-dev, python-ideas, もしくはこのブログ)に反応を返していただきたいと思う。私が読んでいないところに転送して、あれやこれや、推測をするのはやめていただきたい。</p> 
 
<p>とりあえずこの件は置いて、<b>ついでにこの記事はすべて独り言である、と表明</b>したうえで、capabilityとPythonについての、現在の私の考えについていくつか表明したいと思う。</p> 
 
<p>まず、これから説明するのはPythonに限定したいと思う。Capabilityに注力して設計された言語は既に存在して、ある程度の成功は収めているだろうし(例えばE)、その一方で、それらの言語が人気を獲得して、他の魅力的な機能が芽吹くまでには困難な時間を要すると思われるからである。ほとんどの開発者はセキュリティ＝必要悪とみなしている。</p> 
 
<p>こういった姿勢こそが、新しい言語を開発しないで、既存の言語にセキュリティ機能を追加しようという考え方になる理由である。これは、「薄汚れた(訳注：おそらくセキュリティ対策を考えていない、という意味)人々」を、彼らが既に知っている言語の少しだけ異なるバージョンにスイッチするほうが、完全に新しい言語を(一人で採用して)試行するのに比べてはるかに簡単である。もちろんこの説明は、熱狂的なセキュリティ狂信者の行動について否定をするものではない。同様のことは、一般的な「言語のマーケティング」という大きな世界でもいえる。C++はC言語と互換性を持たせる方針で設計され、これから外れるものは却下されている(訳注：実際は型チェックなどはより厳格な方向に変更されている)し、Javaは受け入れやすさを狙ってC/C++と類似するように設計されている。また、良く知られていることでいえば、Larry WallはPerlを設計するにあたり、初期のターゲットユーザがすでにsedとshを使っているという前提のもと、「ねじれた構文」を採用している。</p> 
 
<p>私もPythonの設計においてこのような点から完全に自由であったとは言えないということは認める。私の場合は人気を取るためにそういうことわけではないが。私が他の言語からアイディアを借りてくるときには、そのアイディアがすばらしいものであると認めたときであって、現在のプラクティスに何かを追加するのを目的としていたわけではない。マーケットシェアについて心配はしていなかった。もし心配していたのであれば、グループを表現するためにインデントを使用することはしなかった。</p> 
 
<p>とにかく、このような考えのメリットがあるにもかかわらず、何度も非互換な拡張の要求はやってきては、去り、というのをつづけている。一番最近転生してきたのは、Mark Seaborn氏による<a href="http://plash.beasts.org/wiki/CapPython">CapPython</a>である。Wikiページをざっと読んでみると、このページの半分以上を「問題点」と書かれたセクションがあることから、Mark氏はセキュリティ機能追加による制約については良く気づいているように思える。もっとも最近の議論(Zooko氏のポストのトリガーとなった、と私が思っているもの)は、<a href="http://tav.espians.com/a-challenge-to-break-python-security.html">Tav氏が自分のブログに書いた内容</a>から始まった。これには、CPythonの既存の制限実行モードへの、いくつかの謙虚な提案(これは私にとって励みになります!) と、この制限実行モードへのアタックのチャレンジが書かれていた。<a href="http://tav.espians.com/paving-the-way-to-securing-the-python-interpreter.html">返信</a>を見るとTav氏はこの分野の歴史に関して明るく、私が自分自身で提供するのよりも良いものを提供できそうに思える。</p> 
 
<p>しかし、私はこの手法に関しては極めて疑わしいと思い続けている。Tav氏のスーパーバイザーコードに対するさまざまな攻撃によって、堅牢なスーパーバイザーを書くのがいかに信じられないほど微妙であるかということを物語っている。CPythonの制限実行モデルはサンドボックスの中の(信頼のない)コードが、スーパーバイザーの中へ、コールしにいくというモデルになっている。スーパーバイザーのPythonコードは完全な権限を持って実行されている。Tav氏のバージョンでは、スーパーバイザーがサンドボックス内にいくつかの関数オブジェクトを提供している。サンドボックスは、それらの関数を通じてのみ、スーパーバイザーへのアクセスが行えるというものである。Tav氏の目的としている変更により、いくつかのインスペクション(訳注：内省。Java用語のリフレクション＝反省とほぼ同一)のための属性が関数から取り除かれる。また、スーパーバイザーがサンドボックス内から隠そうとしているデータや関数へのアクセスを提供するようなその他のクラスオブジェクトも取り除くとしている。この基本的な考え方はうまくいくだろうし、まだサンドボックスを直接突破する方法を見つけた人はいない。そのため、今のところサンドボックを堅牢に保つために、これ以上取り除く必要のある属性は存在しないように見える。</p> 
 
<p>しかし、Tav氏のスーパーバイザーコードの中の脆弱性をたたく、いくつかの攻撃方法(不確かであるが)があきらかになっている。サンドボックス内のコードによって作成された、一見したところ安全なビルトイン関数(引数が設定される)の呼び出しにより、セキュリティを突破するのは難しそうに見えるが簡単である。この方法は、何年も前にSamuele Pedroni氏がPython 2.2以降の制限実行環境が危険ではないか、という疑念を明確にするのに使用された。</p> 
 
<p>Samuele氏のアプローチは、(C)Pythonの二つの性質を結びつけるものである。ひとつはスーパーバイザーに使用されたビルトイン関数が、スーパーバイザーの権限で実行されてしまうということである。もうひとつは、Pythonの中では多くの場所、特にオブジェクトに渡される名前付きの属性で暗黙の変換が行われるということである。このような特性により、サンドボックスの抜け穴があると、ビルトイン関数にセットされるような「魔法の属性」を持つクラスを定義することができるようになり、スーパーバイザー権限でビルトイン関数が呼ばれるようになる。これは、いくつかの面白い引数をビルトイン関数に渡し結果を受け取ることができる知恵を持っている。詳しくは<a href="http://tav.espians.com/a-challenge-to-break-python-security.html">Tav氏のブログ</a>に書いてある。</p> 
 
<p>私がこのアプローチに対して心配しているのは、スーパーバイザーが提供しているそれなりに大きなPythonのサブセットがかなり複雑なことをしなければならないということである。例えば、モジュールのインポートの安全な仕組みの提供などである。複雑になればなるほど、私がスーパーバイザーのセキュリティに対して感じる信頼度は指数関数的に下がる。言い換えれば、Tav氏が"safelite.py"というスクリプトに書かれたおもちゃのスーパーバイザーコードに対し、クラックを試して、問題があればパッチを当てるという作業を何度か繰り返して進化させて、強固な防護壁を持つ完全な機能のスーパーバイザーを完成させるには、現実的な時間の枠内(10年単位)には収まるようには思えないのである。</p> 
 
<p>それでは、他のもっと一般的な、堅牢なPythonのサブセットの話題に移ろうと思う。これらは、標準ライブラリに含まれる<a href="http://www.python.jp/doc/2.4/lib/module-rexec.html">制限実行機能</a>、あるいは属性参照に制限を加えたもの(例えばCapPythonや、ZopeのRestrictedPython)のことである。Pythonが褒められる場合、標準ライブラリが褒められることが多い。Pythonの開発スキルが上達することで、組み込みのリストと辞書だけを使って、効率の良いアルゴリズムを実装するのがどれぐらい良くなるか、ということは計測されていない。多くの場合、実装がどれぐらい効率的に行えるかどうかというのは標準ライブラリをどのぐらいマスターしているのか、ということに依存している。Pythonの標準ライブラリは多くの他の言語よりも大きい。唯一Javaは「いつでもそこにある」ということをやろうと思っているらしく、Pythonよりも多くのライブラリを持っている(ただし特定の組み込み環境を除く)。</p> 
 
<p>"堅牢な"バージョンのPythonの成功のためには、ほとんど標準ライブラリのAPIのサポートが必要になると思われる。私はここでは、実装とAPIを区別している。理由としては、多くの標準ライブラリモジュールは、堅牢なサブセットによって使用できないようになっている言語機能を使用している可能性があるからである。これ
は、堅牢なサブセットでのみ使用される別の実装が提供されるのであれば、大きな問題とはならない。</p> 
 
<p>残念ながら、これらの要因が組み合わさると、堅牢なPythonサブセットにマッチした、十分な大きさの標準ライブラリを提供するということはとても実用的ではないと思う。ひとつの問題はPython自身にある。Pythonは高級な動的な言語であり、Cpythonにおけるバイトコードへのアクセスなど、実装固有の部分を含む、あらゆるレベルでのインスペクションをサポートしている(バイトコードアクセスはJythonやIronPythonや他の実装ではこれに相当する機能はない)。もちろん、言語の動的な機能やインスペクションの機能があるからといって、ほとんどの場合はモジュールAPIと、実装の間に直接の影響があるとは限らない。これは時々Pythonユーザのフラストレーションの原因となるが(例えば、最近のpython-devにおける<a href="http://mail.python.org/pipermail/python-dev/2009-March/086668.html">asyncoreについての議論</a>)、ほとんどのケースでうまくいっており、いくつかの動的な機能を利用することでAPIをシンプルにできることも多い。例えば、動的なアトリビュート検索を利用して、APIを拡張する方法がいくつかある自動デリゲーションは、まさにその動的な機能の一般的な使用例の一つと言える。また、コマンドのディスパッチも有名である。堅牢なバージョンのPythonが十分な数のユーザをひきつけるほど完璧になるのは難しい。もちろん、この考えが間違っていると証明されて欲しいと思っているが、人々は追加的なセキュリティにより、手っ取り早く成功する方法を提供して欲しいという考えに惹かれているように思える。しかし、残念ながら、私には、この追加的なアプローチはショートカットになるとは思えないのである。</p> 
 
<p>ここで、私がいくつかの経験をしている<a href="http://code.google.com/appengine/">Google App Engine</a>(現在私の時間のほとんどはこれの貢献に使用している)についても触れる必要があるだろう。Google App Engineでは標準ライブラリのサブセットをサポートした、"堅牢"に改良されたPythonを提供している。今、"堅牢"と、引用符でくくって書いたのには理由がある。App Engineのセキュリティのニーズはcapabilityのコミュニティいつも目的としているようなニーズとは多少異なる。Pythonアプリケーション全体が、ひとつの堅牢なドメインの中にあり、セキュリティはC/Pythonの境界やユーザ/カーネルの境界、仮想マシンの境界で強固に守ることで堅牢な環境が手に入れられる。信頼されていないプロセスとの堅牢な通信は提供されていない。スーパーバイザーのコードはC++で実装され、重要な部分は異なるプロセスとして活動している。</p> 
 
<p>App Engineの場合、Pythonの言語としての方言はCPythonとして実装されたものと完全に同じである。唯一の違いはライブラリのレベルにある。App Engineのユーザはファイルシステムにデータを書き出すことは出来ない。また、ソケットやパイプ、スレッドやプロセスも作成することはできない。また、裏口となるようないくつかのビルトインモジュールも使用できなくなっている。モジュールに関しては、いくつかのケースでモジュールの堅牢性を崩すようなAPIのみが使用できなくなり、それ以外の安全だと思われる便利なAPIは残された。これらはすべてApp Engineの目標を達成するためには、極めて合理的な制約と言える。そして、ほとんどの場合で、この中のひとつの制約だけが、App Engineの<a href="http://code.google.com/p/googleappengine/issues/detail?id=60">ユーザに苦痛</a>をもたらしている。</p> 
 
<p>App Engineのセキュリティの向上には、内部リソースをかなり使用しているが、まだ結果は大きく制限されている。App Engineのセキュリティモデルが、capability信者が好むものよりも、かなりシンプルであることを考えて欲しい。これは乱暴な開発者からの攻撃からGoogleを守るためのオール・オア・ナッシングのモデルである。一方で、開発者がお互いを攻撃しあうのを防ぐ効果もある。推測するに、capabilityをベースとしたPythonの場合は、セキュリティを守るためにもっと多くの努力が必要になったと思うし、開発者にはもっともっと多くの制限が課せられていたと思う。Google App Engineは開発者が使いたいと思うような、とても「魅力的な機能」を持たなければならないと思っている。</p>

<div class="category_articles">
<a href="http://articles.shibu.jp/article/29464661.html">Capabilities for Python?</a><br/>
<a href="http://articles.shibu.jp/article/29464627.html">Scala?</a><br/>
<a href="http://articles.shibu.jp/article/29464593.html">In the Cloud or Not?</a><br/>
<a href="http://articles.shibu.jp/article/29464527.html">2MBのメモリで100万の数値をソートする</a><br/>
<a href="http://articles.shibu.jp/article/29464404.html">Python 3000 and You<br/>
</div>
]]></content:encoded>
</item>
<item rdf:about="http://articles.shibu.jp/article/29464627.html">
<title>Scala?</title>
<link>http://articles.shibu.jp/article/29464627.html</link>
<description>原著者：Guido van Rossum原文：http://neopythonic.blogspot.com/2008/11/scala.html原文公開日：NOVEMBER 21, 2008またまたGuidoのブログの翻訳です。GuidoがScalaを語ってる！と思ったら、なんか色々不満なご様子。Scala用語はイマイチ分からぬことも手伝って、相変わらず適当翻訳ですがどうぞ。   私は、Scala eBookの無料コピーをMartin Odersky氏, Lex Spoon...</description>
<dc:subject>Guido's Blog</dc:subject>
<dc:creator>しぶかわ</dc:creator>
<dc:date>2009-05-30T08:42:41+09:00</dc:date>
<content:encoded><![CDATA[
<p><b>原著者：</b>Guido van Rossum<br/>
<b>原文：</b><a href="http://neopythonic.blogspot.com/2008/11/scala.html">http://neopythonic.blogspot.com/2008/11/scala.html</a><br/>
<b>原文公開日：</b>NOVEMBER 21, 2008</p>

<p>またまたGuidoのブログの翻訳です。GuidoがScalaを語ってる！と思ったら、なんか色々不満なご様子。Scala用語はイマイチ分からぬことも手伝って、相変わらず適当翻訳ですがどうぞ。</p> 
 
<hr/> 

<p>私は、<a href="http://www.artima.com/shop/programming_in_scala">Scala eBook</a>の無料コピーをMartin Odersky氏, Lex Spoon氏, Bill Venners氏の三名からいただいた。私は、<a href="http://www.caltrain.com/">CalTrain</a>(訳注：アメリカのカリフォルニア州を走る通勤電車)で通勤中に読もうと挑戦してみたが、ざっと内容をつかむことしかできなかった。700ページ以上ある大作の本である。私はもちろん、この書籍のターゲットの読者ではない。この本のターゲットは二つあり、一方はより良い言語に挑戦しようとするJavaプログラマーへの誘惑、もう一方はScalaを使うとどのようなことが起きるのか、という紹介である。その二つの間を行き来している感じである。私は最終的には<a href="http://www.scala-lang.org/">Scalaのウェブサイト</a>(<a href="http://www.scala-lang.org/sites/default/files/linuxsoft_archives/docu/files/ScalaTutorial.pdf">チュートリアル</a>や<a href="http://www.scala-lang.org/sites/default/files/linuxsoft_archives/docu/files/ScalaOverview.pdf">概要</a>、<a href="http://www.scala-lang.org/sites/default/files/linuxsoft_archives/docu/files/ScalaReference.pdf">言語リファレンス</a>などをダウンロードした)を訪れることになった。</p> 
 
<p>これを言わなければならないのは残念ですが、私はとてもがっかりしています(あ、言語にです。eBookのほうは、言語使用と同じぐらい大きいということを除けば、言うことは何もありません)。私が最初にScalaについて聞いたのは、昨年の5月の<a href="http://code.google.com/events/io/">Google I/O</a>で、<a href="http://steve-yegge.blogspot.com/">Steve Yegge氏</a>との<a href="http://sites.google.com/site/io/server-side-javascript-on-the-java-virtual-machine">会話</a>の中で触れられていたときのことである。SteveはScalaを「静的な型システムの逆襲」 (そのセクションのビデオを見つけるのが面倒なので、てきとーに言い換えています)。Steveは信じられないほどフクザツな型システムをからかい始めた。例えば、型システムには、型の消去、分散アノテーション(variance annotation) 、実存(existential)型、ポリモーフィックメソッド型など、難解なコンセプトがたくさん含まれているのである。もしより知りたければ、言語リファレンスのToCという項目を調べて見ると良い。</p> 
 
<p>私はSteveに同意せざるを得ない。もしこれがコンパイル時の言語内の型セーフを維持するためのものであるならば、私はいつでも動的な型システムを選択するだろう。より良いやりかたがあるはずである。おそらく<a href="http://www.haskell.org/">Haskell</a>？Haskellは純粋な関数型言語で、関数型言語のI/Oの問題をうまい具合に解決した、動作の速い実装が存在する。Haskellの<a href="http://www.haskell.org/haskellwiki/Monad">モナド</a>は本当に深く、実装はかなり大変であるが、これを使うのは極めて簡単であるように思える。</p> 
 
<p>私がScalaを見て、もっともがっかりした点が、簡単そうに見えるコードを書くことを可能にするような、無数のルールがあるということである。これらのルールはすべて、無数の例外のように見えた。これらの例外により、これらを知らないときにはシンプルなコードを書くのがとても難しくなる。例えば、Scala本では、for構文の中ではif修飾詞をいくつも使用できると説明されている。しかし、パーサに推測して欲しいという位置にセミコロンを挿入してやる必要がある。さらに不可思議なのは、丸カッコの代わりにもし波カッコ({})を使用したときに、セミコロンが省略できるのである。説明も無く、このようなことが堂々と現れるのである。私は、リファレンスマニュアルの内のほとんど関係がないように思えるルールを結び付けて説明を理解した。まずはforステートメント(技術的にはfor内包表記(comprehension)と呼ばれる)であるが、これは波カッコや丸カッコを同じセマンティクスで使用することができる。しかし、セミコロンの推測は、波カッコと丸カッコで異なるのである。えぇっ！:-)</p>

<div class="category_articles">
<a href="http://articles.shibu.jp/article/29464661.html">Capabilities for Python?</a><br/>
<a href="http://articles.shibu.jp/article/29464627.html">Scala?</a><br/>
<a href="http://articles.shibu.jp/article/29464593.html">In the Cloud or Not?</a><br/>
<a href="http://articles.shibu.jp/article/29464527.html">2MBのメモリで100万の数値をソートする</a><br/>
<a href="http://articles.shibu.jp/article/29464404.html">Python 3000 and You<br/>
</div>
]]></content:encoded>
</item>
<item rdf:about="http://articles.shibu.jp/article/29464593.html">
<title>In the Cloud or Not?</title>
<link>http://articles.shibu.jp/article/29464593.html</link>
<description>原著者：Guido van Rossum原文：http://neopythonic.blogspot.com/2008/12/in-cloud-or-not.html原文公開日：MONDAY, DECEMBER 8, 2008クラウドをとても好きな人がいる。ここでいうクラウドというのは、Google AppEngineやAmazon EC2, MicrosoftのAzureのようなクラウドコンピューティングのことである。一方、クラウドが嫌いな人もいる。これを嫌うような人は、ロ...</description>
<dc:subject>Guido's Blog</dc:subject>
<dc:creator>しぶかわ</dc:creator>
<dc:date>2009-05-30T08:40:24+09:00</dc:date>
<content:encoded><![CDATA[
<p><b>原著者：</b>Guido van Rossum<br/>
<b>原文：</b><a href="http://neopythonic.blogspot.com/2008/12/in-cloud-or-not.html">http://neopythonic.blogspot.com/2008/12/in-cloud-or-not.html</a><br/>
<b>原文公開日：</b>MONDAY, DECEMBER 8, 2008</p>

<p>クラウドをとても好きな人がいる。ここでいうクラウドというのは、Google AppEngineやAmazon EC2, MicrosoftのAzureのようなクラウドコンピューティングのことである。一方、クラウドが嫌いな人もいる。これを嫌うような人は、ロックインや、APIの独占なども嫌う傾向がある。(両方の姿勢の例を提示したいと考えているが、ちょうど今は時間がないので勘弁してほしい。情報を集めるのは簡単だから:-)</p> 
 
<p>新しい分野かどうかはさておき、これらの意見の相違が、持ち家に対する意見の相違と同じではないか、と心配になる。「借りる」ということを嫌う家族がいたり、家主との係争を引き合いに出したり、近所の人がうるさかったり、終わることのないメンテナンス(屋根、フェンス、暖炉、バスルーム、キッチンなどきりがない)があったり。私自身は中間であるが、過去には良い家主に会うことが出来たり、最近の自分自身の家のメンテナンスの努力・コストがいやになりつつも、独立していることを楽しんでもいる。</p> 
 
<p>明らかに、クラウドコンピューティングはこの借家に近い。伝統的なデーターセンターの所有権が家の所有権となっているのである(建造するコストを無視して、所有することなしに利益を上げることを考えてみてください:-) アナロジーを使い、大家ができるビジネスの方法として、クラウドサービスのスタイルの違いの比較を行う人もいるだろう。例えば、Google App Engineはカーペットも家具もサービスの一部として含まれるが、食事の配達はオプションである。Amazon EC2はやりたいことが自由にできるコンクリートがむき出しの部屋を貸し出すのに近い。どちらにも市場はある。</p> 
 
<p>このクラウドの課題に関して、好き/嫌いという論争は止むことがないと考えるべきである。クラウドを嫌っている人を好きになるようにと説得することはない。しかし、自分のサーバを所有したくないと考えている家主に対するビジネスはたくさんあるのである。我々はクラウド嫌いの人と一緒に仕事してがっかりするのはやめて、そのような人たちに喜んでもらうことをしたほうが良いだろう。</p>

<div class="category_articles">
<a href="http://articles.shibu.jp/article/29464661.html">Capabilities for Python?</a><br/>
<a href="http://articles.shibu.jp/article/29464627.html">Scala?</a><br/>
<a href="http://articles.shibu.jp/article/29464593.html">In the Cloud or Not?</a><br/>
<a href="http://articles.shibu.jp/article/29464527.html">2MBのメモリで100万の数値をソートする</a><br/>
<a href="http://articles.shibu.jp/article/29464404.html">Python 3000 and You<br/>
</div>
]]></content:encoded>
</item>
<item rdf:about="http://articles.shibu.jp/article/29464527.html">
<title>Pythonを使って2MBのメモリで100万の数値をソートする</title>
<link>http://articles.shibu.jp/article/29464527.html</link>
<description>原著者：Guido van Rossum原文：http://neopythonic.blogspot.com/2008/10/sorting-million-32-bit-integers-in-2mb.html原文公開日：OCTOBER 22, 2008Pythonの著者のGuidoのブログが引っ越しをしたようです。そこに載っていた記事を一本翻訳してみました。今マイブームはオペラ座の怪人で、楽譜を買ったり、小説を買ったりして読んでいるんですが、小説の日本語がやたら直訳で堅い...</description>
<dc:subject>Guido's Blog</dc:subject>
<dc:creator>しぶかわ</dc:creator>
<dc:date>2009-05-30T08:35:28+09:00</dc:date>
<content:encoded><![CDATA[
<p><b>原著者：</b>Guido van Rossum<br/>
<b>原文：</b><a href="http://neopythonic.blogspot.com/2008/10/sorting-million-32-bit-integers-in-2mb.html">http://neopythonic.blogspot.com/2008/10/sorting-million-32-bit-integers-in-2mb.html</a><br/>
<b>原文公開日：</b>OCTOBER 22, 2008</p>

<p>Pythonの著者のGuidoのブログが引っ越しをしたようです。<a href="http://neopythonic.blogspot.com/2008/10/sorting-million-32-bit-integers-in-2mb.html" target="_blank">そこに載っていた記事</a>を一本翻訳してみました。今マイブームはオペラ座の怪人で、楽譜を買ったり、小説を買ったりして読んでいるんですが、小説の日本語がやたら直訳で堅いんです。柔らかい翻訳に触れたくて、衝動的に翻訳してみた次第です。動機とPythonは何の関係もないですが。</p> 
<hr> 
<p>誰かからジョーク交じりに、100万個の32ビットの数値を2メガバイトのメモリでソートできるか？と聞かれたことがある。私はこれに挑戦してみたが、この中でI/Oのバッファリングについていくつか学ぶことができた。</p> 
 
<p>明らかにこの問題はジョークである。バイナリエンコーディングだと仮定してもデータだけで4メガバイトになってしまうのである！しかし、これを可能にする実装方法がある。32ビットの数値が100万個納められているファイルがあるとして、どのようにすればメモリの使用量を最小にしてソートをすることができるだろうか？これは一種のマージソートになるはずである。メモリ内でソートされた小さいチャンク(かたまり)を一時ファイルに保存し、その後この一時ファイルをマージして最終的な出力エリアに出力する。</p> 
 
<p>これは私の考えた解決策である。手短に(1分で)説明しよう。</p> 
 
<p><b>NOTE: すべてのサンプルはPython3.0を使用して書いた。主な違いはバイナリストリームにアクセスするのにfile.bufferを使用している箇所である。</b></p><a name="more"></a>
<pre name="code" class="python"> 
#!/usr/bin/env python3.0
import sys, array, tempfile, heapq
assert array.array('i').itemsize == 4
 
def intsfromfile(f):
  while True:
     a = array.array('i')
     a.fromstring(f.read(4000))
     if not a:
         break
     for x in a:
         yield x
 
iters = []
while True:
  a = array.array('i')
  a.fromstring(sys.stdin.buffer.read(40000))
  if not a:
      break
  f = tempfile.TemporaryFile()
  array.array('i', sorted(a)).tofile(f)
  f.seek(0)
  iters.append(intsfromfile(f))
 
a = array.array('i')
for x in heapq.merge(*iters):
  a.append(x)
  if len(a) >= 1000:
      a.tofile(sys.stdout.buffer)
      del a[:]
if a:
  a.tofile(sys.stdout.buffer)
</pre> 
 
<p>私のGoogleのデスクトップ(Guideは現在Googleで働いている)では、実行に5.4秒かかった。3年前の古いPCでGoogle謹製のLinuxが稼動しており、Python3.0のpystoneのベンチマーク結果は34000である。また、入力には正確に100万個のランダムな32ビットの数値の入ったファイルを使用した。この結果はそんなに悪くない。同じ入力を使用して、すべてメモリ上でソートするという、直球な実装では2秒かかった。</p> 
 
<pre name="code" class="python"> 
#!/usr/bin/env python3.0
import sys, array
a = array.array('i', sys.stdin.buffer.read())
a = list(a)
a.sort()
a = array.array('i', a)
a.tofile(sys.stdout.buffer)</pre> 
 
<p>それではマージソートの方(ファイルを使用する方)に説明を戻そう。最初の３行は以下のようになっている。</p> 
 
<pre name="code" class="python"> 
#!/usr/bin/env python3.0
import sys, array, tempfile, heapq
assert array.array('i').itemsize == 4</pre> 
 
<p>最初の行はPython 3.0を使用するということを言っている。二行目では必要なモジュールをインポートしている。三行目はタイプコードの'i'が32ビットの数値をあらわさない、64ビットのシステムを除外するためのものである。私は特にこのコードをいろいろな環境で動く汎用的なものにしようとは思っていない。</p> 
 
<p>次に、小さなヘルパーを作る。これはジェネレータであり、ファイルから数値を読み込み、一度に1つずつ返すものである。</p> 
 
<p>※訳注：ジェネレータというのは状態を保持する特殊な関数で、yield(擬似return)が呼ばれるたびに処理を中断する。再度実行されると前回yieldが呼ばれたところから処理が続行し、returnか、関数の終わりに達すると処理が終わる。通常、ループと一緒に使用する。</p> 
 
<pre name="code" class="python"> 
def intsfromfile(f):
  while True:
      a = array.array('i')
      a.fromstring(f.read(4000))
      if not a:
          break
      for x in a:
          yield x</pre> 
 
<p>ここの部分のパフォーマンスをチューニングする。このコードは一度に1000個の整数を読み込む。そして、その結果を分割して1つずつyieldで返す。最初に実装したコードはこのバッファリングを使用していないため、一度に4バイトずつファイルから読み込んで、整数に変換して、結果を返していた。しかし、これでは4倍も遅くなってしまうのである！(通常、細かいファイルアクセスは、一度にまとめて読むのに比べて時間がかかる) <tt>a.fromfile(f, 1000)</tt>というメソッドは使えないということは覚えておいて欲しい。この<tt>fromfile()</tt>メソッドは、ファイル上に十分な数のデータがそろっていないときには文句を言ってくるからである。私は、ファイル上にある整数の個数が何個であれ、自動で動作してくれるようにしたかったので使用しなかったのである。</p> 
 
<p>次に来るのが入力のループである。ここでは繰り返し1万個の整数値が含まれるチャンクを入力ファイルから読み込み、メモリ上でソートし、一時ファイルに書き込んでいる。その後、上記の<tt>insfromfile()</tt>関数を使用して作成した、一時ファイルを参照するイテレータを作成する。そして、この次のマージを行うフェーズで使用する、イテレータのリストに追加する。</p> 
 
<pre name="code" class="python"> 
iters = []
while True:
  a = array.array('i')
  a.fromstring(sys.stdin.buffer.read(40000))
  if not a:
      break
  f = tempfile.TemporaryFile()
  array.array('i', sorted(a)).tofile(f)
  f.seek(0)
  iters.append(intsfromfile(f))</pre> 
 
<p>100万個のデータが含まれるデータを使用すると、それぞれ1万個のデータを含む、100個の一時ファイルが作成される。</p> 
 
<p>最後に、これらのソート済みの一時ファイルを一緒にマージする。<tt>heapq</tt>モジュールを使用すると、簡単にこの目的を達成できる。heapq.merge(iter1, iter2, ...)は、順番どおりの入力値をyieldで返すイテレータを作成する。この関数は、今回の場合のように、入力されたそれぞれイテレータは、ソート済みであるということが前提となる。</p> 
 
<pre name="code" class="python"> 
a = array.array('i')
for x in heapq.merge(*iters):
  a.append(x)
  if len(a) >= 1000:
      a.tofile(sys.stdout.buffer)
      del a[:]
if a:
  a.tofile(sys.stdout.buffer)</pre> 
 
<p>ここも、I/Oのバッファリングを利用して、効率的にチューニングできるもう一つのポイントである。ソートされた値を得られる端から一つずつファイルに追加していくと、だいたい２倍遅くなる。これらを総合すると、ファイルの読み込みと書き出しの両方にバッファを設けただけで、10倍のスピードアップが得られたことになります！</p> 
 
<p>以上が今回のストーリーの金言である。</p> 
 
<p>もう一つのheapqモジュールがすばらしいということも、今回の学びである。このモジュールは出力のフェーズで必要となった、イテレータをマージする機能を持っていた。そして、バイナリデータを管理するのにarrayモジュールを使用したことも忘れないで欲しい。</p> 
 
<p>最後に、このサンプルを見て、Python3.0とPython2.5がそんなに大きな違いがないということがご理解いただけたと思う！</p>

<div class="category_articles">
<a href="http://articles.shibu.jp/article/29464661.html">Capabilities for Python?</a><br/>
<a href="http://articles.shibu.jp/article/29464627.html">Scala?</a><br/>
<a href="http://articles.shibu.jp/article/29464593.html">In the Cloud or Not?</a><br/>
<a href="http://articles.shibu.jp/article/29464527.html">2MBのメモリで100万の数値をソートする</a><br/>
<a href="http://articles.shibu.jp/article/29464404.html">Python 3000 and You<br/>
</div>
]]></content:encoded>
</item>
<item rdf:about="http://articles.shibu.jp/article/29464404.html">
<title>Python 3000 and You</title>
<link>http://articles.shibu.jp/article/29464404.html</link>
<description>原著者：Guido van Rossum原文：http://www.artima.com/weblogs/viewpost.jsp?thread=227041原文公開日：March 17, 2008Python作者のGuidoのブログの記事を軽く翻訳してみました。単語を適当に抜かしたりしていますが、だいたいはそのままです。Guideらしいというか、Pythonらしいコメントですね。もちろん、この方針はPython以外にも使えます。    私がこの機会を利用して、ここを見ている...</description>
<dc:subject>Guido's Blog</dc:subject>
<dc:creator>しぶかわ</dc:creator>
<dc:date>2009-05-30T08:25:02+09:00</dc:date>
<content:encoded><![CDATA[
<p><b>原著者：</b>Guido van Rossum<br/>
<b>原文：</b><a href="http://www.artima.com/weblogs/viewpost.jsp?thread=227041">http://www.artima.com/weblogs/viewpost.jsp?thread=227041</a><br/>
<b>原文公開日：</b>March 17, 2008</p>

<p><a href="http://www.artima.com/weblogs/viewpost.jsp?thread=227041" target="_blank">Python作者のGuidoのブログ</a>の記事を軽く翻訳してみました。単語を適当に抜かしたりしていますが、だいたいはそのままです。Guideらしいというか、Pythonらしいコメントですね。もちろん、この方針はPython以外にも使えます。</p> 
 
<hr> 
 
<p>私がこの機会を利用して、ここを見ている方々に本当に伝えたいのは、Python3000にモジュールを移植するときにAPIを変更してはいけないということです。ここを見ている方は以下の話は聞いたことがあるでしょう。Python3.0はAPIが変更になり、後方互換性がなくなる、と。しかし、開発者の方々(特に他のユーザから使用されているライブラリの)はAPIを変更してはいけません。もし変更する予定があるならば、3.0に移植する前に行ってください。あるいは、3.0に変更なしで移植したあとに行って下さい。</p><a name="more"></a><p>なぜそうしなければならないのか？それはユーザのためです。Ima Lumberjackは彼の製作所の管理のためのweb 2.0アプリケーションを実装していました。Imaはあなたの作ったすばらしいweb 2.0フレームワークのユーザです。ImaはアプリケーションをPython3000に移植しようとしています。彼はあなたの作ったフレームワークがPython3000に対応するのを待ち作業を開始しました。彼は書籍に書いてある移植の方法をすべて正確に行いました。2to3のツールを使用し、テストを行いました。そこでテストが失敗してしまったらImaがどんなにがっかりするか、想像できますよね？失敗した原因がAPIの変更にあるのか、アプリケーションの移植が不十分だったのか判別できません。</p> 
 
<p>もしあなたの作ったフレームワークにAPIの変更がなければ、Imaの仕事はもっと焦点のはっきりしたものになります。2to3ツールを実行したあとに残っているバグはImaのコード側のバグです。彼はその部分の修正方法ははっきり理解しています。</p> 
 
<p>あなたのライブラリが他のライブラリから使用されていたとすると、さらにこの問題は重みを持ってきます。トラブルの広がりは加速度的に大きくなります。もし、仮に、これらのモジュールの中にPython3000への移植を諦めたものが出てきてしまうと、多くの他のライブラリやアプリケーションの移植の妨げになっていしまいます。
</p> 
 
<p>もういちど強く言っておきます。<b>Python3000への移植と同時にAPIを変更してはいけません。</b><p> 
 
<p>P.S. 3.0finalリリースは現在2008年の9/3に予定されています。詳しくは<a href="http://python.org/dev/peps/pep-0361/" target="_blank">PEP361</a>を見て下さい。</a>

<div class="category_articles">
<a href="http://articles.shibu.jp/article/29464661.html">Capabilities for Python?</a><br/>
<a href="http://articles.shibu.jp/article/29464627.html">Scala?</a><br/>
<a href="http://articles.shibu.jp/article/29464593.html">In the Cloud or Not?</a><br/>
<a href="http://articles.shibu.jp/article/29464527.html">2MBのメモリで100万の数値をソートする</a><br/>
<a href="http://articles.shibu.jp/article/29464404.html">Python 3000 and You<br/>
</div>
]]></content:encoded>
</item>
</rdf:RDF>
