SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

「IBM Japan Geeks」勉強会レポート(AD)

IBMのとがった人たち ~ 「IBM Japan Geeks」
勉強会レポート(後編)

「Google基盤」と「カリー化」

  • このエントリーをはてなブックマークに追加

前回に続き、IBM社内で毎月開催されている勉強会「IBM Japan Geeks」の模様をレポートします。今回は、「Google基盤について:根本氏」「オブジェクト指向とカリー化:津田氏」を取り上げます。

  • このエントリーをはてなブックマークに追加

 「IBM Japan Geeks」(以下、Geeks)は、2007年に社内で開催された「ITLMC RoR(Ruby on Rails)勉強会」に集まった“とがった”人たちによって発足したもの。「主にプログラミング言語を中心とした最新技術動向の情報交換を行うための社内コミュニティ」として、定期的に勉強会を開催しています。

 今回は前回に続き、これまでに開催されたGeeks定例会から反響の多かったものを再現していただいた「Scala:宮本氏」「Android:小山氏」「Google基盤について:根本氏」「オブジェクト指向とカリー化:津田氏」の後半の2編をお送りします。

インフラ面から見たGoogle基盤

 3番目のGeekとして登場した根本和郎氏は、「The Strength of Google from infrastructure view」(インフラから見たGoogleの強さ)と題した発表を行った。これは社内カンファレンスの10倍の倍率を通過した発表であり、米国でも同内容の発表を行っているという。なお、発表内容はすべて公的な情報を元にまとめられている。今回は発表時間が押していることから、要点のみに絞っての発表となった。

根本和郎 氏
根本和郎 氏

 Googleと言えばクラウドで有名だが、IBMが言うところのクラウドとは異なるものとなっている。その違いをプログラミングの側面から見てみようという内容だ。Googleのテクノロジーを理解するのに必要な最低限の要素技術は「GFS(Google File System)」「Map Reduce(アルゴリズム)」「BigTable(データベース)」の3つであり、この技術を複合させてシステム設計を考えることで、違う世界が見えてくる。

Googleとsaleforce.comとの比較

 根本氏は今回、この3つのテクノロジから「Map Reduce」および「BigTable」を取り上げた。まずは基礎知識である。Googleはしばしば、クラウドという視点においてsalesforce.comと比較されるが、そのシステムのイメージはまったく逆になっている。salesforce.comはSunのサーバやOracleのデータベースによって構成されており、さながら一般的な会社のデータセンターのようである。

Googleとsalesforce.comとの比較
Googleとsalesforce.comとの比較

 一方Googleは、顧客企業ごとにクラスターで性質が違うシステム構成になっているという方式ではない。Webユーザーという単一の種類のユーザーを支える、巨大なサーバー群と考えられる。この比較は「分散とパラレル」に置き換えることもできる。パラレルが1台のPCに複数個のCPUを搭載するセルコンピューティングのようなものであるのに対し、Googleに当てはめられる分散は、安くて性能もそれなりのPCをたくさん並べるスタイルであると言える。

分散とパラレル
分散とパラレル

ネットワークがコンピュータに

 また現在、ネットワークそのものがコンピュータになってくる傾向があるとして、Yahoo! ResearchのChiefであるPrabhakar Raghavan氏の「地球にはGoogle、Yahoo、Microsoft、IBM、Amazonの5台のコンピュータがあれば事足りる」という言葉を引用した。今後個人の使用するPCはかつてのダム端末のような存在に戻り、重要なデータは物理的な場所の分からない空間に保持される形態となっていくと予想できる。

 ムーアの法則とギルダーの法則の比較で言えば、性能はコンピュータが18カ月で2倍になっているのに対し、ネットワークは6~9カ月で2倍になっている。つまり今後、コンピューティングの実行環境は、物理的位置に縛られなくなっていくと言うことを意味する。またNicolas Carr氏の著書「THE BIG SWITCH」には、「インターネットはワールドワイドなコンピュータに進化する」と記述されていることも紹介した。

コンピュータとネットワークの推移
コンピュータとネットワークの推移

