エンジニアの土台、抽象化思考を鍛える


※限定公開で社内向けに書いた記事を、少し編集して一般公開にしたものです。

エンジニアとして働いていく上で抽象化思考の能力はコミュニケーション能力と同じくらい重要な能力の１つだと考えています。ただ、「コミ力大事だよね」という話はいろんなところで聞きますが、「抽象化大事だよね」という話はあまり出てきません。

ということで、抽象化の重要性をもうちょっと広めたいなと思ったので、記事にまとめようと思います。

## 「具体と抽象」の概要

抽象化という概念の詳細は書籍「[具体と抽象](https://amzn.to/44BT3gL)」が入門書としておすすめです。

ここでは「具体と抽象」の内容を私なりにまとめて要点だけ説明します。

「抽象」は「具体」の対義語です。世間一般では、「具体的＝分かりやすい」「抽象的＝分かりにくい」というイメージがあるそうで、その結果「具体的＝良いこと」「抽象的＝悪いこと」のようなイメージがあるとのことです。しかし、抽象的な概念を扱うことは人間が生きていく上でとても重要であり、抽象化思考の重要性を再認識させることを目的とした書籍が「具体と抽象」です。

抽象化という言葉はいろんな意味合いが含まれますが、ざっくり言うと「異なる複数の事象から共通している部分を抜き出し、一般化して扱う」ことです。

人間にとって重要な抽象化の代表例が「数」と「言葉」です。

「リンゴが３個ある」「本が３冊ある」「犬が３匹いる」という、まったく別の事象に対して、これらをまとめて同じものとして扱うことで、数字の「３」という概念が成り立ちます。

言葉についても同様です。
「リンゴ」「みかん」「バナナ」などはそれぞれ別々の果物ですが、それらをまとめて「果物（フルーツ）」という言葉でまとめて扱うことで、コミュニケーションや知識の伝達を容易にすることができます。
さらに言うと、「リンゴ」という果物も現実世界に存在する１つ１つのリンゴはそれぞれ別々のものです。１人１人の人間が別人であるように、リンゴもモノが違えた形や色、味もそれぞれ少しずつ異なります。それら別々のものをまとめて「リンゴ」として扱うことで、言葉によるコミュニケーションが成り立るようになります。

つまり、抽象化とは異なる複数のものを「カテゴリ分け」して同じものとして扱うことだと言えます。

他には、数学や物理の「公式」や、世の中にある「法則」なども抽象化の産物です。数学や物理の公式は、個々の計算式から共通で使える部分を抽出し、変動しても良い部分を変数に置き換えたものです。計算を公式化することによって、どんな数値のパターンでも答えを導くことができるようになります。

具体と抽象の対比をまとめると以下のようになります。

|具体|抽象|
|:--:|:--:|
|直接目に見える|直接目に見えない|
|「実態」と直結|「実態」と乖離|
|１つ１つの個別対応|分類としてまとめて対応|
|解釈の自由度が低い|解釈の自由度が高い|
|応用が利かない|応用が利く|
|実務家の世界|学者の世界|

## 自動車の運転における抽象化の活用例

抽象化によって人間社会を便利にした例として、ここでは自動車の運転を取り上げます。
日本では自動車免許を取得すると車の運転ができるようになります。基本的には１度免許を取得してしまえば、どんな車種の車でも運転することができます。（厳密にはオートマ限定とか、重量による制限はありますが、ここではスルーします）

なぜ１つの免許を取ることで色んな種類の車を運転できるのかというと、車の運転における操作方法が抽象化（一般化）されているからです。車は基本的に「アクセルの踏み方」「ブレーキの踏み方」「ハンドルの回し方」などに慣れればある程度運転することができます。これらの操作方法は、車種によって大きく変わることはありません。車は種類や状態によって「加速のスムーズさ」「ブレーキの利き具合」「ハンドルの重さ」などに違いが出ます。
しかし、それらの違いを差し引いたとしても、車の運転は「だいたい同じ」とみなすことで、「免許を持っていればどの車種でも運転できる」ことにしています。

このように、厳密には違うものだけど「だいたい同じ」とみなしてカテゴリ分けすることで、様々なことを便利にしている例が人間社会の中に数多くあります。

## プログラミングにおける抽象化能力の必要性

ここでは抽象化という考え方がプログラミングに対してどのような影響を与えるかに触れます。

### 理解力への影響

私は数年プログラミング講師をしていたことがありますが、その時に抽象化能力の重要性を感じました。一般に、抽象化能力が低い受講生はプログラミングの理解へのスピードが遅く、逆に抽象化能力が高い受講生はプログラミングへの理解のスピードが速いです。

私が講師をしていた時はプログラミング言語としてJavaを教えていたので、Javaを例に説明します。

Javaでは、メソッドを呼び出す際に以下のようにして呼び出します。

```java
// メソッドの呼び出し
// 「オブジェクト」は「インスタンス」に置き換えても可
オブジェクト.メソッド名();
```

ここで、「入力された文字列から"a"を除いた文字列の長さを取得する」という処理を実現する場合、以下のように書くことができます。

```java
var str = "abcdefg"; // 入力された文字列の想定
var result = str.replaceAll("a", "").length();
```

こういう書き方をすると、
**「メソッドの呼び出しは`オブジェクト.メソッド名()`としか習ってない。こんな風に連続してメソッドを呼べるのは知らなかった」**
と主張する人がいます。これは、おそらく抽象化能力が低いことによる理解不足からくるものです。

このようなメソッドの呼び出し方に出会ったとき、抽象化能力の低い人は、
「メソッドの呼び出しは`オブジェクト.メソッド名()`だけでなく、`オブジェクト.メソッド名().メソッド名()`のように連続して呼び出すこともできる」
と、新たなルールを追加することで無理やり理解しようとします。

一方、抽象化能力の高い人は、
**「`replaceAll`メソッドの戻り値は文字列であり、文字列はオブジェクトである。ということは、`str.replaceAll("a", "")`の結果をオブジェクトとみなせるので`オブジェクト名.メソッド名()`のルールに合致している」**
と、既存のルールに当てはまるものだと気づきます。
`str.replaceAll("a", "")`の結果がオブジェクトになる、と気づけるのは、抽象化の思考が働いているからであると思われます。

このように、抽象化能力の低い人は、自分が理解できない書き方と出会ったときに新たなルールの追加によって無理やり理解しようとするのに対し、抽象化能力の高い人は、なぜこの書き方ができるのかを考え、本質を理解しようとします。

これは、実務におけるプログラミングでも似たようなことが言えます。
抽象化能力の低い人は、実装パターンの知識を増やして対応しようとするのに対し、抽象化能力の高い人は、自分の持っている基礎知識を抽象化して応用することで様々なパターンに対応しようとします。

計算に例えるなら、抽象化能力の高い人は、四則演算のルールと掛け算の九九だけを覚え、その組み合わせで複雑な計算を対応しようとするのに対し、抽象化能力の低い人は、「９９×９９」までを全部覚えて記憶による力業で問題を解こうとするようなイメージです。

プログラミングも、最初のうちは文法やその言語独特のお作法を覚えることが必要ですが、ある程度覚えてくれば後は抽象化によって応用していく能力の方が大事です。

新人研修で研修生に配布する書籍を「具体と抽象」にした方が良いんじゃないかと割と本気で思っています。

---

### 保守性の高いコードは抽象化能力なしには設計できない

コードは書く時間よりも読む時間の方が長いと言われており、可読性や保守性を意識したコードを書くことは大事です。ですが、そもそも保守性の高いコードを書くには、抽象化能力が必須です。

プログラミングでは共通で使える処理は関数として抽出します。共通で使えるデータ構造はクラスとして抽出します。再利用できるクラスや関数を増やすことは保守性を高めることにつながりますが、そもそも再利用可能かどうかを見極められるかはコードを書く際に抽象化して考えることができるかが大きく関わっています。

そもそも、オブジェクト指向の言語では、オブジェクトとクラスの関係がそのまま具体と抽象の関係性に当てはまります。オブジェクト指向プログラミングでは継承を使って差分プログラミングをしたり、インターフェースを使ってオブジェクト同士を疎結合にできますが、このような機能も正しく使いこなすには抽象化の観点が重要です。

また、オブジェクト指向ではデザインパターンと呼ばれる、よく利用される共通の設計パターンをカタログ化されたパターンがあります。デザインパターンは、様々なオブジェクト指向言語のソフトウェアでよく使われる設計手法をパターン化したもので、これはまさに抽象化です。デザインパターンを有効に使おうと思うと、クラス同士の構造を見抜く抽象化能力も必要になるでしょう。

そういった観点から、保守性の高いコードには抽象化能力が欠かせません。

---

### 他のプログラミング言語への転用

私が講師をしていた研修ではプログラミング言語としてJavaを教えていました。今でも、最初に学習するプログラミング言語としてJavaを教えている研修は多いかと思います。

なぜ最初のプログラミング言語としてJavaを教えることが多いのかというと、他言語への応用が利きやすいという理由が大きいかと思います。Javaは今でも多くの現場で利用されていますが、「最も使用されている言語」かと言われると、今の時代はそうでもないように思います。
ですが、一度Javaを深く学べば、そのほかの言語（例えば、PythonやRuby、PHPなど）を使用する場面があった際に、Javaで学習したプログラミングの知識が役立ちます。
プログラミング言語で最初にJavaを学習するには、いわばプログラミング言語の免許を取得しているようなもので、これができるようになれば、他の言語もだいたい同じ要領でプログラミングすることができます。

というのが、私が講師をしていた時の考えなのですが、実際の現場では仕事でJavaを使っていても、「PythonやRubyは使ったことがないからできない」という風に、一度も書いたことがない言語はできないと簡単に主張する場面もよく見ます。これは、私の感覚からすると「免許は持っているけどこの車種は乗ったことないから運転できない」と言っているようなもので、じゃあなぜJavaを学習したのだろう。と思ってしまいます。

---

### プログラミングを教える側の抽象化能力

講師としてプログラミングを教えていると、ソフトウェアの世界の概念を現実世界のものに例えて教えることがあります。例えば、メソッドが何か説明する際に、まずは「オブジェクトが持つ処理」とか「共通の処理をまとめたもの」のように簡潔な表現で伝えますが、プログラミング初心者にはそれだけだとイメージがしにくいので、例えを用いて説明したりします。

よくあるたとえの１つとして銀行のATMがあります。ATMは入金したり、引き出したりできますが、その際の入力や実際のお金、出力される明細などをメソッドの引数や戻り値に見立てて説明したりします。
あとは、ジュースを作る機械に例えたりもします。水や砂糖などの材料が引数になり、その結果出てくる完成系のジュースが戻り値のイメージ。

どのようなたとえ話が理解しやすいかは人によるので、プログラミングを教える側は現実世界で似ている概念のものを探し、様々なたとえ話で相手が理解できるように模索します。
このような、抽象的な概念を具体例に落とし込むのは、抽象と具体を行き来して考える能力が重要になります。

私の場合、講師歴が長くなるにつれて「教わる側が自分で具体例に落とし込めなければ意味がないのでは？」と思うようになり、たとえ話で教えることが年々減っていったのですが。。相手の理解度や性格などに合わせて、相手が理解しやすいであろう具体例に落とし込んで説明することも重要な講師スキルなのだろうと思います。

---

### Excelへの応用

[以前書いたExcelの記事](https://qiita.com/s-dash/items/5c70466ead3ca78ca72f)でも軽く触れましたが、Excelの資料作成とプログラミングは似ている点が多いと感じます。

セルを変数とみなすと、行や列は配列になり、表は２次元配列とみなせます。
Excelをそういう視点で見られるようになると、Excelでの資料作成はプログラミングに似ていると感じる部分が増え、プログラミングする際のテクニック（可読性の高いコードを書く方法論や、保守性の高いコードを書く方法論）がExcelの資料作成にも使える場面が出てきます。

このように、一見違う分野に見えるものでも、共通している部分を見出して同じものとして扱うことで、同じ法則を適用することができる（ここでは、プログラミングのテクニックをExcelに適用する）ようになり、少ない労力で効率よく作業を進められる場面が増えてきます。

---

### 長く使われる技術の見極め

以前、とあるカンファレンスに参加した際、T-WADAさんによる講演で技術に対する審美眼の話を聞きました。

T-WADAさん曰く、長く使われ続けている技術は、「全ては○○である」という抽象化がされているとのことです。

- UNIXで扱えるものはすべて「ファイル」である
- REST/WEBの世界ではすべてのリソースが「URL」で表現される
- RDBMS/SQLではすべては関係/集合で表すことができる

この抽象化により、他の技術との連携を容易にし、結果として長く使われる技術となっているそうです。長く使われる技術を作ろうと思うと、適度に抽象化されていることがきっと重要で、技術選定で長く使われる技術を選ぼうとするなら抽象化の視点を持つことが重要ということでしょう。

## 抽象化（一般化）による弊害

具体と抽象を行き来して考えることは視野を広げるのに役立ちますし、エンジニアの仕事でも抽象化思考は重要です。しかし、抽象化（一般化）には弊害もあるので、抽象化がマイナスに働く場面にも触れておきます。

---

### 一般化による決めつけ

日本人は人をカテゴリ分けして話すのが好きみたいです。
「男性は○○だ」「女性は○○だ」「A型の人は○○だ」「日本人は○○だ」「外国人は○○だ」「東京の人は○○だ」「沖縄の人は○○だ」という風に、性別や血液型、地域などでよく人をカテゴリ分けします。
確かに、「傾向としてこの地域の人はこういう特徴を持つ人が多い」のような統計はあるかもしれませんが、細かく見ていけば人は１人１人違う特徴を持っています。
このようなカテゴリ分けは話をシンプルにして分かりやすくしますが、視野を狭めたり、誤解が生じてコミュニケーションの障壁となってしまう場面もあるので、注意が必要です。

---

### 成功体験による認知バイアス

「仕事はこうやって進めるものだ」のような、仕事の進め方に対する一般化も多いと感じます。人は成功体験を持つと成功の要因を法則化し、同じやり方を踏襲する傾向があります。
これは、自分の中の成功体験を抽象化（一般化）し、再現性を高めようとして起きる行動です。
しかし、成功には進め方だけでなく、様々な環境要因が絡んでいることが多いため、そのような環境要因を排除して抽象化しても、同じような成功を再現できない場合が多いです。

私がよく遭遇するのは、「仕事はゴールから逆算して計画を立てて進めることが大事」という一般化です。確かに、仕事の全体像を把握して効率よく進めていくには計画を立てることが大事で、不確実性の少ない仕事であれば計画を詳細に立てることで仕事がスムーズに進むのも事実であると思います。

ただ、不確実性の高い仕事（ソフトウェア開発などは特にそう）は、計画通りに進まないことが多いので、最初から詳細な計画を立てて、計画通りに進めようとすると最初の計画が逆に足かせとなることも多いと感じています。成功体験を一般化して再現性を高めることは大事ですが、認知バイアスによって多くの情報がそぎ落とされていることも認識することが大事かと思います。

---

### 学習に対する負の転移

Javaを学習していれば、他のプログラミング言語への理解もしやすくなると書きましたが、場合によっては既存の知識が新たな技術習得の弊害になることがあります。
例えば、Javaでオブジェクト指向の考え方に慣れた後、Scalaなどの関数型言語を学ぼうと思うと、オブジェクト指向型言語と関数型言語ではパラダイムが異なるため、オブジェクト指向の知識が関数型言語の理解の妨げになってしまう場合があります。
概念が異なる分野の技術を学ぶ場合、既に持っている知識がマイナスに働く可能性があることを認知しておくことが大事です。
この辺りは「[プログラマー脳](https://amzn.to/44oyqVb)」で詳細が説明されています。

「ウォーターフォール」と「アジャイル」のような開発手法に関してもおそらく同じことが言えます。エンジニアになって最初からアジャイルの現場にいるとアジャイル開発の理解はスムーズですが、ウォーターフォール型の開発経験が長いと既存の知識が新しい知見への弊害になることがあります。

「オブジェクト指向型言語」と「関数型言語」は、考え方が大きく異なります。
「ウォーターフォール」と「アジャイル」も、根底の考え方が大きく異なります。
どちらもプログラミング言語だから、とか、どちらもソフトウェアの開発手法だから、という風に、変に共通点を見出そうとすると、正しい知識が身に付けられなくなってしまいます。

本質的に似ているものは具体と抽象の考えをうまく使うことで理解をスムーズにできますが、根本的に考え方が異なるものはむしろ自分の知識をアンラーニングしてフラットな視点で学習することが重要です。

## 抽象化思考を鍛える書籍

### メモの魔力

https://amzn.to/43bEz5S

私が抽象化という概念を意識するようになったのは、おそらくこの本がきっかけだったように記憶しています。この本の中で「具体と抽象」が紹介されていたので、すぐに読んで抽象化の重要性を意識するようになりました。
正直、個人的には「メモの魔力」よりも「具体と抽象」の方が面白いと思いましたし、タイトルがメモの魔力となっていますが、メモよりも抽象化の方がメインの本なのでは？とも思いました。
ただ、普段からよく手書きでメモを取る習慣があって、メモを活用して思考力を鍛えたい、という人には参考になる部分も多いかと思ったので、紹介しておきます。

---

### 細谷功さんの書籍

先に紹介した「具体と抽象」の著者である細谷さんは、他にも「考える力」に関する書籍を多数出版されていて、そのほとんどで抽象化に関する話題が出てきます。
「具体と抽象」をもっと深掘りしたいと思った方は細谷さんのほかの著書もおすすめです。

以下は「具体と抽象」をより深掘りして、具体と抽象を行き来する思考をトレーニングする目的の書籍で、より具体と抽象についての理解を深めることができます。

https://amzn.to/3YZRoh9

他だと今のところ「[フローとストック](https://amzn.to/3SdJb54)」が最も面白かったです。具体と抽象をさらに拡張してフローとストックという概念を導入することで、より広い視野で全体を俯瞰する思考を学べます。

## 抽象化能力の大事さを感じた書籍

直接抽象化をテーマにした本ではないですが、読んでいて抽象化能力の大事さを認識させられた書籍をいくつか紹介します。

### お金2.0

https://amzn.to/4jB6imt

お金の正体、経済の仕組みについて解説書籍です。

（読んだのがだいぶ前なので記憶が怪しいところもあるのですが、、）
経済の仕組みを説明する際に、脳や自然現象と共通点を見出し、脳科学や自然科学の法則から経済の特徴を説明しているところがあり、抽象化能力の高さを感じました。

「メモの魔力」の著者である前田さんと、「お金2.0」の著者である佐藤さんはどちらも起業家で、どちらもプラットフォームやサービスなどを作っています。起業家の人は高い抽象化能力を持つ人が多いのだろうな、と読んでいた当時思った記憶があります。起業家に限らず、今世の中にないものを生み出したり、新しい何かを創り出す人というのは、本質を見極める抽象化能力が高いのだろうな、と思います。

抽象化とは直接関係ないですが、佐藤さんの著書で最近出版された「[ゆるストイック](https://amzn.to/3GBuaaQ)」もかなり面白かったのでおすすめです。

---

### デザインのミカタ

https://amzn.to/3GxWFWZ

デザインセンスを身に着ける学習方法を学ぶための書籍です。この本の著者は専門学校などでデザインを学んだ経験はなく、全て独学でデザインを学んだそうです。どうやってデザインを学んだのかというと、ざっくり以下のような方法で身に着けたそうです。

1. デザインの葉を見る（デザインの詳細を見て言語化する）
1. デザインの木を見る（デザインの理由「なぜ？」を考える）
1. デザインの森を見る（法則化して知識として落とし込む）

例えば、街中の看板や電車内での広告を見た際に以下のような視点でデザインを観察します。

1. 詳細を見て言語化する
    - 「この文字だけフォントサイズが違うなー」
    - 「この文字だけフォントが違うなー」
    - 「この部分だけ色が他と違うなー」
    - のように、詳細を細かく見ながら言語化を行う
1. 理由を考える
    - 「なぜこの文字だけフォントサイズが違うのだろう？」
    - 「全体を見た時に、１か所だけフォントサイズが小さいと逆に目立って、目が行くようになっているな」
    - 「つまり、目立たせたい箇所でフォントサイズをあえて小さくしているのだろう」
3. 法則化する
    - 一部分だけ目立たせたい文字がある場合、そこだけフォントの種類やサイズをを変えることで目が行くようにできる

観察の対象物となるデザインは、何でも良いです。
街中の広告だけでなく、道路の標識や、本の表紙、物理的な商品のラベルや商品自体のデザインでも良いでしょう。

この本の著者は、上記のような方法で身の回りにあるデザインを観察しながら、デザインに対する法則を増やし、デザイン力を磨いていったそうです。この本で扱っているデザインのサンプルは主に広告に関するデザインですが、Webやアプリのデザインに対しても同じ学習方法は可能だと思います。

この本の中では「抽象化」という言葉は使われていませんが、この本で紹介している法則化の手法はまさに具体と抽象を行き来する考え方そのものでした。何かを学ぶときに重要なのは、「好奇心の強さと抽象化能力の高さだな」と思わされる１冊です。

---

### 思考する英文法

https://amzn.to/3YlKrqv

そろそろ技術系の公式ドキュメントを翻訳せずそのまま読めるようになりたいなーと思い、少しずつですが英語勉強中です。

英単語の知識もかなり足りてないとは思いつつ、まず英文法をちゃんと理解したいなと思い、何冊か文法の本を読んでます。この本はまだ序盤しか読めていないのですが、最初にいきなり抽象化の話が登場し、英文の構造を見抜く抽象化能力を身に着けることを目指した英文法の書籍であるとの紹介がありました。

ボリュームが多くて内容もちょっと難しいなとは思っていますが、確かに、英文の構造を理解するためのポイントが豊富に載っていて、これがすべて理解できるようになると英文の読解がかなりスムーズになりそうな気配があります。どんな分野であっても、応用力を磨こうと思うと、抽象化思考に行き着くのかもしれない、と思います。

※偉そうに本の紹介をしていますが、お金、デザイン、英語のことはまだまだ初心者です。

## まとめ

- 抽象化は、異なる事象（具体）に対して共通点を見つけてカテゴリ分けすること
- エンジニアの仕事において抽象化の考え方は重要
- ただし一般化による弊害も多々あるので注意