見出し画像

プログラミングは総合格闘技である(前編)

今、一部のエンジニアでコンピュータサイエンスが重要なのかそうでないのか?と言った話題が盛り上がっています。

僕の主張は、コンピュータサイエンスも、ソフトウェアエンジニアリングも、コミュニケーションや、言語学、あるいは他のあらゆるものも含めて、プログラミング(設計、実装、テストその他全部含む)はそれらの集合体(総合格闘技)であるというものです。

プログラマ(いわゆるPGではなくSEなども含む)は、理系の職業と思われる事も多いですが、実質、理系と文系、双方にまたがっているケースがほとんどです。研究職だとか特定の例外でのみ理系要素に偏ってるでしょう。

プログラミングは、数学、工学、文学、コミュニケーションその他の総合格闘技である以上、どれかを毛嫌いしたり、どれかに傾倒しすぎるのは勿体ないので、少し興味を持ってみませんか?というのがこの記事です。

ただ、分量が多いので、今回の記事は今話題になってる記事で取り扱われてる話(コンピュータサイエンス中心)について触れておきます。

画像は、Pixabayのやつ。

コンピュータサイエンス

今、震源地の一つとなっているブログ記事で、マウンティング的で炎上する部分もある記事なのですが、そこはさておきましょう。

データ構造
リスト、配列、ツリー、ハッシュ、スタック、キューなどの違いが説明でき、自分がこれから組もうとしているプログラムについてどれを使うべきか適切に選択できる。必要に応じてそれらを応用したデータ構造を自分で定義して使うことができる。

これは言語によっては全部、配列あるいはEnumerableで抽象化されているものです。そういった言語の場合あまり意識する必要性はありません。たとえばJavaScriptはArrayで全部実現可能です。

でも、「リスト構造」というものを少しでも知ってると、データを保持する入れ物にlistというネーミングをすることを躊躇したくなる気持ちがわきませんか?文化圏によってはlistというネーミングであれば、リスト構造を指します。

first in first out とか first in last out みたいな言葉を知っててぐぐったりできると何かの役に立つかも知れません。

個人的にはここらへんは、いくつかの言語を触ってみれば、感覚としてつかめるんじゃないかな?と思っています。

もちろん、C言語でこういったデータ構造を実装してみてもいいでしょう。意外と楽しいです。

計算量(計算複雑性)
自分が書いたコードが O(1) なのか O(n) なのか O(n^2) なのか O(n^m) なのか O(n!) なのか … を説明できる。

気になった時にランダウの記号というのをググって、Wikipedia見ればいいと思います。

めちゃくちゃ雑に言うなら1つの要素までならいいけど、2つの要素が絡み合う繰り返し計算(簡単にいうと二重ループ)は、データ量が増えると爆発的に時間がかかるから気をつけろ!という話です。3つとか考えたくもないよね。

ここらへんは競技コーディングで遊ぶといいと思います。AtCoderお奨め。パズル感覚で楽しめると思います。

遊び is 重要

アルゴリズム
ソート、探索、文字列検索、データ符号化、圧縮、誤り検出・訂正など。「なんでソートが遅いのか」「なんで圧縮してもサイズが減らないのか(圧縮が無意味なのか)」などを適宜判断して修正できる。

ソートはよくアルゴリズムの話に出てきますが、「ソート 可視化」でググってでてきた記事や動画見るといいと思います。動画見てるだけで楽しい。

楽しい is 重要

アルゴリズムは余裕ある時にでもあれこれやってみると楽しいと思います。僕も以前ハクビシンにもわかる全文検索という記事を書きましたが、とにかく頭のパズル的です。

日々の仕事に疲れた脳と、違う領域を使ってる感覚があって楽しかったです。

データ符号化や圧縮なんかも調べてみると楽しいと思います。GitHubで、自分が使っている言語で書かれた圧縮ライブラリのソースを読むのが多分お奨めです。

数値計算
浮動小数点の仕組みと情報落ち桁落ち等の理解、行列、線形代数、モンテカルロ法、ニュートン法、オイラー法、ルンゲクッタなど。「そういうのがあったな」と頭の片隅においといて必要なときにググりつつ応用できる。

