追記2:Groovyのサンプルをまたもや修正。矢野さんにコメントいただいたとおりです。
追記1:Groovyのサンプルにウソがありました。ごめんなさい。eachやinjectはListの拡張なので、[1..5]のRangeでは使えません。eachするとRangeそのものが取れちゃいます。ちゃんと試さずに書いちゃいました。ちなみにデモは[1,2,3,4,5]とやってのでうまくいきました。
ブログもアップできず本当に情けない…。さて、昨日の第2回丸山先生レクチャーシリーズ で「混ぜるな危険!? JavaとLLをマッシュアップせよ」というタイトルで講演させていただきました。資料はこちらからダウンロードできます。
Java業界でもJSR223を機会にLLに対する取り組みが盛り上がりつつあります。しかし、現場では「LLって何に使える?」「Java環境で使える?」「そもそも、なんでLL?」といった疑問も多いことかと思います。これに少しでも答えられればと考えました。
LLを知る
まず大事なのはJavaもLLもプログラミング言語であり、それはプログラマにとっての道具であるという点です。道具を知るには、その仕事や文化を知ることが一番。ハッカーたちの言葉を聞いてみると、
- ポール・グラハム : プログラミング言語はプログラムを考えるためのものであって、既に考えたプログラムを書き下すためのものじゃない。(ハッカーと画家)
- DHH(RubyOnRails作者) : 美しいコードを書くことができる(「美しいコードを書けるからRubyを選んだ」)
- 伊藤直也(はてな) : "創りながら創る"という方法においては静的型付けの言語よりも動的型付けの言語の方が有利(僕やはてながPerlを選ぶ理由)
こうした言葉からはLLが「試行錯誤を行いながらプログラミングするための道具」であることが見えてきます。
このためLLでは直感的な記述形式が好まれます。実際のコードをJavaとLLで比較してみましょう。「1から5の配列の各値を足しこんで結果を表示する」というものの場合、Javaは18行。
import java.util.ArrayList;
import java.util.List;
public class Sample {
public static void main(String[] args) {
int total = 0;
List list = new ArrayList();
list.add(new Integer(1));
list.add(new Integer(2));
list.add(new Integer(3));
list.add(new Integer(4));
list.add(new Integer(5));
for (int i = 0; i < list.size(); i++) {
total += ((Integer)list.get(i)).intValue();
}
System.out.println(total);
}
}
対するLL(Groovy)は、たった3行。
def total = 0
[1..5].each { total += it } (これは間違い)
[1,2,3,4,5].each { total += it } (これでも動くけど、下のほうがスマート)
(1..5).each { total += it }
println total
Javaが厳密に手順(プロセス)をあらわしているのに対して、LLは構造と制御を同時に表現していることが特徴です。LLの2行目は、そのまま「1から5の配列([1..5][1,2,3,4,5](1..5))の各要素に対し(each)、合計に値を足しこむ(total += it)」というように、そのまま読み取ることができます。 このように思ったことをすぐに表現できるため試行錯誤に向くというわけです。
JavaとLLの仕事
現在考えることができるJavaとLLの仕事について比較してみましょう。
Javaは型を通じてコミュニケーションができ、それを無視することはできません。そのためIDEサポートを前提として同時多人数での開発が可能です。一方のLLは型がなく柔軟なため俺様コード・俺様規約が作りやすく自分の作業効率を徹底的にあげることができます。
一見すると現状のエンタープライズアプリではJavaが向いていそうです。しかし、LLを活用しなくて良い、ということではないと思っています。
なぜなら既にJavaではSQL、XML、JSP、ELといったJava言語ではない記述形式を取り入れており、これらが効果を発揮しているからです。エンタープライズ・アプリにはさまざまなレイヤーが部分があり、その分業と統合が重要です。そのため部位特性に合わせて道具(言語)を専門化させるのは当然のことです。
ですからLLもエンタープライズ・アプリのどこで使えるのかと探してみるというのが面白いトライになります。現在でもアプリ外部のツールとして使うパターン(シェルスクリプト、自動生成ツール)は見られますが、あえてアプリ内で使うパターンを紹介しました。それがサーバーサイドDHTMLエンジンのSarugau JSです。
これまではJavaScript(Rhino)を利用していましたが、現在はGroovy版を開発しており、これを使ったデモを少し紹介しました。GroovyのBuilderを使うことでHTMLの加工が非常に簡単に行えるようになっています。
LLが求められる本質
なぜLLなのか、というのをもっと深く考えていくと、それは「設計の幻想」に対する答えだと思っています。設計の幻想とは「設計書どおりにコードを書くことがプログラミングである」という認識です。
これは近代工業の組立ラインに似た発想です。設計を元に製造を行うためのQCD(品質、コスト、期限)を極限まで高め、量としての生産効率を上げていきます。これは100年前に紹介されたテイラーの科学管理法による「作業の分解、測定、改善」という製造プロセスの効率化がベースの考え方です。トヨタ生産方式も同じ。
しかし、プログラミングとは設計を元に製造を行うようなものではありません。僕らがやっていることは知的労働であって、プロセス化して効率化できるようなものではありません。ドラッカーは『テクノロジストの条件』の中で「知識労働の生産性を向上させる六つの条件」として、次の6つを挙げています。
- 仕事の目的を考える。
- 働く者自身が生産性向上の責任を担う
- 継続してイノベーションを行う
- みずから継続して学び、人に教える
- 知識労働の生産性は量よりも質の問題であることを認識する
- 知識労働者は、組織にとってコストではなく資本財であることを理解する
そして次のように述べています。
六番目の条件以外は、肉体労働の生産性向上の条件とはちょうど逆である。<中略>肉体労働では、質は制約に過ぎない。最低の基準があるだけである。<中略>知識労働における仕事の質は制約どころではない。仕事の本質である。教師の仕事は、生徒の数では評価されない。何人の生徒が本当に学んだかが問題である。
知識労働の生産性は質を中心に据えなければならない。しかも最低を基準にしてはいけない。最高ではないにしても最適を基準にしなければならない。量の問題を考えるのはその後である。
つまり、重要なのはプロセスではなく結果として生まれるモノの質なのです。いくらプロセスを効率化してもモノが良くなければ意味がない。知識労働の場合、試行錯誤なく明確な設計図を描くことは不可能なのです。
これは新車開発を考えてみればわかります。車の設計図を描くために彼らがしていることは、まさに車を創ることです。設計図を描くために、モックやクレイモデルを作り、CADやシミュレータを駆使して試験を行い、実車を創って世界中でテストする。そうやってようやくできあがった設計図を元に製造を行っています。
われわれのシステム開発とは新車開発と同じです。製造の組立ラインとはまったく違う。
良いシステムを作るためには絶対にプログラミングの試行錯誤が必要であり、設計の幻想は存在しないのです。
システム開発の再構築期
LLの言語仕様が確かに極端かもしれません。しかし、その精神は「良いものを創るには実際に試行錯誤するしかない」という至極まともな訴えの表れです。この点には真摯に耳を傾けるべきでしょう。
こうした試行錯誤を言語に限らず、開発手法などどあわせていかに導入するのかが、これからのエンタープライズアプリ開発の大きなテーマだと思っています。
これはシステム開発の再構築期が訪れていると考えてよいでしょう。トーマス・フリードマン『フラット化する世界(上)』では「生産性のパラドックス」という言葉が紹介されています。革新的な技術が生まれても、その技術が本格的に産業に影響を与えるには数十年かかる。それは技術だけではなく、その技術の周りを再構築する必要性があるからです。
電球が発明されたのは1879年だが、電化が始まり、経済や生産性に大きな影響をあたえるようになるまでに、数十年の時を要したというのだ。なぜか?電動機を取り付けて古いテクノロジー – 蒸気機関 – を廃棄するだけではだめだからだ。製造の手順すべてを再構築しなければならない
僕らがエンタープライズアプリにまともに取り組んでからまだ十年ちょっと。今まさに変革期の真っ只中だと思います。これは丸山先生の「旧大陸から新大陸への移動」という言葉にも良く表れています。
こうした時代には「マッシュアップ力」が重要だと思います。はてなキーワードから引用すると、
(特にAPIが公開された)ウェブサービス同士を (できることならば)開発者ですら思いもよらない方法で組み合わせて、新たな価値を創造すること。
ということ。ウェブサービスに限らず、言語も手法も、なにもかもマッシュアップし新たな価値を創造する。いまはそういう時代だと思っています。LLのような技術であっても、その本質を考えちゃんと取り入れる。こうした行為が重要ではないでしょうか。
ぜひ皆でトライ&エラーを繰り返してよい世界を創りましょう。
![]() | テクノロジストの条件 P.F.ドラッカー 上田 惇生 ダイヤモンド社 2005-07-29 by G-Tools |
![]() | フラット化する世界(上) トーマス・フリードマン 伏見 威蕃 日本経済新聞社 2006-05-25 by G-Tools |



