本文へジャンプ

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

送信されたすべての情報は安全です。

  • 閉じる [x]

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


送信されたすべての情報は安全です。

  • 閉じる [x]

進化するアーキテクチャーと新方式の設計: JRuby で DSL を作成する

Java コード・ベースの JRuby を使用するという手段によって Ruby の表現力を利用する

Neal Ford, Software Architect / Meme Wrangler, ThoughtWorks Inc.
Neal Ford
Neal Ford は世界的な IT コンサルティング企業である ThoughtWorks のソフトウェア・アーキテクトであり、Meme Wrangler でもあります。また彼は、アプリケーション、教育資料、雑誌記事、コースウェア、ビデオや DVD によるプレゼンテーションなどの設計と開発も行っています。さまざまな技術に関する本の著者、編集者でもあり、最新の著書は『プロダクティブ・プログラマ ― プログラマのための生産性向上術』です。彼は大規模なエンタープライズ・アプリケーションの設計や構築を専門にしています。また彼は世界各地で開催される開発者会議での講演者としても国際的に有名です。彼の Web サイトをご覧ください。

概要: Ruby は現在、内部ドメイン特化言語 (DSL) を作成する最先端の言語として使用されています。Ruby 実装のなかでも最も優れているのは、JVM で動作する JRuby です。シリーズ「進化するアーキテクチャーと新方式の設計」の今回の記事では、既存の (そして今後作成される) Java™ コードのメリットを保ちつつ、Ruby の表現力を活用する方法を説明します。イディオムのようなドメイン・パターンを抽出する 1 つの手段として、Ruby で内部 DSL を作成する方法を学んでください。

このシリーズの他の記事を見る

日付:  2010年 9月 28日
レベル:  中級 この記事の原文:  英語
アクティビティー: 7698 ビュー
お気軽にご意見・ご感想をお寄せください: 


数回前の記事から、ドメイン特化言語 (DSL) を使用してイディオムのようなドメイン・パターン (新しく持ちあがってきたビジネス問題に対するソリューション) を抽出するという話題を取り上げてきました。DSL は簡潔で (ほとんどのノイズが構文から取り除かれます)、開発者でなくても読んで理解できることから、イディオムのようなドメイン・パターンを抽出するには申し分なく役立つと同時に、API 中心のコードからは際立つ存在になっています。前回の記事では Groovy の機能を利用して DSL を作成する方法を紹介しました。今回はこの DSL を使用してイディオムのようなパターンを抽出する話題の締めくくりとして、JRuby を活用することによって、Ruby で一段と洗練された DSL を作成する方法を説明します。

このシリーズについて

このシリーズの目的は、ソフトウェアのアーキテクチャーと設計という、繰り返し議論されていながら捉えどころのない概念を新しい視点で捉えなおすことです。Neal Ford が示す具体的な例をとおして、進化するアーキテクチャーと新方式の設計におけるアジャイル・プラクティスの確固たる基礎を学びます。アーキテクチャーと設計に関する重要な決定事項を最終的に必要な瞬間まで遅らせることで、アーキテクチャーと設計が必要以上に複雑にならないようにし、ソフトウェア・プロジェクトが強固なものでなくなる事態を避けることができます。

Ruby は現在、内部 DSL を作成する際に最もよく使われている言語です。Ruby で開発する際のインフラストラクチャーとして皆さんが思い付くほとんどは、DSL をベースとしています (Ruby on Rails、RSpec、Cucumber、Rake、その他多数 (「参考文献」を参照))。それは、Ruby は内部 DSL をホストするのに適しているからです。また、最近流行の手法となっているビヘイビア駆動開発 (BDD) でも、その人気を得るためには強力な DSL の基盤が欠かせませでした。DSL の熱烈な支持者たちの間でなぜ Ruby がこれほどの人気を集めているのかは、この記事を読めば納得していただけると思います。

Ruby のオープン・クラス

