見出し画像

プログラミングを学ぶ心構え

プログラミングの道を歩く上で知っておいて欲しいことを書いておきます。
プログラミング学習の心構えとして一読下さい。

最初から全部理解できると思うな

プログラミングを始めようと思って本を取って、わからない用語や理解できない内容が多過ぎて辞める人があまりに多いと感じます。
考えてみて欲しい。例えば数学で、自分が学生の時に、予習で全てわかったか。授業で聞いて全部理解できたか。だとしたら、定期テストの点は毎回ほぼ満点だったでしょう。
何故か大人になると、簡単に理解できないことは自分に向いていないことだと線引する人が多いように感じます。お前は天才か、もしくはプログラミングなめてるのかという話です。プログラミングは専門技術です。専門用語が多く出てくるのは当たり前です。

学生時代の例えに戻すと、基本的に大半の学生は学期中は半信半疑です。わかった気になってたけど、次の学期の応用の授業の中で、「ああ、あれってそういうことか!」と突然パズルのピースがはまって理解できたという経験はないでしょうか?学びというのはそういうものだと思っています。最初はなんとなくこういう形のものだろうな、とイメージして、少しずつ細部を埋めていく。ある程度の知識によって大体の形を作って、経験によって、形を整えていく。理解が進むとそれが色付いて実体を作る。業務でも最初、専門知識(業務知識)が必要でコードもわからない状態で学びを続けながら1年位経つと、かなり理解できていることに気付いたりします。というか、完璧に理解できている状態で新しい案件に取り組むことって少ない気もします。人生って、そういうものだし、全てを知ってしまったら自分は絶望すると思う。ぜひ、知ることを、理解したと感じる瞬間を楽しみにして欲しいです。

学び続けること

技術は日進月歩です。次の項目で基礎技術の大事さを書きますが、実際に業務では表面的な技術も必要です。表面では新しい技術が次々に出てくるので都度学ぶ必要があります。自分はこれを極める、と言っても基礎技術や研究レベルでできないと、たいていその技術は廃れて使われなくなります。技術は陳腐化すると言われますが、陳腐化するのは表面的な技術です。特に、プログラミングスクールでフレームワークを使ってweb系のシステムの作り方を学んだ人は、「Rails使えます」と言って仕事に就けても、中で使っているライブラリが違うと学び直しになったりします。
僕は独学から大学院に入って学んで、プログラムを書き始めてから20年が経ちますが、まだまだ学ぶことは多い。それは幸せなことです。この業界で全てを知るにはどれだけ時間があっても足りない。理解できていたと思っていたことも、実はもっと深かったと気づいたりする。職場を変えて、更に先進的な会社に入ると、違う次元でコードを書いていたりする。

学び続けず、経験で仕事をしている人もいるかも知れません。そういう人には、他の人はやりたくない、廃れた技術を使う仕事が回されることになります。何故なら、業務内の経験は同じ仕事をしている全ての人に程度の差こそあれ与えられるものです。誰もが持っているもので勝負をしても差は速度程度で深さもないでしょうし、評価もされないでしょう。また、経験が大事であるなら、プライベートで仕事で経験していないことを個人プロジェクトで経験していたら経験にも差が付きます。更に、新しい経験を与えるとして、学ぶ努力をしている人間と経験だけに甘えてる人、どちらに良い経験のできる案件に参加して欲しいと思うでしょうか?

プログラミングの道は学びを楽しみ、成長を喜べる人にはとても楽しい道です。是非、あなたにも、この素晴らしい道を歩いて欲しいです。しかし、反面、楽をしたい人は天才でない限り取り残される世界です。もし、この道を歩くのであれば、学び続ける覚悟を持って下さい。

深く理解することの重要性

プログラミングスクールでは、「プログラムがどう動いているか」ではなく、「プログラムはどう書けば動くか」だけを学ぶと思います。それでも確かに最初はなんとかなるかも知れない。しかし、それは「何故そう書くのか」がわからないということです。そういう人が現場に多くなると、確実にバグが増えます。問題が起きた時に原因をちゃんと理解して対応できず、サイトを検索して、素人が書いた記事を使い、とりあえず、動いた、というコードがコードベースに紛れ込むわけです。また、継ぎ接ぎにもなりやすいです。