Googleのデータセンター

 Googleの特徴の一つとして、根本氏はGoogleの電力消費に関するレポートを紹介した。このレポートによると、Googleサービスにおけるパフォーマンスおよびコスト当たりのパフォーマンスは向上しているが、消費電力は変化していない。これは、Googleが低価格PCの大量使用という形態で発達してきた経緯があり、確かに発足当初、購入コストは低く抑えられたが、余りに急速に巨大化したため、電力消費の観点での最適なシステム構成とは言いにくい状態になってきている点が考察できる。

 なお、Googleのメインのデータセンターのひとつはオレゴン州にある。ここにはGoogleだけでなくYahooや Microsoft、Ask.comなど多くのデータセンターが集中し、データセンター銀座となっている。これは、近くのダレス川の水力ダムから取れる電力量が大きく、電気代がカリフォルニア州に比べて半分から3分の1で済むこと、PC-1(Pacific Crossing)という太平洋横断ケーブルの揚陸地点のひとつに近いこと理由だという。

 また、非常に珍しいことに、データセンターの写真も公開されていた。これを見ると、管理棟、1号棟、2号棟で構成されるデータセンターが対称形で2つ存在していることが分かる。煙突のような構造がクーラーの排熱機で、その規模で使用電力も想像できる。Googleは、データセンターを必ず1拠点に2個以上建てている、これは以前、火事によってデータセンターを焼失した経験があるためだ。これは世界最大のクラスタ構造と見ることができる。

Googleのデータセンター
Googleのデータセンター

MapReduce

 さて、「MapReduce」だ。Googleのシステムデザインは、概念としてはハードウェアの上に仮想化されたOS、ミドルウェア、アプリケーションが乗るという組み合わせが多数のマシン上にあるということになる。基本的な用途が検索のため、仕組みは簡単だが、それらの規模が極端に大きいことが特徴だ。

 これに対しIBMのシステムデザインは非常に複雑になるが、これはいろいろなアプリケーションを1箇所で動かすためフラグメントも起きやすい、また過去の資産の継承も複雑化を促す要素となる。ただし、これは目的がエンタープライズ・ビジネスであるため当然のことで、誰がデザインしてもこうなるはずだという。

Parallel skeleton

 さらにGoogleのシステムを理解するための基礎知識として「スケルトン並列プログラミング」がある。これはある種のデザインパターンで、そのパターンは「データパラレル」と「タスクパラレル」がそれぞれ2種類の合計4種類しかない。前者はデータを分割して同時に並行処理するもので、後者は処理過程を行程ごとに分割して行うというものだ。

「データパラレル」と「タスクパラレル」
「データパラレル」と「タスクパラレル」

 データパラレルの一つ「Map skeleton」は、入力された1個のデータが何らかの処理を受け、変化した1個のデータとして出力される。もう一つは「Reduce skeleton」で、2個入力されたデータが1個のデータとして出力される。タスクパラレルの一つ「Pipe skeleton」はUNIXの「|(パイプ)」と同じで、行程ごとにどんどん加工され処理が進んでいく。もう一つのタスクパラレル「Farm skeleton」は「Master-worker pattern」とも呼ばれ、マスター(親)が複数のワーカーに処理をディスパッチする。

Bigtable

 次に「BigTable」だ。「BigTable」はGoogle独自のデータベースであり、読み込みが18GB/secと非常に高速であるが、書き込みは700MB/secと速度が大きく異なることが特徴だ。これはGoogleのサービスのメインが検索であるためで、書き込みはWebページをクロールした内容の更新をバッチ的に行っている。その代わり読み出しはリアルタイムで行う必要があるため、0.5秒の処理速度で最新情報を提供しているというわけだ。

BigTableとMap Reduce
BigTableとMap Reduce

 「BigTable」のスキーマは、「Row+Column+Time」の3Dデータベースと呼ばれている。過去の情報を消さないことで過去(キャッシュ)に戻ることができるが、実は過去の情報を消すことが大変なシステムでもあるのだ。またGoogleのシステムを理解する前提知識として「failure-oblivious computing」がある。これは「落ちることが前提のコンピューティング」である。PCは通常、終了プロセスを経て再起動するが、いきなり電源を落としても次回は普通に起動する。だったらシャットダウンは不要というわけだ。つまり、再利用されることのない例外処理は最初から廃棄する方針でシステム設計するわけである。

ダメなデータを切り捨てながら進めるプログラミングスタイル

 以上のようなGoogleのシステムは、インターネットにある不要なものや悪意あるものを無視する、自分が決めた条件から外れるものは全部捨ててしまうという考え方によるものとなっている。「しかし、ダメなデータを捨てながら前へ進んでいくプログラミングはおもしろい」と根本氏は言う。

 このようなプログラミングスタイルは、入出力データの量に大きな差がある場合に有効だ。例えば、チェスの「ベストな次の一手」を考えるものなど、大量の入力に対し少しの出力を行う場合によい。ネットワークの不正を監視しながら警告するようなアノマリ監視にも使えるかも知れない。IBMでも用途を見つけ出せる可能性のあるプログラミングモデルであると、根本氏は発表を締めくくった。

オブジェクト指向とカリー化

 「巻き」が入る中、最後に登場したGeekは津田嘉孝氏。「オブジェクト指向とカリー化」と題された発表は4月に行われたもので、「カリー化の意義を理解する」ことを目標としたものである。そもそもこの資料は、お客様先で勉強会を実施するために制作したものだという。