オープン・クラスを使用して組み込みクラスに新しいメソッドを追加するという手法は、DSL の表現力を強化するために一般的に使用されています。前回の記事では、Groovy がサポートする 2 種類のオープン・クラスの構文を紹介しました。Ruby にも同じメカニズムがありますが、使用する構文は 1 つだけです。例として、料理のレシピ用 DSL を作成するとします。この場合、DSL を作成するには数量を取り込む手段が必要です。そこで、DSL の一部を示したリスト 1 について考えてみましょう。


リスト 1. Ruby ベースのレシピ用 DSL のターゲット構文

recipe = Recipe.new "Spicy bread"
recipe.add 200.grams.of "flour"
recipe.add 1.lb.of "nutmeg"

上記のコードを実行可能なコードにするためには、gram メソッドと lb メソッドを数値に追加しなければなりません。それには、リスト 2 のように Numeric クラスをオープンします。


リスト 2. Ruby でのオープン・クラスの定義

class Numeric
  def gram
    self
  end
  alias_method :grams, :gram

  def pound
    self * 453.59237
  end
  alias_method :pounds, :pound
  alias_method :lb, :pound
  alias_method :lbs, :pound

Ruby では、クラス名は大文字で始めなければなりません。これは Ruby の定数にも当てはまるルールです。つまり、すべてのクラス名は定数でもあることを意味します。Ruby はクラス定義を見つけると、そのクラスがすでにクラス・パスにロードされているかどうかを調べます。クラス名は定数であることから、ある特定の名前のクラスは 1 つしかありません。そこで、クラスがすでにロードされている場合には、クラス定義でそのクラスを再オープンして、変更を加えられるようにするというわけです。リスト 2 では、Numeric クラス (固定値と浮動小数点数の両方を処理するクラス) を再オープンして、gram および pound メソッドを追加しています。Groovy とは異なり、Ruby には、引数を受け付けないメソッドについては空の括弧を使って呼び出さなければならないというルールはありません。つまり、Ruby ではプロパティーとメソッドを区別する必要はないということです。Ruby には、もう 1 つの重宝な DSL メカニズムがあります。それは、alias_method クラス・メソッドです。皆さんは、DSL をできるだけ流ちょうなものにするために、単数形を複数形に変えるなどといった場合にも対処する必要があると考えるかもしれません (単数形を複数形に変えるための手の込んだコードを調べたいのであれば、Ruby on Rails でモデル・クラス名を複数形にする場合のコードを見てください)。追加しているグラム数が 1 グラムを超えていることは明らかなのに、DSL で recipe.add 2.gram.of("flour") などといった文法的に体裁の悪い文を作成するようなことを、私はしたくありません。Ruby の alias_method メカニズムを使えば、簡単に代替名を作成して、メソッドを読み易くすることができます。その理由から、リスト 2 では gram に対して複数形のメソッドを追加し、pound に対しても省略形、複数形のバージョン両方を使えるように追加しています。


流れるようなインターフェースの作成

DSL を使用してイディオムのようなパターンを抽出する目的の 1 つは、プログラミング言語に置き換えた抽象概念から、ノイズとなる構文を排除することです。そこでリスト 3 に記載する、ノイズの多いレシピ用 DSL のコード・スニペットについて考えてみましょう。


リスト 3. ノイズの多い、レシピの定義

recipe = Recipe.new "Spicy bread"
recipe.add 200.grams.of "flour"
recipe.add 1.lb.of "nutmeg"
recipe.directions << "mix ingredients"
recipe.directions << "cook for 30 minutes at 250 degrees"

レシピの材料を加えることと調理の指示を示すリスト 3 の構文は、かなり簡潔なものの、ここではホスト変数の名前 (recipe) が何度も繰り返されています。リスト 4 に、この構文を簡潔にしたバージョンを記載します。


リスト 4. コンテキストを適用した、レシピの定義

alternate_recipe = Recipe.new("Milky Gravy")
alternate_recipe.consists_of {
  add 1.lb.of "flour"
  add 200.grams.of "milk"
  add 1.gram.of "nutmeg"
  
  steps(
    "mix ingredients",
    "cook for some amount of time"
  )
}

上記の構文では、consists_of メソッドを流れるようなインターフェースに追加して、コンテナーを使用できるようにしています (波括弧 ({}) で区切られたクロージャー・ブロックを使用して Ruby にコンテナーを組み込むことにより、ノイズとなるホスト・オブジェクトの繰り返しをなくしています)。このメソッドを実装するのは、Ruby ではわけのないことです (リスト 5 を参照)。


リスト 5. consists_of メソッドを組み込んだ Recipe クラスの定義

class Recipe
  attr_reader :ingredients
  attr_accessor :name
  attr_accessor :directions

  def initialize(name="")
    @ingredients = []
    @directions = []
    @name = name
  end

  def add ingredient
    @ingredients << ingredient
    return self
  end
  
  def steps *direction_list
    @directions = direction_list.collect
  end
  
def consists_of &block
    instance_eval &block
  end
end  

consists_of メソッドは、コード・ブロックを引数に取ります (これに該当するのは、パラメーター名の前にアンパサンドが付いた構文です。アンパサンドによって、このパラメーターはコード・ブロックのホルダーとして識別されます)。このメソッドは、instance_eval メソッドを使用してコード・ブロックを実行します。Ruby の組み込みメソッドの 1 つである instance_eval メソッドは、渡されたコードを実行するために、ホスト・オブジェクトの定義を変更します。別の言葉で説明すると、instance_eval を使ってコードを実行するということは、self (Ruby では、これが Java 言語の this に相当します) が、instance_eval を呼び出した変数になるということです。したがって、add メソッドと steps メソッドを recipe.instance_eval を使って呼び出す場合、recipe ホスト・オブジェクトを使わずに、この 2 つのメソッドを呼び出すことができるということです。そしてこれが、consists_of メソッドが実行している内容です。

このシリーズを毎回読んでくださっている読者は、この概念から、「Leveraging reusable code, Part 2」の記事で取り上げた Java 構文 (リスト 6 を参照) を思い出すことでしょう。


リスト 6. インスタンス・イニシャライザーを使用した、Java コード内の流れるようなコード・ブロック

MarketingDescription desc = new MarketingDescriptionImpl() {{
    setType("Box");
    setSubType("Insulated");
    setAttribute("length", "50.5");
    setAttribute("ladder", "yes");
    setAttribute("lining type", "cork");
}};  

一見すると、上記の構文は Ruby バージョンと同じように見えますが、Java バージョンにはいくつかの重大な制約があります。第 1 に、これが Java 言語では特異な構文であることです (ほとんどの開発者は、日常のコーディング作業でインスタンス・イニシャライザーを目にすることはありません)。第 2 に、この構文は匿名内部クラス (Java で唯一の、コード・ブロックのようなメカニズム) を使用することから、外部スコープからの変数を final として宣言する必要があることです。これは、コード・ブロック内部で実行できる処理に重大な制限を課すことになります。Ruby では、instance_eval メソッドは標準の (特異ではない) 言語機能です。つまり、一般的に使用されています。


ポリッシング

多くの DSL (特に、開発者でない人を対象とした DSL) で共通して使われている手法の 1 つに、話し言葉を使用するという手法があります。ベースにしているコンピューター言語に十分な柔軟性があれば、話し言葉を対象にしたコンピューターの構文を作成することは可能です。これまでの作業で作成したレシピ DSL を例に取ると、単純なデータ構造 (材料のリストと調理手順のリスト) を保持するためだけに完全な DSL を作成するのでは、多少やり過ぎの感があります。それならば、単純にこの情報を標準データ構造に持たせるというのはどうでしょう。DSL に処理をエンコードすることによって、データ構造にデータを取り込むだけでなく、さらなるアクション (有益な副次効果をもたらすようなアクション) も可能になります。例えば、DSL に定義する材料ごとに栄養成分の情報を取得すれば、完成した料理の栄養価を提供することができます。そのための NutritionProfile クラスは、単純なデータ・ホルダーです (リスト 7 を参照)。


リスト 7. レシピの栄養成分レコード

