業務システムでオブジェクト指向は必要か?

半年前に爆発的に盛り上がったネタで今更ですが、
実はオブジェクト指向ってしっくりこないんです!:気分はstatic!:エンジニアライフ
について。多態性ポリモーフィズム)やGoFデザインパターンなどの常識を知らない筆者が、C#でpublic staticメソッドを使えば*1インスタンス化が不要などと知ったかぶりの口調で説明したところ、コメント欄やその他のブログで爆発的に議論(多くは反論)が巻き起こったという、伝説的な内容の記事です。多くの方が既にコメントしているので、ここでは筆者の無知や態度については繰り返し言及しないことにします。ユーザー企業のIS部門という業界のピラミッド構造のかなり上の方に属する立場のSEにはこの程度の見識しか持たない人もいるのか、井の中の蛙の技術者とはこのようなものなのかという事実をあらためて世に知らしめたという意味で、(炎上した多数のコメントも含めて)非常に貴重な記事です。「システムエンジニア 生き残りの極意」ということなのですが、この業界では真面目に技術を勉強して、パフォーマンスを発揮するということが必ずしも評価や出世に結びつかないということでしょうね。熱狂的な信者の多いオブジェクト指向という微妙なテーマを扱っていることもありますが、日ごろからそうした矛盾に不満を感じている技術者というのが多いというのもこのコラムが炎上した理由なのでしょう。
ところで、「業務システムでオブジェクト指向は不要」というのは、DBを中心にした処理しかしないシステムにおいては一理あるところがあります。このコラムの筆者が上から目線ではなくて、初心者という立場で「オブジェクト指向はしっくりこない」と質問する内容であったら、共感する読者が多かったのではないかと思います。実際伝統的な業務システムで必要なバッチ処理や帳票生成、データ入力などの単純な処理しかしないのであれば、筆者のようにクラスからインスタンスを生成して処理するというのが大げさで無駄に感じる人も多いのではないでしょうか。実際、オブジェクト指向狂信者にありがちですが、何でもかんでもDomain Modelにして、複雑なアグリゲートやらValueObjectやらを定義することで、非常にプログラミングが難しくなってしまうことだってあるのですから。要は「要件をみたす最もシンプルな実装」を心がければよいのですから、私だってCRUDしかしないシステムはTransaction Scriptで作成すると思いますし、Domain Modelを構築する場合でもFacadeパターンをつかって手続き的なサービスインターフェースをアプリケーション層に置く事は、多くのシステムでは有用だと思います。この場合サービスの実装はステートレスでインスタンスは一つあればよい(Singleton的)わけですから、筆者のstaticメソッドにすればよいという考えと大きく異なるものではありません。*2
ただし、インターフェースに対するコーディング(多態性の応用の一種)が重視されている、SpringやEJB3のユーザーには常識的なことだと思いますが、staticメソッドのみ持つUtilクラスとDIで管理されたSingletonのステートレスなサービスクラスとの違いは以下が重要です。

  • サービスクラスはProxyパターン、Decoratorパターンを使ってAOPのインターセプターを仕掛けることができる
  • サービスクラスはMockオブジェクトを使った単体試験の作成が容易

C#ではありませんが、少なくともJava EEの世界では上記のような理由から、staticメソッドのみのクラスで業務ロジックを実装することはありえません。
結局、「業務システムでオブジェクト指向は不要」かどうかは要件しだいなのでなんともいえませんが(といってもオブジェクトを一つも使わないことはありえませんが)、業務ロジックを実装するクラスのメソッドを全部staticにするのはありえないというのがこの記事に対する私の見解です。SpringなどのDIコンテナーを利用することで、newによる明示的なインスタンス生成を不要にしつつも、多態性を有効に活用できるのです。DIコンテナーが業務システムと特に相性がよいのはそのようなところもあるのだと思いました。C#でもSpringの.NET版を利用することでDIを活用できるはずです。
Spring.NET - Application Framework

*1:C#にはstaticクラス宣言で簡単にUtilクラスが作成できる機能がありますが。