津田嘉孝 氏
津田嘉孝 氏

 このお客様は業界大手で、Java Webアプリケーション開発を多数実施しており、フレームワークも所有していたが、開発効率に課題があるため、日本アイ・ビー・エム システムズ・エンジニアリング株式会社(以下、ISE)にて、Seasar2をベースにした新規フレームワークを開発・保守していた。2008年に入ってから、その追加機能を含む保守をお客様が引き継ぐに当たり、技術力向上を目指し、勉強会を実施することになった。その中でオブジェクト指向とカリー化を取り上げたのだという。 

閉じた世界と開かれた世界

 津田氏はまず、「閉じた世界と開かれた世界」として比較を行った。ここで言う閉じた世界とは、メインフレームに代表される決まりきった接続先だけの世界で、開かれた世界とはLinuxやWindows、AIXなどのOS、Javaや.NET、Ruby、PHPなどの言語に代表されるように多種多様な接続先がある世界だ(ここで"The Internet"のinterが「~間の」という意味があることを考えると閉じたネットワーク同士が結びつきあうことで開かれたネットワークを形成していったことが感じ取れる)。

 さて、閉じた世界ではプログラムの考慮点がほとんどないため、メソドロジーとして構造化設計手法を採用し、単純にサブルーチン化していけば、サブルーチン呼び出しによる再利用が達成される。そのため開かれた世界に比べ閉じた世界では生産性を高く維持することが可能だ。

閉じた世界と開かれた世界
閉じた世界と開かれた世界

 一方、開かれた世界では、プログラムの考慮点はセキュリティやアーキテクチャ、プロトコル、フレームワークなど多数存在し、かつ、旧来の手法では、これらへの対応項目が増えるほどコード量が爆発的に増えてしまう傾向がある。つまり、世界が開かれていくほど考慮事項が増え、生産性は下がっていく、そのため、開かれた世界のメソドロジーとして、オブジェクト指向が注目されてきたのである。特に開かれた世界では、状況を特定できないという辛さがあると津田氏は言う。 

状況を特定できないことの苦労

 例えば、ResourceBundleを使ってプロパティファイルからキーに対して値を取得することを考えた場合、もし、この世界に住むすべての人間が英語だけを使用しているのなら

a)
bundle.getBundle(key)

 だけで済む。しかし、日本語などの国際化対応を考慮した途端

b)
bundle.getBundle(key, request.getLocale())

 と、ロケールに気を遣う必要がでてくる。また、JavaEEコンテナから利用される状況まで考慮しだせば、アプリケーションのClassLoaderまで特定する必要が出てくるため、

c)
bundle.getBundle(
  key,
  request.getLocale(),
  Thread.currentThread().getContextClassLoader()) 

のように記述が複雑になってくる。本来、キーに対して値が欲しいだけなのに、場合によっては状況の特定にコード上でこれだけの努力が必要となるのだ。

 また状況が変わった場合、例えば、アメリカで作られたアプリケーションでは最初a)の記法を用いて記述されていたが、ある日、日本にも進出しようと考えた結果、国際化対応でb)のような修正が発生したとしても不思議ではない。

 このように旧来の手法では状況に変化が現れた結果、パラメータもすべて書き直すことになり、ひいてはアプリケーションを作り直すことにまで繋がる。この原因はレイヤーの上から下まで必要なパラメータを引き渡していかなければならないことにある。もし、要件の追加だけですべて作り直さなければならないのであれば、レイヤー化に意味はない。

 この課題に対し、パラメータはそのままに要件の追加を可能にするのが、オブジェクト指向が目指したことであり、本質的な答えをコンピュータサイエンスに求めれば、それは「カリー化」ということになる。

カリー化とは

 カリー化とは、「関数を元に引数の減った関数を動的生成すること」である。

  • function f(a,b):=a+b
  • function curry(y,m)(a):=y(a,m)
  • function g2(a):=curry(f,2)(a)
  • g2(1)->3

 のように、カリー化ではg2という関数を作ってパラメータbを2とすることで、状況を特定することができ、パラメータを1個で済ませることができる。

 ただし、Javaではカリー化を明確にサポートしていないのが現状だ(JDK 7ではクロージャをサポートするという話がある)。その理由は、オブジェクトを生成するにはすべてクラスを一旦定義し、そのクラスのインスタンスとしてオブジェクトを生成するクラス指向に基づいているからであり、関数を定義したらそれが即、オブジェクトとはならないためだ。もっとも、Javaでもクラスやインターフェースを多数用意して、疑似的にカリー化を実現することができる。