class NutritionProfile
  attr_accessor :name, :protein, :lipid, :sugars, :calcium, :sodium

  def initialize(name, protein=0, lipid=0, sugars=0, calcium=0, sodium=0)
    @name = name
    @protein, @lipid, @sugars =  protein, lipid, sugars
    @calcium, @sodium = calcium, sodium
  end
  
  def self.create_from_hash(name, h)
    new(name, h['protein'], h['lipid'], h['sugars'], h['calcium'], h['sodium'])
  end

  def to_s()
    "\tProtein: " +   @protein.to_s       +
    "\n\tLipid: " +   @lipid.to_s         +
    "\n\tSugars: " +  @sugars.to_s        +
    "\n\tCalcium: " + @calcium.to_s       +
    "\n\tSodium: " +  @sodium.to_s
  end

end   

上記のような栄養成分レコードをデータベースに取り込むため、各行に 1 つのレコードを記載するテキスト・ファイルを作成します。

ingredient "flour" has protein=11.5, lipid=1.45, sugars=1.12, calcium=20, and sodium=0  

ご想像のとおり、この定義ファイルの各行は Ruby ベースの DSL です。上記の構文を単なるテキストの行と考えるのではなく、コンピューター言語の観点からはどのように「見えるか」を考えてください (図 1 を参照)。


メソッド呼び出しとしての材料のテキスト定義

各行は、メソッド名である ingredient で始まります。メソッドの最初の引数は材料の名前です。has という語はバブル・ワードと呼ばれます。つまり、DSL をより読み易くする一方、最終的な定義には関係しない語のことです。行の残りの部分は、カンマで区切られた名前と値のペアで構成されます。このテキストは正規の Ruby 構文ではありませんが、どのようにして Ruby に変換すればよいのでしょうか。Ruby に変換するための作業はポリッシングと呼ばれます。ポリッシングでは、ほとんど正規の構文に近いコードを取り、それを実際の構文に仕上げます。この DSL の場合、ポリッシング作業は NutritionProfileDefinition クラスによって行われます (リスト 8 を参照)。


リスト 8. NutritionProfileDefinition クラス

class NutritionProfileDefinition
  
  def polish_text(definition_line)
    polished_text = definition_line.clone
    polished_text.gsub!(/=/, '=>')
    polished_text.sub!(/and /, '')
    polished_text.sub!(/has /, ',')
    polished_text
  end

  def process_definition(definition)
    instance_eval polish_text(definition)
  end

  def ingredient(name, ingredients)
    NutritionProfile.create_from_hash name, ingredients
  end    
   
end  

このクラスのエントリー・ポイントは、process_definition メソッドです (リスト 9 を参照)。


リスト 9. process_definition メソッド

def process_definition(definition)
  instance_eval polish_text(definition)
end

上記のメソッドは instance_eval を使って polish_text を呼び出し、polish_text の実行コンテキストを NutritionProfileDefinition インスタンスに切り替えます。polish_text メソッド (リスト 10 を参照) は、必要な置換と変換を行って、正規の構文に近いコードを正規の構文のコードに変換します。


リスト 10. polish_text メソッド

def polish_text(definition_line)
  polished_text = definition_line.clone
  polished_text.gsub!(/=/, '=>')
  polished_text.sub!(/and /, '')
  polished_text.sub!(/has /, ',')
  polished_text
end

polish_text メソッドは、定義構文を Ruby 構文に変換する単純なストリング置換からなります。これらのストリング置換では、等号をハッシュ ID (=>) に変換し、余計な and のインスタンスを排除し、has をカンマに変換します。このようにポリッシングされたコード行が instance_eval に渡されて、NutritionProfileDefinition クラスの ingredient メソッドを介して実行されます。

このコードは Java 言語でも作成することができますが、Java の構文上の制約事項によってノイズが追加されることになり、流れるようなインターフェースのメリットは損なわれてしまいます。したがって、作業する価値があるかどうかは疑問です。Ruby では十分なシンタックス・シュガーを提供して、抽象化を DSL としてキャストすることを可能に (そして価値のあることに) しています。


メソッド・ミッシング