*2:達人プログラマーとしては、要件に応じて最適な実装方法を提案できるように、幅広い技術を知って使いわけることが求められると思います。SQL中心の設計がよければそうするべきだし、既存資産の流用を考えてCOBOLが最適ということもあると思います。技術の進歩が速い上に、スコープは広大なので、すべてを完璧に知り尽くしているというのは神でもない限り絶対不可能だと思いますが。

アナリシスパターン - 非常にとっつきにくいが読めば読むほどに良さがわかる名著

アナリシスパターン―再利用可能なオブジェクトモデル (Object Technology Series)

アナリシスパターン―再利用可能なオブジェクトモデル (Object Technology Series)

  • 作者: マーチンファウラー,Martin Fowler,堀内一,友野晶夫,児玉公信,大脇文雄
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2002/04
  • メディア: 単行本
  • 購入: 7人 クリック: 89回
  • この商品を含むブログ (70件) を見る
Analysis Patterns: Reusable Object Models (Addison-Wesley Object Technology Series)

Analysis Patterns: Reusable Object Models (Addison-Wesley Object Technology Series)

Java EEを含めて、業務システムの開発をオブジェクト指向で行う場合には是非勉強しておきたい名著です。翻訳は必ずしも悪いわけではないとは思うのですが、原文の微妙なニュアンスが伝え切れていないところがあり、できれば原書と読み比べながらじっくりと時間をかけて理解するのがベストと思います。日本語にしてしまうと、原書で感じられるプログラミングとのつながりがどうしても薄くなってしまうというところがあります。アナリシスパターンというと上流のモデリングに関する本で、プログラミングには一切関係がないように思っている人がいるかもしれませんが、もともと、Smalltalkのコード例が書かれていたり、3層レイヤーや参照・値オブジェクトなどの実装よりの視点が書かれていたりするように、ファウラーのプログラマーとしての経験がところどころに織り交ぜられているのを感じとることができます。その中に出てくる分析クラスもAccountとかContractなどと英語で記述されていると、自然にJavaなどのオブジェクト指向言語におけるクラス設計とのつながりを意識して読めるのですが、勘定とか契約などと翻訳してしまうとちょっと距離があるように感じられてしまいます。また、状態図中に描かれたcanBeExercisableなどのキャメルケースで書かれた条件は英語だとメソッドにスムーズに結びつくのですが、「行使可能か」などと翻訳されるとプログラムとは別物のように思えてしまいます。この本で常に重視されているのはクラスのインターフェースや責務、多態的な振る舞いということであり、一般に上流工程でよく行われるような純粋なデータモデリングの本では決してありません。この点、日本で上流と下流が分離されているというのはIT業界のゼネコン構造に加えて、言語の問題も大きいのではと思えてしまいます。Javaでもきれいにコードを設計するとかなりDSLというか英語的には上流の設計に近づけるのですが、日本人はJavaのコードを仕様書としてでなく記号の羅列と考えてしまう傾向があると思います。(最悪なケースだとUC1001とかPrg1503などの無意味なクラス名をつける規約を押し付けている場合さえあるみたいですが。)
あと、この本に出てくる分析モデルやパターンは、表面上特定の業務分野を題材として取り上げているのですが、そこに出てくるパターンは他の業務であっても汎用的に使えるアイデアになっているものが多いというところも見逃してしまいがちですが大切なポイントかと思います。たとえば、本書ではデリバティブ商品のストラドル*1の例を取り上げて、Productパターンというパターンが紹介されていますが、これは、顧客に対してひとつのProductとして組み合わされて取引される場合でも、裏のトレーダーにとってはプットとコールの別々のContractの集合としてばらばらに扱った方がよいという考え方です。この考え方は、FX取引のOCOやIF-DONEのような複合注文を扱う場合や、金融以外でも商品をセット販売するような場合には実際多くのシステムで幅広く応用できる考え方であると思います。このパターンを知らないと明細を独立したエンティティクラスとして抽出する発想に至ることがなかなか困難なのではと思います。
私も最初は本書の内容や本当のよさがなかなか理解できず、半端な理解のまま長いこと本棚に放置していたのですが、最近になって再度読み返してみると、あのシステムではこういう設計にしておけばよかったと反省される箇所が多くあり、あらためて本当によい本だと感心させられます。とくにJPAなどの技術によりPOJOを使ってO/Rマッピングが気軽に使えるようになった今こそ、再度読み直してみるべき価値のある本だと思います。上流から下流までユーザー(ドメイン専門家)やビジネスアナリシスト、プログラマーが共通のドメインモデルに従って会話できるようになるのが私の理想で、そういうことがいつかしたいのであえてJava EE開発などという泥臭い開発の世界で仕事を続けているのですが、今のところ、なかなかそういうファウラーのような仕事ができるチャンスは少ないですね。