外資系プラットフォーマーや、国内でも本当に技術力のある(会社の規模が大きいという基準でなく)企業が採用において、コンピューターサイエンスの基礎を大事にするのは、基礎技術をしっかり理解している人はどの案件でも表面的な技術に左右されない安定したパフォーマンスを発揮できるからです。基礎のないけど専門性だけ伸ばした人は、I型人材と言えば聞こえは良いですが、穴だらけのIの上、違う領域の技術を使う場合(Webからゲーム等)、基礎を1から学ぶ必要があります。応用技術というか、色々やってくれる技術の上(Webフレームワークとか)中心で仕事をしていた場合、驚くくらい転用できる技術は少ないと思います。

大学のコンピューターサイエンス専攻で学ぶ内容を使う機会は少ないかも知れない(プラットフォーマーとか言語を管理してる会社やコミュニティ中心で求められる人が少ないだけなので、業務で関われたらかなり給料は高いかも)ですが、フレームワーク内で何が起こっているか理解してイメージができると、全然別の業界のフレームワークの内部もなんとなく予想が付いたり、ハードウェア(メモリ上でのプロセスやスレッドの動き、データの使われ方とか)がわかっていないとわからないようなバグにも対応できます。基礎技術に疎い人は原因がわからないので応急処置しかできないでしょう。

プログラミングスクールを薦めている人がよく使う例で、仕事得るまでの時間で同じことができるのにプログラミングスクールは必要な実用的な部分を中心(のみと言っても良いかも知れない)に教え、大学の授業では仕事で使わないことを多く学ぶ、と言われますが、求められるスキルセットが変わる度に1から学ぶ必要があり、そして、何より、業務に使っている技術のほとんどが表面的な技術(フレームワークがほとんどやってくれて技術というより、他の人が作った技術の使い方だけの場合も多い)なので陳腐化します。新しいフレームワークが出たら、学び直しだし、書き方が違う内部では同じバグを出しかねないです。基礎技術は基本的に陳腐化しません。技術の芯にあるので、その部分は土台として必要になるのです。差分となる表面に乗せる部分だけ理解すれば対応できますし、内部がイメージできれば同じ原因のバグにも気付けるでしょう。

特に大学の授業で学ぶのは構造化され、抽象化された技術の完成予想図(既に完成しているものも多いけど)のようなもので、それぞれの言語やフレームワークでどう実現しようと、本当に必要な要素は変わりません。そこを学ぶことに価値があるのは言うまでもないでしょう。なので、自分がここで書く内容は表面的な部分であっても、CSの深い部分と絡めて、それがプログラミングにどう役に立つかという視点で記事書こうと思っています(本来自分で気付いた方が良いのですが)。

まさに「急がば回れ」で、深く学ぶことに使った時間は無駄になりません。表面的な技術や手法が変われども、中にある芯はそのままなので、表面的な技術の様に少し使わなければ忘れるものではありません(常に意識してれば使わなくても残る)。結局、太い芯をしっかり作った方が最終的にかかる時間は短くなるわけです。

手を動かすのは必要条件で十分条件ではない

プログラミングの上達には「手を動かすこと」(ひたすらコードを書くこと)とよく言われます。これ自体は間違いではありません。ただ、手を動かすのは学習初期に最低限必要なことであって、手を動かして学べることはレベルが上がるにつれて減っていきます。例えば、プレゼンテーションや講演で人前で話すために、話す能力を磨くことは大事です。とはいえ、会話を多く持てば良いというわけではなく、ポイントを簡潔にまとめ、論理的に構成し、伝わりやすい話の流れを考え、わかりやすい図などの視覚的効果を使い、適切な例を用いて話すことは会話を繰り返すだけ、一人で声を出すだけで身につくわけではありません。水泳でひたすら泳いで平泳ぎやクロールを自分で思いつくより、知識として教わった上で練習した方が良いでしょう。