コメント (4)
本質的な問題ではないですが...
こうやれば、かなり減らせますけど。
public class Sample { public static void main(String[] args) { int total = 0; List list = Arrays.asList(new Integer[]{1, 2, 3, 4, 5}); for (int i = 0; i < list.size(); i++) { total += list.get(i); } System.out.println(total); } }投稿者: さくらば | 2006年12月17日 11:26
日時: 2006年12月17日 11:26
yusukeです。はい、おっしゃるとおりです(汗。うーん、やっぱりサンプルが卑怯ですよね。いかんですなぁ。
クロージャーやbuilderを例にしたほうがスマートですね。次回、機会があれば考えます。
投稿者: yusuke | 2006年12月17日 16:10
日時: 2006年12月17日 16:10
RangeはListを拡張しているので、Rangeを使っていること自体は間違いないですよ。ただRangeとは「1..5」と書くのがRangeなのであって「[1..5]」だと「ListのなかにRangeが一個入っている」ことになっちゃってますね。
(1..5).each { total += it}
なら問題なく動きます。[]を()に変えるだけです。
投稿者: 矢野勉 | 2006年12月18日 03:18
日時: 2006年12月18日 03:18
矢野さん、ありがとうございます。確認しました。そのとおりですね。いやはやお恥ずかしい限りです。
投稿者: yusuke | 2006年12月18日 16:11
日時: 2006年12月18日 16:11