*1:同一銘柄(instrument)に対して同額の売り(プット)と買い(コール)のオプションを同時に購入する取引

日本と欧米ではPOJOの意義に対して微妙な解釈の違いがあるような気がする

EJB2.1など、開発すべきクラスインターフェースに大きな制約のある侵略的なフレームワークに対してマーティン・ファウラーが広めた概念としてPOJO(Plain Old Java Object)という用語があることは、現在Java開発者であれば、周知のことかと思います。私は当時はEJBなど重量フレームワークの使用を推奨する立場の会社にいたので、POJOという言葉を知ったのは意外に遅く、2004年ごろエンタープライズ アプリケーションアーキテクチャパターン (Object Oriented SELECTION)などの書籍を通して初めて知りました。POJOという言葉には少なくとも以下の2つの意味がこめられていると考えています。

前者はPOJOのPlainの部分に主に関係するところですが、後者のOld Java Objectという部分はファウラーのようなベテランのオブジェクト指向プログラマーSmalltalkやSwingのJavaアプリなどで普通に使ってきたオブジェクト指向プログラミングのテクニックを、Java EEの世界でも普通に使いたいという渇望のようなものを感じます。
そこで、最近ちょっと思うのですが、わが国のJava EEプログラマーの間では、以上のPOJOの特性のうち、前者の要素が強調され過ぎる傾向にあるのではないでしょうか?確かに形の上ではgetter、setterのみ定義した構造体のようなクラスもPOJOと呼んでもよいかもしれませんが、意味のあるロジックをカプセル化しないという意味では本来オブジェクトと呼ぶのはおかしいです。もちろん、Domain Modelの設計はプログラマーに相当のスキルが必要で、外国でもTransaction Scriptパターンのような設計をされることは多いようであり、ファウラー自身もそうした設計をhttp://capsctrl.que.jp/kdmsnr/wiki/bliki/?AnemicDomainModelと揶揄していますが、日本ではプログラマーのスキルをあまり重視しない文化からか、オブジェクト指向が本来必要なところでも採用されていないところがほとんどではないのかと思います。その結果Seasar2など優れたDIコンテナが開発されながら、JSFJPAといったオブジェクト指向的なフレームワークと組み合わせて使われることはほとんどはなく、代わりにStrutsやJ2DAO、iBatisのようなTransaction Scriptと相性のよいフレームワークが使われることが多いようです。その上、開発の簡易化・軽量化という側面が強調される一方で、深いドメインモデルの設計というPOJOの本来目指すべき上流的な設計の観点が軽んじられていると感じます。(私は海外で働いたことがないので実際はわからないのですが、書籍の多さや、インターネットの情報からは海外ではJPAなどのO/Rマッピングフレームワークは割合的にもっと使われているように感じています。)
このような背景には、やはり日本固有の多重下請け構造とか上流と下流をきっちり分けてウォーターフォールで開発するといった手法が関係しているのでしょうか?確かに、Domain Modelパターンを使ってDDDで深いドメインモデルを設計するにはプログラマーが直接顧客(ドメイン専門家)と対話しながらモデルを深めていくというような開発スタイルをとらないとやはり現実問題としては厳しいと思いますので。ファウラー自身の本でもはっきりどちらが優れていると書かれているわけでなく、Transaction ScriptとDomain Modelは扱うシステムの特性に応じて使い分けるべきということは当然ですが、本来Domain Modelを使いたいようなケースでも商習慣や政治的理由から手続き型の設計を利用せざるを得ないというのはプログラマーとしては非常に残念に思います。私は個人的には製造業の部品表管理や金融のデリバティブ商品のリスク管理などDDDが適する分野の開発が多かったので特にそう思うのかもしれませんが、上流でDB設計と画面設計を固めて後のフェーズでロジックだけゴリゴリJavaのコーディングという流れでは、やはり本当の意味でオブジェクト指向の開発を実践することは難しいと思います。
結局、POJO時代になって何が違うかというと、侵略的なフレームワークによって以前は抑制されていたプログラマー本来の設計スキルを最大限に発揮できるようになったということが最重要であると思います。私はPOJOだから初心者にも理解できるようになったという発想は本質を正しく捉えていないと考えます。これはRubyなどより自由度の高い軽量言語が外国で流行ってきているという事実でも同じことが言えると思います。(RubyではJava以上にプログラマーのスキルの差による生産性の違いが大きいですから。)OSSで世界中の達人プログラマーが有用なフレームワークやツールを無償提供してくれた結果、プログラマー本来のスキルをいかんなく発揮できる環境が着々と整ってきているという事実に気づくことが重要だと思います。そういうことで、世間ではオフショア化によって日本人のプログラマーは不要になるという極端な意見もあるようですが、私は逆に今後はこうした新しい環境を理解して、上手に使いこなせるような上級プログラマーの需要は逆に増えて、いろいろな案件で引っ張りだこになるのではないかと期待しています。そして、生産性の高いやり方が浸透するにしたがって、時間とともに生産性の極端に低い、プログラマーのスキルがまったく活かされない馬鹿げた作業環境(派遣PG時代の思い出 - Togetter)は自然と淘汰されていくものと信じたいです。

