ワテがプログラミングを独学で始めたのは確か高1の頃か。
懐かしい。
ワテの場合、
- Fortran
- Basic
- Visual Basic
- VBA (Visual Basic for Applications)
- C / C++ (Visual Studio, gcc)
- C++/CLI (あまり得意では無い)
- C#
- ASP.NET
- OpenGL
- OpenMP, MPI
- JavaScript, PHP, AWK, その他スクリプト言語, (Pythonはほんの少し)
- UNIX, Linuxでの各種シェルスクリプト
など、各種のプログラミング言語に精通している。
とは言っても、文法を完全に理解している訳ではなく、知らない命令、関数、手法など沢山ある。
特に最近のC++のラムダ式などは苦手だ。
滅多に使わない。
当記事では、自称プログラミングの世界的達人いや変人のワテが、ワテ流プログラミング上達のコツを伝授しよう。
まあ、そんなのに興味ある人はワテ以上の変人だ。
では、本題に入ろう。
プログラミング言語はどんどん進化する
例えば、「最小のラムダ式の呼び出し」というキーワードで検索すると、こんなC言語コードの例が見つかる。
int main(int argc, char *argv[]) { [](){}(); return 0; }
その意味は、以下の通りらしい。
int main(int argc, char *argv[]) { [] // ラムダキャプチャー () // パラメータ定義節 {} // 複合ステートメント () // 関数呼び出し式 ; return 0; }
さっぽり分からん。
兎に角、ラムダ式はワテには馴染めない。
(でも、最近ではC#のラムダ式は大好きになって使い捲っている。)
しかし、時代に付いて行くにはこれくらいの文法はサッサと理解して使いこなせるようになりたいのだが。
さて、そういう新しい手法の習得が苦手なワテなのだが、プログラミングをこれから勉強しようと思っている全国数百万人(推定)のワテのブログ読者の方々に、ワテ流のプログラミング上達の秘訣をアドバイスしたい。
プログラミングの心構え
ワテがお勧めするプログラミングの心構えを以下に列挙してみる。
- 先ずは何でも良いから自分でプログラムを書いてみる。
- どんな課題でも良い。
- 自分でプログラムを書いて課題を解決するぞと言う猛烈な熱意が重要だ。
- コーディングに関しては、ネットを検索して良さそうなソースコード参考にしても良い。
- 全部を自分で作る必要はない。他に良いコードが有ればそれを組み込む。
- 兎に角、目的のプログラムを短時間で完成させる事が重要だ。
- コーディングスタイルに「美しさ」を求めるあまりに、結果を出せないのは本末転倒
- 兎に角、動くプログラムを最短時間で完成させるのが重要
- プログラムなんて期待通りに動けばいいのだ。
- 良いプログラムを書けば自ずと見易いコードになる。「美しい」かどうかはワテは気にしない。
- Goto文と聞くと異常に拒否反応を示す人がいるが、ワテは気にせずに使う。Gotoを使いたくないのでヘンテコなフラグ変数を即席で導入してループ脱出するなんて本末転倒だと思う。
- グローバル変数は必要に応じて使う。
- 文法上の疑問点は絶対に放置しない。自分で調べたり、他人に質問したりして疑問点は必ず解消する。
- まずは数百行くらいのプログラムを書いてみる。
- 次に1000行くらいのプログラムを書いてみる。
- 慣れてきたら数千行くらいのプログラムを書いてみる。
- 1万行くらいのプログラムなら、かなり高度な処理が出来るはずだ。
- 自分が今までにプログラムを通算で何行くらい書いたのか把握しておくと良い。
- まあ、10万行くらい書けば中級者レベルになれるかもしれない。
- もちろん書いた行数に比例してプログラミング能力が身につく訳ではないが、ひたすら書けば凡人でも中級者レベルには成れると思う。
- 上級者の人は生まれ持った才能かもしれない。素人には思い付かないような洗練されたコードをブラインドタッチで物凄い速度で書ける。
- 凡人にはそれは真似できないので、ひたすら書く訓練して少しでも上級者に近づく努力をする。
その時に重要なのは、
デバッグで決して諦めない。
これが重要だ。
これを守ると、プログラミングは必ず上達する。
プログラミング上達の秘訣は「デバッグで決して諦めない」何故か?
プログラムの動きが期待通りでは無い場合、以下の可能性がある。
- 自分の考えたアルゴリズムが間違っている。
- 自分の考えたアルゴリズムは正しいが、プログラミングが間違っている(バグがある)。
- 自分の考えたアルゴリズムもプログラミングも正しいが、コンパイラにバグがある。
の三通りだ。
まあ、アルゴリズムもプログラミングも両方間違っている場合もあるが、そんなお間抜けな人はプログラミングには向いていない!と言うのは冗談で、それは1あるいは2に含まれると考える事にする。
疑うのは自分
ワテの経験では、三番目の可能性(コンパイラにバグがある)は極めて少ない。
ワテも長くプログラムを書いているが、コンパイラのバグを発見した経験は数回程度だ。
なので、まず疑うのは自分自身なのだ。
つまりプログラムが期待した結果を出さない場合には、アルゴリズムが間違っているか、プログラムが間違っているかのどちらかしか無いのだ。
それを見極めるには、デバッグ作業で諦めずにプログラムを完成させる事が重要だ。
もしアルゴリズムが正しいのに、プログラムにバグが有る場合はそれでデバッグを諦め無ければ必ず正しいプログラムが完成する。
アルゴリズム自体が間違っている場合
一方、アルゴリズム自体が間違っている場合にも、地道にデバッグ作業をしているとその間違いが見えてくる。
その時点でアルゴリズムを修正すれば良いのだ。
と言う事で、ワテ流のプログラミング上達の秘訣は、
デバッグ作業で決して諦めない。
これが重要だ。
ちなみに、ワテは今までにデバッグ途中で断念した事は全くないとは言い切れないが、多分、数回程度だ。
その場合でも、それで放置するのではなくて、新たに別のアルゴリズムを考えたり関数を再作成するなどして目的とするプログラムを完成させた。
兎に角、動くプログラムを完成させる事が重要なのだ。
デバッグで諦めない – 具体的にどうするか
デバッガを使いこなす
効率よくデバッグをするためにはデバッガーの使い方をマスターする事が重要だ。
printfデバッグをしている人を良く見かけるが、それでは初心者だ。
printfデバッグが悪いと言う訳ではない。
開発中は printf や Console.WriteLine などを必要に応じてコード中に挿入しておいて、変数の中身を確認するなどの作業は重要だ。それとは別に、開発環境が持っている高度なデバッグ機能を使いこなすことが重要。
Visual Studioなどの高性能な開発環境ではデバッガの機能も充実しているので是非使いこなすべきだ。
C#, VB.NETなどの .NET Framework アプリなら、デバッグ停止している最中にソースコードを編集出来るなどと言う、昔では考えられないような嬉しい機能がある。
なので、ワテの場合はWindow Formプロジェクトの場合でも開発中は Console 画面を出しておいてデバッグに必要な情報を書き出す事もある。
その際、デフォルトだと Console ウインドウの位置は自動配置で変化するので煩わしいから、プログラム起動時に液晶画面の左側に移動して大きさも指定するようにしている。バッファーも大きく取るなどして、表示される情報を有効に活用している。
こういう環境を自分で整える事もデバッグ作業には重要だ。
その解説記事はこちら。
自分が間違っていると思いながらソースコードを追う
デバッグ作業で最も重要と言っても良いのがこれだ。
つまり「自分が間違っている」と思いながらソースコードを追う事が重要だ。
初心者の場合、デバッグでソースコードを追う場合に、
初心者の人
これが、こうなって、
こうなるから、
これで良い。
全然間違っていないやんけ。
どこにも間違いは無いぞ?
おかしい。
原因が分からん!!
という思考になりやすい。
そうではなくて、どこかに必ず間違いがあるのだから、一見明らかに正しい処理であっても
上級者のワテ
この処理は間違っているかもしれない。
この簡単な処理が、実はうっかりミスの原因かもしれない。
この行は明らかに正しいと思いがちだが、それがバグを見逃す原因だ。
この関数は既に完成していると思っていたがもう一回見直してみるか。
と言う感じで、兎に角一行ずつ疑いながらソースコードを追う事が重要だ。
要するに、デバッグ中は「自分が間違っている」という意識を常に持ちながらソースを追うのが重要である。
実際に間違っているのは100%あなたなのだから。
バグの原因究明にはソースコードを削る作戦も良い
あと、ワテも時々経験するのだが、プログラム開発で厄介なのはソースコードのどこかを修正した結果、なんだか挙動がおかしくなった場合だ。
その箇所がすぐに分かれば良いのだが、普通は何日もかけて開発していると、ある日ある機能が正常動作していない事に気づく。
この数日以内に行ったソースの修正が原因だとは思うが心当たりが無い。
ソースコードの差分など調べても原因が分からない。
そういう時は、挙動がおかしいソースコードを少しずつ削っては実行して、問題の再現実験を行い、徐々にソースコードを短くしながら、原因を突き止めるという地道な作戦だ。
数万行もあるソースコードの場合、こんな作業を行うと半日とか丸一日掛かる場合もあるが、ワテの経験では原因不明のバグはこの作戦で必ず解決する。
ワテの場合、もう何十回、あるいは何百回くらいそんな作業をした記憶がある。
地道で泥臭い手法ではあるが。
プログラミングの学習方法
ワテの場合には、プログラミングは最初は独学で始めた。
昔のコンピュータは今のコンピュータほどは性能も良くないので、メモリも少なく、処理速度も遅い。
そんな低性能コンピュータを使って、
- 円周率Πを1万桁計算するとか、
- 自然対数の底eを計算するとか、
- 3Dの図形を2D平面に投影するとか(陰線処理など)、
- オセロゲームを作るとか、
兎に角いろんなプログラムを自分で作ってみた。
通算で、数十万行くらいのコードを書いたと思う。
とは言っても、ワテの場合仕事としてプログラムを書いた経験は少ししかないが。
たぶん十万行くらいか。
ネットでオンライン勉強するのも良い
プログラミングの知識がない人が一人で独学でプログラミングを習得する事は可能ではあると思うが、最初のハードルが高い。
もし本格的にプログラミングを習得したいなら、ネットでオンライン学習が受けられる有料サービスがお勧めだ。
プログラミングを始めるとビットとかバイトとかアドレスとか、知らない専門用語が沢山出て来る。一つずつ調べて理解すれば良いが、そういう段階で挫折する人も多いだろう。
でも、こういう有料のコースに申し込めば講師の人から色々と詳しく教えて貰えるので短期間でレベルアップが可能だろう。
それである程度の知識が身に付けば、あとは独学でやって行っても良いし、あるいはより上級のコースでさらに高度な知識を身に付けるのも良いだろう。
自分が作ろうと思うプログラムの方針が良いのかどうか分からない
よく言われているプログラミングの学習方法に「写経」と言うのがある。
他人が書いたプログラムをそのまま書き写して試してみると言う意味だ。
ワテの場合もプログラミングを独学で始めた当初は、兎に角、いろんな本を見てサンプルプログラムを必死で手で入力して実行してその意味を勉強した。
数百行のサンプルプログラムを数時間必死で手入力して、いよいよ実行しようと思ったら、雷で停電してデータが全てパー!!と言う経験もある。
それ以来、どんなデータでも必ず入力途中には数分に一回は上書き保存する習慣が付いた。
誰でもそんな写経を経験して、ある程度は自分で思い付いたアイディアをプログラム化する事が出来るようになるのだが、中々そのレベルに到達出来ない人も多い。
つまりひたすら「写経」をしても、いざ自分で何か作ろうと思っても、どういう方針で作ったら良いのか分からないという問題だ。
プログラミング系掲示板で意見を求めると良い
そう言う場合には、ワテのお勧めとしては上級者の人に意見を求めるのが良い。
例えば
〇〇の処理をC#でプログラミングしたいのですが、自分では・・・こんな方針で作成するつもりです。
こう言うクラス□□を定義して・・・、こんな流れ・・・で作成する予定です。
これで良いでしょうか?何かアドバイスが有れば教えて下さい。
と言うような質問文を作成して、プログラミング系の掲示板などで質問すると良いだろう。
例えばその手の掲示板としては、
- MSDNフォーラム
- 2chのプログラム技術板(現在は5ch)
- StackOverflow.com
- その他色々な掲示板
がある。
最近のワテは、この手の掲示板はたまに見る程度だが、初心者の人は遠慮する事無くどんどん質問するべきだろう。
質問をすると色んな反応があり、中には初心者を馬鹿にするような人もいるが、世の中、親切な人も多いので、そう言う人からの真面目な回答を待っていれば必ず適切な回答が得られる。
自分が立てたプログラム作成の方針を、そう言う上級者の人のアドバイスに従って修正して、正しい方針でプログラム設計を行うと遠回りせずに最短でゴールに到達できるだろう。
でもまあ、最初は誰の意見も聞かずに自己流で全部作ってみるのも良い。
その後で、こんなプログラムを作成したのですが、改善すべき点などあれば教えてくださいという感じで、専門家の意見を求めるのも良いし。
掲示板は沢山あるし、色んなところで質問すれば良いだろう。
ワテはマルチポストは全く気にならない
余談になるが、マルチポストを嫌う人が多いが、ワテは何とも思わない。
ワテの理解では、マルチポストが嫌われる本来の理由は、大昔のコンピュータやネットワーク環境が貧弱な時代において、議論が分散すると無駄にコンピュータ資源を使ってしまう。そう言う理由が大きいと思う。
今の時代、インターネットは昔と比べ物にならないくらい巨大化していて、日々増大していている。至る所に掲示板もある訳だから、質問を5chのプログラム板にだけ投稿したとしても、それを目にする人は5chユーザーの中のプログラムに興味あるほんの一部の人だ。
全世界の人が5chを見ているとは限らないし。
多くの掲示板に同じ質問をすれば、より多くの人の目に触れる。そして議論も盛り上がり、良い回答が得られる確率が高い、そう思うべきだと思うのだが。
それで誰かが困るのか?何かにデメリットがあるのか?
ワテは全く無いと思う。
マルチポスト禁止派の人は昔からインターネットをやっていて、その当時からの流れで今も教条主義的に単にそう思い込んでいるだけの人が多いのでは無いだろうかと思う。
今の時代、インターネット上の情報は溢れている訳なので、マルチポストしたくらいでは何も困らない。掲示板の管理者なら、サイトが活発に利用されているので歓迎するだろうし。
と言う訳で、ワテの場合マルチポスト容認派あるいは積極的推進派と言っても良いだろう。
でも、ワテはマルチポストはやらない。何故かと言うと、それは小心者だからだ。
まあ、マルチポストの議論をすると揉めそうなのでこれくらいにしておこう。
コメント欄からマルチポストに関して意見を頂いたとしても、ワテとしては何もお答えしないかもしません。何故かと言うと、小心者だからです。
寝る前に瞑想する
さて、ワテが実践しているプログラミング上達にお勧めの方法を紹介したい。
ワテお勧めのプログラミング上達技法であるが、アルゴリズムを練っている段階で、寝る前に頭の中でそのアルゴリズムを入念にシミュレーションしてみる。
この入力データがこうなって、ああなって、そして最終出力データがこうなる。みたいな感じで順を追ってロジックを検証するのだ。
もしそれで曖昧な点が無ければそれで良いし、もし何か曖昧な点とか未完成な部分があって良いアイディアが浮かばない場合でも、寝る前にそういうシミュレーションをしてから寝ると、ワテの場合には翌朝目が覚めると、物凄い良い解決策が目覚めた瞬間に閃く事が良くある。
で、その閃いたアイディアをコードに書き下すと、良いアイディアが浮かばずに数日悩んでいた問題が一気に解決したなどと言う事が良くある。
なので、みなさんも寝る前に瞑想しながらプログラムのロジックをシミュレーションして眠りに入ると良いかも。
良いプログラムを書くコツ
一般に、良いプログラムを書くコツは(ワテの意見では)以下の通り。
- 一つの関数に沢山の機能を詰め込まない。
- 一つの関数は一つの機能を実装する為に作成する。
- 一つの関数の行数は、まあ長くても100行くらいかな(例外もあるが)。画面に表示出来るのが50行くらいなので100行なら二画面分。それ以上だと混乱の元。
- もし関数が複雑になってきたら細分化して別関数に分離するように考える。
- 関数が複雑になる要因の一つに、関数の入力データが複雑である場合が多い。
- なので、入力データ自身を事前に場合分けして、データ形式がAの場合、Bの場合のように区別する関数を作る。
- それを処理する関数はデータ形式Aのみを処理する関数funcA、データ形式Bのみを処理する関数funcBのように作るとスッキリ書ける場合が多い。
- 初心者が良くやりがちなのは、一つの関数の中で、もしデータ形式がAだったらこの処理をして、もしBだったらこの処理をして、、、のようにif文で場合分けをしていると必ず複雑でややこしい関数が出来あがる。
- 自己流で書いているとヘンテコな癖が付いてしまうので、普段から上級者の人が書いたソースコードを読む習慣を付けておく事。とは言っても上級者の人が必ず読み易いコードを書くとは限らないので色々見てみて自分に有ったスタイルを身に付ける。
- インデントの桁数は何桁でなくてはならないとか、コメントの書き方はこうするべきだなどとあまりこだわらない方が良い。世の中色んなスタイルがあるので、自分はこうだと決めていても他人のコードではそうでは無い。どんな記述方法で有ったとしてもソースを見て処理の流れを把握出来る能力のほうが大事。
- if(!状態変数)やif(状態変数!=true)のような否定形のif文を多用すると後で見直した時に分かり辛い。素直にif(状態変数)やif(状態変数==true)の肯定形で書くのが良い。
などかな。
ループに関してのワテ流お勧め
プログラミングの基本は
- if文による条件分岐
- ループ処理で繰り返す
だろう。
その中で、ループ処理を覚え立ての頃にワテは良く迷った。
つまり、
//① while(条件){ ... }
//② do{ ... }while(条件)
//③ do{ ... }until(条件)
など各種のループがあるが、どれを使ったら良いのかと言う点だ。
最初は while(条件){…} でコードを書いていても、あれ?一回はループ内処理を実行したいからdo~while(条件)を使うべきか?などと良く迷う。
しかし、現在では、ワテの場合基本は
//① while(条件){ ... }
//①の応用版 while(true){ ... if(条件)break; ... }
のどちらかに決めている。
特に後者の while(true){…} で if(条件) break をよく使う。
それは何故かと言うと、
while(i<10) { // ①
処理
}
や
do { // ② 処理 } while(i<10);
を使わなくても、以下の形式を使うと、
while(true){ // ①の while(条件){...} と同じ
if(10<=i) break;
処理
}
while(true){ // ②の do {...} while(条件); と同じ
処理
if(10<=i) break;
}
となるからだ。つまり while(true){…} を一つ覚えておくだけで良いのだ。
あとは if break の位置を調整するだけでどんなループ構造にも変化させる事が可能なのだ。
while, do while, do Until のどのループを使うべきかなどと迷う必要も無い。
長年プログラムを書いている人でもその事実に気付いていない人も多いと思う。
ただし、ループの終了判定が互いに逆の関係になるが、まあ、その点は全く問題ないし。
while, do while, do Until などのループには大きな欠点がある
それと、while, do while, do Until などのループには大きな欠点があるとワテは思う。
例えばwhile(条件){処理} を使うとなると、まず最初に()内の条件式を書かなくてはならない。
そのあとで{処理}の部分を書くことになる。
ところがプログラムを書いている時にループ処理が必要になったとして、行き成りその条件式をスラスラと書き下すのは初心者には難しい。
なぜなら、その条件式の次に行う処理本体の部分をまだ書いていないのに、先に条件式を書くのは無理があるのだ。
それよりも while(true) と書いてまずはループ処理をする事を決める。
そのあとで{処理}の部分を書くのだ。
その処理部分がある程度完成してきたら条件式の部分も決まってくるし、かつ、このループはwhile型にすべきなのかあるいはdo while型にすべきなのかが分かって来るから、状況に応じて if(条件) break; 文の位置を決めれば良いのだ。
ソースコードのコメントは必要最小限にする
モノが捨てられない人、断捨離が苦手な人は気を付けると良いが、ソースコードにコメントを書く場合に、古いコメントを残したまま新しいコメントを追加する人がいる。
まあ古いコメントを消したくない気持ちも分からなくはないが、それは逆に混乱の元だ。
ソースコードは常に最新の状態に保つべきなので、現在のソースコードの機能、引数の意味などを簡潔に記載しておくべき。
それに対して、過去の古いコメントも後生大事に溜め込む人も多いが(ワテやがな)、そうするとコメントがややこしくて読み返しても理解出来ない事もある。
/* 2016-11-22 この関数は・・・の処理の為に作成した。 以下、その説明・・・ ・・・ */ /* 2017-04-05 ↑の説明は一部間違い。 理由はその後、改良して〇〇の処理を□□を使う方式に変更したので。 ・・・ これが現在の最新情報 */ /* 2017-10-05 いや、その後さらに△△の部分を改良して・・・ ・・・ */
ワテの悪いコメント例
みたいに無意味に過去のコメントを残しても分り辛いだけ。
もし残したいなら、ソースコードとは別にワードとかエクセルなど使って個々のソースコードごとに改定履歴や改定内容を文書化して残しておくべきだ。
/* 2017-11-22 この関数は・・・の処理の為に作成した。 機能は・・・ 引数の意味・・・ 使い方は・・・ 過去の改定履歴は〇〇フォルダの△△文書.docに記載有り */
最近のワテは簡潔にコメントを書くように気を付けている
のように簡潔に最新情報のみを記述しておくべきだ。
要するに不要なコメントはバッサリと削除する。
常に最新の正しい情報のみをソースコードに記載する。
一方、〇〇フォルダの△△文書.docでは、時系列で何をどう改定したのかなど、詳しく履歴を書いておくと分かり易い。
もし他の人に引き継ぐ場合でも分かり易いし。
今から書こうとしている処理の流れを文章にする
あと、最近のワテは、関数を書く時にはいきなり思いついた関数を書くのでは無くて、
function func(){ // 目的 // この関数は、...する処理を目的としている。 // この関数でやる処理は以下の通り。 ・・・ };
みたいに、この関数を作成する目的や今から書こうとしている処理の流れを冒頭で文章にするようにしている。
いきなりコードを書き始めると、頭の中が整理できていないので変なコードを書いてしまう危険性がある。コードを書きながらアルゴリズムを考えるのは良くない。時間の無駄だ。
そうではなくて、事前に頭の中で十分にアルゴリズムを練ってそれが完成したらその通りにコードを書くと無駄が省ける。
そのために、まずは頭の中を整理するために、関数の目的や処理の流れを文書化するとその過程で頭の中が整理できるし、もし何か勘違いなどあるとそれに気づくなどのメリットがある。
さらに、そのようにして記述した文章はあとあと、デバッグ時に見直す時にとても役立つ。
後になって何もコメントが無いと、何の処理をする関数か忘れてしまっていて思い出すのに時間が掛かる場合があるが、コメントさえあればどうにか思い出せる。
コメントを書くのは、その関数を作成している時に書くのが最も効率が良い。何故なら、今から作成しようとしている関数なので、その説明がスラスラ書けて当然なのだ。
逆に、コメントを書いている途中に何か詰まるなら、それは頭の中でロジックが十分に完成していない証拠となる。
そういう問題点を発見する上で、関数作成前のコメント記述は、プログラミング上達には、とても効果的だと思う。
結論
ワテ流プログラミング上達の秘訣は以下の通り。
- デバッグ作業で決して諦めない。
- 原因は必ずある。
- その原因は、ほぼ100%あなた自身が間違っているのだ。
- コンパイラ、オペレーティングシステム(OS)などの処理系、環境のバグは、皆無
- 疑うなら自分を。
- なので、最後まで自分を疑い続けてデバッグを続ける
- 決して諦めてはいけない。
- デバッガーを使いこなす。
- 最初は他人のコード、サンプルプログラムをひたすら写経する。
- 自分のプログラムに関して上級者の意見を求める。
- 写経は出来るが自分で設計出来ない人も、上級者・専門家の意見を参考にする。
- その場合は、ネット上の掲示板などで質問するのが手軽でお勧め。
- 低レベルな質問だからと言って投稿を躊躇う(ためらう)必要はない。
- 掲示板で質問して冷やかされたり馬鹿にされたりしても気にしない。
- 掲示板は無料で先生が教えてくれる便利なプログラミング教室だと思えば良い。
- コメントは簡潔に記載、古いコメントは残さない。常に最新状態に書き換える。
などがワテが実践しているプログラミング上達方法だ。
デバッグ関連本
本当に絶対に分かるのかな。ワテは疑い深い。
デバッグの理論、そういうのを研究している人もいるのか。
マンガのようだが、プログラムのデバッグと関係あるのか?
コメント