前のセクションで説明した例とは異なり、次に説明する例は、複雑な構文を使ったとしても Java コードでは実現することはできません。一般に DSL をサポートする言語には、メソッド・ミッシングという便利なメカニズムがあります。このメカニズムは、Ruby に存在しないメソッドを呼び出しても、即時に例外が発生することがないように、存在しないメソッドの呼び出しを処理する method_missing メソッドをクラスに追加するというものです。このメカニズムは、内部データ構造を組み立てる DSL で多用されています。ここで、Ruby の XMLBuilder (「参考文献」を参照) から抜粋した例について考えてみましょう。


リスト 11. Ruby の XMLBuilder を使用する

xml = Builder::XmlMarkup.new(:indent => 2)
xml.person {
  xml.name("Neo")
  xml.catch_phrase("Whoa")
}
puts xml.target!

このコードは、DSL に示された構造で XML 文書を出力します。Builder の魔法を可能にしているのは、method_missing です。xml 変数のメソッドを呼び出すと、そのメソッドがまだ存在していない場合は method_missing に分類され、それによって対応する XML が作成されます。そのため、Builder ライブラリーのコードはかなり小さくなっています。つまりこの仕組みの大部分で、ベースとなっている Ruby 言語の機能を利用しているのです。ただし、この手法には 1 つの問題があります。その問題は、リスト 12 のコードに説明されています。


リスト 12. メソッド・ミッシングと組み込みメソッドの衝突

xml = Builder::XmlMarkup.new(:indent => 2)
xml.person {
  xml.name("Neo")
  xml.catch_phrase("Whoa")
  xml.class("pod-born")
}
puts xml.target!

Groovy と Ruby でのビルダーの違い

Ruby での Builder クラスは、Groovy にある同様のビルダー・クラスに着想を得たものです。Ruby の Builder クラスを作成した Jim Weirich は、Groovy のビルダー・クラスの概念は気に入っていましたが、実装についてはその限りではありませんでした。その理由は、XML タグと生成後の XML との間で複雑なマッピング・ストラテジーが使用されているためです。Weirich はこの問題に対処するため、より単純で、より簡潔な XMLBuilder (および BlankSlate) を作成しました。このことは、言語のコミュニティーが問題の解決に取り組む姿勢をうかがわせる興味深い点です。一般に、Java コミュニティーは問題の解決策として構造要素 (フレームワークやデザイン・パターンなど) を作成する傾向があり、層の上に抽象化層を重ねていきます。Ruby ではその反対に、開発者がメタプログラミングを使用し、ベースとなっている最も単純なメカニズムを使って下位の要素を作成するという傾向があります。Java のいずれかの Web フレームワークと Ruby on Rails を比較するか、Groovy と Ruby のビルダーを比較してみてください。Weirich はメタプログラミングを使用して Ruby のビルダーから必要ないものを取り除き、Ruby 言語の機能を利用できるようにしたのです。

method_missing だけに依存する場合、リスト 12 のコードは機能しません。class メソッドはすでに、(Java 言語の場合と同じく) すべてのクラスの基底クラスである Object の一部として Ruby で定義されていて、method_missing は当然、既存のメソッドでは機能しないためです。このことは、この手法の失敗を決定付けるかのように思えますが、Jim Weirich (Builder の作成者) が考え出した素晴らしいソリューションがあります。それは、彼が作成した BlankSlate です。BlankSlateObject を継承するクラスですが、通常 Object にあるメソッドのすべてをプログラムによって削除します。このようにして既存のメソッドが削除されれば、副次作用に悩まされることなく method_missing インフラストラクチャーを使用できるようになります。

この強力で有用な BlankSlate メカニズムは、次の Ruby のメジャー・バージョンに組み込まれることになっています。Ruby 1.9では、SimpleObject がオブジェクト階層の最上位となり、Object がその直下に置かれます。SimpleObject があれば BlankSlate は必要なくなるため、ビルダー DSL を遥かに簡単に作成できるようになります。

Builder のような DSL を作成できると、なぜプログラミング言語では表現力と処理能力がそれほど重要なのかが明らかになります。Ruby の Builder のコードの量は、他の言語の同様のライブラリーに比べて遥かに少なくなっています。それは、他の言語よりも柔軟な設計媒体となる Ruby を利用して、この Builder が作成されているためです。