プログラミングと設計は本来切り離せないものなのでは

最近はアーキテクトという役割で客先に常駐し、フレームワークの選定をしたり、事前に共通部品を設計したりする役割を担う仕事を引き受けることが結構あります。そこで運よくお客様のマネージャーがオブジェクト指向開発の経験が十分にある方だと、IDEなどの開発環境やインターネット接続環境を当然のように用意してくれるので最初から仕事がスムーズにできるのですが、そうでないとMS Officeしか入っていないロースペックのノートPCを渡されて、要件定義フェーズの期間中、フレームワークの設計をお願いしますとか、私としてはちょっと首をかしげてしまうような困ったことを言われてしまう場合があります。開発フェーズが始まる半年後まではコーディングは基本的に不要という考え方です。アプリケーションのアーキテクトという役割では少なくともコーディング規約を考えたり、ツールやフレームワークの選定をしたりする必要がありますし、プロジェクト全体をウォーターフォールで進めたいのであれば、なお一層のこと事前検証の意味で、アーキテクトがコーディング作業も含めてアプリケーションの開発方法やパターンを明確化しておくことが重要なはずなのですが。
そのPMにそのことを話したら「コーディングが好きな人もいますが、いきなりコーディングできるようなプログラムはたいした思慮が入っていない設計であるからあまり信頼できないし、じっくり時間をかけて事前設計してください」と言われてしまいました。また、そういう人は作業の手戻りということを極端に気にしますから、要件定義できていないのにコードを書いて後から捨てるというのはもったいないと考える傾向が強いです。(なぜか、1年とか長い時間をかけてExcelの表とかUMLの図などの大量の分析資料を量産することは無駄なコストとは考えない。)そういう人の存在を老害だと一言で片付る議論もあるようですが(SI業界の老害が若手と下請けを蝕む理由 - yvsu pron. yas)、30代の若手のマネージャーでもそういう発想をする人はたくさんいるし、50代のベテランエンジニアでコーディングの重要性を理解してくれる人も世の中にはいるので、必ずしも年齢は関係ないと思います。運悪くそういう環境で働くことになったら、「変化の触媒たれ」という達人プログラマーの心得でもって徐々に時間をかけて考え方を変革していってもらうよう努めています。多くの場合その人がプログラミングという行為を設計と結びつけて考えられないのは、単にその人の経験不足、知識不足ということが多く、リファクタリングなどでいかに無駄なコーディングが減らせるか、生産性が向上するかということを実演して見せれば簡単に現代的な開発におけるコーディングと設計のつながりを正しく理解してもらえるようになることも多いと思います。
現在のようなオブジェクト指向の開発環境が一般化する前の言語では、データ構造を設計し、それに対する処理の流れを設計してしまえばよかったですし、いきなりアセンブリCOBOLでコードを書き出さなくても、そういった設計は事前に設計図上で時間をかけて検討するということは可能であり、コンパイルに膨大な手間と時間がかかっていた時代であれば理にかなっている行為であったと思います。しかし、少なくとも現代的な開発環境上でJavaなどのオブジェクト指向言語を使って開発することを考えた場合、それらの伝統的な設計の他に

  • インターフェースの設計
  • アノテーション(注釈)などのコード中のメタデータの使い方の検討
  • パッケージなどのモジュール分割
  • 適切な数のレイヤーの分割
  • デザインパターンの適用
  • ジェネリクス(総称型)などの型の設計
  • jarファイル分割などの物理的なモジュールの設計
  • eclipseなどのプロジェクト分割
  • mavenやant+ivyを使ったビルドシステム構築
  • 単体試験方式の確立
  • OSSライブラリーなどの依存関係の調査
  • 通化可能なアスペクトの設計

