とあるブロガーさんの記事を読んで少し考えさせられた。
確かに、プログラミングが出来る出来ないって基準は何なんだろう。
プログラムはあれこれ一応習った
私の卒業した学部は、情報工学科という学科で、所謂コンピュータ・サイエンスに属する学科だ。
しかし、プログラミングを習うが、それほどみっちり習った記憶はない。
最初は、C言語、その後は基本的にJavaだった。
Basicもやったが、それは本当に数時間触る程度だ。
後やった言語と言えば・・・アセンブラ?
これは、低級言語と呼ばれるプログラミング言語で、CPUへの命令に近いところの言語だ。
この言語は、CPU(実習で使ったのはマイコンと言って、本当に初期のCPUだ。)が解釈出来る命令を組み合わせて、ちまちまと書くプログラムで、そのCPUの記憶できる容量や、使用できる演算命令などを調べて書く必要性がある。
CやJava と言った言語はそれに比べて高級言語と呼ばれる。人間が理解しやすいような言語で、これをコンパイラーという翻訳ツールで機械語に変換する。
CとJavaをメインで習った割には、画像処理のライブラリ(Open GL)がC#からだと使いやすいと言う理由で、C#にあっさり鞍替え。
大学の卒論で計算に使った言語は、MatLabとC#だった。
その後、会社で利用する言語も基本的にC#なので、今ではC#しか書けないと思う。
プログラミングが出来るとは?
これは確かに判断が難しい。
でも幾つか、「この人はプログラミングスキルが高いな!」と思えるポイントはある。
ただし、これは私個人の見解なので、ちげーぞ!!ってツッコミはあるかもしれない。
プログラムが綺麗かどうか
綺麗ってなんだよ!って思われるかも知れないが、プログラムには美しさというものがある。
汚いプログラムは本当に酷い。
同じ変数名や似た変数名を使わない
何度も同じ変数名が出てくるプログラム。これは可読性が著しく低下する。
また、誤解を招くプログラムになり、メンテナンス性が低くなる。
昔経験しためちゃくちゃなソースは、
c = a + b
と、本当にそのまま書かれていて、一体全体何を計算して、どこに格納しているのか意味が分からなかった。
しかも、
public int A() { c = a + b; return c; } public int B(int d) { c = a + b + d; return c; } ・・・
もっと中身は色々書いてあったのだが、計算の数値を入れている変数がaとかbとかcとかだったり、それをいくら他のメソッドには影響ないからといって同じ名前で乱発されると、ソースを読んでいる側からすると混乱する。
これは史上最低のプログラムだった。
フラグを乱用しない
他のダメパターンは、やたらとフラグを立てまくるプログラム。
必要以上にフラグを使用すると、いったい何を制御しているフラグなのかが分からなくなる。
挙句には、何をどうしたらこの分岐に入るのかさっぱりわからない!なんてことも・・・
インデントが深くなる(ネストしていく)前に解消する
また、インデントがかなり落ちていくプログラムもいただけない。
つまり、ifやforを繰り返していき、どんどん段が落ちていくプログラムだ。
インデントが深くなる前に、一旦はif文で区切ってしまえばいい。
条件成立なら後続処理を続行。ダメならreturnって具合だ。
例1:インデントが深くなるパターン
public int test () { bool result = true; int calcresult = 0; if (testmethod ()) { if (result) { for (int i = 0; i < 1000; i++) { if (i >= 10) { calcresult += i; } else { //処理なし } } } else { return 0; } } else { return 0; } return calcresult; }
例2:インデントが深くなる前に解消するパターン
public int test () { bool result = true; int calcresult = 0; if (testmethod ()) { //処理続行 } else { return 0; } if (result) { //処理続行 } else { return 0; } for (int i = 0; i < 1000; i++) { if (i >= 10) { calcresult += i; } else { //処理なし } } return calcresult; }
やっている内容は同じだ。でも、インデントが深くならないようにするだけで、随分と読みやすくなる。
また成立する条件も分かりやすい。このように書いてくれたほうが後からメンテナンスする側としては楽なのだ。
メソッドには1つの意味を持たせる(再利用可能にする)
美しいプログラムとは、出来るだけ短く書いたプログラムだ。
これは無駄がないことを意味する。
また、処理をまとめて行うのではなく、あくまで1メソッドには1機能というルールを保っていると良い。
1メソッドの中に、あれこれと処理を詰め込むと可読性が落ちるだけでなく、再利用出来なくなって同じような処理(クローンな処理)があちこちに乱立する。
だから、これを見越してちゃんと区切って短く書かれたプログラムは美しい。
ただ、これらのことは数をこなしていくうちに慣れてきて、強化できる部分だ。
なので、沢山プログラムを書けば書くほど、美しいプログラムとはどんなものか理解できるようになると思うのだ。
機能変更した時にメンテナンスがしやすいかという目線で見ることが鍵だ。そうすれば自ずと、クラスの分け方、メソッドの分け方が意味のある状態で分離され綺麗になっていく。
その場しのぎの処理は、後で100倍ぐらいになって自分を苦しめる。
「誰だ!こんなクソみたいなコード書いた奴は!ぶん殴ってやる!」と思ってたら、自分が3日前に書いたコード。なんてことはよくある(笑)
プログラミングのセンス
大学の頃、プログラミングが超優秀な人物がいた。彼のソースコードを見た時に、「俺には一流になるのは無理だ。」と悟ったので、それ以来、私自身はプログラミングセンスは無いと思っている。
プログラミングセンスってなにかって考えた時、それはアルゴリズムを考えだすことが出来るかという点だと思う。
アルゴリズムのバックボーンとなるものは数学、及び物理だ。
つまり、どのように効率よく計算が行えるかということだ。また、データ保持の仕方も結局は数学が理解できないと、美しく書くことが出来ない。
例えば、1から1000まで足し算せよと言われた時に、どのように書くかという問題があるとする。
1つの確実な例は、素直に1つずつカウントアップして足しこんでいく方法だ。
for (int i = 1; i <= 1000; i++) { result += i; }
もっと楽な方法として、以下がある。
result = (1 + 1000) * (1000 / 2);
端同士を足しこみ、これが何組あるかを掛け算すればよい。
プログラミングセンスがあるというのは、こういう風に同じ処理だとしても、いかに効率よく計算させることが出来るかということなんじゃないかと思う。
確かにぐちゃぐちゃと書いていけば一応動く物は出来る。でも、処理速度が遅くて使い物にならないなんてこともある。
だから、結局は数学や物理が出来るかということが、プログラムの効率的なアルゴリズムを組めるかという話になるのだ。
因みに、私は数学センスはない。なので、圧倒的に前者のぐちゃぐちゃなプログラムばかりを組んでしまう。
大学の頃、ソートに関する演習が出された。(ソートとはデータの並べ替えだが、データを並べ替える方法は沢山ある。)
これは、プログラムで基本中の基本の様なアルゴリズムなのだが、私は理解するのに一苦労した。(馬鹿でごめんなさい;)
また、これをプログラム実装せよという演習もあって、あーでもないこーでもないと頭を抱えて苦しんでいたのだ。
がしかし、友人はいとも簡単にスイスイと解いていき、ギブアップした私は彼に解説を求めた。
まぁ・・・何となくは分かったが(ね?簡単でしょ?とか言われたが、言われた内容の1/10ぐらいしか理解出来てなかった。)、この時彼と完全に頭のつくりが違うことを実感した。
この瞬間に「私は一流プログラマーにはなれないな。」ということだけは理解した。
この問題は後から、あーそういうことかと何とか理解出来たのだが、彼との圧倒的な理解速度の違いを体験した衝撃の時間だった。
そういうわけで、並のプログラムぐらいは書けるけど、私はスーパープログラマーには一生かかってもなれないと思っています。
やはり、そこにはセンスが必要なんだよ。
だからといってひねているわけじゃない。そんな彼らのスピードに置いてけぼりにはされるが、コツコツやれば”並”の中では頭一つ飛び出せるかも知れない。
それが大事だ。私の場合は持久力で勝負するしかないんだろうなと思っている。
そういうわけで、プログラミングが出来るというのは、まず綺麗なプログラムを書けるようになること。
もうひとつは、数学や物理のセンスから効率的なアルゴリズムを実装できること。
この2点だと思うなぁ。