2日目のゴールと今日やること
2日目のテーマは
「画面(UI)とロジック(ドメイン)をつなぐ“アプリの流れ”を設計すること」です。
昨日は
User / Auth / Customer / CustomerRepository / Permission
という“役割ベースのクラス設計”を学びました。
今日はそこに、
- ログイン画面の流れ
- 一覧 → 詳細 → 編集の画面遷移
- 権限による UI の出し分け(擬似)
を組み合わせて、
「業務アプリらしい動き」を設計できるようにします。
まだ本格的な DOM コードは書きません。
今日は “画面の流れをクラスでどう表現するか” に集中します。
画面遷移を「Controller の責務」として扱う
画面遷移は“画面の仕事”ではなく“アプリの仕事”
初心者がやりがちな構造はこうです。
ログイン画面の JS がログイン処理を持つ
一覧画面の JS が一覧処理を持つ
詳細画面の JS が詳細処理を持つ
これだと、画面ごとにロジックが散らばり、
「どこで何が起きているか」が分からなくなります。
業務アプリでは、
画面遷移は Controller が一元管理する
という設計が圧倒的に保守しやすいです。
AppController を作って“アプリ全体の流れ”を管理する
AppController の役割を言葉で定義する
AppController は、
「どの画面を表示するか」
「どの操作を許可するか」
「どのデータを渡すか」
を決める司令塔です。
コードのイメージはこうなります。
class AppController {
#auth;
#customerRepo;
constructor() {
this.#auth = new Auth();
this.#customerRepo = new CustomerRepository();
}
start() {
this.showLogin();
}
showLogin() {
console.log("=== ログイン画面 ===");
// UI にログインフォームを表示する想定
}
showList() {
console.log("=== 一覧画面 ===");
const user = this.#auth.getCurrentUser();
if (!Permission.canViewList(user)) {
console.log("権限がありません");
return;
}
const list = this.#customerRepo.findAll();
list.forEach(c => console.log(c.getId(), c.getName()));
}
showDetail(id) {
console.log("=== 詳細画面 ===");
const user = this.#auth.getCurrentUser();
if (!Permission.canViewDetail(user)) {
console.log("権限がありません");
return;
}
const customer = this.#customerRepo.findById(id);
console.log(customer.getName(), customer.getEmail());
}
showEdit(id) {
console.log("=== 編集画面 ===");
const user = this.#auth.getCurrentUser();
if (!Permission.canEdit(user)) {
console.log("編集権限がありません");
return;
}
const customer = this.#customerRepo.findById(id);
console.log("編集対象:", customer.getName());
}
}
JavaScriptここでの重要ポイントは、
画面遷移の判断(showLogin → showList → showDetail)は
AppController に集約されている
ということです。
ログイン画面の流れを“状態遷移”として考える
ログイン成功 → 一覧へ
ログイン失敗 → ログイン画面に留まる
この流れをコードで表すとこうなります。
class AppController {
// 省略
attemptLogin(userId, password) {
const ok = this.#auth.login(userId, password);
if (ok) {
this.showList();
} else {
console.log("ログイン失敗");
this.showLogin();
}
}
}
JavaScriptここでの設計ポイントは、
ログインの判定は Auth の責務
ログイン後にどこへ遷移するかは AppController の責務
という分離ができていることです。
一覧 → 詳細 → 編集の流れを“Controller の判断”でつなぐ
一覧画面で「詳細を見る」ボタンが押されたら?
AppController がこう動きます。
onClickDetail(id) {
this.showDetail(id);
}
JavaScript詳細画面で「編集する」ボタンが押されたら?
onClickEdit(id) {
this.showEdit(id);
}
JavaScript編集画面で「保存」ボタンが押されたら?
saveCustomer(id, newName, newEmail) {
const user = this.#auth.getCurrentUser();
if (!Permission.canEdit(user)) {
console.log("編集権限がありません");
return;
}
const customer = this.#customerRepo.findById(id);
customer.setName(newName);
customer.setEmail(newEmail);
this.#customerRepo.save(customer);
this.showDetail(id);
}
JavaScriptここでの責務分離はこうです。
編集していいか判断する → Permission
編集内容を反映する → Customer
保存する → CustomerRepository
どこへ遷移するか決める → AppController
1つの処理に複数の責任を混ぜない
という設計ができています。
権限制御を“UI と Controller の両方で”行う理由
UI だけで制御すると危険
例えば、
「一般ユーザーには編集ボタンを表示しない」
という UI 制御だけだと、
悪意あるユーザーが直接 URL を叩けば編集画面に入れてしまいます。
Controller 側でも必ずチェックする
だから、AppController の showEdit には
必ず Permission.canEdit が入っています。
if (!Permission.canEdit(user)) {
console.log("編集権限がありません");
return;
}
JavaScriptUI で隠すのは「親切」
Controller で止めるのは「安全」
この2段構えが、
実務アプリでは必須です。
2日目のまとめ:画面遷移は“Controller の責務”
今日の本質はこれです。
「画面の流れは Controller が決める。
画面は Controller の指示に従うだけ。」
これができると、
画面の見た目を変えてもロジックが壊れない
権限ルールを変えても画面を直さなくていい
データの保存方法を変えても画面を直さなくていい
という“保守性の高いアプリ”になります。
次のステップ(3日目)でやること
3日目では、
今日作った AppController の流れを
実際の DOM(HTML)とつなげて動く画面にしていきます。
ログインフォーム
一覧のテーブル
詳細の表示
編集フォーム
これらを Controller と連携させて、
「業務アプリらしい UI の動き」を作っていきます。
設計がしっかりしているので、
UI を作るのが驚くほど楽になりますよ。