などなど、IDEを起動してあらかじめサンプルを作りながら検証しないと本質が理解できない要素があまりにも多く存在します。Javaのプログラムは、単純にifやforループの集まりとして捉えることはできないということです。実際、Seamなどの便利なフレームワークを活用すれば、型変換なども含めて大部分はロジックを書かなくても宣言的に再利用できてしまいますし、アーキテクチャーの設計といった場合、個別のロジックに絡まない以上のような要素の設計の方がむしろ重要になってきます。これらはUMLなどを使ってある程度コーディングなしで設計できる部分はあるとは言え、アノテーションなどの言語固有の設計要素や開発ツールのくせを考慮した実装方式は実際にコーディングして慎重に検証しながら考える以外に効率的に設計することは難しいです。このような要素をあらかじめ開発フェーズまでに明確にしておく、つまり、生産性の高いプログラミングモデルを決めておくということは、経験上開発プロジェクトの成功の上に欠かせない作業項目であると考えます。まずはコード上でじっくり設計を考えた後で、説明資料として後から必要に応じて要点をUMLで文書化するという流れの方が作業手順としてしっくり来ることが私の経験上ほとんどです。コードこそが設計の本質をもっとも正確かつ簡潔に表現できる手段なのであり、UMLはそのある側面を捉えやすくする方便としての一表現に過ぎないなどと言うと怒られてしまうでしょうか?(間違えないでいただきたいですが、EAとかSOAなどの粒度のアーキテクチャーではなくて、単一のアプリケーションのアーキテクチャーを設計することをここでは念頭に置いています。もちろん、プログラミングモデルの検討以外に、セキュリティや性能、保守性などアーキテクトとして検討すべきことは他にも山ほど存在するという前提で。)
あと、複雑な業務領域のシステムでは、DDD(Domain-Driven Design: Tackling Complexity in the Heart of Software)を使ったドメインモデリングが有効ですが、JPAなど採用するデータアクセスフレームワークの特性に応じて設計のフィージビリティーを確認するには、早期にエンティティクラスを作成しながらモデルを洗練させることが有効です。また、JSFなど複雑なプレゼンテーションフレームワークを利用するなら、あらかじめ画面紙芝居を開発して、そのフレームワークで画面遷移などが簡単に実現できることを実際に検証しながら画面設計をするべきです。
コーディングなどは単価の低いプログラマーの仕事であり、アーキテクトにやらせるのはもったいないなどと考えて、開発フェーズまでコーディングしないなどというやり方をしていては、後々設計の足りていない箇所がたくさん見つかり、結局個々のプログラマーが場当たり的に設計しだすのでアーキテクチャーは余計に混乱することになると思います。アジャイル開発を採用せず、ウォーターフォールで開発するのであれば、なお一層のことアーキテクトチームや事前開発チームのような体制を作って、要件定義と並行して早期にプログラミングをしながら設計を固めるというのが大事だと思います。(RUPの推敲フェーズのようなものを取り入れるべき)
さらに、付け加えるとこのような事前開発は、技術リスクの軽減効果だけでなく、開発メンバーのスキルアップという教育面での効果も高いです。事前開発を通してツールの使い方やフレームワークの使い方をそのプロジェクトの文脈で学ぶことができるのですから非常に効果的な教育ができます。
SEとPG、どっちが頭がいい?(2):下流から見たIT業界:エンジニアライフでは、「PGもSEも頭が空っぽ」と結論していますが、多くのプロジェクトでは残念ながらそのとおりだと認めざるを得ないと思います。面倒だけれど根気さえあれば誰でもできるようなExcelの項目一覧表や画面定義書の作成に終始しているSEがいる一方で、規約に従ってそれをそのままコードに落とす(しかない)PGがいるということで。Excel表がその場合上流と下流の間の契約というかインターフェースを決めているのですが、そのせいでSEもPGもその存在が足かせとなってCOBOLやVB5時代の設計手法しか使えず、特にオブジェクト指向技術を使った開発効率や再利用性、保守性の向上をまったくといっていい程達成できないようになっていると思います。せいぜい可能なのはExcelの達人になってマクロを思いっきり工夫するとか、SQLのチューニングの名人になるとか、そういった分野でしか技術力を生かす余地がないのです。
元請と下請をコーディング有り無しの観点から上流・下流と分けるのは、Java EEや.NETのようなオブジェクト指向を前提とした開発環境ではどう考えても絶対に不適切だと思います。アウトソースするとしても、コアドメインと非コアドメインなど業務領域で分けるなどの工夫ができないものでしょうか。たとえば、金融に特化した会社であれば、トレーディングなどコア部分の開発はコーディングを含めて自社開発し、汎用のパッケージの流用部分とか画面周りや認証などの一般的な知識があれば開発できる領域は外部の専門の会社にアウトソースする(オフショアを含む)などが本来はできてしかるべきだと思います。
ゼネコン体質など日本のIT業界固有の商習慣から難しいところもあるかとは思いますが、要件定義フェーズ中に一切プログラミングしないという厳格なウォーターフォールを採用しているプロジェクトでは、この点是非なんとか改善してもらいたいです。
このエントリーをはてなブックマークに追加

