ビジネスロジック実装進化論
2010年10月27日佐藤 匡剛
http://ameblo.jp/ouobpo
An Evolution of Business Logic Implementation
• 仕事- Software AG株式会社グローバルコンサルタンシーサービスwebMethodsコンサルタント
- 書籍の執筆/翻訳など
• Web- ブログ: http://ameblo.jp/ouobpo
- Twitter: tadayosi
• 趣味- Kindleで読書- 日本ベジタリアン協会会員
佐藤 匡剛(さとう ただよし)
http://www.flickr.com/photos/robertnyman/189691155/
『プログラミングScala』年明け発売!
日本語版
Domain Modelパターンは難しい?
http://www.martinfowler.com/eaaCatalog/domainModel.html
Domain Modelパターンは...
•実在する•超人的なマジックではない•ビジネスロジック実装の試行錯誤の中で自然に辿り着く道である
プログラマ黎明期
http://www.flickr.com/photos/nickhubbard/2878833485/
#!/usr/bin/env perl
use strict;use CGI::Carp qw(fatalsToBrowser);require ‘util.pl’
my %FORM = util::read_form('POST', 'utf8');
# ビジネスロジック?...
print "Content-type: text/html\n\n";print<<HTML_END;<html><head> <title>注文確認</title></head><body> ...</body></html>HTML_END
Perl/CGI
order.pl
DB
ファイル
ビジネスロジック
HTML
データアクセス
public class OrderServlet extends HttpServlet { protected void service( HttpServletRequest request, HttpServletResponse response) { processOrder(request, response); request .getRequestDispatcher( “/order/confirm.jsp”) .forward(request, response); } private void processOrder( HttpServletRequest request, HttpServletResponse response) {
// ビジネスロジック? ... } ...
Servlet/JSP
OrderServlet DB
XML
ビジネスロジック
データアクセス
/order/confirm.jsp
HTML
レイヤアーキテクチャの発見
http://www.flickr.com/photos/bloggingbookshelf/5084749109/
ドメイン層 データアクセス層プレゼン層
Transaction Script
DB
アクション
アクション
アクション
アクション
サービス(ユースケースA)
サービス(ユースケースB)
サービス(ユースケースC)
サービス(ユースケースD)
DAO
DAO
DAO
public class ProcessOrderServiceImpl implements IProcessOrderService {
private IOrderDao fOrderDao; private ICustomerDao fCustomerDao;
public List<OrderBean> findOrders( CustomerBean customer) { ... }
public void confirmOrder( OrderBean order, CustomerBean customer) { ... }
public void cancelOrder( OrderBean order, CustomerBean customer) { ... } ...
Transaction Script
• プレゼン、ビジネスロジック、データアクセスの各層は分離される
• ビジネスロジックはユースケース単位で構成される
× ビジネスロジックが複雑になると、コード重複の制御が難しくなる
Table Moduleドメイン層 データアクセス層プレゼン層
DB
アクション
アクション
アクション
アクション
サービス(ユースケースA)
サービス(ユースケースB)
サービス(ユースケースC)
サービス(ユースケースD)
DAO
DAO
DAO
ロジック(テーブルX)
ロジック(テーブルY)
ロジック(テーブルZ)
public class ProcessOrderServiceImpl implements IProcessOrderService {
private IOrderLogic fOrderLogic; private ICustomerLogic fCustomerLogic;
public List<OrderBean> findOrders( CustomerBean customer) { return fOrderLogic.findByCustomer(customer); }
public void confirmOrder( OrderBean order, CustomerBean customer) { fOrderLogic.confirm(order, customer); }
public void cancelOrder( OrderBean order, CustomerBean customer) { fOrderLogic.cancel(order, customer); } ...
public class OrderLogicImpl implements IOrderLogic {
private IOrderDao fOrderDao; private ICustomerLogic fCustomerLogic;
public List<OrderBean> findByCustomer( CustomerBean customer) { return fOrderDao. findByCustomerId(customer.getId()); }
public void confirm( OrderBean order, CustomerBean customer) { ... }
public void cancel( OrderBean order, CustomerBean customer) { ... } ...
Table Module
• プレゼン、ビジネスロジック、データアクセスの各層は分離される
• ビジネスロジックはさらに2層に分かれる
- Service Layer = ユースケース単位
- ドメインロジック = DBテーブル単位
• 実用レベルでは問題ないが、コードにムダが多く美しくない
キャズムを超える
http://www.flickr.com/photos/matheus_momesso/4469788827/
総称関数(CLOS)
;;; クラス定義(defclass order () ((number :accessor order-number ...)))(defmethod confirm ((self order)) (... (order-number self)))
;;; 実行コード(setq o (make-instance ‘order :number 12345))(confirm o)
confirm(order);
order.confirm();
総称関数 → オブジェクト
class OrderLogic { static void confirm( OrderBean order, CustomerBean customer) { order.getOrderNo(); ...
OrderLogic .confirm(order, customer);
class Order { String orderNo; void confirm( Customer customer) { this.orderNo; ...
order.confirm(customer);
Table Module Domain Model
Domain Modelドメイン層 データアクセス層プレゼン層
DB
アクション
アクション
アクション
アクション
サービス(ユースケースA)
サービス(ユースケースB)
サービス(ユースケースC)
サービス(ユースケースD)
ORM
ORM
ORM
ドメインオブジェクト
ドメインオブジェクト
ドメインオブジェクト
public class ProcessOrderServiceImpl implements IProcessOrderService {
private IOrderRepository fOrderRepository; private ICustomerRepository fCustomerRepository;
public List<Order> findOrders( Customer customer) { return fOrderRepository.findBy(customer); }
public void confirmOrder(Order order) { order.confirm(); }
public void cancelOrder(Order order) { order.cancel(); } ...
public class Order {
private Customer fCustomer;
public void confirm() { ... }
public void process() { ... }
public void cancel() { ... } ...
Domain Modelのメリット
•再利用性、メンテナンス性が高くなる•ロジックの置き場に悩まない•複雑なビジネスロジックをモデルによって可視化できる
•コードの字面がシンプルになり、美しい
まとめ
•コードの重複排除を追究すると、自然とTable Moduleまで辿り着く
•Table Moduleが総称関数によるOOの実装と気づけば、Domain Modelへの道が拓ける
最後に
“Architecture teams must not siphon off all the best and brightest.”
アーキテクチャチームに最も優秀なメンバを集めてはいけない。
— Eric Evans, Domain-Driven Design
テクノロジからドメインへ
• テクノロジの活用に忙殺されていないだろうか?
- 顧客に価値をもたらすのはインフラやフレームワークではない
• ビジネスに真の力を与えるのは、ドメイン=ビジネスロジック
http://www.flickr.com/photos/wwworks/2222523486/
ドメインを戦い抜くための武器
•オブジェクト指向分析/設計の基礎
•GRASPパターン- 情報エキスパート- 高凝集- 低結合
•必要なのはDIコンテナ、ORM、RIA、NoSQLなどの知識ではない!
ドメインで皆さんの力を発揮しよう!
ありがとうございました!