手を動かすのは基本的には慣れであり、自分が知らない技術を使うなら、それを知る必要があるし、それが正しく動くかは、本来先に考え、証明できる状態で書き始めるべきです。中級者から上では、上達するには何より考えることが大事です。上級者だと、考える下地として求められる知識量も増えます。適切に設計され、動作が証明されたものを実装すると、拡張性があり無駄の少ない美しいコードになります。手を動かすだけで難しいもの、複雑なものを作ろうとすると迷路に迷い込み、継ぎ接ぎだらけで絡まった、いわゆるスパゲッティコードになりがちです。

知識で差が出る例でいうと、例えば、関数内でローカル変数のポインタを戻り値として返したり、と特にC型文字列を使うと起きがちなバグがあります。これは変数の裏側での使われ方(スタックとヒープの違いなど)がわからないと原因にたどり着かないでしょう。応急処置はできるかもしれませんが、原因を理解しないと同じミスを繰り返します。ポインタが難しいと言う人はメモリ上でのデータの保持され方、取り出され方がわかっていない証拠です。ポインタは大学1年の最初の学期の授業で習う知識で本来理解できます。しかし、ひたすら手を動かし続けても原因はわからないでしょう。

実際の現場で、レベルが上がるにつれ業務の中でコーディングに使う時間は減っていきます。技術力のある会社だと、だいたい15〜30%程度でしょう。他の時間は、たいていアジャイル開発(開発手法)を使っているので会議も多く、また、デザインドキュメントを書いたり設計を揉む時間もしっかり取り、レビューもガッツリやります。チームでの合意、説得をできる状態で業務を進めて、全員でコードに責任を持つのです。
逆にブラックと呼ばれるシステム業界ではプログラマは上から投げられた設計書(しかもコードを書けない人が書いたのでグダグダ)に従ってただ書くだけなので、コーディングの時間が非常に多いと思います。そこで働きたいなら手を動かすだけで良いと思いますが、そこを目指す人はほとんどいないでしょう。

結局のところ、手を動かすのが最も有効なのはプログラミングを始めたての時で、徐々に効果が落ちてきて、中級以上では感覚を衰えさせないというのが手を動かす理由として強くなってきます。当然書き続けるべきで、書かないと衰えますが、書くだけだと、基本的な構文の使い方に慣れるだけで、簡単なことが早くなるだけです。それは上達ではなく慣れです。中級以上では「コードを早く書ける」かつ「速く動くコードを書ける」が大事です。特にビッグデータ、スマホ1人1台の時代では遅いコードは役に立たないことが多いです。

デバッグ力の重要性

「わからなかったらすぐ聞け」と教えるプログラミングスクールもありますが、これは現場で働く上では使えません。聞くというのは、誰かの時間を奪うということです。そこで聞かれた人間の学びにもなれば素晴らしいですが、自分で調べれば解ることをいちいち聞いていたら、チーム全体での作業量が下がる一方です。聞く相手は当然自分よりできる人間です。プログラミングスクールでは聞かないとスクールの存在意義がなくなる(独学でいいじゃん、という)のですが、実際の現場では、自分で考え、難しい問題を解決できる人間ほど評価されます。とはいえ、独りよがりではいけないので、考えを共有するのも大事ですが。

そこで重要になってくるのが「デバッグ力」です。具体的にはコードリーティングやログの挿入、エラーメッセージの読解力になります。優秀なエンジニアは頭の中でコードを動かせる様に思えます。これは慣れが必要ですが、コードが何をしていて、どういう意図か読めば理解できるわけです。

とはいえ、初心者には難しい技術なので、まずはエラメッセージと向き合うことから始めた方が良いと思います。たいてい、何故コードが動かないかを教えています。英語が基本なので、少なくともエラーメッセージを読める程度の英語力は身につけて下さい。質問の際に「こんなエラー出たんですけど」と、メッセージを読まずに聞くのは最悪です。また、エラーメッセージでググればたいてい答えは見つかります(まずは自分で考えてからやりましょう)。

