複雑さと戦う : ソースコードの破綻の兆候

ソフトウェアの開発が進む中で、あらたにドメイン(問題領域)の知識が発見され、ソースコードに追加する。ひとつひとつはちょっとした変更。 その結果...

・メソッドが長くなる
・条件記述( if 文 ) が複雑になる
・クラスが巨大になる(変数やメソッドの増加)
・メソッドの引数が増える

マーチンファウラーの リファクタリング や、ジョシュア・ケリーエブスキーの パターン指向リファクタリング入門 で、コードの「いやな臭い」とされている現象ですね。

この現象は、さまざまなドメインの知識をソフトウェアに盛り込んだ結果として、評価はできる。単純なソフトウェアから、問題領域の知識を増やし、もっと役に立つソフトウェアに洗練しようとした結果だから。

ソースコードとしては、分かりにくく、扱いにくくなり、大問題。
内容が理解できない、ひとつの変更の副作用があちこちで発生する。それ以上の改良(変更)は、だんだん現実的ではなくなる。

メソッドが長くなりはじめ、条件記述が複雑になりはじめ、クラスが大きくなりはじめ、メソッドの引数が増え始めたら、迷わずリファクタリングをしましょう。

開発を何日もストップするわけではありません。
日々の開発の作業で、ソースコードのインデントの調整や、空白行を入れて読みやすくするのと同じ感覚で、ちょこちょこやる。それがリファクタリングの基本だと思います。
しかも、最近はIDEが、リファクタリングをサポートしてくれるので、リファクタリングはずいぶん簡単に安全にできるようになった。

実践 Domain-Driven Design  ドメインモデルを実装する

ドメインモデルは、例えば、UML でクラス図で表現する。

実際に動くソフトウェアにするためにモデルを実体に変換しなければいけない。

・メモリ上に実現するために、Java とか C# とかで記述する。
・ハードディスク上に実現するために、 SQL を使う。
・画面上に実現するために、 例えば、 XHTML + CSS 。
・通信ライン上に実現するために、例えば、XML を使う。

のように、それぞれの装置用の言語で、マッピングが必要になる。

O-R マッピング, O-X マッピング, Http リクエストとオブジェクトのバインド、オブジェクトの Http レスポンスへのレンダリング。

Spring をはじめ、いろいろなフレームワークがでてきて、ここらへんのマッピング作業は、コードを書く必要がどんどん減ってきている。

Ruby on Rails は、モデルを設計してデータベースに実装すれば、他の領域とのマッピングは、自動でやってくれる。

開発全体の中で、ドメインモデルを開発により多くの時間・エネルギーを使えるようになってきた。

問題領域を深く理解し、そこから、良いドメインモデルを創ることができれば、その問題領域の利用者にとって、より使いやすい、より役に立つソフトウェアを提供できるはず。

それがソフトウェアが開発者の使命であり、やりがい。

Eric Evans も "Domain-Driven Design" (「ドメイン駆動設計」) の中で、良い開発者とは、顧客の問題領域を理解することに情熱と喜びを持つ人、という記述があった気がする。

ドメインロジックの実装方法

こんなスライドが公開されてますね。
参考になります。

ドメインロジックの実装方法とドメイン駆動設計Ouobpo佐藤 匡剛
JUGEMテーマ:インターネット



iBatis 1+N 関連の SELECT

JUGEMテーマ:インターネット

1+N関連のテーブル、例えば、受注ヘッダーと明細とかの SELECT を iBatis で実現する方法。

1+NのSELECT は、O-Rマッピングの大きな問題の一つです。
単純な解決策として、親レコードを取得する SELECT 文と各親レコードごとに子レコードを取得する SELECT 文を定義して、1+N回、SELECT 文を実行する方法があります。

iBatis でもこの nest したSELECT 文の実行が、基本的な方法とされています。

しかし、この方法は、取得するレコードが多いと、性能面で深刻な問題が発生します。複数のSQL文を繰り返し実行することは、いかに高速なネットワークでも非効率。(データベースアクセスの通信プロトコルは複雑なので、単純なデータ転送に比べ100倍は遅い。)

また、私の環境では、この 1+N SELECT 時の親レコード取得時に、SELECT FOR UPDATE 文が発行され、ロックがかかる、という問題が発生し、大きな問題になりました。
最初は、Spring の宣言トランザクション管理の記述ミスかと思い、格闘しましたが、実は、iBatis 側の機能でした。

論理的には、正しい処理です。親レコード取得時と子レコード取得時には、同じ状態を保障するためには、排他制御(ロック)が必要です。

