わかりませんスマートフォン用の表示で見るよくわかりませんこの広告は、90日以上更新していないブログに表示しています。2009-05-16そのソースコードが汚い理由:共通した根源的な間違いソフト開発この内容には私も全面的に賛成で、クラスやフィールド、メソッド、名前空間など、とにかく文字として表れる名前には、必ず、例外なく、正しく誤解のない命名を徹底することが非常に重要だ。http://blog.livedoor.jp/lalha/archives/50261226.html先のエントリは、danさん*1やlalhaさんにまで言及いただき大変光栄で、なにより多くの人に読んでもらえた。一方で、自分で読み直すと「先のエントリ」は、いくぶん観念的でいまいちよく分からないところもあるかなと思った。いうわけで、より実践に結びつきやすいように、「何に気をつければいいのか」「どういう考え方でコードを書けばいいのか」を書いてみる。たくさんのソフトウェアの「つくり」に触れ、APIを熟知しようと非常によく整合して親和する考え方だと思ってる。プログラマの良心を自ら邪魔している、プログラマ自身の誤解に基づく行動、それはプログラマたる者、誰だって自分のソースコードはきれいに書きたいと思っている、はず。プログラマはきれいにしたいと思っているのに、その希望に反してソースが汚くなるとき、またはきれいではなくなるとき、プログラマは決まってある事をやっている。自分はこれが諸悪の根源で、かつ、ソースを汚くする原動力となる上にハマリによる時間の浪費を招き、バグをも増やしてコードの汎用性まで下げる、コーディングに現れる悪魔みたいなものと思ってる。(゚Д゚)ハア?これを徹底的に排除する事で、様々な効果得られ、ソースコードも必然的に綺麗になる。わからねーと思うが(ry。「そんなん、きれいとか汚いとか関係なく、やらなきゃしょうがないことだろ」と思う読者が多いかもしれない。実際はそうではないこと、「必要な動きにしようという考えで、ソースに手を入れる」事を排除して、ソースコードを綺麗に書き、バグを減らして、変更に強いプログラムにできる事を以下で述べたい。「必要な動きにしようという考えで、ソースに手を入れる」と、どういう事が起きるか、から。正しい名前、つまり「それは何?」という思考が抜ける・弱まる・後回しになる名前の重要性は、前回書いた通り。「正しい名前」とは、それが何なのかを、そのスコープにおいて的確に表現している名前のこと。「それは何?」を一言で言うには、その名前以外に言い様がないような名前。「正しい名前」へのこだわりは、名前そのものがよくなるだけでなく、「正しい名前」を考える事で「それは何?」という思考がはたらき、ソースの整理をうながし、設計まで改善される所にその威力がある。きれいなソースとは、すべてについて「それは何?」が明確となっていて整理されているソース。逆に汚いソースとは、「それは何?」という事が曖昧で整理もままならないようなソース。「必要な動きにしようという考え」でソースをいじり、「必要な動き」を実現したらどうなるか。普通の人間なら、「ふう、できた。」とひとつの達成感が得られるだろう。そのとき、「必要な動き」が出来ただけならば、ソースコードについて「正しい名前である事」が壊れている。「必要な動き」を実現する事自体には、「正しい名前」を維持する必要がまったくないのだから。「必要な動き」がソースを破壊するスーパープログラマーは分からないが、自分のような平凡なプログラマは、コーディングで大なり小なりの試行錯誤が入る。テスト段階でもNGが出たら直すし、使い始めてバグが出てもソースを直す。ソースは一度タイプしたらそれで完成するものではなく、どんどん書き直されるものだ。最初の時点ではすべてについて「それは何?」が明確となっていて整理されたきれいなコードを書いていても、「こうすれば必要な動きになる」という修正が入っていく事で、本来の「それは何?」を表していた名前と、実際の実態が少しずつずれていく。「hogehoge」という関数・メソッドに、「ここでこれをやれば『必要な動き』になる」と、「hogehoge」には不要な処理が追加される。「fugafuga」という関数・メソッドが、「ここでやる事を変えれば『必要な動き』になる」と、「fugafuga」じゃないものに変容する。「pugepuge」という変数に、「ここでこういう値を入れれば『必要な動き』になる」と、「pugepuge」じゃない値が入れられる。「geregere」というクラスに、「ここにこういうメソッドがあれば『必要な動き』を作れる」と、「geregere」の責任ではない機能が追加される。やって、きれいだったソースも、だんだんきれいでなくなっていき、汚くなっていく。これはそのコードを最初に書くときも同じ。「こういう動きが必要だな」という事を考えて、その動きをさせるべくソースを書いていくと、上記のようにめちゃくちゃなソースになる。負ける汚いソースは様々な害悪を振りまきながらも、そのときはなんとか「必要な動き」だけはやってくれる*2。その場限りの労力を考えると、ソースをきれいに保つより汚く修正する方が非常に楽ちん。「動き」は否応なく結果が出るのに比べて、「きれい」かどうかというのは人が判断する分、かなり曖昧。「きれいに保ちたい」という漠然とした気持ちを持っていてそれに従って頑張ろうとしても、「必要な動き」という発想を基本思考としてソースを修正する限り、「動き」の強さに負けて基本的にソースは汚くなっていく。逃れられれば、ソースはきれいになる。ソースをきれいにしたいと思って頑張っても、「必要な動き」を追う限り、ソースは汚くなる。逆に言えば、「必要な動き」にさえ束縛される事がなければ、ソースをきれいにしたいと思いがあり「正しい名前」を維持する労力を払えば、当然ソースはどんどんきれいになる。解決方法は決まっている。いう発想を最初から捨ててしまえばいい話は簡単。ソースをきれいにするには最初から「必要な動き」という発想を捨ててしまえばいい。worldみたいな例から入って、if文やfor文などの説明に入っていき、「こういう書き方をするとプログラムがこう動く」という観点で説明が書かれる。自分が読んだのもそうだったと思う*3。そのため、ほとんどのプログラマは「プログラム=動きを書く物」という基礎認識を最初から持たされることになり、習熟して経験を積んでもその認識の影響から逃れることが難しい。そのような認識は、初心者向けの方便に過ぎない。ソースをきれいにしたければ、そのような誤った認識から脱却しないといけない。プログラムとはどういうものと認識すればいいのか。対象が大きければ、対象を分析して、定義に必要なプログラミング言語上の語彙を増やす。名前だけじゃなくて、それが示すものの定義をプログラミング言語で書く。やって語彙を積み上げていって、実現しようとしている事の定義を書く事がプログラミングに他ならない。プログラムを書き始めるときに使える語彙は、環境に用意されたライブラリしかない。その語彙を利用して組み合わせて、新しい語彙の定義を書く。やって新しく作った語彙、環境に用意されている語彙を組み合わせて、対象の定義を書くのに必要な新しい語彙を積み上げる。やって作った、対象にフィットした語彙を使って、実現しようとしていること全体の定義を書いた物がプログラム。「正しい名前を付けて、正しい名前である事を維持」する事=「プログラム=対象の定義」という認識このプログラムに対する認識は、大仰な書き方に見えるかもしれないけど、実際は発想の問題に過ぎない。「正しい名前を付けて、正しい名前である事を維持する」事を本当に至上命題としてプログラミングしていたら、実際にやる事はまったく変わらない。対象を定義するのに必要な物を考える。それに名前を付けて、名前の定義を書く(=名前のついた物を実装する)。実装を動きではなく意味で見直し整理・洗練させる。名前を付けられる独立性がある部分は名前を付けて独立させる。名前と定義(実装)が合っているか確認する。単純に定義(実装)の方が間違っていたら定義(実装)を直す。必要だと思っていた物(名前)が実は違っていて定義(実装)の方が必要なことを正しくやっていたのであれば、名前のほうを直す。繰り返しこの認識で、プログラムのきれい・汚いは、プログラムが汚いとは、語彙の意味があやふやで不安定であることプログラムがきれいとは、語彙の意味が明確で一貫していることという風に考えられる。語彙の意味があやふやで不安定だとどうなるかプログラミング言語でなくて日本語などの普通の言語でも、言葉はその意味が安定しているから使うことができる。「赤」は、波長700nm前後の光であると言うことに安定しているから、「リンゴが赤い」「真っ赤な血」「フェラーリの赤」のように様々な物の記述に使えて、その記述が意味をなす。これが、「動き」という意味不明な物の都合のために、あるときは500nm前後の光を指し、またあるときは1000nm前後の光を指し、しまいには「よくわからないけどこれで必要な動きになるんですよ」といってリンゴを指したり、というようでは、そんな言葉でまともに何か書くことはできない。プログラムも全く同じ。いうよりもっともっと厳しい。日本語を読む人間は融通を利かせて意図を汲んでくれるが、コンピュータは一切融通が利かない。めちゃくちゃな言葉で書かれていたら、書かれたとおりのめちゃくちゃな結果を出す。言葉がめちゃくちゃでも結果オーライになることは確かにある。それはそのときその場だけの結果オーライ。定義(プログラム)に手を入れるとき、使える言葉の意味がこの「赤」のようにめちゃくちゃであれば、そんな言葉を使ってまともな定義を書くことは、きわめて困難で無駄な労力を必要とするうえに、結果も予測困難な危険な作業になる。バグ=語彙(名前)の定義記述の誤りプログラムがプログラミング言語での対象の定義だとすると、それがおかしくなるのは、こういう時。使ってる語彙の定義が間違ってる「それ」を指しているはずの名前に対して、その定義が「それ」の定義としておかしい語彙の使い方が間違ってる「それ」をさしている名前を、「あれ」を指していると思って使っているこれがバグの目に見えない本当の姿。使ってる語彙の定義が間違ってる「それ」を指しているはずの名前に対して、その定義を「それ」の定義になるように書き直す。語彙の使い方が間違ってる「それ」をさしている名前は「それ」として使う。「あれ」が必要なら「あれ」を使う。「あれ」がなければ、「あれ」を使わない定義方法を考えるもしくは、「あれ」を新しく定義するこうやる。いう発想でプログラミングをしていけば、「必要な動き」に足を絡め取られることなく、ソースはどんどんきれいになり、ハマりによる無駄が回避され、バグも減り、変更に強いプログラムになる。API・ライブラリ=最初から用意されてる語彙。よい作り=うまい言い回し・文章構造ここまで、ソースをきれいに書くということを中心に述べてきた。効率よくには、なんでも自前で語彙を作るのではなく最初から用意されてる語彙を熟知して、うまく使うことが重要なのはいうまでもない。日本語の言葉を知らない作家が失格であるように、プログラミング言語に用意された語彙を軽視していてはプログラマとして問題だ。わかりやすく整理された文章は、うまい言い回しやうまい文章構造を備えている。先人たちがたどり着いたうまい言い回しやうまい文章構造を学ばずに、全部自分でオリジナルに考えるというのは無謀に過ぎる。プログラミングにおいても、全く同様。