大学でコンピュータ科学を学びながら、個人でアプリやフロントを書き続けた結果得られたもの

![Second-title.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10943/3b47cab7-9b75-e499-5eee-da8c31a35ae0.png)

## 0. はじめに

こんにちは、とうようと言います。
普段は東大大学院のコンピュータ科学専攻の学生をしていたり、Life is Tech !というところで中高生にiOS開発などを教えたり、個人や受託の形でiOS/AndroidアプリやReact.jsを使ったWebサービスを作ったりしています。

今回のアドベントカレンダーは「[プログラミング技術の変化で得られた知見・苦労話](https://qiita.com/advent-calendar/2020/pasonatech-experience)」がテーマということで、少し変化球ではありますが、大学で情報科学・コンピュータ科学の古典的な知識を学びながら、個人の活動で最新の技術を追い続けるようなスタイルをとっていた大学生活で何が得られたのか、どんなことが良かったのかということをポエムにしていこうと思います。

今の中高生というと、一部の物好きがプログラミングをしていた僕の中高生時代からだいぶ進んできて、企業でインターンしたり、自分で起業できるぐらいのコーディング力をすでに現段階で身につけている子がゴロゴロいるような世代になってきています。
そんな子達の進路相談なども時々受けたりするのですが、その際よく観点として上がるのが**「大学に行くべきなのかどうか？」**という点です。

もちろんこの質問自体にはいろんな観点がありますし、そもそもコンピュータ科学を大学で学ぶべきか、後から興味がわいた時に自分で学べばいいのでは？みたいな話もあったりするので、一概には言えないのですが、そういう中高生たちやこれからコンピュータ科学を独学しようかと思っているエンジニアのみなさんの参考になるのではないかと思い今回の記事を書くことに決めました。

前置きが長くなってしまいましたが、最後に大前提として僕のスペックを箇条書きにしておくので「このくらいのレベル感の人が得られた知見」だと割り切って、少しでも参考にしてもらえればと思います。

- 大学の専門科目のテストは総合して際立っていいわけでもめちゃくちゃ悪いわけでもなかった。落単は基本的にしていなかったが、定着度もそこそこぐらいだった。
- iOSアプリ開発は個人でいくつかリリースしたのと、受託の手伝いやサマーインターンをこなしたぐらい。ただし教える立場上ある程度最新の情報は追っていたり、学生の中ではそれなりに技術力があるという程度のレベル感。
- Webフロントについては研究プロトタイプや、先日リリースされたオンライン劇場zaでNext.jsを活用していたというぐらい。そこまでちゃんと最新技術を追えているわけではないが基本不自由なく書けるぐらいのレベル感。
- プログラミング自体は中高生からやっていて、そのころは競技プログラミングを主にやっていた。

## 1. コンピュータ科学って結局何を学ぶの？

まずはじめに、どんなことを学ぶのかの全体像がわかってないと今後の話もあやふやになると思うのでまずはそこから行きたいと思います。

というわけで今回は自分の成績表から科目名をざっくり引っ張り出してきてみました。一部選択科目などもあるので一概にこれがコンピュータ科学の科目です！とは言い切れないのですが、東京大学理学部情報科学科・東京大学大学院情報理工学系研究科コンピュータ科学専攻で学べるシラバスの一例としてみてもらえればと思います。

それではドン！

|科目名|簡易説明|
|:--:|:--|
|情報数学|情報分野で扱うような数学、符号理論とか群環体あたりの話|
|形式言語理論|オートマトンとか正規言語とか|
|計算機システム|計算機の仕組み、アセンブリの知識など|
|ハードウェア構成法|ASICや論理回路設計の話|
|アルゴリズムとデータ構造|基本的なアルゴリズムを学ぶ|
|情報科学基礎実験|C,Scheme,アセンブリで色々実装してプログラミングの基礎を叩き込む|
|コンピュータグラフィクス論|CGの仕組み学んだり、実際に実装したり|
|オペレーティングシステム|OSの仕組みを実習もしながら学ぶ|
|離散数学|グラフ理論、線形計画法とか|
|情報論理|一階述語論理とか、不完全性定理とか|
|言語処理系論|言語処理系を構築する理論とか構文解析について|
|情報科学演習I|離散数学と情報論理の問題を解いていく|
|知能システム論|人工知能の基本的なこと|
|計算機構成論|計算機アーキテクチャについて、特定のCPUについて調べて発表したり|
|言語モデル論|プログラミング言語のモデル、意味論、型推論のこととか|
|計算量理論|チューリングマシンやNP完全、近似アルゴリズムについて学ぶ|
|連続系アルゴリズム|浮動小数点や数値積分などを扱うアルゴリズム周りのあれこれ|
|情報科学演習II|計算量理論、連続系アルゴリズムの問題を解く|
|コンピュータネットワーク|インターネットの仕組みなどを学ぶ|
|システムプログラミング実験|Linuxをいじったりシェルを作ったりする演習|
|関数・論理型プログラミング実験|関数型言語を学ぶ、PrologとかOCamlとか|
|ハードウエア実験|VHDLを使って論理回路とかを実装|
|プロセッサ・コンパイラ実験|FPGAを使って3~4人チームでCPU,コンパイラ,シミュレーターなどを分担して作り、レイトレーシングプログラムを動かすことを目指す|
|ユーザーインターフェイス|ユーザーインターフェイスの歴史を学び、課題に応じてユーザーインターフェイスを実装|
|計算アルゴリズム論|数値積分や偏微分方程式の数値解法について|
|離散アルゴリズム論|離散アルゴリズム（確率を使ったものや量子系）について|
|計算科学シミュレーション|HPCについて学び、HPC向けのアルゴリズムなどについて学ぶ|
|計算機言語論|コンパイラとかの理論の発展|
|自然計算|自然科学が関わるようなアルゴリズムなどについて、セルオートマトンとか|
|量子計算科学|量子コンピュータとかで扱われるもろもろについて|
|知識処理論|機械学習の授業|
|統計的機械学習|機械学習の中でも統計で扱うようなものについて|
|メディア情報学|ユーザーインターフェイスの論文を輪講した後、最後に題材を使って面白いものを作る|
|配列解析アルゴリズム特論|配列を扱うようなアルゴリズムに関して|

言っても大学と大学院の4年半のカリキュラムの中で行われている授業の一覧なので多少端折ったとはいえ量は結構多いですね。
このように一般的なプログラミングや普段使っているパーソナルコンピュータの仕組みはもちろんのこと、アルゴリズム一つとっても通常のCPU、HPC、量子コンピュータそれぞれに向けたものを各科目で学んでいたりと、**古典となる理論から最新の機械学習事情まで幅広く学ぶのが情報科学・コンピュータ科学を「アカデミックで」学ぶということ**になります。

なおここではこのざっくり説明以上のことは本筋からも逸れてしまうので語りません。もっと詳しく知りたい方は[学科のHP](https://www.is.s.u-tokyo.ac.jp/index.php)で色々みてみてください。

![Old-to-new.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10943/fbb8232a-339b-8ca4-1620-f98616e74595.png)


## 2. 大学の知識が役立った瞬間5選

ざっくり説明でどんなことをやっているかさらってもらったところで続いて大学で学んだことが役立った瞬間をいくつか例にあげていきたいと思います。

### Case 1: 関数型の気持ちがわかった瞬間

まず1つ目は**関数型の気持ちがわかった瞬間**です。このこと自体は関数型が好きな人からしてみれば別に大学でやらなくてもというところだと思いますが、大学では関数型言語をただ学ぶだけでなくその仕組みや背景などもいろんな科目を通して学ぶことになります。

そのため中高時代は競技プログラミングメインで命令型に慣れていて、なかなか関数型を使いこなすレベルまで行けていなかった自分でも**関数型の気持ちがわかってきて、SwiftやTypeScriptを書くときも関数型的な機能を自然に使いこなせるようになりました。**

### Case 2: 自分のする解説・理解に厚みが出た瞬間

次は**自分のする解説・理解に厚みが出た瞬間**です。例えばプログラミング言語のほとんどが配列を0-indexedで扱うようにしているということ自体は有名な話ですが、これを初学者に説明する場合みなさんならどのように解説するでしょうか？

普通に考えると「そういうふうになってるから注意してね」というようなワンポイント解説的なものに留まってしまうことが多いのではないでしょうか？
ですが僕はこれに関してちょうどOSやらシェルやらを扱っている授業を通して次のような気付きを得ました。

>「Cの配列とポインタって同じように扱えるよな、array[3]とarray + 3が同じ意味になると考えると0-indexedになるのは確かに自然な実装だよな」

さらに

>「ポインタってことはこれはメモリ上でのアドレスを示しているよな、配列の先頭のアドレスを配列の名前で表せるとして、そこから連続して値が入ってるわけだから配列のsubscriptにどのくらいアドレスをずらすと目的の値がみれるのか渡せば目的の値を取り出すのに一番必要な論理演算少なく取り出せるよな、だから1-indexedにはしないのか」

みたいな。（※ 個人での気づきなので本当にこう考えて設計されたという証拠はあまりないです）

もちろんこれをそのまんま解説しても基礎がわかっていない人には何の話じゃという感じになってしまいますが、ある程度理解してきたときに「実は...」的な感じで話せばプログラミングっておもしろい！って思ってもらえる一つのきっかけ程度にはなるんじゃないでしょうか。
このように**多角的にコンピュータのことを学んでいるからこその気付きが出てくる**のがアカデミックに学ぶ利点の大きなところかなと思っています。

### Case 3: 知見のない分野に「こうすればいいのでは力」を発揮できた瞬間

3つ目は**知見のない分野に「こうすればいいのでは力」を発揮できた瞬間**です。
IT技術って本当に多岐に渡りますよね。そんな中一つの分野について極めてくるとその分野の新しい技術や仕組みに出会ったときに「こうすればうまくいくんじゃないか？」みたいな予感が働くことってあるんじゃないでしょうか。

こういう力っていうのは通常、自分が深く関わっている分野に何かしら関連がないと働かないものだと思いますが、アカデミックなコンピュータ科学では広範囲に手を広げているので、かなりの範囲でその力を働かせることができるようになります。
これはもちろんその分野をかじっていて、そこまで覚えてなくても記憶の片隅に何か残ってるから、というのもありますが、もっと大きな要因としては**各分野のつながりをわかっているから**というものがあるのではないかなと思っています。

だからこそ自分の引き出しの中からこれに当てはめれば似たようなやり方でできそう、がかなりの広範囲でできるということです。あくまで個人的な感覚でしかないですが、おそらくこのおかげでかなりフルスタックにカバーできる技術力を身につけられたのではないかなと思います。

### Case 4. 曲芸のようなデバッグができた瞬間

4つ目は**曲芸のようなデバッグができた瞬間**です。
アプリ開発やサービス開発をしていると往々にして「謎のバグ」に立ち向かうハメになることはありますよね。
そんなときその分野での一般的なデバッグ方法が役に立たない瞬間というのもあるのではないでしょうか？

そこで**「何となくこんな感じの原因な気がする」とあたりをつけて全くの別角度から攻めてデバッグ成功する**、こういう曲芸というか飛び技というかができるのがコンピュータ科学を知っている強みだと思います。

### Case 5. 日常の開発にアルゴリズムを活用できた瞬間

最後は**日常の開発にアルゴリズムを活用できた瞬間**です。これはどちらかというと大学の知識、というより競技プログラミング力なのかもしれませんが、何か日常の開発で**「こういうロジックを組めばうまくいきそう」とアルゴリズムを組んでいけるのは大きな強み**かなと思っています。

以上他にも自分で気づいてないうちに恩恵を受けている部分はもっとあると思いますがその中でも印象深いものを例にあげてみました。
このような恩恵が活かせるのが「コンピュータ科学」です。

![surprise.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10943/7ae808da-317b-2b91-2fd3-98a0c56545c3.png)

## 3. 技術の進化に関係なく使える力

さて、本編最後としてアドベントカレンダーのテーマにもかけて**技術の進化に関係なく使える力**というテーマで語っていきたいと思います。

ここまで紹介してきた大学で学ぶ学問としてのコンピュータ科学、幅広いとは言いましたがそのほとんどが現代型計算機ができたノイマンの時代、さらにはその前から着実に積み上げられたもので最近の技術の発展のスピードから見たら古典的な知識が多いことは事実だと思います。
一見これらの知識は不要なものかもしれません。事実、現代のエンジニアの中にはここらへんの知識を一切知らないけど活躍している方は相当数いると思います。

ですがそんな知識でも役に立つ瞬間が数多くあるのは前の章で見てもらった通りだと思います。進化の早いこの世界、3年もすれば古くて使い物にならないなんてざらなこの業界でなぜそんなことがありうるのでしょうか？
そこに僕は**技術の進化に関係なく使える力**というものが関わってくると思います。

正直に言うと、僕自身最初に定着度はそこそこと述べた通り各授業の詳細はほとんど覚えていません。もともと授業を受けている間も苦手だった離散数学の問題なんか持ってこられても1ミリも解けずに終わってしまうと思います。またHPCやOSをいじることなんてこの先ソフトウェアエンジニアとして生きていく中で少なくとも仕事ではほとんどないと思います。これらの知識は**ある意味直接的には使わない知識**です。

ですがどんなに知識を忘れていても**考え方のエッセンスみたいなものは身についている**と思います。それこそが技術の進化に左右されない力なのではないでしょうか。

もう少し踏み込んでこれを説明してみましょう。物事の定着にはいかに自分のすでに持っている知識と結びつけられるかが大事です。僕自身はそれを**ここまで語ってきたコンピュータ科学の分野、さらにリアルタイムに最新の技術を追うことでその知識も絡めて行うことができました。**
つまり、コンピュータの過去から現在を一気通貫でリンクする、そんな経験を大学時代にできたわけです。これが何よりの僕の経験で得られた財産であると思っており、これこそが考え方のエッセンスそのものなのではないかと考えています。

![Connection.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10943/d4bd8543-0724-482f-fdcd-663642fa4f89.png)

## 4. 番外編： 大学に入ったからこそ得られた機会

おまけとして大学に入ったからこそ得られた機会についてみていこうと思います。

これは結論から言ってしまいますが、一番は「人」だと思います。ありきたりの答えですが、この結論は揺るがないかもなと思っています。

大学には本当に多様な人がいます。特に総合大学だとなおのことでしょう。

法学部でバリバリのアプリエンジニアになったサークル同期がいたと思えば、全くプログラミングをしていなかったクラスの同級生がCTOになってたり、同じ学科の中でも理論が好きな人からゲーム制作が得意な人までさまざまな人がいるのが大学の多様性です。（もちろんエンジニア関連以外にもいろんな人がいますよね、同じ学科から吉本興業のマネージャーに就職した人なんかもいます）

もちろんインターンを渡り歩いたりいろんなところに顔を出すことで同じ経験を大学に行かずとも得られる人もいるとは思います。ですがアカデミック志向な人ってなかなか、大学じゃないと出会えないんじゃないでしょうか。いや、別にそんな例を無理に見つけ出さなくても、**自分から頑張ってようやくその機会を得られるのか、いるだけでその機会を得られるのか**は多分雲泥の差だと思います。

そんな利点があるのが、大学です。これを見て利点と思わなかったり、もっと大事なことがあるひとは別の道を選ぶのもありなのかなと思います。

あくまでこの記事は「参考」でしかないので。

## 5. まとめ

以上大学でガチガチの情報科学・コンピュータ科学を学びながら、趣味や仕事ではフロントやアプリの最新技術を追い続けた僕なりの知見をつらつらと語ってみました。

ちなみにこの記事は「だから○○がいいよ」と宣伝するような意図の記事ではありません。あくまで**「冒頭で述べたようなスペックの学生がこういう経験をするとこんなことを得られるよ」という一例**であるので、ぜひそこを十分に踏まえた上で進路を決めたり、コンピュータ科学を学ぶ上での参考にしてもらえればなと思います。

また手前味噌ですが、今年のアドベントカレンダーでこの記事とは別に今度は**「教える側」**について語った記事も用意しています（あわせると卒業文集になります。嘘です。修論がんばります。）
研修をする際や、自分で学ぶ際、ぜひこちらも参考にしてみてください。

- [アプリ開発を「教える」ということ / Life is Tech ! #1 Advent Calendar 2020 | 7日目](https://qiita.com/touyoubuntu/items/26e6d1cabce0da7366fb)

それではみなさん、メリークリスマス！笑

*illustrated by unDraw*