自動車工場の生産ラインを超おおざっぱに言うと、だいたいジャングルジムくらいの機械をベルトコンベアで何台かつなげたもので、いろんな小っさい部品(輪っかとか、丸っこいのとか、筒みたいなのとか)を組み合わせて、より上位の足回りやブレーキといった部品を作るような、一連の流れ作業を担っている。
ラインに組み込まれる個々の機械は、部品と部品を組付けたり、溶接したり、塗装したり、油を注入したりするもので、あるものは全自動、別のものは半自動だけど、人手が介入する部分は単純化されていて、工学的素養や、職人的技能が要求される事はほとんどない。出稼ぎ労働者や期間工が、担当したりする。
工場では、新車種対応だとか、増産だとかいったきっかけで、生産ラインを組み替えたりするので、そこに組み込む機械を、自社の部門だとか外部の「ナントカ精機」みたいな機械製造会社にオーダーメイドで発注する。で、普通は、設計、電気、組み付けのそれぞれの職人がアサインされて、協力して機械を製作する(旋盤やフライスを使って、鉄の塊から部品を切り出す加工屋さんも関わってくる)。
この職人さん達は、それぞれの担当分野のプロフェッショナルなわけだけど、それぞれの腕前が品質や生産性に反映するから、やり甲斐があって面白いし、だからよく勉強もする。それに基本的に世の中に一台から数台しかない機械なので、なんとなく愛着のようなものも持っていたりもする。
当たり前の事だけど、生産設備を作る機械職人と、その設備を使って部品を組み立てるライン作業者との間には、基本的には棲み分けがある。メーカの社員が両方をこなす事も、あるにはあるだろうが、基本的には前述のとおり、機械職人は機械屋さんだし、ライン作業者は出稼ぎの期間工だったりする。仕事の成果物も違うが、それ以前に、持っている職能も、もの造りへのスタンスも背景も、全く異なっている。
前置きが長くなったが、このところ聞かなくなったソフトウェア・ファクトリについて、上述のような、「技術者の棲み分け」を促進するのではないかと、ちょっと期待していた。つまり、ファクトリという生産設備を作る高スキル・グループと、それを使って製品を作る低スキル・グループに、いっその事、従来以上にスッパリ分離してしまってはどうかという疑問に、答えを提供してくれるのではと。
従来、SI屋が技術者の棲み分けを施す場合、フレームワーク/ライブラリに関連するチームに比較的高スキルの要員を割り当てて、それを用いるビジネスロジックを担当するチームに低スキルの要員を割り当てる事が多かった。
でも、この役割分担だと、つまるところ同じ平面上で共通部分と固有部分に要員を振り分けているにすぎず、結局は同じ言語、同じ規約、同じ最終成果物に対しての作業になるわけだから、いたるところでギャップが生じて、互いの不経済を引き起こす。
すなわち、低スキル技術者は、高スキル技術者達の間ではごく当たり前な慣用句に過ぎない、ありふれたデザイン・パターンやイディオムがチンプンカンプンだったりするし、一方、高スキル技術者の方でも、三項演算子すら分からない低スキル技術者が迷子にならないように、自己の能力も言語/APIのポテンシャルも大幅に抑制する事になる。
例えば、良かれと思って、「流れるようなインターフェイス(fluent interface)」のスタイルでAPIを書いたとしても、使う側が最底辺技術者のグループだと、「いつもと違う。見たことが無い。」なんて感じで、総スカンを食らう可能性がある。
こういった無駄な軋轢を避けるためにも、高スキル技術者をメタレベルの作業領域、つまり生産設備=ファクトリの開発作業に従事させて、低スキル技術者とは干渉しようもないレベルに分けてしまうのが良案なのではないかと。(もちろんギャラも、容赦なく差をつけるべきだが。)
低スキルな技術者達というのは、プログラム言語や APIについて勉強する事が、本当に何よりも嫌いでたまらない人達なわけだから、そんな理不尽な苦痛は、人道的観点からもなんとかして少なくしてあげたい。そのために、覚える事がいっぱいな従来通りの汎用言語に替わる簡易な言語として、DSL を与えてあげるのが良いのではないか。
この DSL を定義する 高スキル技術者グループの方でも、リテラシの貧弱な読者を気にする事無く、スキルを最大限に発揮して、言語/API の本来の力を最大限に引き出して、最高のコードを書くことができる。最も簡易で優しいドメイン特化言語を、最も高度な技術で、のびのびと開発すればいい。
と、まあ、理想はこうだけど、何をどう分離して、どこまでファクトリ化するか具体的に考えたら、やはりなかなか難しい。正にそれをソフトウェアファクトリが提示していたんだろうけど、普及する前に消えてしまったようだし、やはり何か無理があったのか。
2010年7月19日月曜日
2010年1月6日水曜日
ANTLR IDE/分数電卓
金額計算に使えそうな外部 DSL を書きたいが、その前に軽くウォームアップ。
分数電卓を作ってみる。コンソールで式の入力を受付けて計算結果を返す。ただし小数は受け付けない。またゼロ割り算はシンプルに例外送出のみとする。
作業環境・実行環境は Eclipse を使用。コンソールビューの入力と出力がこんな風になるようにしたい。
以下のような仕様で、簡単なJava の有理数クラスも要るので用意しておく。自明なのでコードは省略。
この Rational クラスを、以下のような ANTLR コードから使う。AST 生成文法とAST 処理文法を別々にした。
まあ、普通に動くようだ。
流れ的には、まず文法定義を書いてから、JUnit を用いたテストファーストで Rational クラスを書きながら、ANTLR コードと Java コードの結合を手作業で確認した。実戦だと ANTLR コードの検証も自動化したい。
次にやる事
分数電卓を作ってみる。コンソールで式の入力を受付けて計算結果を返す。ただし小数は受け付けない。またゼロ割り算はシンプルに例外送出のみとする。
作業環境・実行環境は Eclipse を使用。コンソールビューの入力と出力がこんな風になるようにしたい。
1+2/5 |
(1+2)/5 |
1/2-1/2 |
0/3-1/4 |
7/5 |
3/5 |
0 |
-1/4 |
以下のような仕様で、簡単なJava の有理数クラスも要るので用意しておく。自明なのでコードは省略。
- 分子と分母を long 値のペアで表現する、Rational という名前の不変クラス。
- コンストラクタで約分する。
- add, subtract, multiply, divide メソッドは計算結果を新規インスタンスで返す。
- toString()は、分母が1なら整数、そうでないなら分数での文字列表現とする。
- 上記のとおりゼロ割りは例外送出。
この Rational クラスを、以下のような ANTLR コードから使う。AST 生成文法とAST 処理文法を別々にした。
grammar Expr;
options {
output = AST;
ASTLabelType=CommonTree;
}
//prog: (stat {System.out.println($stat.tree.toStringTree());})+;
prog: stat+
;
stat: expr NEWLINE -> expr
| NEWLINE ->
;
expr: multExpr (('+'^ |'-'^) multExpr)*
;
multExpr : atom (('*'^ |'/'^) atom)*
;
atom: INT
| '('! expr ')'!
;
INT : '0'..'9'+ ;
NEWLINE: '\r'? '\n' ;
WS : (' '|'\t'|'\n'|'\r')+ {skip();} ;
tree grammar Eval;
options {
tokenVocab=Expr;
ASTLabelType=CommonTree;
}
@header {
import rational.Rational;
}
prog: stat+
;
stat: expr {System.out.println($expr.value);}
;
expr returns [Rational value]
: ^('+' a=expr b=expr) {$value = a.add(b);}
| ^('-' a=expr b=expr) {$value = a.subtract(b);}
| ^('*' a=expr b=expr) {$value = a.multiply(b);}
| ^('/' a=expr b=expr) {$value = a.devide(b) ;}
| INT {$value = new Rational(Long.parseLong($INT.text), 1);}
;
まあ、普通に動くようだ。
流れ的には、まず文法定義を書いてから、JUnit を用いたテストファーストで Rational クラスを書きながら、ANTLR コードと Java コードの結合を手作業で確認した。実戦だと ANTLR コードの検証も自動化したい。
次にやる事
- 行列の計算。もともとやりたいのは按分計算込みの事務処理用DSLだけど、その前に簡単な行列の計算がいりそうな感じ。
- 変数と代入式
- Java とのインターフェイス。コンソールを使わない形で Java から使えるようにする。