0.1を10回足して1.0にならないというのを知ってれば大丈夫だと思います。

素数を求める最速アルゴリズムって何?とかやってみるといいと思います。プロジェクトオイラー楽しいです。

グラフ理論
有向・無向グラフ、木、ループ、カット、彩色、結婚定理とかの基礎の理解。「そういうのがあったな」と頭の片隅においといて必要なときにググりつつ応用できる。

データが複数つながる構造のときに、「向きがあるか?」「循環しているか?」ですね(雑な認識)。

向きがあるなし、循環あるなしで、そのデータを処理するめんどくささに違いが出ます。

木構造なんかは割と色々なところに出てくると思います。変数名に、childrenとかnodeとかleaf出てきたら、それっぽいと思っていればいいと思います。

そういった構造を扱うときに、ビジターパターンや、幅優先探索深さ優先探索といった単語を思い出すといいでしょう。

理論計算機
ステートマシン、オートマトン、チューリングマシン、正規表現、ラムダ計算など。「そういうのがあったな」と頭の片隅においといて必要なときにググりつつその考え方等々を応用できる。

皆さん大好き正規表現です!あとチューリングコンプリートみたいな会話は日常に出てきますよね!

ブロックチェーン技術に興味ある人はEthereumのステートマシンとか面白いです。

ステートマシンは、状態が遷移するヤツです。例えば「初期化前」「初期化中」「初期化失敗」「初期化完了」みたいな状態がある時、どう遷移するか?とかですね。多分みんな知らないうちに使ってるでしょう。きっと。

がっつり知っておくと、なんか偉い気分になれるけど、ざっくり知ってるだけでも、普通に役立ちます、ここらへん。

セキュリティ・暗号化
公開鍵認証、共通鍵、ハッシュ(ダイジェスト)、署名、乱数生成のためによく使われるアルゴリズムとその使い方。アルゴリズムそのものに対する簡単な理解(さらでアルゴリズムを書ける必要はないが、だいたいどういう原理で何をやっているのかを説明できる程度の知識)。

暗号技術めっちゃ面白いです。hyuki先生の 暗号技術入門 第3版 秘密の国のアリス お奨めです。

僕が過去に書いた同人誌であるJavaScriptで覚える暗号通貨入門#1 Bitcoin完全に理解した 前編では、楕円曲線暗号とかハッシュとかをJavaScriptで実装してるので、良かったらこっちも読んでみてください。

プログラミングパラダイム
手続き、構造型、オブジェクト指向、関数型、静的型付け、動的型付け、ダックタイピングなどがそれぞれどんな特徴を持っているか理解していることと、好みはあれど特定の一つが最強と思い込まず柔軟に使い分けることができる寛容さ。

TypeScriptいいぞ!(少し疲れてきた)

並列・非同期処理の基礎
並列処理と並行処理の違い、並列処理が困難であるという認識、並列処理プログラムのデバッグができること、スレッド、ブロッキング、メッセージング、セマフォ、ミューテックスあたりの理解。Future, Promise, async, awaitを使え、かつ裏で何をやっているのか説明でき、どんなときに何を使うべきか、何を使ってはならないのかを判断できる。

マルチスレッドは人類には難しすぎる。Actorモデルとかやるといいかも。

あと、Go言語とか面白いですよ!

ソフトウェア工学
設計論、エンジニアリングなど。ウォーターフォール、アジャイル、DDDとかそういうのとその実践経験。

ぶっちゃけ、こっちもめっちゃ重要。多大なる話になるので詳細はさすがにこの記事に書ける分量ではないので割愛しますが、重要。

クリーンアーキテクチャとかレイヤー構造とかportの概念は割と便利。

現代コンピュータの性能
どのメーカーでどんなCPUがあって、だいたいどれくらいの性能で、シングルスレッド性能とコア数の違いを理解しているとか、各種ストレージやメモリへのおおまかなアクセス速度の差などを理解してどんなコードを書いたらどのくらい時間がかかるかという見積もりができる。

雑学として知っておくといいです程度。ここらへん興味あるなら、Impressの後藤さんの記事などをひたすら読むんだ!