コボラーに一日でSeamを理解してもらう

以前、VB6しかやったことのない人に2週間でSeamをマスターさせる!?という記事を書いたのですが、本日担当していた講師の仕事が無事終わりました。
実態としてはもともとの想定をこえる講師としてかなり困難な仕事でした。受講生の人数は3人と少なかったのは幸いでしたが、経験・スキルは主にCOBOLと一部PL/SQLのバッチ系が中心ということでVB6やWebなどオープン系、画面系の開発は業務上ほとんど開発経験がないとのことでした。まだVB6だとJSFの画面部品ベースの開発モデルやイベントドリブンという点で似ているところもあるのですが、COBOLですと同じプログラムといっても相当違いますから。そもそも手続き指向のプログラミングに慣れている方は、mainから処理の流れを追いかけようとしてしまう傾向があるため、オブジェクト指向だとあちこちのクラスに処理が分散してしまうというところがまず理解の敷居を高くしているようです。また、COBOLにしてもPL/SQLにしても基本的に静的なデータ構造を扱う言語であり、ヒープやスタックなどを使うC言語Pascalとも発想が大分異なります。また、SeamJPAでは付き物のコンテキストはMapなどの動的なデータ構造のイメージがないとやはり理解しにくいと思います。
基本的なJavaの文法を3日半で学習してもらってから最後の一日でSeamをやるというシナリオだったのですが、どこまで理解していただけたでしょうか?前提知識として、

などから教える必要があったため、教えられる側も相当忙しく大変だったと思います。
ただ、基本的なサンプルを中心に、EL式を使ったバインディングや、画面遷移の記述方法、さまざまなスコープのコンテキストという話を説明し、実際にプログラムを動かしながら理解してもらうというやり方は有効でした。特にホットデプロイにより、細かい修正を行いながら演習してもらえるのはSeamのメリットであったと思います。
ただ、Seamは学習の敷居が高く、ホスト系のプログラマーの再教育のための最初のフレームワークとしてはやはり最適でないとは感じました。多少泥臭くでもStrutsなどから入った方が良かったかもしれなかったです。また、Seamなどでオブジェクト指向開発を成功させるには、経験豊富なプログラマー(アーキテクト)がプロジェクトに参画し、プログラミングモデルを規約としてある程度決めていくことが不可欠であると思います。