7日目のゴール
7日目のテーマは
「1クラス1役割を“自分の言葉で説明できるレベル”まで落とし込むこと」 です。
ここまで6日間で、あなたはすでにかなりのことを体に入れています。
クラスを役割ごとに分ける
依存の向きを意識する(上→下)
境界線を引いて“他人の仕事”を奪わない
未来の変更を想像して保守性を評価する
役割をインターフェースとして切り出す
7日目は、それらを
「なんとなく分かる」から「言語化できる」へ
一段引き上げる日です。
これまで作ってきた構造を“設計の目”で言い直す
ファイル保存アプリを、あえて言葉だけで説明してみる
あなたのファイル保存アプリは、今こういう設計になっています。
メモという“意味のあるデータ”を表す Memo がいる。
メモをどこかに永続化する“役割”を表す MemoStore インターフェースがある。
その役割の具体的な実装として、ファイル版の FileMemoStore がある。
保存先パスなどの環境依存の情報をまとめる AppConfig がある。
ユーザーと会話し、アプリの流れを制御する MemoApp がいる。
依存の向きはこうです。
MemoApp → MemoStore(役割)
MemoApp → Memo
FileMemoStore → Memo
FileMemoStore → ファイルシステム(Path, Files など)
AppConfig → ファイルシステム
逆方向の依存はありません。
これを一言でまとめると、
「UI は永続化の“役割”だけを知り、
永続化の実装は UI を知らない」
という設計になっています。
これ、かなり“現場で通用する”構造です。
責務を自分の言葉でラベル付けしてみる
Memo:意味の世界の代表
Memo の責務を、あえて一文で書くとこうなります。
「Memo は、1件のメモ(ID・日付・本文)という“意味のあるデータ”を表すだけのクラスであり、
保存方法や表示方法には一切関与しない。」
ここで大事なのは、
ファイル形式を知らない
保存先を知らない
UI を知らない
という“知らないことの強さ”です。
知らないからこそ、
保存方法が変わっても、UI が変わっても、
Memo はそのまま生き残れます。
これが責務の純度の高さです。
MemoStore:役割そのものの契約
MemoStore の責務はこう言えます。
「MemoStore は、“メモを永続化する人”が必ず提供すべき操作(保存・取得・削除・更新)を定義する契約であり、
具体的な保存方法(ファイル・DB・メモリなど)には立ち入らない。」
ここでのポイントは、
「何をできるべきか」だけを定義している
「どうやるか」は一切書いていない
ということです。
役割をインターフェースとして切り出す、というのは
「できることの一覧だけを先に決める」
という行為でもあります。
FileMemoStore:役割の“具体的な職人”
FileMemoStore の責務はこう言えます。
「FileMemoStore は、MemoStore という役割を“テキストファイルで実現する職人”であり、
ファイルパス・保存形式・文字コード・一時ファイルでの再構築など、
永続化の具体的な手段を一手に引き受ける。」
ここで重要なのは、
MemoApp(UI)を知らない
画面表示をしない
ユーザー入力を扱わない
という線引きが守られていることです。
「自分の仕事に集中しているクラス」 は、
読んでいて気持ちがいいし、壊れにくい。
MemoApp:司会者としての責務
MemoApp の責務はこう言えます。
「MemoApp は、ユーザーとの対話とアプリ全体の流れを制御する司会者であり、
永続化の詳細は MemoStore に委ね、
メモというデータの意味は Memo に委ねる。」
ここでのポイントは、
自分では保存しない
自分ではファイルを触らない
自分では ID を決めない
という“やらないこと”の多さです。
司会者は、
「誰に何を頼むか」を決めるのが仕事であって、
自分で全部やるのが仕事ではありません。
分離が生む“差し替え可能性”をもう一度感じる
実装を差し替えても、App を変えないという贅沢
インターフェースを導入したことで、
こういうことができるようになりました。
本番環境では FileMemoStore を使う。
テスト環境では InMemoryMemoStore を使う。
将来、DbMemoStore を追加しても、App はそのまま。
コードで書くと、こういう世界です。
// 本番
MemoStore store = new FileMemoStore(memoPath);
// テスト
MemoStore store = new InMemoryMemoStore();
// 将来
MemoStore store = new DbMemoStore(dataSource);
Javaどの場合も、
MemoApp の中身は一切変えません。
store.save(memo)store.findAll()store.deleteById(id)
といった呼び出しは、
「役割に対する依頼」 だからです。
この「差し替え可能性」こそが、
分離とインターフェースがもたらす保守性の本質です。
保守性を“自分の設計ポリシー”として言葉にする
あなたの中にある OOP の軸を、あえて文章にしてみる
7日目でやってほしい一番大事なことは、
「自分の設計ポリシーを言葉にする」 ことです。
例えば、こんな感じで書けたら最高です。
自分は、アプリを設計するとき、
まず「意味のあるデータ(ドメイン)」を表すクラスを作る。
そのデータをどこかに保存する必要があるときは、
具体的な保存方法に入る前に「役割(インターフェース)」を決める。
UI は具体的な保存クラスではなく、その役割に依存させる。
保存方法を変えたくなったときに、UI を一切触らなくて済むようにする。
クラスには「このクラスは何をする人か」という一文を付けられるようにし、
その一文からはみ出す仕事をさせないようにする。
これ、もう立派な
「あなたの OOP 設計ポリシー」 です。
教科書に書いてある一般論ではなく、
ファイル保存アプリを通して
あなた自身が体で感じたことから出てきた言葉です。
7日目の小さな仕上げ:コードに“設計の意図”を刻む
コメントで未来の自分にメッセージを書く
最後の仕上げとして、
各クラスの先頭に、
あなたの言葉で「役割コメント」を書いてみてください。
例えば MemoStore なら、こう。
/**
* Memo を永続化するための役割を表すインターフェース。
* 保存方法(ファイル・DB・メモリなど)には依存せず、
* App はこのインターフェースだけを相手にすることで、実装の差し替えを容易にする。
*/
public interface MemoStore {
...
}
JavaFileMemoStore なら、こう。
/**
* MemoStore のファイル実装。
* テキストファイルに 1行1レコードで Memo を保存する。
* ファイル形式や一時ファイルでの再構築など、永続化の詳細はこのクラスに閉じ込める。
*/
public class FileMemoStore implements MemoStore {
...
}
JavaMemoApp なら、こう。
/**
* ユーザーと対話し、メモの追加・一覧・削除・編集の流れを制御するクラス。
* 永続化の詳細は MemoStore に委ねることで、UI と保存方法を分離する。
*/
public class MemoApp {
...
}
Javaこういうコメントを書けるようになっている時点で、
あなたはもう
「なんとなく OOP を使う人」ではなく、
「設計の意図を持って OOP を使う人」 です。
7日目で本当に伝えたいこと
1クラス1役割は、
単なる“お作法”ではありません。
それは、
このクラスは何を担当するのか
このクラスは誰を知っていていいのか
このクラスは何を知らないままでいるべきか
この役割はインターフェースとして切り出すべきか
将来、何を変えたくなりそうか
そういう問いに、
自分なりの答えを持とうとする姿勢そのもの です。
ここまで7日間、
あなたはずっと「動けばいい」ではなく
「どう設計するか」を考え続けてきました。
それはもう、
立派に“中級者の入り口”を超えています。
あとは、この感覚を
別のアプリ(ToDo、家計簿、日記、ゲーム…)にも
どんどん持ち込んでみてください。
書くコードすべてが、
「あなたの設計ポリシーが通ったコード」
になっていきます。