プログラマーが知っておくべき「PC内部の通信速度」は知っておくと便利ですが、時代によって変化するのでご注意を。

CPUの仕組み
どういう命令セットがあって、CPUにはどんなモジュールが乗っていて、分岐予測やハイパースレッディングは何をやっているのかとか理解できる。

エミュレータ作るのでもなければ、後藤さんの記事読んでおけば雑学として楽しいです。

個人的にはメモリとは何か?CPUとは何か?メモリの中には「数字しか入ってない」ということを認識するのは重要だと思います。文字列も画像も数字が集まって「そう表現されてる」だけなのです。

OSの仕組み
メモリ空間、メモリ管理、仮想記憶、シグナル、IO、割り込み処理、タスク管理、ファイルシステムなど。

知ってると楽しいけど、ここらへんの概要をしるいい本って今あるのかな?あれば教えてください。昔なら、Minix本とかLion's Commentaryとかだったと思うけど。

ネットワーク(7階層モデル, IP, TCP, UDP, HTTP, HTTPSなど)
なんかよくわかんないけどネットワークがつながらない、うまくうごかない、みたいなときにWiresharkやtcpdump, ngrepなどでメッセージをダンプして原因を判断できる。OSがネットワーク関連のリソースをどう管理しているか大まかなところを理解している。TCPの状態遷移を大まかに理解していて、netstatとかnmapとか基本的なコマンドを使用して知りたい情報を取得できる。

RFC嫁(記事が長くなって飽きてきた)。

知っておいて損はないやつ。TCPとUDPの大雑把な仕組み知ってると、QuicだのHTTP/3だのの強みがわかるかも。

セキュリティ
WifiやHTTPSでの鍵交換で何をやってるのかとか、どういうコードを書いたらどういう脆弱性が生まれるとか、世間での攻撃手法として一般的なものは何で、その対策としてどういうことをしておく必要があるのかなどをある程度語れる。重要情報を平文で保存しない。方法の秘匿で担保するような方法(方法やソースがバレたらクラッキングも容易にできる方法)やバックドアを無闇矢鱈につかわない。

これも語り出したら本何冊分にもなるヤツなので割愛。

・ パッケージなどのアップデートはこまめに対応しましょう
・ 鎖の一番弱いところ、狙われるぞ
・ 一般的な知識はある方が断然良い
・ セキュリティはコストと守りたいもののバランス

統計・データマイニング・機械学習系の基礎知識
回帰分析、最小二乗法、ニューラルネット、SVMとか?個人的には必要になったときにやり始めればいいと思うものの流行りに乗っかって一応書いてみた。

興味があればやったらいいんじゃないのー

まとめ

コンピュータサイエンス、数学的で難しそうという人も、パズル解くように遊んでみると楽しいですよ!という話でした。

実際、僕はアカデミックに縁が無い独学派ですが、学がなくても楕円曲線暗号を実装する程度はできます(実用に足るとは言わない)。

間違いなどあったら、コメントやTwitterなどで教えてください!

蛇足

masuidriveさんのコンピュータサイエンスの基礎を学ぶと何ができるようになるのかという記事で「先の技術を読めるようになる」ということが触れてあったので、もしかしたら関連するかもしれない話。

これ、ブロックした理由はコメントにも書きましたが引用ツイートしてきた人が気持ち悪かったからブロックしただけです。

技術のトレンドを予測するのは難しいというのは僕も同意見だし、むしろ「予測するの基本的には無理ゲーでしょ?だったら、せめて新しい技術に対応できる、できれば3年・5年のスパンでコケそうな技術には足踏み入れない方がいいよ」というのが本来の主張です。

ここらへんは気が向いたら記事にします。(優先度が低いけど)

あと、個人的考えで言うと、先の技術を読むのに、コンピュータサイエンスだけでは出来ないと思っています。あくまで重要な要素の一つに過ぎないと思っています。どちらかというと、ソフトウェア工学的な「筋の良さ」とかコミュニケーション論とかそっちに根ざした部分が大きいと思っています。あと、お金とかお金とかお金とか「大人の事情」な。

この記事が気に入ったらサポートをしてみませんか?