前回までの記事
「構造が見える」ってこういうことかもしれない
朝。
カフェの窓際。師匠と若手は、ノートPCの画面を一緒に覗き込んでいた。
師匠:「お。見えるようになってきたじゃないか。
構造が外から読める。そういう設計になってきたな」
若手:「……ありがとうございます。
少しずつですけど、自分でも整理できてる感覚あります」
師匠はコーヒーを飲み干し、立ち上がった。
師匠:「じゃ、今日からは一人でやってみな。
構造ってのは、“人に伝えようとする”ときに磨かれるもんなんだよ」
少し歩き出してから、振り返ることなく、ぽつりと続けた。
師匠:「……まあ、まだ一つ、大事なことが抜けてるけどな。
それは、自分で気づいたときに一番響くんだよ」
若手はその言葉の意味が、すぐには分からなかった。
でも、「なにかがまだ残っている」――その余韻だけが、静かに胸に残っていた。
ノートPCの画面を開く。
昨日まで緊張していたコードが、今日は違って見えた。
入力、判断、出力――自然と“役割の位置”が目に入る。
若手:「……これ、もしかして“読める設計”ってやつか?
コードって、こんなに静かに読めるものだったんだ……」
一歩前に進んだ実感と、
まだ見えていない“何か”があるという予感。
その両方を抱えながら、
若手はコードに向き合いはじめた。
人に説明できたことで、設計の手応えを感じる
チームのコードレビュー。
若手は自分の書いたコードを、チームメンバーに説明していた。
若手:「ここが入力で……ここが状態を変える処理で……で、これが表示ですね」
その説明を聞いたメンバーは、すぐにうなずいた。
メンバー:「あー、なるほど。役割で分かれてるから、わかりやすいですね」
レビュー後、若手はふと、
**「今までよりもずっと説明しやすくなっている」**ことに気づいた。
若手:「……言葉にするのが簡単になってる。
これが“読める設計”ってことなのか……?」
しばらく画面を見つめる。
役割ごとにコードが分かれ、見通しがよくなったのはたしかだ。
だがそのとき――
師匠の言葉が、頭の中に浮かぶ。
「……まあ、まだひとつ、大事なことが抜けてるけどな」
そのとき若手の目が、再び App.tsx の中を走る。
若手:「今、やってるのは“機能の分離”。でも“構造の並び”はまだ……」
その違和感が、次の気づきへの扉を開こうとしていた──
構造は“横にも縦にも見える形”でなければ伝わらない
若手は、App.tsx を開いて見返していた。
責任は分けた。UIも外に出した。状態も useReducer にまとめた。
けれど、どこかまだ「見えない」気がしていた。
若手:「……責任は分かれてる。けど、まだ“流れ”が伝わらない気がする」
画面を上下にスクロールしながら、入力や状態の定義を探しては戻る。
そのとき、ふと気づいた。
若手:「……前のコード、“入力の下に変換”が来てた。
つまり、“構造が縦にズレてた”んだ」
「でも本来、“入力・変換・出力”って、
“横に分けて並ぶべき責任”だったはず……」
若手は一度、理想の構造を紙に書き出してみた。
const App = () => {
const [text, setText] = useInputText(); // 🔵 入力
const [todos, handleAdd] = useTodoLogic(text); // 🟢 変換
return renderView(text, handleAdd, todos); // 🟣 出力
};
若手:「これだと、意味だけが縦に並ぶ。構造は見やすい……けど。
この形、現場で受け入れてもらえるかは……ちょっと怪しいな」
そこで若手は、UI構造(出力)だけ別に逃しつつ、App.tsxに責任を縦に残す形に整理しなおした。
import { useState, useReducer } from 'react';
import OutputView from './OutputView';
import { todoReducer } from './todoReducer';
const App = () => {
// 🔵 入力:テキスト入力の状態
const [text, setText] = useState('');
// 🟢 変換(判断):Todoリストの状態管理
const [todos, dispatch] = useReducer(todoReducer, []);
// 入力値に基づき「追加してよいか」を判断し、状態を変化させる
const handleAdd = () => {
if (text.trim() === '') return; // 🔸 判断:空白は追加しない
dispatch({ type: 'add', text }); // 🔸 状態の変化(追加処理)
setText(''); // 🔸 入力リセット
};
// 🟣 出力:UI構造(責任をOutputViewに委譲)
return (
<OutputView
text={text} // 🔵 入力:ユーザーが入力中のテキスト
onTextChange={setText} // 🔵 入力:テキスト変更イベント
onAdd={handleAdd} // 🟢 変換:追加処理の指示
todos={todos} // 🟣 出力:表示するTodoリスト
/>
);
};
export default App;
※この構造は「ひと目で構造が見えること」を重視した構成です。
通常のReactの書き方より少し分解していますが、“責任を明確に分ける”設計を意識しています。
あくまで一例ですが、構造化設計(STS設計)に基づく視点として参考にしていただければと思います。
若手:「よし。意味の流れも保ちつつ、“Reactらしさ”も残せた気がする」
その両方のコードを、師匠にメールで送った。
そしてすぐに電話をかける。
若手:「……構造をAppの直下に役割・責任としてで並べてみました。今度は、ひと目で“どこで何をしてるか”見えると思います」
師匠の声は、どこか嬉しそうだった。
師匠:「前のコード、たしかに責任は分かれてた。でもな、
“入力の下に変換”じゃ、読んだ人に流れが伝わらないんだよ」**
構造ってのはな、“責任を分ける”だけじゃ足りない。
“横に意味を分けて、縦に読みやすく配置する”。それでやっと意味が見えるんだよ」
若手は、ようやく実感した。
“見える構造”とは、責任が「横にも分かれて」いて、
その流れが「縦にも読める形」になっていて初めて伝わるものなのだ、と。
設計は、人に伝えるためにある
若手は、自分で整理したコードをあらためて見直していた。
入力 → 変換 → 出力
それぞれが明確に責任を持ち
App.tsx の中で“縦に流れる構造”になっている
そのとき、ふと気づいた。
若手:「……この構造、テストもしやすい……」
UIとロジックが切り離されているから、ロジックだけを対象にテストできる。
UIは props を通して確認するだけでいい。
若手:「責任を分けたことで、読めるし、直しやすいし、テストもしやすい……。
なんだ、設計って、“全部つながってた”んだ……」
師匠の言葉が思い出される。
師匠:「設計ってのは、“人に伝える形”にすることなんだよ。
コードは動いている。でも、それだけじゃ足りないんだよ」
若手はようやく実感した。
動くコードを作ることと、伝わる設計にすることは違う。
設計とは、自分だけでなく“誰か”のために整えることだった。
目の前のコードは、まっすぐ縦に流れていた。
その構造を自分の力で整えたことが、なによりの自信になっていた。
若手:「やっと、“設計できた”って言える気がする」
── これが、若手が “伝わる設計”に出会った最初の物語 だった。
だがそれは、設計の“初歩の入口”にすぎなかったと、
若手が気づくのはもう少し先のこと──
そして若手は、次に控えている新しい機能追加で、
この構造が“どれほど変化に強いか”を体感することになる──
次回の記事予告
ここまでお読みいただき、ありがとうございました。
本記事では、AIを使って開発を進める中で直面した「設計不在」の怖さと、それを乗り越えるために必要な“伝わる設計”の視点について紹介しました。
次回は、師匠から教わった設計の基本――「STS設計(入力・変換・出力)」というシンプルで強力な考え方を軸に、実際にReactアプリの構造を改善していくプロセスを紹介します。
もし、AIの出力をそのまま使ってコードが混乱してきた方、自分の設計に不安を感じている方には、きっと役立つ内容になるはずです。ぜひご期待ください!
また、今回紹介した内容をより実践的に学びたい方には、以下のUdemy講座もおすすめです。
Udemyコース(8,800円 → クーポンで割引中)
▶️ AIとC#で極める!クリーンコードの技法(限定クーポン付き)
- C#でクリーンコードと設計力を身につける実践講座
- ChatGPTの活用方法や、伝わるコードの考え方を解説
出版書籍『あきらめない者たち』
▶️ Amazonで見る
- 技術の基礎からやり直すために、なぜ一歩勇気を振り絞れたのかのノンフィクション作品です。