次にログの埋め込みですが、JavaとかならEclipseなどのIDEでデバッグ機能があって、一行ごとの変数の状態が確認できたりするので、そちらで十分だと思います。デバッグで止めるのが難しい場合は、怪しい場所で変数を出力して、あるべき値になっているか確認を繰り返します。大抵これでバグは見つかります(ハードウェア起因や未定義な動作を除く)。

この辺の話はまたプログラミング講座の中で時間を取って詳しく触れたいと思います。覚えておいて欲しいのは、できるだけ自分でバグを特定・修正できるようになると独学でも成長できるようになるということです。

とはいえ、誰にも聞いちゃいけないというわけではありません。ちゃんとした会社なら、メンターを付けてくれるでしょう。その際、指導を受けながら業務に取り掛かると思いますが、目的を持ったタスクをもらい、そのタスクを通して何をメンターが目的として得て欲しかったかを答えられるように考えて働くのが良いと思います。裏に目的があるとなると否が応でも考えることになります。繰り返しますが、質問する場合は考え抜いてすることが大事です。メンターと悩むリミットの時間を相談して、そこまでは自分の頭で考えると良いと思います。

サイトより本を読もう

今は検索をすれば何かしらの情報がヒットする時代です。ただし、検索エンジンはそのサイトの情報が正しいかは保証してくれません。初学者すら情報を発信していて、プログラミングスクールですら間違った情報を発信しています。趣味のプログラミングでサイトを参考にするなら良いですが、プログラミングを仕事にするつもりなら、公式サイトや技術力が保証されている人やコミュニティのサイト以外は信用できないと考えた方が良いでしょう。そのコードは最低限考えうる全てのテストを充てた上で使用すべきです。公式ドキュメントは英語が多いので、英語力はエンジニアには大事です。

処理を調べるには公式ドキュメントで良いですが、応用技術等は書籍を読んだ方が良いです…あれ、ここだめじゃん…。信頼できるソースと思って頂けることを願います。

それで、書籍は編集者の編集や校正による内容の検証、同業技術者のレビューを通過して出しているので、技術的な話の確度はかなり高いです。記事が正しいかの確認に使う時間を考えるなら、書籍の方が結局早いでしょう。サイトはプロトタイプで実現可能かを最短で調べるには良いですが、プロダクトに入れる際には念入りに確認をすることをお薦めします。

コードの全てに理由を

あなたの書くコードは、
・何故変数を置いたか
・何故その変数なのか
・何故関数を分けたか/分けないか
・何故そこに改行があるのか/ないのか
・戻り値はそれでないといけないのか
・引数の順序は何故そうあるべきか
などなど、説明ができるでしょうか。美しいコードはその処理がそこにあるべき理由があります。説得力のあるコードというのは、それ自体が仕様書のように変数名や関数名で何をしているかがわかり、適切にスコープが切られ(メモリを無駄に占領しない)、処理やクラスが適切な単位でまとまっています。

常に、コードの存在理由を考え、把握して、誰かに聞かれたら説明できるようなコードを書くように心がけましょう。この適切さは「Clean Code」や「リーダブルコード」のような良書がヒントになると思います。別記事で書きますが、ソフトエンジニアが読むべき名著は是非読んで下さい。

まとめ

良いエンジニアになるためのプログラミングの道は決して楽な道ではありませんが、楽しみながら歩いてくれることを願います。何より大事なのは考えることです。ソフトウェアエンジニアがプログラマ(もしくはコーダー)と違うのは考え、判断して最適解を求めることです。
手を動かすのは基本的なことで、大事なことです。でも、簡単なコードでも書きながら考えて下さい。これで最善か、もっと良い書き方はないか。他の人のコードをいっぱい読んで下さい。なんでこう書いてあるのだろう。こう書いたほうがよいのでは?思考停止しての写経はタイピングの練習にしかなりません。脳を鍛えて下さい。プログラミングはいつまでも成長できる世界です。

ここに書いたような意識でプログラミングの道を歩いてもらえれば、3ヶ月前の自分のコードが全然ダメだった、と思う日々が続きます。それは成長です。一緒に楽しい世界を生きましょう。

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