設計ツールとして扱う「抽象の梯子」の話
はじめに
- 設計がうまくできない
- 全体像がぼやける
- 局所的な対応ばかりになる
こうした悩みの背景には、「抽象化」の技術や姿勢が未整理なまま設計に向き合っていることがあります。
本記事では、設計の本質を理解する鍵となる概念「抽象の梯子(ladder of abstraction)」を中心に、設計思考の段階を見直し、知的飛躍を得るための視座を提供できればと思います。
想定読者
- 実務経験はあるが、設計時に「なぜその構造にしたのか」をうまく説明できないエンジニア
- MVCやRESTの基礎は理解しているが、要件から設計に落とし込む過程に迷いがあるエンジニア
- 設計レビューで「この責務は何?」と問われて困ったことがある方
- 設計パターンは知っていても、それをいつ使うべきかの判断に悩む方
「抽象の梯子」とは?
語源と背景
「抽象の梯子」という概念は、言語学者・政治家である S.I.ハヤカワの著書『思考と行動における言語(Language in Thought and Action, 1949)』で提唱されました。
ハヤカワは、人間の言語は抽象化のレベルを持ち現実の出来事から言葉を通して徐々に抽象度を高めていく構造をもっていると述べています。
"The word 'animal' is an abstraction from the word 'cow', which in turn is an abstraction from 'Bessie, the cow in the field'."
目の前の「ベッシー」という牛は、次第に「牛」→「動物」と言語上・認知上の階層を上がっていくということです。
抽象の梯子の図解
[高抽象度] 動物
↑
牛
↑
ベッシー(個別具体)
[低抽象度] 「あの牛が今食べている干し草」
このような抽象構造は、実務において問題を分類したり、設計の共通解を導くための基盤になります。
システム設計における抽象の梯子
システム設計においても「抽象の梯子」はとても重要な思考モデルかなと思います。
例えば、業務要件から最終的なコード(クラス、関数)へとブレイクダウンしていく過程そのものが、抽象度の段階を移動していく作業です。
システム設計での抽象の階層例
[高抽象度] 業務課題(会員の継続率を向上させたい)
↓
要件定義(会員ランク制度を導入)
↓
機能定義(月間の購入金額に応じてランク付け)
↓
モデル設計(User, Rank モデル)
↓
クラス実装(UserService@assignRank)
[低抽象度] 実行コード(rank_id を更新する SQL)
メタ的に考える
外山滋比古の著書『思考の整理学』では、「情報のメタ化」「メタレベルで考える」ことの重要性が繰り返し語られています。
これは単なる情報処理や整理術の話ではなく、“思考そのものを対象化し、俯瞰して眺める”という行為であり、現代的には「メタ認知(metacognition)」という概念と極めて親和性が高いものです。
メタ認知とは何か
メタ認知とは、「自分の認知(思考・判断・記憶・学習など)を認知すること」、つまり「自分が何をどう考えているか」を把握する能力を指します。教育心理学の世界では、学習の成否に大きく関わる要因として扱われています。
外山は『思考の整理学』の中で、次のように述べています:
「自分の頭の中を、もう一人の自分が上から見下ろして整理する。」
これはまさに、自分の思考活動に“メタレベル”で関与し、どのような視点・枠組みで考えているかを点検・修正する行為です。
プログラミングにおけるメタ認知の具体例
たとえば、あるエンジニアが「コントローラが肥大化してきたな」と感じるとき、これは単に視覚的にコードが長いというだけでなく、「本来の責務に照らして、適切かどうか?」という“視点の視点”を働かせています。これがメタ認知です。
あるいは、コードレビューで「この実装は仕様変更に弱い」という指摘を受けたとき「なぜ自分は変更可能性を考慮しなかったのか?」と内省することもメタ認知の働きです。
外山滋比古の思考モデルと抽象の梯子の関係
『思考の整理学』では、思考を「一次加工」と「二次加工」に分けています。
- 一次加工:情報をそのまま受け取る、記憶する、処理する
- 二次加工:情報の意味を再構成する、文脈の中で意味づける、他の情報と関連づける
これは抽象の梯子における“上へ登る”営みであり、サービス層の設計やパターン抽出などの活動がこれに該当します。
Laravelにおけるメタ認知の例
コード例:Controllerが膨らんできた場合
class ReportController extends Controller
{
public function generate(Request $request)
{
// ... ロジックがどんどん増えている
}
}
開発者の内省:
- 「このロジックはControllerの責務か?」
- 「将来、別の形式でレポートを出すとしたら再利用できるか?」
- 「
ReportService
などに移すべきか?」
リファクタ後
public function generate(Request $request, ReportService $reportService)
{
return $reportService->generateMonthlyReport($request->user());
}
この判断の背後には、どこにどのような関心事を置くべきかという認知フレームの点検があり、これはまさにメタ的な視点です。
自家薬籠中の術としてのメタ化
外山は、思考の技術とは自家薬籠中(じかやくろうちゅう)の術
であるべきだと語っています。
思考を外部のツールや誰かの指示に頼るのではなく、自分の内的な技術・感覚として持っていることが大切なのだそうです。
「情報を情報として扱うためには、情報から一歩退いて見つめる位置に立つことが必要である。」(外山滋比古)
この“退く”という姿勢が、抽象の梯子を登るために必要な視点のジャンプです。
具体と抽象を行き来する力
細谷功氏は著書『具体と抽象』の中でこう述べます:
「抽象とは共通項を取り出し、具体とは文脈に戻すことである」
設計における「パターン思考」と「インスタンス思考」は、まさにこの行き来に該当します。
-
パターン思考とは
- 複数の事例に共通する構造や仕組みを抽出し、それを設計に活かす思考法です。
- 例えば、オブジェクト指向におけるデザインパターンや、DDD(ドメイン駆動設計)で使われるアーキテクチャパターンなどが挙げられます。
- こうした思考は抽象化を通じて設計の再利用性や可読性を高め、長期的な保守性に寄与します。
-
インスタンス思考とは
- 特定の文脈や業務要件に強く依存した個別の設計・実装を行う思考です。
- これは目の前の課題を迅速に解決するのに適しており、現場での即応性や要件対応力を発揮します。
この2つの思考法に優劣はなく、状況に応じて行き来することが重要です。
抽象化しすぎて汎用的にしすぎると設計は使いづらくなり、逆に具体性ばかりだと再利用性がなくなってしまいます。
図解:
抽象化(共通化)
↓↑
具体化(文脈適用)
サービス層の設計と抽象の梯子
例えばサービス層(Service Layer)を導入する際、設計の抽象度を適切に保つことが重要です。
コントローラにロジックを書かれすぎて、様々な関心事が混在し保守が困難になった経験がある方も多いかもしれません。
サービス層の役割:抽象度を一段上げる
サービス層はユースケースを中心に抽象化された振る舞いを提供します。
例として、会員ランクを更新するユースケースを考えてみます。
コントローラーの責務(低抽象)
class UserController extends Controller
{
public function updateRank(Request $request, UserService $userService)
{
$userId = $request->input('user_id');
$userService->assignRank($userId);
return response()->json(['status' => 'ok']);
}
}
サービスの責務(中抽象)
class UserService
{
public function __construct(private UserRepository $userRepo, private RankEvaluator $evaluator) {}
public function assignRank(int $userId): void
{
$user = $this->userRepo->findById($userId);
$newRank = $this->evaluator->evaluate($user);
$user->rank_id = $newRank->id;
$user->save();
}
}
評価クラス(高抽象)
class RankEvaluator
{
public function evaluate(User $user): Rank
{
// 評価基準は将来的に差し替え可能な設計
return Rank::where('min_purchase', '<=', $user->monthly_total)
->orderByDesc('min_purchase')
->first();
}
}
このように、サービス層を挟むことで、コントローラでは「何をしたいか」に集中でき、サービスでは「どうやってそれを達成するか」を責務として分離できます。
抽象の梯子と責務
[高抽象度] 評価アルゴリズム(RankEvaluator)
↓
ユースケース処理(UserService)
↓
リクエスト処理・レスポンス生成(Controller)
[低抽象度] HTTP通信・Viewとのやり取り
この構造があれば例えば評価基準の変更、A/Bテストの導入もRankEvaluator
のみを差し替えることで実現できそうです。
まとめ
「抽象の梯子」は、設計力向上のための思考装置です。
- 抽象化によって共通化し、責務を整理する
- 抽象から具体へ適用していく際、実行可能な設計に落とす
- 設計レイヤーごとの役割と抽象度を意識することで、スパゲッティな構造を防ぐ
抽象的な構造(Service, Repository, UseCase)を自分の中で“言葉”として整理することで、設計書やコードの読み手への説得力もより増すかもしれません。
エンジニアリングは思考の連続です。具体と抽象を自在に行き来できる知性こそ、設計を支える柱になります。
参考文献
- S.I.ハヤカワ『思考と行動における言語 原書第四版』(岩波書店)
- 外山滋比古『思考の整理学』(ちくま文庫)
- 細谷功『具体と抽象』(dZERO)
- Martin Fowler『POEAA: Patterns of Enterprise Application Architecture』
Discussion