Javaでの擬似カリー化
Javaでの擬似カリー化

 昔ながらのオブジェクト指向関連の書籍では、「オブジェクト=メソッド+データ」と説明されているが、オブジェクトは「あるデータに関してカリー化された関数の集合」と捉えることができる。このためJavaでメソッドを呼び出すには、オブジェクト(集合)名、メソッド名、パラメータの順に記述するわけだ(何かについてカリー化された関数の集合から、特定の関数を取り出して、必要なパラメータを渡して、関数の結果を得る)。これがオブジェクト指向が「開かれた世界」への対応手段とされる所以となる。

 不安定な部分をカリー化の対象とし、安定した部分はインターフェイスとすることで、クライアント側はサーバの実装をあまり気にすることなく処理を呼び出せるようになる。これは、状況が変わっても対応部分は局所化することを意味し、生産性を維持できることになる。

アプリ開発へのカリー化の適用

 アプリ開発での効果をみてみると、構造化設計手法的にレイヤー化しただけでは基本的に下位レイヤーで必要なパラメータも上から下に順次に渡していく必要があるため、非機能要件まで引きずることになる。

 例えば、JavaEEを使用する場合、当然JavaEEに付随するパラメータも渡すことになるため、JavaEE上で動かそうとするとJavaSEで動かなくなり、逆にJavaSE上で動かそうとするとJavaEEで動かなくなる。これでは単体テストも難しくなってしまう。

 そこでAOPということになるのだが(AOPもカリー化を用いた技術、因みにSeasar2は対象となるクラスを継承したクラスを動的に生成することでAOPを実現している)、AOPを前提にしたレイヤー化では機能要件の単体テストは通すことはできるものの、非機能要件を実装したアドバイス(業務ロジックをフックして呼び出される処理)から使用したいパラメータへのアクセス手段がなくなってしまう。これはWebコンテナからアプリケーションへ環境に関する情報を渡す口はHttpServletのdoGet / doPostで渡されるHttpServletRequest / HttpServletResponseを用いて取得する仕様に起因する。AOPは「ログにしか使用できない」といわれるのは、環境から情報を取得する機能に乏しかったためだ。

AOPだと非機能要件で使用するWebコンテナへのアクセス手段がなくなる
AOPだと非機能要件で使用するWebコンテナへのアクセス手段がなくなる

 そこでコンテキストということになる。コンテキストを直訳すれば、文脈という意味だが、ここでは実行状況を指す。コンテキストはパラメータを生成する役割を担うため、前述のフレームワークではカリー化で状況を特定するパラメータを表現している。状況が変わったら、新しいコンテキストを用いてカリー化し直せばよい。これならアプリケーションロジックを変更することなく状況変化に対応できる。 

 次にこのコンテキストの具体的な実現手段を前述のお客様フレームワークでの実践を基に考える。実は、Seasar2(厳密にはS2Container)は、Web環境のコンテキスト情報「HttpServletRequest」をどこからでも取り出せるようにThreadごとに保存しているのでこれを利用すればよい。実際、S2DaoやS2StrutsなどはSeasar2を直接利用してこれらの情報を取得している。しかし、それではコンテキストが欲しいコンポーネントは全てSeasar2に依存するため、より抽象的な「WebContextインターフェース」を定義し、その実装として、Seasar2を利用する「SeasarWebContext」という実装を用意した。コンテキストが欲しいコンポーネントは「WebContext」インターフェースを介してSeasar2が保存しているコンテキスト情報を取得するため、Seasar2への依存がなくなる。

 これが例えばSpringを使用するように変わったときには、「SpringWebContext」を作り情報を取得するようにすればよい。これより上で動いているコンポーネントは、SeasarかSpringかを意識することなく実装できる。 

抽象的なレイヤーを用意
抽象的なレイヤーを用意

 また、そもそもWebであることさえ意識する必要がないコンポーネントも多数存在するので、更にコンテキストを「WebContext」から切り離して定義することが可能だ。例えば認可に関わるコンポーネント用に「UserContextインターフェース」を用意し、「WebContext」に依存した「WebUserContext」を本番用に「ConstUserContext」を単体テスト用に作成すれば、本番とテストで切り替えて使用したり、更にはバッチ環境に持っていくことも可能になる。  

 津田氏は最後のまとめとして、「カリー化は昔からある極めて強力な道具であり、この道具がオブジェクト指向プログラミング言語を可能にしたのである。このためプログラマ、設計者、分析者は理解すべきものである」と締めくくった。なお、前述のようにJavaでも擬似的にカリー化は可能であるが、現在のところは関数型言語であれば、1行で済むこともクラスに切り出し、インターフェースを抽出し直し、単体テストケースを用意した上で、更にそれらにJavaDocやコメントを用意することを考えれば、100行くらい記述することになるという。 

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加

【AD】本記事の内容は記事掲載開始時点のものです 企画・制作 株式会社翔泳社

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/2992 2008/09/10 18:40

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング