@kyanny's blog

My thoughts, my life. Views/opinions are my own.

Code Complete 第2版 上

どうにか読み終えた。長期間かけて長い本を読めると自信がつく。全体のうち七割くらいはすでに知識や経験として知っていて驚きも感動もしない内容だった。十何年もやってきて驚き感動の連続だったら逆にまずそうなのでこんなもんなのかもしれない。残り三割の内訳は、半分はなるほどと納得でき、半分は意図を理解した上で賛成できない、みたいな感じだった。

目次を見た感じだと上巻は特に基礎っぽい内容のようで、序盤のコンストラクションというやや聞き慣れないテーマを過ぎてからは至って普通の話が延々と続く。変数名をわかりやすくしろとか、ループや条件分岐のネストを深くしすぎるなとか。この手の話題だと「リーダブルコード」のほうが詳しくて実践的、しかも薄くて安いので、あえて cc2e でなければならない理由はもはやないのでは、という気がする。ただ「リーダブルコード」はややもすると駆け足・詰め込みすぎな感は否めないので、あれでは濃密すぎてついていけない場合はこちらのほうがゆったりしていて読みやすいかもしれない。

Code Complete 第2版 上 完全なプログラミングを目指して

Code Complete 第2版 上 完全なプログラミングを目指して

以下、ハイライトした箇所を Kindle の Your Highlights 一覧ページからスクレイピングして取り出した。さすがにけっこう多い。スクレイピングは https://github.com/kyanny/playground/tree/gh-pages/nokogiri-kindle-highlight-scrape みたいな感じで適当にやった。下手に汎用的に書こうとして失敗した感じになった。画像として本文中に埋め込まれているコードのハイライトは空白になってしまってちょっと残念。

プログラミングでは、食物連鎖の各段階に健康に良い食物があると、幸せなプログラマによって書かれた健全なコードが得られる

水にありがとうと話しかける、みたいな話だ

こうして、栄養不足の不機嫌なプログラマと、放射能に汚染された欠陥だらけのソフトウェアが生じることになる。  
ソフトウェア製品の構築は、プログラマにとってもユーザーにとっても学習プロセスである
SapirとWhorfの仮説によると、物事を考える能力は、その考えを表現できる言葉を知っているかどうかにかかっている

読書家はえてして頭が良い

PHP:‥Hypertext Processo

Hypertext Preprocessor では?と思ったらやっぱりそうだった。どうでもいいことをよく覚えているものだ。

Griesは、言語の中でのプログラミングと、言語の中へのプログラミングを区別している

ここと次の段落を再読すると良い

この一見矛盾しているような理論は、基本的に、問題を明確に定義するためにいったん「解決」した後、有効な解決策を作成するためにもう一度解決しなければならないことを示すものだ

確かにそういうことよくある気がする。

「凝った」設計はだいたい理解するのが難しいので避ける。代わりに「単純」で「理解しやすい」設計にする。ある1つの部分に集中して取り組む際に、プログラムの他の部分を簡単に無視できないような設計は、その目的を果たしていない
ユーザーとのやり取りを1つのクラス、パッケージ、またはサブシステムにまとめれば、システム全体に影響を及ぼさずに変更できるようになる

何年か前に Perl 界隈で「API 層を設ける(外部に公開された HTTP アクセスできる API ではなく)」という話がまさにここで述べられていることだな

情報隠ぺいについて考えることが、オブジェクトについて考えたときには得られなかった設計へのひらめきを与え、その決断を促すのである
「何を隠ぺいすべきか」と自問する習慣をつけよう
情報隠ぺいの原則を守れば、こうした業務ルールに基づくロジックがプログラムにまき散らされることはなくなる

この視点はすごく大事だと気付いた。まき散らかされると始末に負えない(経験あり)