まとめ

このシリーズの当初から、ソフトウェア・システムの設計はそのソース・コードのすべてを包含すると主張してきました。この主張の言外に含まれる意味は、使用する言語の表現力が豊かであればあるほど、広範な設計基盤を使えるということです。このことは、皆さんが汎用言語 (Java、Ruby、Groovy、Clojure) を選択する場合に当てはまるだけでなく、ある言語をベースに DSL を使用して作成できる言語にも当てはまります。ビジネスの概念を正確に表現する言語を作成すると、組織にとってかけがえのない資産になります。そのビジネスの目的に極めてよく適合する言語で実際の問題を解決するという、重要な手段を獲得することになるからです。

組織が大々的に Ruby または Groovy などの言語での開発に乗り換えないとしても、Ruby で実装された RSpec や Groovy で実装された easyb などのツール (「参考文献」を参照) を使用するという方法で、これらの言語を忍び込ませることはできます。Ruby または Groovy をこっそり採り入れることによって、新しい言語の導入に対して必要以上に慎重になっている人々でも、これらの言語がもたらす顕著なメリットを理解できるようになるはずです。


参考文献

学ぶために

  • プロダクティブ・プログラマ – プログラマのための生産性向上術』(Neal Ford 著、オライリー・ジャパン、2008年): Neal Ford の最新の本で、このシリーズで取り上げるいくつもの話題を詳細に解説しています。

  • JRuby: JRuby は、あらゆるプラットフォームでの Ruby 実装のなかで、最も優れた実装の 1 つとして数えられます。

  • Ruby on Rails: Rails はよく使われている Web 開発プラットフォームで、多数の DSL を使用します。

  • RSpec: Ruby で作成されたテスト・フレームワーク、RSpec では DSL 手法を使用しています。

  • Rake: Rake は Ruby プラットフォーム用のビルド・ツールです。

  • Cucumber: Cucumber は、Ruby の多くの優れた DSL 手法を実証する強力な BDD テスト・フレームワークです。

  • easyb: easyb は、Groovy ベースの Java プラットフォーム対応 BDD フレームワークです。

  • Builder: Builder は、プログラムによる XML 文書の生成を簡易化する Ruby ライブラリーです。

  • developerWorks Java technology ゾーン: Java プログラミングのあらゆる側面を網羅した記事が豊富に用意されています。

議論するために

  • My developerWorks コミュニティーに加わってください。ここでは他の developerWorks ユーザーとのつながりを持てる他、開発者が主導するブログ、フォーラム、グループ、ウィキを調べることができます。

著者について

Neal Ford

Neal Ford は世界的な IT コンサルティング企業である ThoughtWorks のソフトウェア・アーキテクトであり、Meme Wrangler でもあります。また彼は、アプリケーション、教育資料、雑誌記事、コースウェア、ビデオや DVD によるプレゼンテーションなどの設計と開発も行っています。さまざまな技術に関する本の著者、編集者でもあり、最新の著書は『プロダクティブ・プログラマ ― プログラマのための生産性向上術』です。彼は大規模なエンタープライズ・アプリケーションの設計や構築を専門にしています。また彼は世界各地で開催される開発者会議での講演者としても国際的に有名です。彼の Web サイトをご覧ください。

不正使用の報告のヘルプ

不正使用の報告

ありがとうございます。 このエントリーは、モデレーターの注目フラグが設定されました。


不正使用の報告のヘルプ

不正使用の報告

不正使用の報告の送信に失敗しました。


developerWorks: サイン・イン


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。 プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。 お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

表示名をお選びください

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

(半角英数字で3文字以上31文字以下にする必要があります)


「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


この記事を評価する

コメント

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Java technology
ArticleID=556050
ArticleTitle=進化するアーキテクチャーと新方式の設計: JRuby で DSL を作成する
publish-date=09282010
author1-email=nford@thoughtworks.com
author1-email-cc=

タグ

Help
このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。

スライダーバーを使用することで、より多く(少なく)タグを表示します。

人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。

マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。

このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。