文系未経験出身が考える 要となるコンピュータの知識と知見

# 1 - はじめに

## 1.1 - 自己紹介
こんにちは、まいきーと申します！
2024年現在で開発者経験5年目のプログラマです
現職は主にwebアプリケーションの受託開発を行っている会社で働いています
僭越ではありますが、今までの経験から得た知識や知見を共有することで、微力でも誰かに貢献できればと思ったのと、自身の知識整理も兼ねて初のQiita記事執筆に挑戦してみました！
自分は周囲の人々や社会にたくさん助けられてきまして、恩返しや恩送り、何かしらの還元をしていきたいとずっと思っていたので、本記事を通して皆様に何かしら収穫を得ていただければとてもとても嬉しいです・・・m(_ _)m
それでは対戦よろしくお願いします！

## 1.2 - 目次
- [1 - はじめに](#1---はじめに)
    - [1.1 - 自己紹介](#11---自己紹介)
    - [1.2 - 目次](#12---目次)
    - [1.3 - 本記事の目的](#13---本記事の目的)
    - [1.4 - 読者別おすすめの読み方](#14---読者別おすすめの読み方)
    - [1.5 - 筆者のスペック紹介](#15---筆者のスペック紹介)
        - [1.5.1 - 職歴以外っぽい部分（就職時点でのスペック）](#151---職歴以外っぽい部分就職時点でのスペック)
        - [1.5.2 - 職歴っぽい部分（現在のスペック）](#152---職歴っぽい部分現在のスペック)
- [2 - 本題](#2---本題)
    - [☆2.1 - 本題超要約☆](#21---本題超要約)
    - [2.2 - スタート地点と目的地の確認](#22---スタート地点と目的地の確認)
        - [2.2.1 - 節要旨](#221---節要旨)
        - [2.2.2 - 基礎の理解は地図とコンパスになる](#222---基礎の理解は地図とコンパスになる)
    - [2.3 - 頭に入れておきたい考え方などについて](#23---頭に入れておきたい考え方などについて)
        - [2.3.1 - 抽象度レベルを意識する](#231---抽象度レベルを意識する)
            - [2.3.1.1 - 考察する観点文脈と抽象度レベル](#2311---考察する観点文脈と抽象度レベル)
            - [2.3.1.2 - 情報隠蔽と抽象化](#2312---情報隠蔽と抽象化)
            - [2.3.1.3 - 筆者のすゝめ](#2313---筆者のすゝめ)
        - [2.3.2 - 最初から100%理解しようとしなくてよい](#232---最初から100理解しようとしなくてよい)
        - [2.3.3 - 遅延評価学習](#233---遅延評価学習)
        - [2.3.4 - 積極的に休息を取ろう](#234---積極的に休息を取ろう)
            - [2.3.4.1 - 自己研鑽への圧力を真に受けない](#2341---自己研鑽への圧力を真に受けない)
            - [2.3.4.2 - 自分を責めない](#2342---自分を責めない)
            - [2.3.4.3 - 人間は充電池](#2343---人間は充電池)
    - [2.4 - そもそもプログラミングとは？](#24---そもそもプログラミングとは)
        - [2.4.1 - ソースコードを書くだけがプログラミングじゃない](#241---ソースコードを書くだけがプログラミングじゃない)
            - [2.4.c.1 - コラム　アプリケーションとシステム](#24c1---コラムアプリケーションとシステム)
    - [2.5 - そもそもアプリケーションとは？そもそもコンピュータとは？](#25---そもそもアプリケーションとはそもそもコンピュータとは)
        - [2.5.1 - コンピュータは計算機](#251---コンピュータは計算機)
        - [2.5.2 - コンピュータは四則演算と論理演算で計算する](#252---コンピュータは四則演算と論理演算で計算する)
            - [2.5.c.1 - コラム　四則演算と論理演算が計算の最小要素](#25c1---コラム四則演算と論理演算が計算の最小要素)
        - [2.5.3 - 現実の情報を値と計算で表現して処理するということ](#253---現実の情報を値と計算で表現して処理するということ)
            - [2.5.c.2 - コラム　符号化](#25c2---コラム符号化)
            - [2.5.c.3 - コラム　計算論的思考](#25c3---コラム計算論的思考)
        - [2.5.4 - コンピュータの論理的な3層構造](#254---コンピュータの論理的な3層構造)
            - [2.5.4.1 - ハードウェア層](#2541---ハードウェア層)
            - [2.5.4.2 - OS層（システムソフトウェア層）](#2542---os層システムソフトウェア層)
                - [2.5.4.2.1 - 物理装置など計算資源の管理や分配を行う](#25421---物理装置など計算資源の管理や分配を行う)
                - [2.5.4.2.2 - ハードウェアの抽象化とインターフェースの提供](#25422---ハードウェアの抽象化および人間やアプリケーションがコンピュータを扱いやすくするためのインターフェースの提供や仲介を行う)
            - [2.5.4.3 - アプリケーションソフトウェア層](#2543---アプリケーションソフトウェア層)
                - [2.5.c.4 - コラム　ミドルウェア](#25c4---コラムミドルウェア)
    - [2.6 - プログラミングに含まれる作業](#26---プログラミングに含まれる作業)
        - [2.6.1 - 大まかな分類](#261---大まかな分類)
            - [2.6.c.1 - コラム　ソフトウェア開発手法](#26c1---コラムソフトウェア開発手法)
        - [2.6.2 - ウォーターフォールモデルに沿った細かな分類](#262---ウォーターフォールモデルに沿った細かな分類)
            - [2.6.2.1 - 要求/要件定義](#2621---要求要件定義)
            - [2.6.2.2 - 設計](#2622---設計)
            - [2.6.2.3 - 開発環境やアプリケーション実行環境の整備（環境構築）](#2623---開発環境やアプリケーション実行環境の整備環境構築)
                - [2.6.c.2 - コラム　環境とは](#26c2---コラム環境とは)
            - [2.6.2.4 - 実装/コーディング](#2624---実装コーディング)
            - [2.6.2.5 - テストおよび評価](#2625---テストおよび評価)
            - [2.6.2.6 - ビルド](#2626---ビルド)
                - [2.6.2.6.1 - コンパイルとリンク](#26261---コンパイルとリンク)
            - [2.6.2.7 - アプリケーションの配布やデプロイ](#2627---アプリケーションの配布やデプロイ)
            - [2.6.2.8 - 運用保守](#2628---運用保守)
    - [2.7 - アプリケーションやソフトウェアが動く仕組み](#27---アプリケーションやソフトウェアが動く仕組み)
        - [2.7.1 - ちゃんと理解するには基礎知識が必要](#271---ちゃんと理解するには基礎知識が必要)
        - [2.7.2 - アプリケーションが動く仕組みの大枠](#272---アプリケーションが動く仕組みの大枠)
            - [2.7.2.1 - 補助記憶から主記憶](#2721---補助記憶から主記憶)
            - [2.7.2.2 ,3 ,4 - プロセッサとメモリと処理](#2722-3-4---プロセッサとメモリと処理)
            - [2.7.2.5 - プログラムの破棄](#2725---プログラムの破棄)
    - [2.8 - ネットワークの基礎を学ぶことの重要性について](#28---ネットワークの基礎を学ぶことの重要性について)
- [3 - おすすめ書籍や教材等](#3---おすすめ書籍や教材等)
    - [3.1 - 入門/取っ掛かり](#31---入門取っ掛かり)
    - [3.2 - ハードウェア](#32---ハードウェア)
    - [3.3 - OS](#33---os)
    - [3.4 - ネットワーク](#34---ネットワーク)
    - [3.5 - 数学](#35---数学)
    - [3.6 - 英語](#36---英語)
- [4 - まとめ](#4---まとめ)

## 1.3 - 本記事の目的
「**開発者としての自力を伸ばすために身に着けておきたいと感じた知見や事柄の共有**」
「**何を勉強していけばいいのか分からない人に学習の指針/参考を示すこと**」
が本記事の主な目的です

コンピュータやソフトウェア開発において基礎的な部分の知識不足を感じている方に「こういうことを知っておくと良いよ」というアドバイスを提供できれば良いなと思っています
また、開発者ではないけどエンジニアと話をする上で知識を持っておきたい、ITリテラシーを上げたいといった方にも参考にしてもらえるかなと思います

特に、筆者は教育機関でコンピュータサイエンス（以下CS）やプログラミングを学んでいない所謂非CS出身開発者なのですが、そういう人でもちゃんとキャッチアップしていけばある程度自立した開発者になれる（と筆者は信じています）ということを伝えられればと思っています
CS出身開発者の方には頭が上がりませんが、非CS出身の開発者でも現場で活躍されている方々を見てきましたし、業界や社会に貢献することは十分できると信じています
ので、開発者だけでなくエンジニアを採用するビジネスサイドの方々にもそういう考え方を共有できれば良いなという思いも本記事に込めています

## 1.4 - 読者別おすすめの読み方
本記事は開発者向けの内容になっていますが
開発者ではない方やITの話に興味がある方など、たくさんの人に読んでいただきたいと思っています
・・・とは言っても、本記事の内容を通読するにはある程度プログラミングに関する知識がないと辛いかもしれません :cry:
実際本記事はオブジェクト指向言語（上級言語）のプログラミング経験が少しある人や、経験1~3年目の開発者のレベル感を想定して書いてきました
少なくとも本記事を通読したりしっかり読み込む上では変数や関数、クラスやインスタンスなどプログラミングやCSに関する入門レベルのキーワードを聞いたことがあるという程度の前提知識は欲しいかもしれません
なので自身の属性に合わせて以下のような読み方をしていただくのが良いかなと思います

1. **プログラミングやCSの知識は全くないけどこれからプログラミングを始めようとする人**
本題超要約に書いてあることは頭に入れつつ、全部しっかり読み込もうという意識ではなく、ざーっくりなんとなく、分からないところは読み飛ばしながら読んでみるという意識で読むのがおすすめです
あとは上級言語である程度プログラミングをしてみて、断片的知識を得てから読むのもおすすめです
本記事に目を通しながらプログラミングをしてみて、知識が少しできたらまた本記事に帰ってくるなどは自分のお好みでOKです
2. **上級言語の経験が少しある人、経験1~3年目くらいの人**
本記事で主に想定している読者層です
なので普通に通読してみてもらって、説明が足りないなと思う部分は都度調べながら読んでみてください
本題の章はもちろんですがおすすめ書籍の章はそのものがジュニアレベルの人の自力をレベルアップするためにどんな内容を勉強すればよいのか？という答えになっていると思うのでぜひチェックしてみて欲しいです
3. **開発者ではない人、プログラミングやITに興味がある人、なんとなく話を聞いてみたい人など**
本当ににざーっくり、読み物として読む、目を通してみるくらいのノリでOKです
ところどころ技術者以外の人にもタメになりそうな話（人間は充電池、人間の営みは値と計算で表現できるなど）をしているのでそういう部分を探しながら読んでみてもらえると嬉しいです

## 1.5 - 筆者のスペック紹介
本題に入る前に筆者のスペックを示しておきます
筆者の就職時点のレベルと、開発者経験5年目（2024年現在）のレベルを示すことで
どういった方にどの程度の再現性をもたらすことができるのかの指針になればと思い参考程度に筆者のスペックを記載しておきます
就職時点でレベル0の人が、業務外でUE5を使ってゲームを一本自力で作れるくらいにはなれましたので、本記事の内容にある程度の信憑性を与えられれば良いなと思います・・・:thinking:
（以下に作ったゲーム（無料）のリンクを載せておくので良かったらぜひチェックしてみてください :grinning:）

https://k117117117.itch.io/sunny-side-up

### 1.5.1 - 職歴以外っぽい部分（就職時点でのスペック）
| 項目 | スペック | 備考 |
|:-:|:-:|:-:|
| 学歴 | 私大商学部卒（19卒） | 英語日本史受験 <br>　英語は昔から好きで得意 <br> 数学は当時食わず嫌いしていた |
| 理系的素養 | 数1A2B 習得程度 <br> 物理化学生物等のその他自然科学の知識は無し | 数学は学部卒業前に算数から勉強し直した <br> 今となっては数学や科学、技術の話は好き |
| 開発知識の有無 | パソコンにそこそこ詳しい程度で開発に関する知識は無し | 就職してから実務と並行して勉強していったタイプ |

### 1.5.2 - 職歴っぽい部分（現在のスペック）
筆者は職務経歴から言えばアプリケーションソフトウェアの開発者といえると思います
webアプリケーション開発が主ですがAndroidやiOS、Windows向けのネイティブアプリケーション開発やクロスプラットフォーム開発を行うプロジェクトにも参画していました
webアプリケーション開発ではクライアントサイドとサーバサイド両方携わることが多いです
| 項目 | スペック | 備考 |
|:-:|:-:|:-:|
| 実務でよく使用していた言語等 | C#/.NET <br> Java/spring <br> PHP/Laravel/CakePHP <br> HTML/CSS <br> JavaScricpt/TypeScript/vue.js 等 <br> Flutter/Dirt | ある程度練度のあるものを記載 <br> 業務外ではC++なども触ったりしています |
| 実務で使用したその他技術等 | DB（MySQL, MariaDB, SQL Server） <br> Webサーバ（Apache, IIS） <br> クラウド（AWS, Azure）<br> その他（Docker, git） | おなじみの面々ですね |
| 担当した業務領域 | 設計 <br> 実装 <br> テスト <br> 保守 <br> 顧客折衝ヒアリング | ウォーターフォール開発の一通りの工程は経験しているかと思います |

# 2 - 本題

:::note warn
**記事を読む上での注意事項等**

- 本記事はあくまで筆者の経験や考え方を基に書かれていますので一個人の意見に過ぎません
- 本記事の内容はアプリケーションソフトウェア開発者の視点から書かれています
- 本記事では用語等の定義の厳密性を欠いた表現があるかもしれないことに注意してください
- 単にアプリケーションといった場合はアプリケーションソフトウェアのことを指し、PCやスマホのアプリと言った場合のニュアンス（ネイティブアプリケーションやモバイルアプリケーション）とは少し異なることに注意してください
- エンジニアやプログラマという言葉を開発者という言葉で広義的に表現しています
:::

## 2.1 - 本題超要約
かなり長大な記事になってしまったので要約を示しておきます
本記事を読み進めていくなかでも都度要約に立ち返りこの記事が伝えようとしていることは何かを整理して各節と照らし合わせて読むと良いでしょう

- 仕組みを理解した上でプログラミングしていける力
- 自力で問題解決していけるプログラミング力
- コンピュータに関する様々なトピックを自力で読み解いていける力

これらを身につけるためにはコンピュータそのものの理解と知見を深めることが超重要🧑‍💻
コンピュータそのものの理解を深めるにはハードウェアとOSの学習を行うのが超重要🧑‍💻
ハードウェアとOSの基礎知識を最低限抑えればコンピュータに関する様々なトピックを自力で読み解いていけるようになると思います🧑‍🏫
コンピュータそのものの理解と知見が十分身についてきたら様々なことがスラスラ頭に入ってきて色んなことをある程度自力で解決できるようになることが実感できるようになると思います🧑‍💻

また、プログラミングとコンピュータを用いた情報処理について、「値と計算」を利用しているということを紐づけて頭に入れておくことも有用です
コンピュータの本質は計算を行うことです
入力に応じて計算（処理）を行い出力を返すというのがコンピュータが行う本質的な仕事です
我々はこの計算機たるコンピュータを用いて現実の様々な営みや問題、情報を処理していますが、上記の値と計算というものにそれらを当てはめることでコンピュータを用いた様々な情報処理を可能にしているのです
プログラミングをする上ではこうした値と計算への対応付けをしているんだという意識があると考え方や見える世界が広がっていくと思います

## 2.2 - スタート地点と目的地の確認
### 2.2.1 - 節要旨
まずは本記事で伝えたいことを改めて整理して、出発地点と目的地を明確にしておきたいと思います

**「開発者になったけどそもそも自分が何をしていて、どこを目指せば良いのかも分からない。とりあえずある程度自立して開発が行えるようになりたい」**
という人に向けて
**「プログラミングとはそもそも何か？コンピュータとは何か？を知ることから始めると良い」**
ということを伝えたいです

### 2.2.2 - 基礎の理解は地図とコンパスになる
コンピュータおよびプログラミングの分野はとても広大な森と言えるでしょう
自分は就職当時、その森の中に右も左も分からず、自分が今いる場所や目的地も分からないまま入りずいぶんと暗中模索をしてきました
ただ、どれだけ広大な森でも地図とコンパスを手に入れれば自力で探索できるようになるのではないでしょうか
**その地図とコンパスが「コンピュータとはそもそも何か」「プログラミングとはそもそも何か」という基礎的なことに対する理解や知見だと思っています**
なのでこの地図とコンパスを獲得する手助けをしたいというのが本記事の主な目的です
自身のいる場所が分かって地図とコンパスを手に入れればコンピュータ分野というとてつもなく広大な森も、ある程度自力で探索していけるようになるでしょう

ただし最終的な目的地は自分で定めることになると思うので本記事ではその点については深く入り込みません
ネットワーク、クラウド、AIなどどの分野を専門に進んでいくかは自身のキャリアや志向次第であり、その道を進む上で自身に何が必要になってくるかは地図とコンパスを手に入れれば自身で導き出すことができるでしょう

コンピュータの分野を自力で探索できるようになるためにはコンピュータとプログラミングに関する理解や知見が重要だというのは言ってしまえば当たり前のことですが、右も左も分からない人からすると最低限何を勉強すれば自力で探索できるようになるのか、それすらも分からないかと思います
就職当時の自分が正にそうで、ただひたすらに、闇雲に上級言語の入門書を勉強していました
新米開発者に向けた学習ロードマップといったものも目にしましたが、最低限どこからどこまで身に着ければ自分の足で歩いて行けるのか分からなかったです（今考えればコンピュータとプログラミングについての理解や知見を最低限身に着ければ色々なことを自分で読み解いていけるようになると思います）
まずは自分が開発者として行っていきたいこと、進んでいきたい道を整理することで全体像とやるべきことが見えやすくなると思います

また**本記事の本旨はあくまでどういうことを学ぶと良いのか、ここを理解すると何が嬉しいのかといったことを伝えること**であり、あるトピックについて技術的な詳細に踏み込んで説明するというよりは理解しておきたい部分、知っておくと良いことをかいつまみながら説明していく感じにするつもりです
本記事で学習の足掛かりを掴んだ後は技術書等を読んで自身に必要な知見や事柄の理解を深めると良いでしょう
記事の最後では筆者がおすすめする書籍や教材等も紹介したいと思います

## 2.3 - 頭に入れておきたい考え方などについて
「コンピュータとはそもそも何か？」「プログラミングとはそもそも何か？」
という話に入る前に、コンピュータに関する学習をする上で筆者が大切だと思うことについても示しておきます
1. ある対象を考える際は考察する文脈に応じて抽象度レベルを使い分ける
1. 最初から100%理解しようとしなくて良い
断片的学習と体系的学習をバランスよく繰り返すことで理解度を上げていく
1. 必要になったら勉強するでも良い（遅延評価学習）
1. 自分を追い込みすぎないこと
積極的に休息を取ること

### 2.3.1 - 抽象度レベルを意識する
※正直全てを言語化しきれているか自分でも分からないので図と一緒に頭に入れて、自分の中で咀嚼しながらああそういうことねと実践を通して少しずつ実感していってもらえれば幸いです
抽象度レベルに関していただいたコメントからも示唆を得られると思うのでぜひ見てみてください
[植物学者と大王様](https://qiita.com/mikey_117/items/d2de10a889bcecf9370b#comment-118ec14e90468945d51d)
> 銀河系を統治する大王様はとても忙しいので、この森の中の、とある泉の岸に咲く、一輪のルビー色のユリの花を意識してはいられません。逆にルビー色のユリを研究する植物学者は、目の前のユリが大事なのであって銀河系の動きなどどうでも良いのです。考える＝イメージする対象に合わせて、オブジェクトの抽象度を変えるのは必須ですね。

#### 2.3.1.1 - 考察する観点文脈と抽象度レベル
いきなり小難しい話で恐縮ですが
CPUやOSといったコンピュータの世界の登場人物について考える際、それらを考察する文脈に適した捉え方というものがあると筆者は感じています

例えばコンピュータについて学習するため入門書を買いにいくとしましょう
書店に行くと
「コンピュータが物理的に計算を行う仕組み：ハードウェア技術と各パーツの物理的構成」
「コンピュータは如何にしてアプリを動かすか？ソフトウェアの魔法の背景」
という二つの本が目につきました
同じコンピュータについての本でもその切り口や観点によってコンピュータをどのように捉えようとしているかが違うことが分かると思います
つまりCPUやOSなどコンピュータの世界の登場人物を考えようとする時、それを考察する観点や文脈が異なるとその登場人物の姿や見え方も変わってくるということが分かると思います
上の例ではハードウェア的な観点から見た時の側面に注目してコンピュータを捉えようとしているものと、ソフトウェア的観点から見た時の側面に注目してより抽象的/概念的にコンピュータというものを捉えようとしているといった感じです

コンピュータはハードウェア/ソフトウェア両面で様々な技術が詰め込まれていますが、それらは下図の層構造のように積み重なって構成されています

![layer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646125/d68c3f16-cfad-f6f8-ed1a-a44b7805f8c6.png)

そのため例えばCPUについて考える時、ハードウェア層から見た時、ソフトウェア層から見た時など、それぞれの文脈に応じて捉え方を適切に変えることがその文脈におけるCPUに対する理解を深めるカギになると思います

このようにコンピュータ分野の様々なトピックを学ぶ上では、ある層から見た時のその登場人物の具体的側面と抽象的側面を分けて考えることができる点を意識し、様々な観点から具体と抽象を行き来するように考察するとより理解が深まると筆者は感じました
具体と抽象を行き来し、近くで見た時の姿と俯瞰して見た時の姿を交互に考察していくことでその登場人物の姿形をよりよく捉えることができ、その知識をより有効に効果的に活用できるようになるでしょう

#### 2.3.1.2 - 情報隠蔽と抽象化
ちなみに上記の考え方は情報隠蔽（カプセル化）や抽象化といった概念に則しています
ある対象について考える際の抽象レベルに応じて必要な/本質的な情報に焦点を当て、逆にそのレベルでは隠蔽した方が見通しが良くなる詳細情報は隠す/踏み込まないといったような感じです
内部的な詳細を隠蔽することでその詳細に触れずにより大きな構成要素との関連や仕組みについて見通しよく考察できるようになると思います
この考え方に慣れるには
AについてBの文脈から考える
といった意識を頭に入れておくと良いでしょう
例
ハードウェアについてアプリケーションの文脈から考える　⇒　ハードウェアを捉える抽象度を上げる（抽象的に考える）
ハードウェアについてハードウェアの文脈から考える　⇒　ハードウェアを捉える抽象度を下げる（具体的に考える）
逆にアプリケーションについてアプリケーションの文脈から考えるといった場合はアプリケーションの抽象度を下げて具体的に考えるといったようにするといいのではないでしょうか
ある対象についてどういった文脈から、どういった側面に注目して考えるかという意識を持つという感じですかね

#### 2.3.1.3 - 筆者のすゝめ
一つ付け加えると、個人的にはコンピュータそのものについて学習していく時はハードウェア層からアプリケーション層に上っていくように学習を進めると良いと思います（ある程度上級言語を触ってコンピュータについての断片知識がそこそこ蓄積されている場合は特に）
何故なら下位層の詳細は上位層に対して隠蔽されている場合が多く上位層の視点から下位層を読み解いていこうとするとピンとこないことが少なくない、情報の欠落や網羅性を把握しにくいと感じたためです
数学で数の種類を勉強する時は自然数から整数、実数…といった具合に数の概念を下から上に（数の集合の下位集合から上位集合に向かって）拡張していくと思いますがイメージとしては具体から抽象に向かっていくこの学び方が良いのではないかと思います
実際筆者も論理回路からハードウェアを作りOSを作りといった学習をしましたが振り返ってみるととても良かったと思います

### 2.3.2 - 最初から100%理解しようとしなくてよい
コンピュータ分野に限った話ではないかもしれませんが、ある事柄を学ぶ上で
最初から100%理解しようとしなくても良い
と筆者は考えています
物事への理解は、断片的に仕入れた知識が次第に自分の中で整理され体系的に紐づいていく過程で深まると思うからです
断片的学習と体系的学習をバランスよく行っていけば最初はぼんやりとしか理解できていなかったことも、後から氷が解けるように、霧が晴れるように理解が深まることがままあると思います
なのでまずは習うより慣れよで断片的に知識を入れて、後から体系的に学び直すことで知識を整理していくのが学習効率が良いのではないかと思います（点と点が線で繋がる感じですね）
もちろん最初から体系的学習を行う（入門書をイチから読むとか）のも良いと思いますしそうする場合ももちろんあります
ですが、断片的知識も少ない状態から体系的学習をした時、（筆者的には）いまいち使いどころや重要性が分からず頭に入ってこないことがままあるなと感じることも未だに少なくありません
やはり具体的な情報をまずは取り入れて、そこから本質的/抽象的な理解を深めていくというのが効果的に思えます
なのでまずはとりあえず触ってみて、具体的に分からない点を把握してから答え合わせをしていくように学習を進めていくというのが筆者的にはおすすめです
プログラミングもまずはとりあえずコードを書いて何か作って、分からない部分が出てきたらそこから調べて、後から体系的に学んで整理していこう、と仰っている方も多いですよね
ただどちらも大事というのは変わりないので断片的学習と体系的学習をバランス良く交互に行っていきましょう

### 2.3.3 - 遅延評価学習
コンピュータの世界はそれ自体がとても広大で深い森であり、それに紐づくOSやネットワークといった各分野も広範かつ深い森になっていると筆者は考えます
その全てを体系的に学ぼうとするのはとてつもなく大変であると言わざるを得ません
そもそも全ての分野に精通しているコンピュータ技術の神みたいな人は滅多にいないのではないでしょうか
なので基礎を抑えた後は必要な知識は必要になってから学ぶ遅延評価学習法という学び方が開発者の間では提唱されています
遅延評価とはCSの用語で、評価すべき値がある時、それが実際に必要になるまで値の計算を行わないということを言うのですがこれを学習方法に適用したものと言えるでしょう
実際に必要性を認識している上理解したい点も明確になっていることも多いのでこの学習方法は学習効率が良いと思います
また、遅延評価学習法で断片的に学んだことを後から整理して学び直せば更に理解が深まるためこのような学び方も積極的に取り入れると良いでしょう
義務教育では全てを最初から体系的に学ぶよう教えられてきたため最初は慣れないかもしれませんが段々この学習法の考え方に慣れてくると思います
逆に言えば断片的学習と体系的学習のそれぞれの長短が分かるのでうまく使い分けることで自身の学習能力向上にもつながるでしょう

### 2.3.4 - 積極的に休息を取ろう

#### 2.3.4.1 - 自己研鑽への圧力を真に受けない
インターネット上では様々な分野の開発者さんが様々な有益知識を記事や動画などで共有してくれています
開発者コミュニティのこういった文化は非常に素晴らしいですよね！私も先人が残してくれた叡智に幾度となく助けられており、正に巨人の肩の上に乗らせてもらっているなと日々実感しています

ただその中で
開発者は余暇も熱心に勉強すべきだ
という論調を見かけることがあります
技術は日進月歩で発展していくので開発者として生きていく以上勉強を続けていくことは重要であることには間違いありません

しかし自己研鑽に対する強制圧力を真っ向から受け取る必要はないと筆者は思います
自分のペースで成長していければそれで良いと思います。
個人的には好奇心や興味を惹かれるトピックや意欲に応じて勉強していくことがモチベーションと楽しさ、心身の健康をバランスよく保っていくコツだと思います
技術書とかでなくちょっとした読み物やニュース、ネット上の記事に目を通すレベルでも十分でしょう
特に勉強したいと思うものがない時は勉強しなくても良いと思います
無理して勉強するくらいなら勉強せずに休息を取ったり運動や趣味などに時間を使う方が健康に良いです（だからといって全く何も勉強しないというのもそれはそれで考えものですが）

#### 2.3.4.2 - 自分を責めない
一番やって欲しくないのは勉強していない時の自分、勉強していない時間を作る自分に罪悪感を感じたり責めることです
「勉強しなきゃいけないのに勉強してない、自分はダメな奴だ」
「勉強したけど全く進んでない、自分はダメな奴だ」
「勉強しようとは思ったけど全く集中できなかった、自分はダメな奴だ」
とは決して考えてはいけません
勉強に身が入らず無為な時間を過ごしたと思うのではなく、次の勉強に向けてエネルギーを蓄えていると捉えるようにしましょう
多少ダラダラしすぎたなと思うこともあるでしょうがそれでも罪悪感を感じたり自分を責めたりしないでください
サボることも休息を取ることも悪いことではありません
むしろ積極的に休息を取ることは非常に重要です

#### 2.3.4.3 - 人間は充電池
今述べていることは学習以外の話にも当てはまると思います
人間は充電池のようなものでエネルギーを使って活動した分、休みを取ってエネルギーを充電しないといずれ力尽きてしまいます
普段あまり意識していないかと思いますが、アクティブに活動できる場面があるのは裏で休息を取ってエネルギーを充電しているからこそです
この活動と充電（休息）のサイクルは循環しているという意識を忘れてしまいがちですが休息のサイクルでしっかりと休んで充電するからこそ次の活動をアクティブで生産的なものにできるし、アクティブに活動した後はしっかり休息を取って次の活動に備えることもアクティブに活動することと同じくらい重要だと思っています
何かをすることと同じくらい何もしない（休む）という時間は大切だと思います
機械のような完璧な勤勉さを保てない自分に罪悪感を持ったり責めるのはやめましょう（自戒）
人間は機械のようにこまめに休息を取らずとも働けば働くほど右肩上がりにパフォーマンスを出せるようにはできていません
正弦波の波のように活動と休息をこまめに周期的にサイクルさせていってこそ継続的にパフォーマンスを出せるというものです
例えば疲れて疲労困憊の中無理して残業して一時的にパフォーマンスを上げてもそれはその場しのぎのオーバークロックに過ぎず、その後の業務や作業のパフォーマンスがガタ落ちするという経験をされた人もいるのではないでしょうか？
自分的に無理のないペースで勉強しつつ、適度に休息運動趣味を織り交ぜて楽しい開発者ライフにしていきましょう♪

## 2.4 - そもそもプログラミングとは？
さて、それではいよいよプログラミングとは？コンピュータとは？という話に入っていきたいと思います

就職当時の筆者はプログラミングのプの字も知らない状態でプログラマになりましたが、その状態を出発点としてプログラミングとは何かを理解した上で自力を発揮していける開発者になる、というところを目指して論を進めていきたいと思います

### 2.4.1 - ソースコードを書くだけがプログラミングじゃない

さて、あなたは新人プログラマとして入社し、研修を受けることになりました
研修ではHTMLやCSSといったマークアップ言語、Javaといったプログラミング言語を学んでいくことになるでしょう
この段階ではひたすらソースコードを書くことになると思うので、プログラミングとはソースコードを書くことだと思うかもしれません
しかしソースコードを書くという行為はプログラミングの一部にすぎません
筆者は「ソースコードを書くこと=プログラミング」だという認識で様々な言語の入門書を勉強していきました
そうすればプログラミングへの理解を深めていけるだろうと思っていたからです

しかしそれだけではプログラミングというものの理解はさほど深まっていかないということに次第に気づいていきました
プログラミングとは何かを適切に捉えないと学習や努力の向けるべき方向がずれてしまうので注意しましょう
（言語の入門書は一つ読み終えてある程度習得したら一旦十分だと思います。次は言語以外のことを勉強するようにすると良いでしょう）

それではプログラミングとはそもそも何でしょうか？
アプリケーション開発者の観点からあえて焦点を絞った言い方をすれば
「**アプリケーションソフトウェア/システムを作成する行為全般**」
をプログラミングだと言うことができるでしょう
より広義的な意味では大小問わずコンピュータ上で実行されるプログラムを作成する行為でありアプリケーションソフトウェア開発に限定された話ではないですが、新人アプリケーション開発者としてこれから勉強を進めていく場合、今の段階では一旦上記の認識を持っておけば差し支えないと思います

:::note info
#### 2.4.c.1 - コラム　アプリケーションとシステム

<details>
<summary>補足を読む</summary>

上述した文脈に則してプログラミングとは何かをもう少し視野を広げた言い方をすればアプリケーションソフトウェアそれ自体だけでなくそれに関連する別のアプリケーションやミドルウェア等その他の構成要素を連携させ、それを一つのシステムと捉えて全体を構築することとも言えると思います（更に一つのシステムを別のシステムと連携させるようなこともあるでしょう）
あえて細かく区別するならアプリケーションソフトウェアの開発とは文字通りアプリケーションソフトウェア（システムの中のモジュールの一つとしてのアプリケーション、テキストエディタやお絵描きソフトなど自己完結性の高いアプリケーション等含め）の開発を、システム開発とは上述したような一つ一つのモジュールやコンポーネントを繋ぎ合わせたシステム全体を構築することと言えるのではないでしょうか
ただしアプリケーションソフトウェアそれ自体もシステムであると言えると思いますし、アプリケーション=システムというニュアンスで使われることもあると思うので文脈に応じて解釈を行うと良いでしょう
</details>

:::

## 2.5 - そもそもアプリケーションとは？そもそもコンピュータとは？
先の節ではプログラミングを「**アプリケーションソフトウェアを作成する行為全般**」としました
それではアプリケーションソフトウェアとはそもそも何でしょうか？
また、アプリケーションソフトウェアを作成する行為には具体的にどんなものが含まれているでしょうか？

### 2.5.1 - コンピュータは計算機

アプリケーションソフトウェアとはなにか？について説明していきたいのですが
アプリケーションソフトウェアを説明する上では
アプリケーションソフトウェアがコンピュータというものの中でどのような存在であり、どのような役割を担っていて、どのような立ち位置にいるのか、またそもそもコンピュータとは何かを交えて考えていくのが良いでしょう
そのためこの節ではアプリケーションソフトウェアの説明をコンピュータとは何か？ということに含めて包括的にに説明していきたいと思います

さて、まずはコンピュータについて
ここまで散々登場してきたコンピュータとはそもそもどんなものでしょうか？
何をしてくれるものなのか？という観点から非常に単純化して言ってしまえばコンピュータとは「**計算を行ってくれる機械**」です
**入力を受けて計算を行い、出力を返す**
大胆かつ端的に言ってしまえばコンピュータが行ってくれていることの本質はこのように抽象化できます

### 2.5.2 - コンピュータは四則演算と論理演算で計算する

もっと言うと上記の計算とは「四則演算」と「論理演算」でありコンピュータ上で行われる様々な計算はこれら四則演算と論理演算という比較的単純な演算に収束します
現代のコンピュータは非常に高度で複雑な様々な計算をする能力がありますがその根底では四則演算と論理演算を駆使しているのです
微分や積分、三角関数の計算といった数学で登場してくるような演算も、入力に対してどんな処理をしてどんな出力を行うかということを定めたアルゴリズムも、CPUで実行/処理されるタイミングでは四則演算や論理演算といった単純な演算に分解/置き換えられて処理されているのです
コンピュータは単純な演算を非常に高速に行えるため複雑な計算もそれらに置き換えて処理していると考えると良いでしょう
複雑で高度な計算も本質的には足し算や引き算のような単純な演算に分解して処理していると分かれば、なんだかコンピュータのことを理解できそうだと思ってきませんか？少なくとも人間にはその仕組みが到底理解できない黒魔法を使っているわけではなく、複雑で難しいことをシンプルで単純な要素に分解して処理しているんだということを頭に入れておけば物怖じせずにコンピュータというものに立ち向かっていけると思います
デカルトの「困難は分割せよ」、ビル・ゲイツの「問題は切り分けろ」を実直に体現している存在ですね

:::note info
#### 2.5.c.1 - コラム　四則演算と論理演算が計算の最小要素

<details>
<summary>補足を読む</summary>

コンピュータが計算を行う中枢たるCPUには実行できる命令の種類（命令セット）があるのですがこの命令セットを眺めているとやはりCPUのレベルでは基本的に四則演算と論理演算をメインにサポートしているのが分かります
CISCの流れを汲むx86, x86_64、RISCの流れを汲むarmなどCPUのアーキテクチャによってCPUでサポートされる命令セットアーキテクチャも異なるので一概には言えませんが基本的にはそうだと思って差し支えないでしょう
正直ここら辺の話はあまり詳しくないので数学的計算を直接行う命令もサポートされているよといった場合は指摘いただければ幸いです（命令セットに三角関数の計算を行うものが含まれているものもあるなど）
ちなみに浮動小数の演算に特化したFPUや画像/並列処理に強いGPUなど、特定用途の演算に特化した演算装置（コプロセッサ）をCPUが補助的に使用することで計算処理のパフォーマンスを上げていたりします
</details>

:::

### 2.5.3 - 現実の情報を値と計算で表現して処理するということ

**コンピュータは計算を行ってくれる機械**
ここまで単純化すると逆にピンと来ないかもしれません
計算を行ってくれるだけの機械で何故こんなにも様々なことができるのか？
何故こんなにも多様な用途や目的に活用することができているのか？
ゲームをしたりインターネットを見る時に計算というものがどう結びつくのか？
普段パソコンを使っている時に数式なんて使わないし計算をさせている気がしないけど？
という疑問が湧くでしょう

本質的には計算をするための機械であるコンピュータを用いて何故こんなにも様々なことができ、様々なことに活用できているのか
その根底には、我々が日常的に行っている行為や物事を「**値と計算**」**に当てはめて表現/処理することができる、それを計算が得意なコンピュータ上で表現し処理させている**という事実があります（このようなコンピュータの活用をコンピューティングと言ったりします）

我々が日常的に行っている行為や物事を値や計算で表現することができるから、計算が非常に得意なコンピュータを様々なことに活用できているということもできるし
計算が非常に得意なコンピュータを人間の様々な営みに活用するために様々な行為や物事を値と計算に当てはめて表現して処理させているとも言えると思います
コンピュータの活用とは、人間が地道に行うよりも計算が非常に得意なコンピュータに計算をさせることで非常に効率的に結果を得る行為/仕事をさせる行為だと言えるでしょう
このように現実の問題や様々な事象を値と計算で表現してコンピュータに処理させるという行為の根底には符号化と計算論的思考という考え方があります

:::note info
#### 2.5.c.2 - コラム　符号化

<details>
<summary>補足を読む</summary>

コンピュータサイエンスにおける符号化、あるいは情報の符号化とは簡単に言うと文字や色など現実世界の様々な情報や物事を数値で表現することを言います
コンピュータは根底的にはビット列で表される数値（2進数値）を用いて計算を行います
そのためコンピュータを用いて情報処理を行う場合文字や色といった情報を数値に対応させることでコンピュータ上での処理を可能にしているのです
関連する言葉にエンコードとデコードというものがありますが（今の文脈に則して説明すれば）エンコードは文字や色といった情報を数値に変換することを、デコードは数値から元の情報に変換することを言います
（より一般的には符号化/エンコードはある情報を別の形式の情報に変換し、デコードはその逆を行うことを言います）
なお文字や色といった情報に対応付けられる符号(数値)は前提とする文字コードやカラーコードといった数値と情報の対応付けに関する規格によって異なるため注意が必要です
例えば"a"という文字をasciiという文字コードを前提に符号化/エンコードすると"a"に対応する数値は10進数で97、16進数で61(0x61)、2進数で01100001(0b01100001)となります
これら符号化した数値から元の情報に戻す（デコードする）際、エンコードされた値と同じ符号化方式を用いてデコードを行わないと正しい情報に戻すことができません
エンコードされた値に対して異なる符号化方式でデコードするといわゆる文字化けといった不具合が起こったりします（各文字コード間で互換性がある場合は一部合致したりします）
文字コードをUTF8にして作成された文書をSHIFT_JISで表示(コンピュータ的にはUTF8でエンコードされたものをSHIT_JISでエンコードされたものと解釈しようとして)しようとして文字化けしたというのはあるあるなのではないでしょうか？
これはUTF8に基づいてエンコードされたものをSHIFT_JISでエンコードされたものだと解釈しようとしてもSHIFT_JISで規定される文字と数値の対応付けがUTF8のものと異なるために起こります
</details>

:::

:::note info
#### 2.5.c.3 - コラム　計算論的思考

<details>
<summary>補足を読む</summary>

計算論的思考（Computational Thinking）とはコンピュータ（計算機）が特定の問題を解けるように現実の事象や問題を計算機上で計算可能となるように表現しようという考え方です
現実の問題を小さな要素に分解し、値や計算によって表現できるように抽象化を行い、それらをパターン化して計算によって解決できるようなアルゴリズムを考えるといったことが行われます
数学的に表現できるあらゆる種類の情報処理にはこの計算論的思考が根底にあると言えるのではないでしょうか
ちなみにコンピュータを用いてある問題を解くことができるかどうかを研究するCSの一分野として計算可能性理論というものがあるので調べてみるとより知見を得られると思います
</details>

:::

### 2.5.4 - コンピュータの論理的な3層構造

さて、コンピュータは本質的には計算を行う機械だという風に言いました
それではその中身はどのようになっているでしょうか？
ここではハードウェア的な中身についてではなく論理的な中身について述べます

<img width="300" alt="layers.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646125/c17bdd08-c052-7994-0cfa-415ce5c19f64.png">

我々が普段使っているパソコンなど一般的なコンピュータの中身を抽象的に考えると、画像のような3層構造で構成されているといえます
それぞれの層について下から上に向かって簡単に説明しましょう

#### 2.5.4.1 - ハードウェア層
CPUやメモリといったコンピュータを物理的に構成するパーツ、マウスやキーボードなどの入力装置、モニタやスピーカーなどの出力装置が属する層
ハードウェア層について考える場合は各装置の物理的構成（装置内の回路の構成や入出力の仕様）やその役割を物理的装置としての側面から考察する
なお、ソフトウェア的な観点から抽象的に考えるとコンピュータハードウェアは大きく分けて以下の要素で構成されていると考えることができます
・プロセッサ（CPU）
・メインメモリ（主記憶）
・入出力機器（補助記憶:ストレージ、NIC、USBデバイスなど様々なものが含まれる）

#### 2.5.4.2 - OS層（システムソフトウェア層）
CPUやメモリなどを制御するオペレーティングシステムやマウスやキーボードなどの入出力機器を制御するデバイスドライバ、言語処理系などが属する層
OSといった時狭義にはカーネルを指すことが多いがシェルやデバイスドライバなどもOSの一部に含めて論じることも多いです
OSには様々なスタイルがあるため何を以てOSであるかという一元的な定義をするのは実は難しいのですが一般的には次のような役割や側面があります

- 物理装置など計算資源の管理や分配を行う
- ハードウェアの抽象化および人間やアプリケーションがコンピュータを扱いやすくするためのインターフェースの提供や仲介を行う

※なお本記事ではOSを含めコンピュータ自体を使いやすくするためのソフトウェア群全般をシステムソフトウェアと呼んでいます

##### 2.5.4.2.1 - 物理装置など計算資源の管理や分配を行う
コンピュータは物理的にはCPUやメモリ、その他の入出力機器によって構成されていますがこれらの物理装置や計算資源を制御、連携させることで個々の物理装置全体を一つの計算システムとして成り立たせる役割をOSは担っています
またそういった計算資源を利用するアプリケーションやOS自身への適切な計算資源の割り当てや分配を行うことで複数のアプリケーションやOSを同時並行にかつ効率的に扱えるようにする役割も担っています
こうした機能や役割はマルチタスク、プロセス管理、割り込み、タスクスケジューリング、仮想化を含めたメモリ管理といったOSが備える機能を用いて実現されています

##### 2.5.4.2.2 - ハードウェアの抽象化および人間やアプリケーションがコンピュータを扱いやすくするためのインターフェースの提供や仲介を行う
コンピュータの生のハードウェアをそのまま扱おうとすると非常に煩雑なのですが、ユーザやアプリケーションから見て本質的な目的遂行において邪魔になる複雑で煩雑な詳細を隠蔽（カプセル化）し、コンピュータを使いやすくするための抽象化/単純化されたインターフェース（操作の窓口など）を提供するのもOSの役割の一つです
OSがない場合個々のアプリケーションやソフトウェア自身が演算装置や周辺機器の制御を行わないといけないのですが、OSはこれらの演算装置や周辺機器の制御を行う抽象化されたインターフェースを提供してくれています
つまりOSは生のままだと非常に扱いにくいコンピュータ自体の操作や制御を一挙に引き受けて、人間やアプリケーションが本質的な目的遂行に必要な作業に集中できるようにしてくれる存在だと言えます
アプリケーションはOSが提供するシステムコールといったインターフェースを利用することでOSに対してハードウェアの操作や処理を依頼し計算資源を簡単に利用できるようになっていたり、人間はOSが提供するCLI/GUIやウィンドウシステム、ファイルシステム等を介して簡単にコンピュータを操作することができるのです
OSやシステムソフトウェアは人間や全てのアプリケーションが必要とするコンピュータに対する基本的な機能を扱いやすいインターフェースで提供してくれる仲介者だと言えるでしょう

#### 2.5.4.3 - アプリケーションソフトウェア層
OSやシステムソフトウェア以外のソフトウェア、つまりアプリケーションソフトウェアが属する層
ようやくアプリケーションソフトウェアとは何か？の説明にたどり着けました
アプリケーションソフトウェアとは概念的/利用者的な観点から言えば
「ある特定の用途や目的のために使用されるソフトウェア」
のことです
OSやシステムソフトウェアがコンピュータ自体やハードウェアを制御したり、（人間やアプリケーションが）より扱いやすくするためのソフトウェアだとするとアプリケーションソフトウェアはその基盤の上で特定の用途や目的の達成のために使われるソフトウェアだと言えます
普段から馴染みのあるWebブラウザや音楽動画などのメディアプレイヤー、メモ帳などが分かりやすいですね
その他にもブラウザを介して使うことのできるwebアプリケーションなどもこれに当たります（GmailやGoogle Mapなど）

:::note info
#### 2.5.c.4 - コラム　ミドルウェア

<details>
<summary>補足を読む</summary>

上記の画像ではハードウェア層、OS層、アプリケーション層の3つだと簡単のために言いましたがOS層とアプリケーション層の間にミドルウェア層というものがあると考える場合も多いです
ミドルウェアとは簡単に言うと様々なアプリケーションが必要とする機能を提供するソフトウェアのことです
OSに組み込むほどではないが多くのアプリケーションから必要とされる機能をOSとアプリケーションの間に入って提供してくれるものです
代表的なものとしてはデータベースやwebサーバーなどがあります
</details>

:::

## 2.6 - プログラミングに含まれる作業

### 2.6.1 - 大まかな分類

本記事ではプログラミングを**アプリケーションソフトウェア/システムを作成する行為全般**と言いました
本節ではそれらについて少し具体的に見ていきましょう
アプリケーションプログラミング、システム開発で行われる作業や工程をまずはざっくり大きく分けると以下のように分類することができると思います
（※開発手法を問わずソフトウェアを作る上で必ず行うであろう作業を大まかに分けるという基準で以下のようにしています）

- ソフトウェアに対する要求/要件の分析や設計
どんなものを作り、作るものに何を求めるか
ソフトウェアアーキテクチャはどうするか
といったことを考える
- 実装
設計や仕様に基づいてソースコードを書いていく
- 制作物の評価
制作物が設計通り/意図した通りに動くか、バグがないかなどを確認する

どんな開発手法でプログラミングを行っていくにしても「まずどんなものを作るかを考え、実際に作って、出来上がったものを評価する」という大枠の流れは共通しているのではないでしょうか

:::note info
#### 2.6.c.1 - コラム　ソフトウェア開発手法

<details>
<summary>補足を読む</summary>

ソフトウェア開発手法とはソフトウェア開発をどのような作業工程、作業順序で行っていくかという開発方針のモデルやスタイルのことです
ソフトウェアの作り方に関する方針のことですね
ソフトウェア開発手法にはウォーターフォールやアジャイル、スパイラルなど様々なものがありますがどれが良い悪いではなく、それぞれに一長一短あり開発規模や体制、プロダクトに応じて適切なものを選択したりそれぞれを組み合わせた開発手法を採用することが大切です
例えばウォーターフォール開発は上から下に順に開発工程を進んでいき、実装段階以降で仕様変更を行うといった前工程に戻ることは基本的に悪しとされますが、前工程で固めたものを正として開発を行っていくため管理が大変な大規模開発などに向いていると言われます
アジャイルやスパイラルモデルなどは一連の開発工程を繰り返し行ったり開発の柔軟性や迅速性を重視した開発手法で、後からの機能の追加や仕様変更といった柔軟なソフトウェアの拡張や改善も積極的に受け入れて行っていくイメージです
が、トライアンドエラーや要件仕様の頻繁な変更を受け入れる分大規模開発よりも小規模開発に向いていると言われます
</details>

:::

### 2.6.2 - ウォーターフォールモデルに沿った細かな分類

プログラミングに含まれる作業や工程についてもう少し具体的に見るために、本記事ではウォーターフォールモデルに沿って各作業や工程について説明していきたいと思います
業務開発や個人開発、規模感や組織などによって細々とした部分は変わるかもしれませんが一般的に以下のような作業や工程が含まれるといえるでしょう

・要求/要件定義
・設計（基本設計や詳細設計）
・開発環境やアプリケーション実行環境の整備（環境構築）
・実装/コーディング
・テストおよび評価
・ビルド
・アプリケーションの配布やデプロイ
・運用保守

#### 2.6.2.1 - 要求/要件定義
そもそも何を作るか、作るものに対して何を求めるかを分析/考えて整理したりそれを仕様として策定していく工程です
アプリケーションやシステムに求める機能や仕様などを整理してまとめたり必要となる要素を固めますがこれを基にアプリケーションを作っていくことになるのでこの段階でどれだけ要求や要望を言語化していけるかが重要になります
開発期間や体制、各工程のスケジュールや納期といった部分もこの工程で策定していくことが多いでしょう
アプリケーションの設計や実装、評価は要件定義で決めたことを正としてこれに基づいて行っていきます
そのため基本的に最初の要件定義で固めた仕様から大きく逸脱した仕様変更を行うと設計や実装に大きな影響を及ぼすのでどんなサービスや機能を提供するのか、必要となるものはなにかを明確にしておくことが重要となります

料理で例えるとどんな料理を作るかといったそもそもの献立を考えたり、どんな人に食べてもらうかといったことを考える工程だと言えるでしょう
付け合せやサラダも提供するか、セットでライスやスープを付けられるオプションも提供するかといった粒度で大枠を固めていきます
最初にカレーを作ると決めていたのに開発がスタートしてからやっぱりステーキを作ろうというレベルの変更をすると大変なことになります
カレーの味付けや辛さを変えるといったレベルの変更なら対応可能かもしれませんがそもそも料理自体を変えてしまう場合はそれまでの工程で積み上げてきたものや費やしたコスト、労力を放棄することになると考えて良いです

#### 2.6.2.2 - 設計
要件定義で策定した要件や仕様を満たすアプリケーションを作っていくうえで、そのアプリケーションやシステムを具体的にどんな構造や構成要素（ソフトウェアアーキテクチャ）で作っていくか、構成要素たる各モジュールやコンポーネント自体の構造や関係性などを考えていく工程です
プログラム的にはクラス設計やAPI設計、データフローを含め実装に際してどのようなデザインパターンや方針で開発していくか、使用するライブラリやフレームワークの選定、各モジュール間のやり取りや凝集性、結合性、拡張性、保守性をどのようにするかといったことを考えていきます
画面などのUI、利用者の使い心地といったUXなどもこの段階で設計を行います
設計の良し悪しは作るものやその他条件で変わりますがこの段階で如何に適切な設計をできるかがその後の開発効率や保守性、拡張性といった部分を良くできるかの重要なカギになります

料理の例でカレーを出しましたがこの段階では具体的に使う具材の種類、作り方や味付け、どんな調理器具を用いるか、市販のお惣菜やルウを利用するかあるいは全部自前でやるかといったことを考えると例えられるのではないでしょうか
肉にチキンを使うのかビーフを使うのか、付け合せの野菜は何にするか、カレールウはジャワかバーモントかといった粒度で考えていきます

#### 2.6.2.3 - 開発環境やアプリケーション実行環境の整備（環境構築）
アプリケーションを作るにはアプリケーションを作るための道具やアプリケーションを動かすために必要なものを適切に揃えなければいけません
これらを揃えることを環境構築と言います

::: note info
#### 2.6.c.2 - コラム　環境とは

<details>
<summary>補足を読む</summary>

コンピュータやソフトウェアに慣れていない人からすると「環境」という言葉がピンとこないかもしれません
分かりやすいように例えてみます
家でカレーを作るとしましょう
そもそも「キッチン」がないといけませんし具材を切るためには「まな板」と「包丁」が必要です
また「コンロ」と「鍋」がないと切った具材を炒めたり煮ることができません
「エプロン」や「ミトン」といったキッチン用品があればより快適に料理をすることもできるでしょう
このように料理をする時には様々なものが必要になるのが分かりますよね
これら料理に必要なものが揃ったキッチンが環境にあたるというイメージです

ソフトウェア的な例を出すとJavaで作成されたアプリケーションはJVMという仮想マシン上で動くのですが、JVMを含めJavaアプリケーションの実行に必要なソフトウェア群をJava実行環境（JRE）と言い、パソコンでJavaアプリケーションを動かすにはJava実行環境をインストールする必要があります

環境という言葉の意味が最初はイマイチつかめないかもせしれませんが次第に体に馴染んでくると思います
</details>

:::

環境構築というとアプリケーションを動かすために必要なデータベースやwebサーバーといったミドルウェアやランタイムを揃えるといったイメージがありますがテキストエディタやVisual Studioのような統合開発環境といった開発に必要なツールなどを導入することも環境構築に含めることも多いかと思います
環境構築で躓くことが多い、苦手という方も少なくないかと思いますがそれは何故かと言うとネットワークやインフラ、コンピュータ自体に対する知見や理解が必要になる部分が多いからかと思います
例えばphpで作ったアプリケーションをweb|アプリケーションサーバーに配置する際、apacheなどのwebサーバーソフトウェアでドキュメントルートをどう指定するかといった設定を行わなければいけないかったり、DBサーバーへの接続先として適切なIPアドレスやポート番号を指定しなければいけなかったりと、ソースコードを書く以外の知識が必要になる場面に出くわすでしょう
最近ではdockerやawsといった便利で簡単に環境を整えられるプラットフォームやIaaSがあり開発環境や実行環境を整備する手間を大幅に削減できるようになっていますがそれらを扱う際にもやはり基礎的な知識が不足していると躓く場面が出てくるかもしれません
環境構築が苦手だという方は一度基礎に立ち返りコンピュータそのものを勉強し直してみると良いかもしれません

#### 2.6.2.4 - 実装/コーディング
要件定義で策定した要件や仕様、設計工程で策定した設計に基づいてソースコードを書いたりして実際にアプリケーションを作っていく工程です
実装段階では設計を基に仕様を実現するようにソースコードを書いていくことになります
チーム開発を行うような場合は特にコーディング規約に則ったコード作成、可読性や変更に対する柔軟性を意識したり関数やメソッドなどを単機能でできるだけ簡潔に記述したりすることが重要になってくるでしょう
なお「とりあえず一旦動けば良いや」という考えで雑に実装を行ったり、そうして書いたコードを放置したりするのはおすすめできません（自戒）
可読性が低かったり変更に対する柔軟性が低いコードは例え自分で書いたものでも扱いづらく実装が進むにつれて足を引っ張るようになりますし、そういったコードはバグの原因やトラブルの元になりやすいです
なので目の上のたんこぶになりそうなコードはできるだけ排除し、後々痛い目に遭わないように懸念の芽は早期から摘むように意識していきましょう
また、自分では問題ないように見えても人から見たらイマイチな場合もままあるためコードレビューを行ってもらうことも重要かと思います
余談ですがプログラミングといえばソースコードを書くという""THE""のイメージがある工程ですよね
しかし実装やコーディングが開発における最大の工程であるとは必ずしも限らないです
設計のほうが比重が大きく実装は思っていたよりもすんなり終わったといった場合もあるでしょう
適切な設計や要件定義が行われていれば比較的スムーズにコーディングができるのではないでしょうか

#### 2.6.2.5 - テストおよび評価
実装工程で作成したアプリケーションの動作が要件や仕様通りであるかどうかを本格的に確認する工程です
実装工程でもバグの修正や動作確認をしますがこちらの工程ではプログラムを構成する関数やメソッドといった小さな単位で行う単体テストやシステム全体として各モジュール間の連携も含めた結合テストなどを行い、よりユーザ的な観点からもアプリケーションの動作を確認します
実装段階からバグを出さないようにするのも重要ですがテスト工程ではあらゆる観点からバグの発生可能性を検証しできるだけ多くのバグを発見して修正することが重要になってきます

料理で言うなら味見をして目指した味になっているかを確認する工程です
当初目指していた味と違ったら塩を足したりもう少し加熱したりといった調整を行って目指していた味に近づける感じです

これまた余談ですがたまにテストを軽視したりテスト要員になりたくないといった人を見かけますがテストは非常に重要だと思います
経験が浅い内はテスト業務メインでプロジェクトに参画したりすることもあると思いますがテスト工程では要件や仕様を把握してアプリケーションの動作がそれに沿ったものになっているか、なっていなかったらどこがおかしいかを検証するというアプリケーション開発において重要なマインドセットを身に着けることができると思います
テスト工程で身につけたそうした経験は実装や設計等に参画するようになった際にも活きるでしょう

#### 2.6.2.6 - ビルド
テスト工程を終えてアプリケーションが運用要件を満たしたことを確認したら次はソースコードから実行可能なプログラム（実行ファイルや配布パッケージ、ライブラリなど）を作成するビルドを行います
PHPやPython等インタプリタが処理を行う言語では実行時に直接ソースコードを解釈するためプログラマが明示的にビルドという作業は行わないかもしれません
が、C#やJava、C/C++などソースコードをコンパイラが機械語に一括で変換する言語ではこのビルドという作業が必要になります
たいていの場合IDEなどを用いてビルド（実行ファイルやライブラリ等の生成）をおこなうのではないでしょうか

料理で言えば味見してオッケーサインが出たカレーを提供するためにお皿に盛り付けるといった感じの作業になります

##### 2.6.2.6.1 - コンパイルとリンク
なおビルドは簡単に言えばコンパイルとリンクをまとめて行う作業のことです
言語によってはビルドに含まれる細かい工程は異なってくるのですが大まかには以下のような流れになっています
ソースコード→コンパイル→リンク→実行ファイルやライブラリが出来上がる
以下ではそれぞれについて説明します

| 項目 | 説明 |
|:-:|:-:|
| コンパイラ | コンパイルを行うソフトウェアのこと |
| コンパイル | 1. ソースコードから実行ファイルを生成する<br>2. あるいは中間ファイル（オブジェクトファイル）を生成する<br>処理のこと<br><br>1は一つのソースファイルのみで実行ファイルが生成できる場合なので実際は2に該当するケースが多いのではないでしょうか<br>中間ファイルとはコンパイラがソースコードを変換した機械語バイナリコードを含むファイルですが参照している他の中間ファイルやライブラリ等必要なモジュールへのリンクは行っていない中間的な状態のファイルのことです<br>中間ファイルの状態ではまだプログラムとして実行することはできないため他の中間ファイルやライブラリとのリンク（後述）を行って最終的な実行ファイルを生成する必要があります |
| リンカ | リンクを行うソフトウェアのこと |
| リンク | 中間ファイルやライブラリなどプログラムの断片を結合して最終的な実行ファイルを生成する処理のこと<br>リンクには後述する静的リンク、動的リンク、動的ロードといったものがあります<br> |
| 静的リンク | リンク時に、実行ファイルが必要とする中間ファイルやライブラリに含まれるプログラムを一つの実行ファイルに組み込むリンク方式のことです<br>全ての中間ファイルやライブラリを静的リンクすればアプリケーションの実行時には実行ファイルのみあればアプリケーションを動かすことができます<br>静的リンクをした場合実行ファイルに中間ファイルやライブラリのプログラム実態が組み込まれることになるためその分実行ファイルのサイズは大きくなります |
| 動的リンク | リンク時に、実行ファイルが必要とする中間ファイルやライブラリに含まれるプログラムへの参照を名前で解決し、それらが含むプログラムを実行時にリンクするリンク方式のこと<br>アプリケーションの実行時にリンクされるライブラリのことを動的ライブラリと言います<br>動的リンクを行った場合ライブラリのプログラム実態は動的ライブラリが持ち実行ファイル自体は持たないため実行ファイルのサイズを小さくすることができます<br>また動的リンクを行った場合は実行ファイルとライブラリの再リンクを行わずとも動的ライブラリを入れ替えるだけでアプリケーションの動作を変更することができます |
| 動的ロード | 動的ライブラリのリンクをアプリケーション実行中の任意のタイミングで行うこと<br>動的ロードはアプリケーションのソースコード中でプログラマが明示的に行う必要がある |

なおC#やJavaなどで作ったアプリケーションは仮想マシン上など独自の実行環境で動作するため言語特有の中間コードに変換した後それらの実行環境に合わせて機械語に翻訳されて実行されることになります
またC/C++のマクロはコンパイル前のプリプロセスでコードの置換処理が行われます

#### 2.6.2.7 - アプリケーションの配布やデプロイ
ビルドしたアプリケーションのパッケージを配布したり実行環境にデプロイする工程です
料理で言うなら出来上がった料理を実際に提供する段階です
クライアントのPCで動かしてもらう場合は実行ファイルや必要なライブラリモジュールなどをまとめたパッケージを配布することになるでしょう
サーバ上で動かすwebアプリケーションなどは必要な実行環境を揃えたサーバに配置し、これをデプロイすると言ったりします
前者の場合はexeなどの実行ファイルとビルド時に生成された関連ファイルをまとめて配布すれば良いので比較的イメージしやすいかと思います
webアプリケーションの場合はwebサーバやDBサーバといった他のミドルウェアとの接続設定を行う必要があるなどある程度知識がないとつまりやすいかもしれません

#### 2.6.2.8 - 運用保守
アプリケーションをリリースして晴れて運用を開始しても出してはいそれで終わり、という場合はあまり多くないでしょう
ユーザからのフィードバックを反映したり発見されたバグの修正を行ったりという保守を行う必要も出てきます
特に商業的なサービスとしてアプリケーションを運用していく場合は定期的なアップデートが行われていきます

## 2.7 - アプリケーションやソフトウェアが動く仕組み
これまでの節では
「プログラミングとは何か？」
「コンピュータとは何か？」
「アプリケーションとは何か？」
といったことを説明してきました
これまでの節を読んでもらって
「**コンピュータのハードウェアをOSが管理制御してくれていて、そのOSの力を借りてアプリケーションは動いているんだ**」
ということがなんとなくでも分かっていただけていれば幸いです

さて、この理解が得られたうえで
「ではもう少し具体的にアプリケーションが動く仕組みはどんなものなんだろう？」
という疑問が湧いてくるかもしれません
本節ではそれについて説明していこうかと思います

### 2.7.1 - ちゃんと理解するには基礎知識が必要

まず最初に断っておきたいのですが、アプリケーションが動く仕組みをちゃんと理解しようと思ったらコンピュータに対する理解を得ることが極めて重要であり、コンピュータに対する理解を得るにはハードウェアとOSに関する理解を深めることが重要になります
何故なら**アプリケーションの動作はOSが提供する機能や仕組みに強く依存しており、またOSもハードウェアに依存しているから**です
アプリケーションはハードウェアやOSという土台の上で動くのである意味当たり前かもしれませんね
いわゆる低レイヤ（ハードウェアやOS）のことが良く分かっていないままアプリケーションが動く仕組みを理解しようと思ってもハードウェアやOSに関する霧がかったイメージを基にした中途半端な理解しか得られないと思います
結局基礎をしっかり学ぶことが一番の近道だと言う訳ですね
逆に言えばハードウェアやOSなど低レイヤの理解を深めればアプリケーションに対する理解も自然と深まり、コンピュータサイエンスにおける様々なトピックの理解も捗るようになると思います
本節ではそうしたことを前提とした上で簡単にアプリケーションが動く仕組みを説明してみようと思います

### 2.7.2 - アプリケーションが動く仕組みの大枠

さて、アプリケーションが動作する大枠の流れは以下のようになります
1. HDDやSSDなどのストレージ(補助記憶装置)からメインメモリ(主記憶装置)にアプリケーションのプログラムやデータをロードする
1. 入力や操作に応じてメモリを使いながらプロセッサで処理を行う
1. 処理結果を画面等に出力したり補助記憶に保存する
1. （2, 3の繰り返し）
1. アプリケーションを終了したらメインメモリからプログラムをアンロードする

ではそれぞれについてもう少し深堀りしてみましょう

#### 2.7.2.1 - 補助記憶から主記憶
我々がアプリケーションを起動して使うといった場合、動作しているプログラムやデータの実態はメインメモリに存在します
バックグラウンドで動いているものやコンピュータ起動時に自動的に起動されるようなものも同じく実際に動作しているプログラムの実態はメインメモリに存在します
「アプリケーションはSSDやHDDといったストレージにあるんじゃないの？」
と疑問に思うかもしれません

この疑問に対して端的に答えを言えば
「現在一般的に使われているコンピュータでは補助記憶装置(ストレージ)に保存したアプリケーションのプログラムやデータを主記憶装置(メインメモリ)に読み込み、プロセッサ(CPU)はメインメモリ上にあるそれらプログラムやデータを用いてアプリケーションを動作させている」
となります

なぜこのような仕組みになっているのかを主記憶と補助記憶の特徴に触れながら説明しましょう
まずそれぞれの特徴は以下のようになります

| 項目 | 特徴 |
|:-:|:-:|
| 主記憶装置<br>（メインメモリ） | プロセッサから比較的高速にアクセスすることができる<br>揮発性(コンピュータの電源を落とすと内容が失われる)<br>高速だが価格が高い |
| 補助記憶装置<br>（HDDやSSDといったストレージ） | プロセッサからのアクセスはメインメモリ等に比べると遅い<br>不揮発性(コンピュータの電源を落としても内容が失われない)<br>メインメモリより遅いが価格は比較して安価 |

上記のように主記憶装置は高速なのでプロセッサが扱う一時記憶領域として使用するのに向いていますが、価格が高いため容量を多く積むのが厳しくかつ電源を落とすとデータが消えてしまうためデータの保存には向いていません
そうした欠点を補うために不揮発性かつ価格が比較して安価で多くの容量を確保しやすい補助記憶装置をデータの保管場所(ストレージ)として使用し、アプリケーションを実際に使う時にこの補助記憶装置に保存したプログラムやデータを主記憶装置に読み込んで使うといった設計が一般的に採用されています
よくされる例え方としてストレージは本棚、メモリは机で本を読んだり実際に作業する時になったら本棚から本を取り出して机に本を置いて作業をするといったものがありますね
要は価格と速度、データの揮発性に関する特徴に応じて記憶装置を分け、適材適所で併用するのがベターなためこうした仕組みになっているといった感じです
なお本記事では深く踏み込みませんがコンピュータの記憶階層にはプロセッサのレジスタ、キャッシュメモリなどもう少し様々な登場人物が出てきます
また最近ではストレージにSSDを積むのが一般的になり、ストレージアクセスを高速化する技術も段々と普及し始めてきていてワクワクすることが増えてきましたね（NVMe接続やWindowsのDirectStorage、PS5のSSD最適化技術など）

#### 2.7.2.2 ,3 ,4 - プロセッサとメモリと処理
実際に動作しているアプリケーションのプログラムやデータの実態はメインメモリに置かれていると言いました
ユーザなどからのアプリケーションに対する入力や操作を受けて、メインメモリ上にあるそれらプログラムやデータの実態に対する操作はプロセッサ(CPU)が行います
プロセッサが命令を実行する過程の一時的なデータや操作結果なども（プロセッサが持つレジスタも使いつつ）メインメモリに置かれ、必要とあらばメインメモリの内容を補助記憶に保存するといったことも行います
アプリケーションやソフトウェアが動く仕組みのキモとなるのは正にこの部分ではないでしょうか
プロセッサはそのアプリケーションプログラムに含まれる命令を逐次実行し、次の命令を取り出し、といったことを繰り返すことでアプリケーションの動作を実現しているのです
ここら辺の話をちゃんと理解しようと思ったら以下のトピックについて触れざるを得ず本記事で説明しきることはできません
そのため本記事での説明はここまでとし、詳しくは後述するおすすめの本等で学習していただければと思います
※OSとハードウェアで分けていますが横断的に説明されるものもあるため厳密な分類というよりは目安として考えてもらえると幸いです
OS：プロセス/スレッド管理、マルチタスク、スケジューリング、コンテキストスイッチ、CPUモード、システムコール、メモリ管理、仮想記憶、ページング、割り込み、ファイルシステム
ハードウェア：物理記憶、プロセッサのレジスタ、キャッシュメモリ、メモリ管理ユニット(MMU)、命令セットアーキテクチャ、ノイマン型アーキテクチャ、プログラム内蔵方式

### 2.7.2.5 - プログラムの破棄
これは題名通りですね
アプリケーションを終了するとプログラムやデータの実態はメインメモリから破棄されます

## 2.8 - ネットワークの基礎を学ぶことの重要性について
ここまでの内容ではコンピュータそのものに対する理解の重要性について説いてきました
これまでに紹介した内容が自身の血肉となり有機的に扱える知識や知見となればコンピュータの分野を自力で戦っていけるようになると思います
そうなったら次にネットワークの基礎について学習することを強くおすすめします
後述のおすすめ書籍や教材等の節でも紹介しますが、言わずもがな我々はネットワーク（インターネット）を通じて様々なサービスを利用したり他者とやり取りしており、開発者視点から考えてもネットワークと通信の仕組みに対する知見は不可欠だからです
本記事でここまで紹介してきた、コンピュータそのものについての理解が深まっていればネットワークの基礎を扱う入門書等を読むのにそれほど苦労しないかと思います
というかむしろこういう仕組みで実現されているんだ、という発見があって楽しいものとなるでしょう

# 3 - おすすめ書籍や教材等
さて、最後に筆者がこれまで読んできたおすすめの書籍や教材などを紹介して本記事を締めていきたいと思います
以下のものを全て吸収しようと思ったら相応の時間と労力がかかりますがそれらを費やすに足る強固な知識と知見を得ることができると思います

## 3.1 - 入門/取っ掛かり
- **コンピュータ、どうやってつくったんですか？　はじめて学ぶ、コンピュータの歴史としくみ - 東京書籍 - 川添愛**
2進数値を使った計算を行う仕組みや論理回路、コンピュータハードウェアの触りなどを程よい浅さとカジュアルさで説明してくれる本です
計算やコンピュータの歴史にも触れつつ現代のコンピュータの仕組みがどういった必要や経緯に基づいて進化していったのかといったことにも触れるため現代のコンピュータのアーキテクチャがどうして今のような形に落ち着いていったのかという理由もなんとなく知ることができ、またそういった観点を知ることもできます
本書の各トピックについての説明は良い意味で浅いため他の本を読む前に読んでおくと後々の学習をスムーズに行えるようになるのではないかと感じています
なおCPUなど一部説明が回りくどいように感じられるかもしれませんがCSの知識が無い読者を前提としているためこれはある程度仕方ないでしょう

- **キタミ式イラストIT塾 基本情報技術者 - 技術評論社 - きたみりゅうじ**
筆者が読んだ基本情報技術者試験の資格本です
本書はタイトル通りイラストが多めでコンピュータサイエンスに関する様々なトピックを網羅的に把握するのにちょうど良いかと思います
ただし各トピックの関連性を掴んだり、コンピュータの各トピックに対する横断的かつ有機的な知見や理解を深めるのにはあまり向いていないかなと思いました
あくまでコンピュータサイエンスにはどんなトピックがあるのかを知る、それらトピックの知識の点を少し大きくする（点と点は後から繋いで線にする）といったことを前提にして読むと良いでしょう
正直基本情報技術者試験の資格本なら類似の本でも良いかもしれません
余談ですがたまに基本情報は取っても意味がないといった言説を見かけますよね
たしかに資格取得するためだけに勉強していった場合実開発に活かせる知見や知識は身につかないかもしれません
しかし基本情報技術者試験はCSに関する基本的な内容を網羅的に問うものであるため一夜漬けや小手先のテクニックではなく自身の血肉となった知識や知見でこの資格が取れるレベルになればそれは十分に価値のあるものだと私は思います
実際基本情報で扱われる内容に対する有機的な理解を得ていればそれは実開発に十分活用できる、というかむしろそうした有機的な知見や理解が無いと色々困ったり壁にぶつかった時に自身で乗り越えることができないのではないかと思います

## 3.2 - ハードウェア
- **コンピュータシステムの理論と実装 ―モダンなコンピュータの作り方 - オライリージャパン - Noam Nisan (著), Shimon Schocken (著), 斎藤 康毅 (翻訳)**
開発者には言わずと知れた天下のオライリーが出すいわゆるnand2tetris本ですね
本書ではNANDゲートと呼ばれる論理回路の最小部品からCPUやメモリといったハードウェアを作り、簡易的なOSやアセンブラ、コンパイラといった言語処理系と高水準言語も作り、その言語を使ってこれまた自作した仮想マシン上でアプリケーションを動かそうという、見ただけでお腹いっぱいになりそうな非常に歯ごたえのある全部乗せな内容が学べます
正直内容もボリュームも重厚長大で中々骨の折れるものですが実際に自分で手を動かしてコンピュータを作っていくため本書の内容を実施していけばコンピュータに対する有機的な理解を得られることは間違いありません
またハードウェア層からアプリケーション層に向かっていくボトムアップ方式でコンピュータを学んでいくので普段は上位層に対して隠蔽されている低レイヤの詳細も理解しながら進めていけるため分かりやすいです
本書で扱う内容を簡単に整理すると以下のような感じです
論理ゲート（ANDやORといった基本的な論理ゲート）→論理回路（加算器、ALU、レジスタなど）→ハードウェアコンポーネント（CPUやメモリ）→CPU命令セットやコンピュータアーキテクチャ→アセンブラ→仮想マシン→高水準言語とコンパイラ→簡易的なOS→アプリケーション
本書にはnand2tetrisというフォーラムサイトがあり詰まったときには各章に対応したソースコードなどをダウンロードできたり質問が見れたりとそういったところも充実しています
nand2tetrisと謳ってるのに実際に作るのはpongというところもウケポイントです
ただしハードウェアより上のレイヤについてはそれぞれにより特化した別の本を追加で読むことをおすすめします
特にOSは簡易な作りで現代のOSで一般的なマルチタスク/プロセス管理、タスクスケジューリングやコンテキストスイッチ、割り込みといったトピックについては学べません
とはいえコンピュータを全部自分でイチから作り上げていくという経験は非常に素晴らしい糧になりますので本書は必読レベルでおすすめします

- **コンピュータアーキテクチャのエッセンス - 翔泳社 - Douglas E. Comer (著), 吉川 邦夫 (翻訳)**
こちらはハンズオン形式ではありませんが、ソフトウェア開発者が頭に入れておくべきハードウェアやコンピュータアーキテクチャのトピックやその詳細を分かりやすく解説してくれる良著です
本書のコンセプトはそれらの概念やエッセンスを学ぶことでありソフトウェア開発者からすると過分な技術的詳細には立ち入らない丁度良い塩梅になっています
本書ではプロセッサ（CPU）、メインメモリ、I/Oといったコンピュータの中核を成す要素をハードウェア的な側面から着目して、現代のコンピュータを理解するのに欠かせない要点となる技術の詳細を学ぶことができます
上述のコンピュータシステムの理論と実装では深入りしなかったプロセッサの詳細、割り込み、キャッシュメモリの存在やメモリの仮想化といったことについても様々深堀りして触れるので本書まで合わせてハードウェアの知識を学べばソフトウェア開発者としては十分な知見を手に入れることができると思います
ただしコンピュータを理解するためにはハードウェアだけでなくOSの理解も不可欠だと思うので次はOSの本も読むことを念頭に置いておきましょう
なお本書はハードウェアをメインに解説していますが各ハードウェアに関連のあるOSの機能や並列処理、パイプライン処理などについても触れているためより知見を広げられるかと思います

## 3.3 - OS
- **ゼロからのOS自作入門 - マイナビ出版 - 内田 公太**
表紙がミカンであり作るOSの名前もmikanOSであることからミカン本と呼ばれております
本書は題名通り現代的な機能を備えるOSを、実際に作ることを通して学ぶことができます
Linuxのディストリビューションを作るとかではなくUnix系っぽいOSをC/C++を用いてほんとにゼロから実装していきます
ブートローダーとUEFI BIOSを作ってOSをメモリにロードして立ち上げるところからやるほど気合が入ってます（実機で動かすかwsl等の環境上でハードウェアシミュレーターを用いて動かすかといったことも選べます）
上述のように本書を通じては以下に挙げる現代の一般的なOSに備わる機能を実装していくことで学ぶことがてきます
    - カーネル
    - プリエンプティブ（割り込み駆動）マルチタスク
    - プロセス管理
    - タスクスケジューリング
    - コンテキストスイッチ
    - タイマ
    - ファイルシステム
    - CPUモード
    - システムコール
    - ウィンドウシステム
    - メモリ管理と仮想記憶
    - デマンドページング

デバイスドライバは作者が用意したものを用い、また言語処理系の実装等は行いません
実際に手を動かしながらOSについて学ぶことができるため本書の内容を実施していけばOSに対する理解を深め有機的に活用できる知識と知見を得られることは間違いありません、非常におすすめです

- **工学基礎シリーズ オペレーティングシステムの仕組み - オーム社 - 安倍 広多 (著), 石橋 勇人 (著), 佐藤 隆士 (著), 松浦 敏雄 (著), 松林 弘治 (著), 吉田 久 (著)**
こちらはハンズオン形式ではありませんがOSに関する様々なトピックの要点を体系的に説明してくれている本です
初版が2022年出版という比較的新しい本なので最近の技術との関連も含めてOSについて学ぶことができます
上記のミカン本をやった後に本書を読むことでOSの知識をおさらいしつつ体系的に整理することができるでしょう
1~6章はOSの基本的な要素に関しての説明を、7章でUnix系OSについて、8章でWindowsについて、9章でコンピュータやOSの仮想化について説明をしてくれており特に7章以降の内容は各トピックの知見を頭に入れるには丁度良い内容になっているなと感じました

- **オペレーティングシステムの仕組み - 朝倉書店 - 河野 健二**
上記の「工学基礎シリーズ オペレーティングシステムの仕組み」と大方の内容は被りますがこちらの方がボリュームも少なく説明もサラッとしているのでサクサクおさらいしたい場合はこちらもおすすめです
本書の8章ではネットワーク、9章ではセキュリティについての説明がされておりそれぞれの触りを頭に入れるには丁度良いかと思います（なお10章ではWindowsについて触れています）

## 3.4 - ネットワーク
- **ネットワークがよくわかる教科書 - SBクリエイティブ - 福永 勇二**
コンピュータそのものについての理解と知見が十分身についてきたら次はネットワークについても勉強しておきたいです
言わずもがな我々はネットワーク（インターネット）を通じて様々なサービスを利用したり他者とやり取りしており、開発者視点から考えてもネットワークと通信の仕組みに対する知見は不可欠だからです（大事なことなので2回言いました）
本書はコンピュータやスマートフォン、ネットワーク機器がネットワークを通じて通信を行う仕組みを本当に分かりやすく解説してくれている良著です
イーサネットやLAN（有線/無線）、IPアドレスとポート番号、TCP/IPやHTTPといった通信プロトコル、公開鍵暗号やSSL/TLSを用いた通信の暗号化などなど、ネットワークの文脈でよく聞くキーワードは大体説明がなされているため本書を読めばネットワークに関して抑えておきたい基本を頭に入れられること間違いなしです
自分はこの本を読んで感動したレベルで分かりやすかったです

## 3.5 - 数学
エンジニアとして開発を行っていくうえで基礎的な数学の素養を持っておくのは割と大事かなと個人的には感じています
直接数式を扱ったりするかどうかは開発分野によると思いますが数学の知見や数学的な考え方を利用して物事を考えたり分析したりするといったことは開発する時に意識しないレベルの自然さで行っていると思います
ひとまず高校卒業程度の数学の素養があればとりあえずOK、大学初等レベル以降の素養があればより開発に活かせるものとなるのではないでしょうか

- **新体系　中学数学の教科書上/下 - 講談社 - 芳沢 光雄**
中学数学からやり直す場合はコンパクトでありながら必要十分な内容を解説してくれている本書上下巻がおすすめです
平易な説明で読みやすいですし過不足なくサクサク学びなおすのにはベストだと思います
学生の時数式の解き方だけ覚えていて関数とは何か？方程式とは何か？方程式の解とは何か？といった概念そのものを理解していなかったような人（自分です）に向けてそういったものの説明からしてくれているため「そういうことだったのか！」と再発見できる楽しさも得られるでしょう

- **新体系　高校数学の教科書上/下 - 講談社 - 芳沢 光雄**
上記と同著者の高校数学版です
こちらも上記説明同様とても読みやすくおすすめです

- **新装版　数学読本シリーズ（1～6） - 岩波書店 - 松坂 和夫**
中学～高校数学の全範囲を網羅的に広く深く扱い大学での数学学習を見据えた解説をしてくれているシリーズです
平易で過不足のない説明で教科書のように無駄のないある意味数学らしい文調で解説してくれています
個人的には純粋数学的な見地に基づいて執筆されたのかなという印象を覚えました
1冊辺り200~300ページ程度あり内容もとても歯ごたえがありますので全シリーズをやりきるのはかなり大変かと思いますがこのシリーズで数学を学びなおせば数学の知見を強固なものにできることは間違いないでしょう

## 3.6 - 英語
- **一億人の英文法 ――すべての日本人に贈る「話すため」の英文法 - 東進ブックス - 大西 泰斗 (著), ポール・マクベイ (著)**
プログラムはそもそも英語で書くだけじゃなく使用する技術のドキュメントを読んだりStackoverflow等のサイトで英語の情報に触れる（触れざるを得ない）機会は少なくないでしょう
英語の読み書きができて英語の1次情報に直接あたることができ、ある程度理解できることの恩恵は非常に非常に大きいと感じています
それができるレベルの英語理解力を身に着けるには英文法を学ぶのがおすすめです
英語は文の中の品詞（名詞や動詞、形容詞といった単語の種類）の配置場所や語順、文型、文の構造がある程度規則的で、基本的には4つの基本文型をベースに文が構成されています
4つの基本文型とは中学高校で習った「主語+動詞+目的語（SVO）」「主語+動詞（SV）」「主語+動詞+説明語句（SVC）」「主語+動詞+目的語+目的語（SVOO）」などのことですね（SVOCを加えて5文型としている場合も多いでしょうが本書に準じて4文型としています）
本書冒頭で解説されていますが英語は語句の配置と文全体の意味の結びつきが強い配置の言葉なのです
英語の文の構造やルール、考え方に慣れれば英語原文の内容もある程度読み取ることはできるようになると思います
英語の基礎力が身についていればGoogle翻訳等を使って翻訳した時も翻訳された文章のニュアンスが原文から大きく逸脱していないかといったことも確認することができるようになります
ちなみに学校の教科書のような味気ない説明ではなく読者に寄り添った分かりやすく読みやすい説明、面白い文調も本書の良い点だと思います
義務境域では説明がなされなかった語句や英語の持つニュアンスや雰囲気、考え方などについても説明してくれているので「そういうことだったのか！」という気づきも得られる楽しい本だと思います

# 4 - まとめ

いかがだったでしょうか？（定期）
気づけば中々ボリューミーな記事となってしまいましたが今自分が出せる最大限の内容にできたかなと思います
重ねてになりますが本記事を通して読んでくださった皆様が何かしらを得ていただけたならとてもとても嬉しいです！
それでは良き開発者ライフを！