組織駆動設計という考え方
システムとは、作業を体系化し、適切に組み合わせることで効率化することを意味します。人々は、自分たちの作業をシステム化するために組織を作り、適切な作業分担をすることで効率化を図ってきました。
コンピューターシステムとは、人間が行っていた作業をプログラミングすることによりコンピューターに行わせることです。人の作業をコンピューターに置き換えることにより、たしかに格段に効率化が進みました。しかし、これはコンピュータの計算速度やミスをしないという特性によって効率化されただけで、作業の内容自体は人間の模倣にすぎません。
つまり、プログラミングはコンピューターの中に組織や人、作業を再現するものであると言えます。このことから、プログラミングを組織作りと考えることで、顧客から末端のプログラマーまでが同じイメージを共有できるようになると考えます。
この考えのもとコーディングする方法を組織駆動設計と名付けました。
サンプルコードは、コードの形状に集中してもらうため英語の翻訳に余計な認知を使われないように日本語を多用しています。
Javaの基礎から組織化してみます
まずは、Javaの入門で行うようなコードを組織化してみたいと思います。
一番単純な組織
店員が挨拶をするだけ、これが最小組織です。
class 店員 {
void 挨拶() {
System.out.println("いらっしゃいませ");
}
}
publicは命令許諾
店長はA君を呼んで挨拶をさせています。
A君は店員なので、挨拶を命令されることを許諾しています。
public class 店長{
public void 挨拶しろ(){
店員 A君 = new 店員();
A君.挨拶();
}
}
public class 店員 {
public void 挨拶() {
System.out.println("いらっしゃいませ");
}
}
privateは保護
A君は店長に挨拶を命令された後、店長を呼び出して売り上げを改ざんさせようとしました。
しかし、売り上げは保護されているため変更することができませんでした。
public class 店長{
private int 売上;
public void 挨拶しろ(){
店員 A君 = new 店員();
A君.挨拶();
A君.売上改ざん(this);
}
}
public class 店員 {
public void 挨拶() {
System.out.println("いらっしゃいませ");
}
public void 売上改ざん(店長 B店長){
// B店長.売上 = 100; エラー!!
}
}
extends は役職(一つしかもてない)
本店長(本部の店長)が出店名簿に店長を任命していますが、店長という役職を持っていない店員は任命することができませんでした。
public abstract class 店長職{}
public class 本店長{
private ArrayList<店長職> 出店名簿 = new ArrayList<店長職>();
private void 支店長の任命() {
出店名簿.add(new 支店長("東京支店"));
出店名簿.add(new 支店長("静岡支店"));
//出店名簿.add(new 店員("群馬支店")); エラー!!
}
}
class 支店長 extends 店長職{
String 担当店舗名;
public 支店長(String 店舗名){
担当店舗名 = 店舗名;
}
}
public class 店員 {
public void 挨拶() {
System.out.println("いらっしゃいませ");
}
}
finalは変更不可
店舗名は出店名簿の登録の際に決定したら誰も変更できない
public abstract class 店長職{}
public class 支店長 extends 店長職{
private final String 担当店舗名;
public 支店長(String 店舗名){
担当店舗名 = 店舗名;
}
public やっぱり店名変更(){
// 担当店舗名 = 担当店舗名 + "DX"; エラー!!
}
}
抽象メソッドは責務
店長は売り上げを報告する義務がある
public abstract class 店長職{
public abstract int 売上報告する();
}
public class 本店長{
private ArrayList<店長職> 出店名簿 = new ArrayList<店長職>();
private void 支店長の任命() {
出店名簿.add(new 支店長("東京支店"));
出店名簿.add(new 支店長("静岡支店"));
}
private int 売上集計() {
出店名簿.stream().mapToInt( 店 -> 店.売上報告 ).sum();
}
}
public class 支店長 extends 店長職{
private int 売上;
private final String 店舗名;
public 支店長(String 店舗名){
担当店舗名 = 店舗名
}
@override
public int 売上報告する() {
return 売上;
}
}
public class 店員 {
public void 挨拶() {
System.out.println("いらっしゃいませ");
}
}
staticと非static
本店長は1人しか存在しないのでstatic
出店名簿も1つしか存在しないのでstatic
支店長は任命された人数だけ存在するので非static
public abstract class 店長職{
public abstract int 売上報告する();
}
public static class 本店長{
private static ArrayList<店長職> 出店名簿 = new ArrayList<店長職>();
private static void 支店長の任命() {
出店名簿.add(new 支店長("東京支店"));
出店名簿.add(new 支店長("静岡支店"));
}
private static int 売上集計() {
出店名簿.stream().mapToInt( 店 -> 店.売上報告 ).sum();
}
}
public class 支店長 extends 店長職{
private int 売上;
private final String 店舗名;
public 支店長(String 店舗名){
担当店舗名 = 店舗名
}
@override
public int 売上報告する() {
return 売上;
}
}
抽象クラスは権限を与える
ハイクラス支店長は発言できるが、支店長はもっていないのでできない。
発言する権限があると同時に、発言する義務も発生している。
abstract class 発言権がある人 {
public abstract String 発言する();
}
public abstract class 店長職{
public abstract int 売上報告する();
}
public static class 本店長{
private static ArrayList<String> メモ = new ArrayList<String>();
private static ArrayList<店長職> 出店名簿 = new ArrayList<店長職>();
private static void 支店長の任命() {
出店名簿.add(new 支店長("東京支店"));
出店名簿.add(new 支店長("静岡支店"));
}
private static int 売上集計() {
出店名簿.stream().mapToInt( 店 -> 店.売上報告 ).sum();
}
public static void 意見を聞く(発言権がある人 人){
メモ.add(人.発言する());
}
}
public class ハイクラス支店長 extends 店長職 implements 発言権がある人{
private int 売上;
private final String 店舗名;
public 支店長(String 店舗名){
担当店舗名 = 店舗名;
}
public void 意見を言いに行く(){
本店長.意見を聞く(this);
}
@override
public int 売上報告する() {
return 売上;
}
}
public class 支店長 extends 店長職{
private int 売上;
private final String 店舗名;
public 支店長(String 店舗名){
担当店舗名 = 店舗名;
}
public void 意見を言いに行く(){
//本店長.意見を聞く(this); エラー!!
}
@override
public int 売上報告する() {
return 売上;
}
}
もう少し現実に近づける
次は、実際に作りそうなシステムにしてみます。
システム概要
仕様1.電話で注文を受けて入力した在庫を確認する。
仕様2.一日の終わりに在庫を確認して報告をする。
外部の人間
入力とは、外部の人(キーボード)が受け取った入力をシステムに報告しています。
出力とは、システムが外部の人(ディスプレイ)に報告しています。
DB参照とは、外部の人が台帳(データベース)を参照して報告しています。
受付
外部の人が教えてくれた内容を記録しています。
class 受付 {
private int 商品名;
private int 本数;
public int 電話の結果を聞く(){
商品名 = 外部の人.商品名確認();
本数 = 外部の人.発注数確認();
}
}
在庫
受付が在庫を確認しています。
在庫台帳
商品名 | 在庫数 |
---|---|
コーラ | 10 |
サイダー | 20 |
class 受付 {
private int 商品名;
private int 本数;
public int 電話の結果を聞く(){
商品名 = 外部の人.商品名確認();
本数 = 外部の人.発注数確認();
}
public int 在庫を聞く(){
return 外部の人.在庫台帳の確認(商品名);
}
}
在庫報告
サイダーの本数を報告しています。
在庫台帳
商品名 | 在庫数 |
---|---|
コーラ | 10 |
サイダー | 20 |
class 報告者{
public void サイダー在庫を報告(){
int サイダー在庫数 = 外部の人.在庫台帳の確認("サイダー");
外部の人.サイダー在庫数の報告(サイダー在庫数);
}
}
在庫管理者
外部の人は、組織外のため制御しにくい。なりべく一人が対応してほかの人は組織内と対応したほうがいいです。
在庫台帳
商品名 | 在庫数 |
---|---|
コーラ | 10 |
サイダー | 20 |
class 在庫管理者{
public static int 在庫を確認(String 商品名){
return 外部の人.在庫伝票の確認(商品名);
}
}
class 受付 {
private int 商品名;
private int 本数;
public int 電話の結果を聞く(){
商品名 = 外部の人.商品名確認();
本数 = 外部の人.発注数確認();
}
public int 在庫を聞く(){
return 在庫管理者.在庫を確認(商品名);
}
}
class 報告者{
public void サイダー在庫を報告(){
int サイダー在庫数 = 在庫管理者.在庫を確認("サイダー");
外部の人.サイダー在庫数の報告(サイダー在庫数);
}
}
組織駆動設計はすべての原則やデザインパターンを再現できるはず
今後も、この方法を使って様々な原則やデザインパターンなどの設計論を説明していけたらと思っています。