概要そのものをプログラムに落としてみる

例えば、以下の業務を考える。この業務をシステムに落とす場合、どうする?

営業部門は顧客から受け付けた注文書を元に、生産部門へ出荷指示書を発行し、生産部門は顧客へ指示通りに商品を出荷する。

「注文書にはどういう内容があるのか?商品、数量、納期、発送先…。」「指示書に記載された商品が納期までに出荷できない場合はどうするのか?」とか色々詰めなきゃいけないことは思い付くだろう。というか、俺は色々心配になるwww

けど、上の文章には上の文章以上のことは書かれていない(当たり前だけど)。上の文章に書かれていることは以下のことしかない。

  • 顧客は営業部門へ、注文書を送る
  • 営業部門は生産部門へ、注文書に対応した出荷指示書を送る
  • 生産部門は顧客へ、出荷指示書に対応した商品を出荷する

「AはBにCを送る」は「オブジェクトAはオブジェクトBにメッセージCを送る」と考えると、

  • オブジェクト「顧客」はオブジェクト「営業部門」にメッセージ「注文書」を送る
  • オブジェクト「営業部門」はオブジェクト「生産部門」へ、メッセージ「注文書」に対応するメッセージ「出荷指示書」を送る
  • オブジェクト「生産部門」は対応する「顧客」へ、メッセージ「出荷指示書」に対応するオブジェクト「商品」を送る

言い換えてみる。

  • オブジェクト「営業部門」は、オブジェクト「顧客」からメッセージ「注文書」を受けることができる
    • オブジェクト「営業部門」は、「注文書」を受け付けたら、対応するメッセージ「出荷指示書」を生成し、オブジェクト「生産部門」へ送る
  • オブジェクト「生産部門」は、オブジェクト「営業部門」からメッセージ「出荷指示書」を受け付けることができる
    • オブジェクト「生産部門」は、「出荷指示書」を受け付けたら、対応するオブジェクト「商品」を生成し、オブジェクト「顧客」へ送る

さて、こう解釈したら取りあえずプログラムに落とせない?

プログラムへ落とす

落としてみました。日本語クラスとか内部クラスとか使ってるけど、取りあえず動きます。動かせ!!

public class 業務ストーリー {
    final 顧客 _顧客 = new 顧客();
    final 営業部門 _営業部門 = new 営業部門();
    final 生産部門 _生産部門 = new 生産部門();
    
    void ストーリー() {
        _顧客.注文する();
    }
    
    public static void main(String[] args) {
        new 業務ストーリー().ストーリー();  //prints "商品が届いた!"
    }
    
    class 顧客 {
        void 注文する() {
            _営業部門.顧客からの注文書を受け付ける(_顧客, new 注文書());
        }
        
        void 商品を受け取る(商品 _商品) {
            System.out.println("商品が届いた!");
        }
    }

    class 営業部門 {
        void 顧客からの注文書を受け付ける(顧客 _顧客, 注文書 _注文書) {
            出荷指示書 _出荷指示書 = new 出荷指示書(_顧客, _注文書);
            生産部門へ出荷指示書を送る(_出荷指示書);
        }
        
        private void 生産部門へ出荷指示書を送る(出荷指示書 _出荷指示書) {
            _生産部門.営業部門からの出荷指示書を受け付ける(_出荷指示書);
        }
    }

    class 生産部門 {
        void 営業部門からの出荷指示書を受け付ける (出荷指示書 _出荷指示書) {
            商品 _商品 = new 商品(_出荷指示書);
            顧客へ商品を送る(_出荷指示書._顧客, _商品);
        }
        
        private void 顧客へ商品を送る(顧客 _顧客, 商品 _商品) {
            _顧客.商品を受け取る(_商品);
        }
    }

    class 注文書 {
    }
    
    class 出荷指示書 {
        顧客 _顧客;
        出荷指示書(顧客 _顧客, 注文書 _注文書) {this._顧客 = _顧客;}
    }
    
    class 商品 {
        商品(出荷指示書 _出荷指示書) {}
    }
}

考察

営業部門が受け付けるのは注文書そのものだし、生産部門が受け付けるのは出荷指示書そのもの。「注文パラメータbean」ではない。「○○書」と書くと業務要件的に帳票をイメージするけど、帳票は物理的な実装にすぎず、概念的にはメッセージそのものとして扱うことができそう。「注文書」のPDFによるシリアライズが「注文書帳票」みたいなイメージなんだけど、伝わります?

生産部門の「new 商品」部分も、例えば受注生産なら「工場」で同時にさまざまな商品を生産してるかもしれない。その場合は並列化したり、「工場で生産する」というモデルを導入して、生産部門の「営業部門からの出荷指示書を受け付ける」というモデルが修正されるとか…。

営業部門の「生産部門へ出荷指示書を送る」部分は営業部門内の作業なのでprivateなメソッドとしてみた。生産部門の「顧客へ商品を送る」も同様。これは今後のパッケージ構成やクラス設計の影響で変更されるかも知れないし、きっちり作りこめばprivateなままで良いかもしれない。よくわからない。けど、概念的には部門に対してprivateなわけで、何らかの方法で実現できる方向を目指してみても面白いかもしれない。

この後の打ち合わせでシステム化の範囲が「出荷指示書のPDFを生産部門にメールで送信する」までと決まったとすると、営業部門の「生産部門へ出荷指示書を送る」の内容を修正すればいい。その場合、クラス「生産部門」は使うだろうけど、生産部門の先のクラス「工場」はそのシステムから可視ではないので、作成する必要はない。あっても邪魔にはならないだろうけど。

あと、とりあえず「出荷指示書には顧客を持つ」とした。コレだけは先のストーリーにはなかった表現だけど、生産部門は誰に送るかわからないと送りようがないから、なんらかの方法で出荷指示書と顧客を結びつける必要があった。つまり、この部分が「追加ヒアリングが必須になる」部分だと考えられる。「どの顧客に送るかについて、出荷指示書に書かれているんですか?」みたいな。

もちろん、注文書や出荷指示書を永続的に扱いたいなら永続化するように仕込めばいい。営業部門が注文書を受け付けた時点でDAOに注文を渡すとか。もしくは「顧客が注文する」と「営業部門が注文書を受け付ける」の間とすると、AOPっぽい考え方が有効かもしれない。

んー、結構いけそうな気がしてきた。

これがビジネスロジックってやつなのか?