わかりませんスマートフォン用の表示で見るよくわかりませんこの広告は、90日以上更新していないブログに表示しています。さんが公開しているわかりやすい技術文章の書き方の改変です。このページは、プログラムやコードなどを書く方々のために、分かりやすいプログラムを書くためにはどうすればよいのかについて説明しています。自分が伝えたいこと・訴えたいことを誤解しないように相手に読んでもらうにはどうするべきか。プログラムを書くにあたって知っておくべきルールは何か。プログラムを書く前にどのような手順を踏めば、分かりやすいプログラムを作れるか。ついて参考にしていただければ幸いです。プログラムを書く前にプログラムを書く前に次のことをしっかりとイメージしておく。書こうとしている物は正確に何であるのか。仮定して良い、必ず成り立つ前提(状況/状態)は何か。成り立つ事が単に多いだけ/今はたまたま成り立っている、という仮定してはならない前提(状況/状態)は何か。核となる概念・構成物は何か。プログラムを知るプログラムとは何か現実世界の課題が与えられ、または自分が課題を提起し、その課題に対して明確な解を与え、その課題を取り巻く現実世界を正確に定義する語彙を作成して、それによって解を記述する。標準的な構成要素とは何かプログラムの構成は、言語により様々であるがモジュール・パッケージ・名前空間クラス・インタフェース・モジュールメソッド・関数ブロック・コード片という要素が標準的である。次にそれぞれの要素について簡単に見てみる。互いに強く関連するクラス・インタフェース・モジュールをまとめる。クラス・インタフェース・モジュール提供するメソッド・関数によって実現するただひとつの責務は何か。責務に対する考え方は明確で十分単純であり、かつ、一貫しているか。その責務を果たすために本当に依存すべき前提は何か。状況依存や前提を切り離して、責務がより単純にならないか。必須ではない他のクラス・インタフェース・モジュールに依存していないか。依存先を上位の型に変更できないか。必須ではない値を保持・利用していないか。依存先の型に任せられないか。引数に対して返却すべき物は何か。それは明確であり、かつ、一貫しているか。切り離せる状況依存や前提を抱え込んでいないか。引数に追い出せないか。引数の型を上位の型に出来ないか。必須ではない非ローカルの変数(グローバルやクラスなど)を利用していないか。引数に追い出せないか。記述のレベルは詳細過ぎないか、具体型に依存し過ぎてないか。意味が明確な下位関数に切り出してそれを利用して書けないか。引数側に任せられないか。複数の事をしていないか。そのほかに、プログラムの利用のためにはプログラムのドキュメント・マニュアル、確認にはテストなどを書く。対象が大きければ、対象を分析して、定義に必要なプログラミング言語上の語彙を増やす。名前だけじゃなくて、それが示すものの定義をプログラミング言語で書く。やって語彙を積み上げていって、実現しようとしている事の定義を書く事がプログラミングに他ならない。プログラムを書き始めるときに使える語彙は、環境に用意されたライブラリしかない。その語彙を利用して組み合わせて、新しい語彙の定義を書く。やって新しく作った語彙、環境に用意されている語彙を組み合わせて、対象の定義を書くのに必要な新しい語彙を積み上げる。課題を取り巻く現実世界を細分化するプログラムを書くときにはまず実装を省いた概略プログラムつまり主要語彙集を作る。実装を省いたプログラムを作成するためには、課題を取り巻く現実世界を細分化する。細分化するためには、課題に対する解の思い付きに対して次のような質問をする。本当にそうなのか?どういう意味だ?いつから、いつまで?どこで?誰からの視点か、誰にとって該当するか?どのようにして?どんな状態なのか?どうやって行うのか?なぜなのか?ほかの事例ではどうか?これについては?これだけか?すべてそうなのか?どうすべきだろうか?それぞれの質問について、現時点で思いつくことのできた答えのアイディアや仮説をメモする。この答えは仮の目標であり、語彙集のネタである。答えを思いつかなかった場合は、どんなことを調べれば答えられそうかを調べ、そのアイディアを書き込む。思いついた答えに問いを与え、それぞれの問いをさらに細分化する。細分化した問いから主要語彙集へ細分化した課題を取り巻く現実世界を、実装を省いた概略プログラムつまり主要語彙集に持っていくためには問いを捨てる。解を記述するのに最も重要な問いを中心に据える。その課題を解決するために関連する問いや話題をピックアップする。使用できるライブラリや既存実装を調べ、利用できそうかどうか、語彙がうまく噛み合うかを検討する。粒度は適切か主要語彙集からプログラムへ簡単なトップレベルのみの動かないプログラムを作る。語彙の不足があれば補う使用している語彙に、短くて正確な名前を与える。名前に適合する実装を与えるため、必要なブロックやコード片を付け加えて、メソッド・関数を作る。それぞれのメソッド・関数から不要な物を削り、実装を簡潔にする長くなりすぎたメソッド・関数を、いくつかのブロックやコード片に整理し直し、可能ならそれらを別の下位レベルまたは同レベルの語彙として独立させるそれらを再度精査する。分かりやすい表現で書く語彙の用意とその定義記述を区別する木下是雄氏は「事実と意見(判断)との区別を明確にすることが特に重要である」と述べている。木下氏の考えはおいておいて、語彙の選択とその定義記述際の注意点を紹介する。課題を取り巻く実世界に関してそのプログラムのなかで書く必要があるのは何かを十分に吟味する。抽象的であっても、どのような場合でも成り立つ明確な意味にする。できるだけ明確な意味を持たせ、引数などのパラメタや子クラスなどの各実装側が責務を負えばよい詳細や具体性を混入させない。語彙の意味を完全に記述する。その定義に必要なレベルの粒度の語彙を使用して出来るだけ短く書く。詳細は他の語彙に頼るが、正確に使用する。語彙の意味に対して、勝手に前提条件を加えていないか注意する。先に考えた語彙の意味に問題があれば、語彙自体を見直すさまざまな表現に対する指針プログラムはさまざまな表現で成り立っている。その表現の書き方を次に紹介する。変数スコープはできるだけ短く。変更不要であれば変数ではなく定数にする同じ変数を複数の用途に使用しない原則的に変数の数は減らして簡潔にする。hoge();return関係ない場合はすぐにreturnする。if(hoge){長い長い実処理;;}returnではなくif(!hoge)return;長い長い実処理;;ループループは繰り返しではなく契約で考えて記述する。ループ事前条件、ループ中不変条件、ループ事後条件。型の名前はそれがどういうものであるかを、値の名前は使い途を。キャメルケースやスネークケースなどは、コーディング規約や言語の通例に従う。プログラムを書く上でのポイントなど最後に、プログラムを書く上でのさまざまなポイントをリストアップしておく。したWebページ『わかりやすい技術文章の書き方』(http://www.123kobe.com/doc/writing/)改変元ネタ『あなたのソースを汚くして生産性も下げている、たったひとつの間違い』(http://d.hatena.ne.jp/r-west/20090516/1242489952)『きれいなソースコードを書くために必要な、たったひとつの単純な事』(http://d.hatena.ne.jp/r-west/20090510/1241962864)この作品は、クリエイティブ・コモンズ・ライセンスの下でライセンスされています。※中盤辺りで順番がおかしいなどネタレベルの草稿なのであとで断りなく修正するかも知れません。17:33[ソフト開発][ネタ]わかりやすいプログラムの書き方Tweet広告を非表示にするもっと読むコメントを書く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・ライブラリ=最初から用意されてる語彙。よい作り=うまい言い回し・文章構造ここまで、ソースをきれいに書くということを中心に述べてきた。効率よくには、なんでも自前で語彙を作るのではなく最初から用意されてる語彙を熟知して、うまく使うことが重要なのはいうまでもない。日本語の言葉を知らない作家が失格であるように、プログラミング言語に用意された語彙を軽視していてはプログラマとして問題だ。わかりやすく整理された文章は、うまい言い回しやうまい文章構造を備えている。先人たちがたどり着いたうまい言い回しやうまい文章構造を学ばずに、全部自分でオリジナルに考えるというのは無謀に過ぎる。プログラミングにおいても、全く同様。