しかし、実践的には、これは、厳密すぎて、性能面で問題がおきます。

この解決策として、iBatis では、1+N 関連のテーブルを JOIN で、一回の SQL 文で取得する方法が提供されています。

ResultMap に "groupBy キーカラム" を宣言しておくと、 iBatis は、 指定されたカラムをキーにした、1+N 関連のオブジェクト構造に自動的にマッピングしてくれます。
( SQLの GROUP BY 句とは別の、iBatis 定義ファイル中のキーワードです。)

これだと、SQLの実行は一回だし、排他制御も不要なので、とても効率的。
iBatis の開発者ガイドには、この groupBy が、どんな時でも最善の方法とは、限らない、という記述があります。
しかし、私は、groupBy ではなく、 nested ResultMap を使うべきケースは思いつきませんでした。

開発者ガイドに書いてある以上、groupBy 宣言にも、なにか問題があるんだと思うので、ちょっと不安はありますが、今のところ、groupBy 宣言で、 join したSQL文を実行する方法で、うまくいっています。

1+N 関連は、 ORマッピングの弱点だといわれているようですが、iBatis の groupBy 宣言を使えば、オブジェクト側(Java)もDB側(SQL)も、自然に記述でき、あとは iBatis が面倒を見てくれるので、問題はとても簡単になります。

iBatis を採用している理由は、データベース側は、テーブル設計も、SQL文も、データベースとして自然に設計したかったからです。
フレームワークの仕組みや特徴のために、テーブル設計に制約がでるのは本末転倒。
また、SQL文をフレームワークに隠蔽するより、テキストとして明示的に記述する iBatis は、保守性の点で有利だと考えています。

データベースの設計や、SQL文は、開発者から隠すべきではない、と思うんですよね。

Spring iBatis で O/R マッピング

Java で、データベースアクセスをする基本手段は、 JDBC API。
このレベルで、ゴリゴリコーディングするのは、たいへんだし、保守性も悪い。

で、Spring の登場。

まず、 JDBC サポート。 

JdbcTemplate クラスを使うと、コネクション処理などパターン化された処理を、簡単に記述できる。

あと、ResultSet の内容を、オブジェクトやオブジェクトのコレクションにマッピングすることも、パターン化されたやり方で、エレガントにコーディングできる。

SQL 例外も、ベンダーの依存性をなくして、抽象化したり、ランタイム例外にして、上位のプログラムでは、例外処理を記述不要にしたり、なかなか便利。

とは、いっても、やはり Java のプログラムをゴリゴリ書く、というイメージは残るやり方。

で、登場するのが、 Spring の iBatis サポート。

ResultSet とオブジェクトのマッピングや、検索パラメータを保持したオブジェクトから、SQL文にパラメータを埋め込んだり、動的にSQL文を生成する方法を、すべて、XMLファイルで記述する。

Spring と iBatis を使えば、データベースアクセスについて、プログラミングは極端に少なくなる。 
JDBC API でゴリゴリ書いた人なら誰でも感じる「同じパターンの繰り返し」を、なくせる。
Java プログラムに埋め込まれた SQL文の断片より、XML ファイルに宣言した SQL のほうが、書きやすいし、保守も格段に楽ができる。

最初に使うと、なんでこんなに簡単にできるの?という、ちょっとマジックでも見せられた気分。

とはいっても、現実のデータベースアクセスに使うとなると、もちろん習得するべきことは多いし、最初はなかなかたいへん。

この時、結局、役にたつのは、基礎知識です。

つまり、

レベル1: JDBC API を理解し、使い込んだ経験
レベル2: Spring JDBC サポートが提供する利便性とその仕組み
レベル3: Spring iBatis サポートが提供するさらなる利便性

というように、まずは、ネイティブの JDBC API をきちんと理解すること。
次に、いきなり、 iBatis にいかないで、 Spring の JDBC サポートを理解する。
(もちろん、前提として、 Spring のコアテクノロジーの ApplicationContext の基礎は理解する)

急がば回れです。

少なくとも、私の経験では、iBatis のサンプル、ドキュメントと格闘するより、Spring の JDBC サポート を最初に理解してしまうのが、 iBatis 理解の近道でした。

calendar
     12
3456789
10111213141516
17181920212223
24252627282930
31      
<< March 2024 >>
システム設計日記を検索
プロフィール
リンク
システム開発日記(実装編)
有限会社 システム設計
twitter @masuda220
selected entries
recent comment
recent trackback
categories
archives
others
mobile
qrcode
powered
無料ブログ作成サービス JUGEM