たとえば、エラーの状態変数と関数の現在の状態を示す変数との組み合わせをチェックしたい場合、その評価がルーチンに隠ぺいされていれば簡単だが、プログラムに複雑な評価がハードコーディングされていると難しい
恋人どうしのようにくっついているのではなく、職場の同僚のように冷めた関係にしよう
図を使用する目的の1つは、問題をかなり抽象的に表すことができるからだ。したがって実際には、「百聞」のほとんどは必要ない
ほとんどの場合は単に目新しさを求めて、あるいは凝ったことがしてみたいという理由でしかない
最も効果的なガイドラインの1つは、1つの方法にこだわらないことである
ほぼ必ずと言っていいほど、2回目の設計の方が1回目よりもうまくいく
プログラムはどこまで分解すればよいのだろうか。次のレベルを分解するよりもコーディングする方が簡単に思えるまで続けよう。設計があまりにも明白かつ単純で、これ以上は耐えられないと思えるまで続ける。その時点で、作業は完了である
プロトタイプのリスクは、開発者がコードを使い捨てコードとして扱わない場合である
「設計手法の適用に関して独断的であればあるほど、解決される現実世界の問題は少なくなる」(Plauger 1993
読むのはたいへんだが、ヒューリスティクスに興味があれば、望もうと望むまいと、結局は読むことになる
クラスインターフェイスにルーチンを追加する際、必ず「このルーチンは既存のインターフェイスが実現する抽象化と矛盾しないか」どうかについて検討す
何が起きているのかを理解するために基本実装を調べなければならないとしたら、それは抽象化ではない

なんかしびれるセリフだ。

クラスの使用法を理解するためにクラスの実装を調べていることに気付いたら、それはインターフェイスに対するプログラミングではない。インターフェイスを通じて実装に対するプログラミングをしているのである

これほんとにその通りだなぁ。身に覚えがありすぎる。

インターフェイスで公開されているドキュメントだけではクラスの使用法がわからないという場合は、ソースコードを引っ張り出して実装を調べたりしないことが正しい反応である。調べるという姿勢は評価できるが、判断を誤っている。正しい反応とは、クラスの作者に連絡をとり、「このクラスの使用法がわからない」とはっきり言うことであ
そして、そのときのクラスの作者の正しい反応は、あなたの質問に面と向かって答えないことだ。そして、クラスインターフェイスのファイルを調べ、クラスインターフェイスの仕様書を書き直し、新しいファイルをチェックインして、「これでわかるかどうか見てくれないかな」と知らせることであ
このやり取りをインターフェイスコード自体で行えば、将来のプログラマのために残しておける。あなたの頭の中だけでやり取りすると、そのクラスを使用するクライアントコードが意味的な部分に微妙に依存するようになる。また、個人どうしのやり取りは、あなたのコードの助けになるが、他人のコードの助けにはならな
包含とは、クラスが基本のデータ要素やオブジェクトを保持しているという単純な概念である。継承に比べて取り上げられる機会は断然少ないが、それは継承の方が難解でエラーの原因になりやすいためであり、継承の方が良いからではな
プログラマは、そのAccountオブジェクトがどの派生クラスのインスタンスなのかを意識せずに、Accountクラスのすべてのルーチンをすべての派生クラスで呼び出せなければならない
プログラムが派生クラスの実装の意味的な違いを常に意識しなければならないとしたら、継承は複雑さを軽減するどころか、逆に増大させる
派生クラスのコードを読んだプログラマは、そのようなルーチンを見て混乱するだろう。なぜなら、ポリモーフィックでなければならないものに見えて、実際にはそうでなく、同じ名前が付いているだけなのだ
ルーチンを上位レベルへ移動すると、上位レベルのオブジェクトの抽象化がうまくいかなくなるような場合は、そのレベルへ移動しないこと
将来必要になることを見込んでそうしたのだろうが、だいたい、将来の必要性が何なのかを十分に理解しないまま設計している。将来のために準備するとしたら、「いつか必要になるかもしれない」層の基底クラスなどは設計しないことが得策であ
現時点の作業をできるだけ明白に、まっすぐに、単純にすること。それは、絶対に必要な継承構造以外、何も作成しないということ
深い継承階層は複雑さを増大させる。まさに、継承を使って実現すべきこととは正反対である。本来の目的を見失ってはならない
分別するためにcase文が使われることがある。オブジェクト指向プログラミングにふさわし い

「ふさわしくない」では?

継承は、プログラマの第一の責務である複雑さへの対処にマイナスに働く傾向があ
複雑さを抑えるには、継承に対して大きな偏見を抱くべきである
パフォーマンスが改善するという確証がないのに複雑さを増大させることは、良い打開策であるとは言えな
シャローコピーを使用すべき根拠が明確になるまでは、ディープコピーを使用するこ
設計者が異なれば、抽象化される一般概念も異なる
クラスを作成する最も重要な理由は、プログラムの複雑さを低減することである
小さな処理は大きな処理に変わりやすいことだ
機能的凝集度を達成するために複数のルーチンを修正するのはよくあることだ
全体的に見て、ルーチンに名前を付ける際には、名前をできるだけ明確にすることに重点を置く。つまり、ルーチンの意味を理解するのに必要な長さにする
コードは200行を超えた時点で、わかりやすさの上限にぶつかる運命にある
inputValThatBecomesWorkingValといった気の利かない名前や、xやvalといったなげやりな名前にしてみることもできるが
ルーチン自体とルーチンが呼び出される場所の両方に条件を明記することは、決して無駄な作業ではない。ルーチンをすべて書き終えてから、あらためてコメントを書くのは良くない。それでは、すべての条件を覚えていないかもしれない
一般に、ルーチンの呼び出しの「準備」をするコードと、ルーチンが呼び出された後の「後始末」をするコードの存在は、ルーチンがうまく設計されていないことの証であ
安全性や高い信頼性が重視される環境では、引数が期待どおりに一致することに保険をかけるのは、決して無駄な行為ではない
コードをプロファイリングして、パフォーマンスがどれだけ改善されたか測定してみよう。コードをプロファイリングして改善具合を確認する手間をかけるほどの向上が見込まれないのであれば、コードの品質を低下させる必要はな
アサーションは、絶対に発生すべきでない状況が発生していないかどうかを確認す
一般に、エラー処理では不正な入力データを確認し、アサーションではコードのバグを確認する
例外の最大の利点は、無視できないような方法でエラー状態を知らせることであ
他の方法でエラーを処理すると、コードを通じてエラー状態を伝達しても、気付かれない可能性があ
例外はアサーションと同じような状況で使用される。つまり、まれにしか発生しないイベントではなく、絶対に発生してはならないイベントで使用され
配列のインデックスのエラーが原因で例外がスローされた場合は、配列の上限と下限、および不正なインデックスの値を例外メッセージに盛り込
単に言語のエラー処理メカニズムがそれだからという理由で、エラー処理に例外を使用するプログラマもいる。そうではなく、エラー処理のすべての可能性を検討すべきである
通常は外部データが渡されたときにそれらを消毒することだ

このへんが入力値のバリデーションと「サニタイズ」支持の誤認識による根拠になってるのだろうか

入力データは入力されたときに正しい型に変換する  一般に、入力データは文字列か数値の形式で渡される
バリケードの内側でいずれかのルーチンが不正なデータを検出したとしたら、それはデータのエラーではなく、プログラムのエラーである
デバッグコードを使って防御的プログラミングをサポートする方法については、『Writing Solid Code』(Maguire 1993)を参照
そこで、リンクリストの整合性を確認するためのメニューオプションを追加した
プログラマにEnterキーを押して既知の問題を無視する習慣を身につけさせてはならない。問題に痛みを伴わせて、問題が修正されるようにす
データの損失につながるようなコードがプログラムに含まれている場合は、それを製品バージョンから削除する
あまりにも防御的なプログラミングも、それはそれで問題である
何でもやりすぎはよくないが、ウイスキーは飲みすぎたくらいがちょうどよい。  ─ Mark Twai
「擬似プログラミングプロセス」(Pseudocode Programming Process:‥PPP
「擬似コード」という用語は、アルゴリズム、ルーチン、クラス、またはプログラムのしくみを説明するための略式の表記法を指
プログラミング言語の構文要素を使用しない
プログラミング言語の構文を使用すると、詳細レベルに下がってしまうので、少し高いレベルで設計するという利点がなくなってしまうし、意味もなく構文上の制限に縛られてしまう
こうした一般的な状況に対して提案されたアプローチ以外に、個々のルーチンのレベルで効率に取り組むことは、通常は無駄な努力である
それが必要であることがわかるまで、改良を繰り返して時間を無駄にしてはならない
一般に、ルーチンの役割をコメントに要約することが難しいとしたら、何かが間違っていると考えてよいだろ
いったんコーディングを開始したら、コードへの愛着が湧いてしまい、悪い設計を捨てて最初からやり直すことが難しくなる
どれくらい単純になればよいかというと、擬似コードの文章の下にコードを書いていき、元の擬似コードをコメントとして残せるくらいが目安であ
仕様は詳細なものだったが、それでも、ルーチンを作成するには擬似コードと実際のコードでかなりの設計作業が必要だった
この詳細レベルの設計は、「コーディング」がなぜ重要な作業なのか、なぜ本書のテーマが重要なのを説明する1つの理由である
趣味のプログラマとプロのプログラマとの最大の違いの1つは、迷信の域を出て理解の域へ達しているかどうかである。ここで言う「迷信」とは、満月の夜の恐ろしいできごとや、なぜかその夜に限ってエラーが増えるプログラムのことではない。コードに抱く理解以外の感情である
30~32 鼻持ちならない詐欺師。「細長いストリーム(elongated stream)」、「逆向シナプス(retroactive synapse)」、「値の連鎖(value chain)」は、データ型の用語ではなく、わざと混ぜておいたものだ。下巻第33章の「33.4 知的な誠実さ」を読もう
暗黙の宣言は、どの言語においても最も危険な機能の1つに数えられる
■変数は最初に使用する場所の近くで初期化す
これは、「関連する作業を1つにまとめる」という近接の法則の一例である
コンパイラの設定を使用する場合は、ドキュメントに必ず明記すること。そうしておかなければ、特定のコンパイラの設定に依存する条件はなかなか見つけられない
。変数の参照を近くにまとめると、コードの読み手がコードをセクションごとに読んでいけるようになる。参照が離れていると、読み手がプログラムをあちこち拾い読みしなければならなくなる。よって、変数の参照をまとめる最大の利点は、プログラムが読みやすくなることである
変数の持続間隔と同様に、変数の寿命もできるだけ短くする、つまりステートメントの数を少なくすることが目標とな

でもオブジェクトの親子関係が何段階かにネストしているとき、親から子、孫、ひ孫へ渡して、子孫の間でデータを同期するために使うオブジェクト、の変数は、寿命が長く、参照箇所が離れてしまうけど、これはどうしたらいいんだろ。

変数の寿命が短いと、コードが読みやすくなる。読み手が一度に頭に入れなければならないコードの行数が少なければ少ないほど、コードは理解しやすい
変数の値が酸っぱくなっていてエラーになることもあれば、変数に古い値が残ったままになっていたために、変数を正しく使っていると思い込んでしまうこともある
ソフトウェアの要件を満たすために必要な柔軟性を組み込み、それ以上の柔軟性(および、それに伴う複雑さ)にこだわらないのが、腕の立つプログラマである
良い名前というテーマは重要であるにもかかわらず、良い名前の作り方を10項目以上にわたって取り上げた本を読んだことはない
1つ目の特徴は、解読しやすいことである。実際には名前を読めばわかるので、解読する必要はない
平凡な単語が最もやさしい答えであることが多いにもかかわらず、プログラマはそれを忘れてしまうことがよくある
currentは何がcurrent(現在)なのかを示さないので、悪い名前であ
名前の最適な長さは、xの長さとmaximumNumberOfPointsInModernOlympicsの長さの間にありそうである
修飾子を使って名前を修飾する場合は、修飾子を名前の最後に付ける
Numを変数名の先頭に付けると、合計を意味す
Numを変数名の末尾に付けると、インデックスを意味す
顧客の総数を表すのにはCountまたはTotalを使用し、特定の顧客を表すのにはIndexを使用して、Numを避けるのが得策だろ
フラグの名前をflagにするのは考えものである。これでは、それが何のフラグなのかさっぱりわからないから
コードの一部を「推理」していることに気付いたら、変数の名前を変更することを検討しよ
コードは推理する必要などないはずである。コードは読んで理解できるものにしよう
一般に、一時変数はプログラマが問題を十分に理解していない証拠であ
肯定的なブール変数名を使用す
命名規則の威力は、特別に選ばれた規約によってもたらされるのではなく、規約が存在するという事実によって生じるものである
される可能性がある(Arnold, Gosling and Holmes 2000) 。

参照渡しでは?

これはナンバープレートの文字を指定するときに人々が考えそうなことにあまりにもそっくりなので、個人的には推奨しない。試しに、次の名前の意味を考えてみよう。

なるほど、さっぱり意味がわからない

名前に含まれる数字が本当に重要であるなら、別個の変数ではなく配列を使用すること。配列が適していないとしたら、数字はなおさら適していない
ただし、数字を絶対に使ってはならないとは言い切れない。現実世界のエンティティには数字が埋め込まれているものがあるからだ(旧国道66号線、州間道路405号線など)
他のプログラマのコードを読むだけでも一苦労なのに、異国の意味不明な言語で書かれたコードを読むことはとうてい不可能である
「color」と「colour」のどちらなのか、「check」と「cheque」のどちらなのか悩まずに済むよう、英語をどれか1種類に統一すること
これを使うのは正真正銘の愚か者である。
恋人の名前、妻の名前、大好きなビールの銘柄といったひねった(ばかげた、ともいう)名前を変数に付けないこと
実際に恋人や妻や大好きなビールのために書かれた場合ならまだしも、そうした場合でさえ、それらの名前がいつ変わるかわからないことを考え
ブール変数には、真(true)の場合にそれらの意味が明確になるような名前を付けているか
この数は変更されないという確信があったとしても、名前付き定数を使用すれば、コードが読みやすくなる
プログラムの本文で使用されるリテラルは0と1のみ、というのが原則である
大きさが極端に異なる数を加算しなければならない場合は、数をソートしてから、絶対値の小さい順に足していく
鍵となるのは、すべての文字列を外部リソースに保存するかどうかを決定することと、言語ごとに異なるビルドを作成するのか、それとも実行時に言語を判定するのかを決定することである
列挙型の最初の要素をわざと無効な値に設定す
原則的に、変化するものを一元管理する手法には、保守作業を軽減する効果がある(Glass 1991)
安易に配列を使うのはやめて、シーケンシャルにアクセスできるコンテナクラス(セット、スタック、キューなど)を使用することを検討しよう
プログラマが定義するデータ型は、プログラムを理解しやすくするための言語の機能のうち、最も強力なものの1つに数えられる
倍精度浮動小数点数が必要になりそうだが、本当に必要であることがはっきりするまで、単精度浮動小数点数を使ってプログラミングしたいと考えている
プログラムが変更され、結局、すべての座標を倍精度浮動小数点数型の変数で表さなければならなくなったとしよう
社員名の長さが最大30文字であるとしよう。これは、顧客から名前が30文字を超える社員は1人もいないと聞いたからだ

あるあるだ

それよりも、社員名の専用の型を定義する方がよい。
複数のプログラマが作業する開発環境では、パッケージの仕様だけを配布することができる。そうすれば、別のパッケージを担当しているプログラマがCoordinate型を調べ上げることは難しくなり、情報は文字どおり隠ぺいされることにな
新しい型を作成する作業はほんのわずかだが、それによって柔軟性が大幅に向上する
ユーザー定義型を作成する最大の利点は、プログラムと実装言語との間に絶縁体を設けることである。プログラミング言語の型を指すような名前にするのは、絶縁体に穴を開けるようなものだ。これでは、ユーザー定義型を使用する意味はほとんどない
機能に基づいた新しい型は簡単に作成できるが、ハードコーディングされた型を使用するプログラムのデータは、そう簡単には変更できない
プログラムを理解するうえで最も難しい部分は、どのデータがどのデータと関連しているのかを突き止めることかもしれない
このテクニックをさらに進めて、プログラムのすべての変数を1つの大きな変数に詰め込み、どこにでもそれを渡すという方法も可能である

:coding_horror:

ポインタの使用は、現代のプログラミングにおいて最もエラーの原因になりやすい領域の1つである
最近の言語に至っては、ポインタデータ型そのものを提供しな
ポインタの使用は本質的に複雑であり、それらを正しく使用するためには、コンパイラのメモリ管理方式を知り尽くしていなければならない
使用している言語ではポインタを使用する必要がないとしても、ポインタをよく理解しておけば、プログラミング言語のしくみを理解するのに役立
メモリ上の位置と、その位置に含まれている内容をどのように解釈するかという知
特定のアドレスにあるビットが意味のあるデータに解釈されるのは、特定の型のポインタを使った場合だけであ
通常は、エラーの場所を特定することはエラー処理の中で最も容易であり、それを修正するのは困難であ
ポインタのエラーは、ポインタが指すべきではない場所を指していることが原因で生じることが多
ポインタのエラーの症状は、ポインタのエラーの原因とは結び付かないことが多
ポインタのエラーを修正する作業のほとんどは、原因の場所を突き止めることに費やされ
ルーチンでメモリを割り当てて、クライアントコードで割り当てを解除する仕様にすると、矛盾が生じてエラーの原因になりやすい
ドッグタグフィールドを使って、破壊されたメモリを検査す
どのような犠牲を払おうとも、ポインタ変数をけちってはならない
ほとんどのプログラムは、大雑把な意味で「グローバルデータ」を使用している。データベースのデータはグローバルデータであり、Windowsレジストリのような構成ファイルに含まれているデータもグローバルデータである。名前付き定数は、グローバル変数でなくてもグローバルデータである
概念的にプログラム全体に適用されるデータがあ
呼び出しチェーンの途中にあるルーチンがオブジェクトを使用しない場合、そのオブジェクトは「トランプデータ」と呼ばれる
情報隠ぺいを目的として設計されていなくても、アクセスルーチンは情報隠ぺいの一例であ
>∨ MAX_LINESというコードを書く代わりに、if PageFull()というコードを書くことができる 。

でもこういうの経験上結局名前だけでは信用できなくて実装見るまで安心できず潜っちゃうけどなぁ。

ほとんどの場合、グローバルデータは設計や実装がうまくいっていないクラスのクラスデータであ
グローバル変数のリストは、知らないだれかが書いたプログラムを使用する人にとって、最も効果的なツールの1つである
グローバル変数を使用しない。単にリスクがあるからという理由だけでなく、他にもっと良い方法があるからだ
「type casting」は、演劇用語では蝶々夫人の役を日本人に演じさせるといったステレオタイプなキャスティングを意味する
会計処理に詳しければ(あるいは常識かもしれないが)、3行目の年間利益を計算するためには、その前に四半期の利益を計算しなければならないことがわかる
長すぎるので良くないように思えるかもしれないが、ルーチンの機能を説明していることを考えれば、名前自体はそれほどひどくない。ひどいのはルーチンの方である
正常なケースの実行パスを最初に書いてから、例外的なケースを書
正常なケースの処理はelse文ではなくif文の後に書
例外的なケースを選り分けることなくメインの流れを読めることに主眼を置いているので、コード全体が読みやす
ネストしたif文の最後にエラー状態がまとめられているのは、エラー処理コードがうまく書かれている証
case文を使用するために仮の変数を作らな
case文は簡単に分類できる単純なデータに使用すべきである。データが単純でなければ、代わりにif-then-else文を使用す
case文の構文に合わせるために仮の変数を使用すると、その変数が嘘の評価をすることもあるので、使用すべきではな
case文のdefault句は正しくないコマンドを評価するはずだが、うまく機能しない。なぜなら、コマンドが正しいかどうかではなく、その1文字目が正しいかどうかを評価しているからだ
default句ではその他扱いにするものだけを検出す
case文が1つだけ残っていると、それをdefault句としてコーディングしようと考えることがある。その誘惑に負けてはいけな
終了しないループを使用することがある。あるいは、ループが終了するのはイベントに応答するときだけ、という場合もある。このようなループを「イベントループ」と
これでは、recordCountがループを制御するような誤った印象を与えてしまう
continue文については、if-then句を使ってループのその回の残りを実行しないようなものと考えればよいだろう
『Software Engineering Notes』の記事によれば、1990年5月にニューヨーク市の電話を9時間にわたって不通にしたソフトウェアエラーは、余計なbreak文が引き起こしたものだった(SEN 1990)
Javaは、ニューヨーク市の電話事故を繰り返さないために、ラベル付きのbreak文をサポートしている
break文やcontinue文を使う理由を説明できないのなら、使わないことである
こうした確認を行う意志があるかどうかが、有能なプログラマと有能でないプログラマの分かれ目になる。有能なプログラマは、頭の中でシミュレーションし、電卓で計算する。なぜなら、そのような評価がエラーの特定に役立つことを知っているからだ
有能でないプログラマは、いろいろな組み合わせをでたらめに試して、うまくいきそうなものを見つけようとする傾向にある。うまくいくと思っていた方法がうまくいかないと、有能でないプログラマは不等号<∧を<∧=に変えてみたりする。それでもうまくいかないと、ループインデックスに1を足したり、ループインデックスから1を引いてみたりする
処理しなければならないことは、構文やループ変数や配列のインデックスの詳細を考えないときの方がまとめやすい
何か具体的なものから始めて、一度に1つのことを検討していき、単純なものからループを作り上げていくとよい
この例のポイントは、問題を解決するためのプログラミングを行うこともあれば、問題が特定の言語では自然に解決されることもある、ということである。問題の解決に使用する言語は、解決策を大きく左右する
ほとんどの人は、再帰を初めて使用したときに、再帰の自己参照に何かしっくりこないものを感じるだろ
循環再帰がある場合は、ルーチンの設計を見直して、再帰を1つのルーチンに限定する。それは無理だが、やはり再帰が最善の解決策であると考えるなら、安全カウンタを使って再帰に保険をかけること
■階乗やフィボナッチ数列に再帰を使用しな
コンピュータサイエンスの教科書における問題の1つは、再帰のくだらない例を掲載していることである
この例から3つの教訓が得られる。1つ目は、コンピュータサイエンスの教科書に載っている再帰の例は、世の中のために役立たないことである
goto文を使用すると、コンパイラの最適化が無効になる
goto文を1つでも許可すれば、良いコードに悪いコードが紛れ込むことになる。したがって、goto文は一切許可しない方がよい
良いプログラミングはgoto文をなくすことではない。秩序だてて分解し、詳細化して制御構造を選択すれば、ほとんどの場合はgoto文のないプログラムが自然に生じ
goto文のないコードを実現することは、目的ではなく結果であり、goto文を避けることに終始しても良い結果は得られない
goto文なしでも簡単にコーディングできることを披露するはずだったプログラミング本は、あろうことかサンプルの書き換えにしくじっている
あなたが管理者である場合は、たった1つのgoto文をめぐって争うことは、敗北に値しないという姿勢でのぞむこと。プログラマが代わりの方法を知っているうえで論争をいとわないという場合は、おそらくgoto文を使用しても問題はな

ここちょっとよくわからなかった。どういう意味だろう

プログラムのコードをその場で生成し、そのコードを実行するこ

これはメタプログラミングとしていまもまだ支持されているのでは?

ソフトウェア開発の分野は、プログラマがコードを使ってできることを制限することによって大きく前進してきた
データはロジックよりも柔軟な傾向にある

したがって壊れやすく、コードを壊しやすい。

継承やポリモーフィズムを使用したからといって、それが良い設計であるとは限らない
各自の状況に適した選択肢の中から、いずれか1つを選ぶことだ。一番良いものを選ぶことにこだわる必要はな
最善の解決策を見つけ出そうとするよりも、良い解決策を見つけるための努力をし、大惨事を避ける方がよ
肯定的でない短くない文字列を理解するのに一切苦労しないわけではない人々は少なくない。つまり、ほとんどの人が否定文を繰り返されると理解するのに苦労する
論理式を肯定的に作成するというアドバイスは、正常なケースをelse句ではなくif句にコーディングするというアドバイスと矛盾することがあ
そのような場合は、双方の利点を考慮して、どちらが状況に有利であるかを判断すること
だが、これはプログラミングプラクティスとしては最低で、コードの読み手を混乱させる可能性がある
これに対し、&&(and)は左から右へ評価されるので、リスト19-18のステートメントは論理的に等しいものの、うまくいかない
Javaの&論理演算子と|論理演算子は、式を完全に評価しなくてもその真偽を決定できるかどうかにかかわらず、式のすべての項が完全に評価されることを保証す
また、コードの読み手が書き手ほど鋭いとは限らないので、評価の順序や短絡評価をあてにせずに、ネストした評価を使ってコードの意図を明確にしておくとさらによいだろう
19.1.6 | 数値を含んでいる式は数直線の順番に並べ
0を使用する目的を強調するようなコードを書くべきである
通常は、標準以外のマクロを作成するよりも、コンパイラの警告レベルを最大にしておく方がよい
一般に、Javaプログラムではa==bよりもa.equals(b)形式の式を使用すべきである
if文の評価に続くステートメントを1つだけにすれば、審美的にはアピールするかもしれないが、保守作業にとってはやっかいなブロックになりがちで、エラーの原因にもなりやすい
この方法では、ループ制御変数が新しく追加され、余分なコードが必要になるが、副作用を巧妙に利用したものでない、ストレートなプログラミングプラクティスがはっきりと示されている。製品コードはこれくらいはっきりとわかりやすい方がよい
きく改善するので、検討する価値がある 。

これはあんまり同意できないなー複雑な条件式のほうがやっかいなときはよくある。

評価が冗長である。quantityが1,000よりも大きいかどうかを評価するために、quantityが100や10よりも大きいかどうかを評価する必要はない
この解決策は、数字が大きい順に並んでいるのでわかりやすい
else句を使用する方が望ましい理由は、評価を無駄に繰り返さないことに尽きる
Deposit、Withdrawal、Transfe
また、一般的には、複雑なコードはプログラムへの理解が足りないために単純にできないことの表れである
ルーチンを修正しなければならないと決まっているわけではないが、そうしないのなら、それを説明する十分な理由がなければならない。
「構造化プログラミング」という言葉の起源は、1969年にNATOのソフトウェアエンジニアリングカンファレンスでEdsger Dijkstraが発表した歴史的な論文「Structured Programming」にさかのぼる(Dijkstra 1969)
構造化プログラミングとは、構造化されたトップダウン形式の設計のことではない。構造化プログラミングはコードの詳細レベルにしか適用されない
読みにくいということは理解しにくいということであり、結果的に、プログラムの品質は低下する
構造化プログラミングのテーマは、どの制御フローも、連続、選択、反復という3つの構造から作成できるということである(Bohm and Jacopini 1966)
私に言わせるなら、構造化プログラミングの3つの構造以外の制御構造(break、continue、return、throw-catchなど)が使われていたら、批判的な目で見るべきである
制御構造を正しく使用しなければ複雑さが増し、正しく使用すれば複雑さが減る
「プログラミングの複雑さ」を表す1つの基準は、プログラムを理解するために頭の中で一度に整理しなければならないオブジェクトの数である
Tom McCabeは、プログラムの複雑さはその制御フローによって定義されるとする有名な論文を発表している(McCabe 1976
有能なプログラマは自分の脳みそがほんのちょっとしかないことを十分承知している。だから、とても謙虚な姿勢でプログラミングにのぞむ」(Dijkstra 1972
驚異的な複雑さに対処することはとうてい無理なので、複雑さをできるだけ緩和する措置を講じなければならない
■論理式を単純で読みやすいものにすることは、コードの品質に大きく貢献する
どのようなプログラムも、連続、選択、反復の組み合わせで作成することができる