バグ退治を促進する開発を行うためのヒント
デバッガーは使わないという人はいますか? 最後に使ったのはいつだったか、記憶にないですね。 それは、嫌いだからではなくて、単に必要ないからなんです。 その一番の理由は、ある種の開発手法を使っているおかげで、バグの発生を少なく抑えたり、単体テストのレベルで発見したり、バグをとても簡単に追跡できたりするからです。
以下にいくつかヒントを紹介します...
1. 独自の COS チートシートを作成する。
これは主に COS の初心者が対象になります。 バグを引き起こす大きな原因の一つとして、特定のコマンドや関数の動作を理解していないということがあります。 時間をかけて言語を学び、そのすべてのバリエーションを試すことをおすすめします。 それから独自のチートシートを作成することで、知識が固まり、さっと使えるレビューツールも出来上がります。 生産性アップにつながるほか、避けられるはずのバグをうっかり書いてしまう頻度を確実に減らすことができます。
2. スタジオで「変数の追跡」をオンにする
まだオンにしていない方は、スタジオの 「 ツール 」「 オプション 」メニューにて、「 環境」フォルダの「クラス」と順に移動し、「変数を追跡する」のチェックボックスにチェックを入れてください。 宣言時に初期化されていない変数を使用する場合は、その変数の下に波線が引かれます。 このおかげで、うっかりタイプミスはありません。
また「option explicit」も使用できます。 個人的には使わなくてもいいと思いますが、ひょっとしたら役に立つかもしれません。 すべての変数において、最初に #dim 宣言を行うことが強制されます。
3. 構文チェックをオフにしない
これは、主な理由として、エラーに下線を付けてくれるので、デフォルトでオンにしておくべきです。 パフォーマンスに影響すると不平を言いながら、このオプションをオフにするデベロッパーを何人が見たことがあります。 言い訳はやめて、処理の早いマシンにしてください。 これもスタジオのオプション設定にあります。
4. 常にオートコンプリートを使用する
変に聞こえるかもしれませんが、私はオブジェクトに対してプロパティやメソッド名を最後まで入力することは一切ありません。 いつも数文字だけ入力してから、オートコンプリートの項目を明示的に選択するようにしています。 こうすれば、インスタンスメンバーの入力ミスでバグが発生することは絶対にありません。 使っていると思っていたクラスと実際に使っているクラスが違うという深刻な問題を見つけることもできます。
オブジェクトがオートコンプリートしない場合は、コードに #dim を追加してください。そうすれば、オートコンプリートするようになり、他のデベロッパーにとってもそのコードが読みやすくなります。
5. コードを簡潔にする
分かりきったことですが、コードを簡潔にすれば、バグが発生しにくくなります。 よく考えずに数百行にもおよぶコードを書き出すデベロッパーを何度か目にしたことがあります (実際に必要だったのはその半分もしくはそれ以下でした)。 コードをコンパクトにまとめるということではなく、慎重に整理すべきだということです。 もちろん、最初は少し時間がかかるかもしれませんが、結局は先週他の人が書いたコードのデバッグ作業で無駄になる時間をそれに充てていると考えればいいのです。 落ち着いてやれば、作業はスムーズに進みます。
6. コードを適切な場所に書き込む
「患者」というようなエンティティクラスがあれば、患者に影響するすべてがそのクラス内に記述されている必要があります。 ベテランの OO (オブジェクト指向) デベロッパーには当たり前に聞こえるかもしれませんが、このようなコードを非エンティティのメソッドに埋め込むデベロッパーは未だ少なくありません。
このコードを移動させることで、厳しくテストされたコードの再利用が促進されるほか、非エンティティのメソッドも小さくなり、デバッグしやすくなります。
7. すべてのステータスコードを処理する
この戦略は必要不可欠なもので、私は習慣的に行っています。 ステータスコードが返されることがあれば、次の行に進む前に検証しています。 エラーが出る場合は、ステータスコードを確認してから終了し、エラーを処理するレベルに戻ります。
これは、私が見る限りでは、他のデベロッパーが実行していないという問題の中で一番大きな問題でしょう。 やっていない方にはおすすめします。
Ensemble で開発している方には、Ensemble ライブラリのあちこちで使用されている、便利なマクロがあります...
$$$QuitOnError(sc)
macro soup を好まない私も、これは気に入っています。コードをより簡潔にしてくれるので、肝心な部分だけを読むことができます。
また、try-catch 文を使う場合は、catch をそのメソッドのステータスコードとして強調表示します。
8. 再利用可能なモジュール単位のコードを書く
これはおそらく「コードを簡潔にする」の見出しに該当すると思われますが、できるだけ小さくて機能性の高いメソッドを書く、ということに重点を置いています。 各メソッドの目的は 1 つに限定するべきです。 1 つのメソッドを入力と出力を明確にした、いくつかの小さなメソッドに分割できるなら、そうするべきです。
9. 単体テスト、単体テスト、単体テスト
上述のヒントをすべて実行したら、このアクションが次に行う最も重要なステップとなります。なぜなら、デバッガーを起動することが必要になる前に、エラーを除去できるからです。 単体テストの結果としてエラーが発生すれば、該当する小さなコードブロックからそのエラーを除去することに集中できます。 デバッグ作業を行ったり、この問題を探してコードの中をあちこち探し回ったりする必要はありません。エラーの発生場所は的確に分かります。
私は、ブラウザーから動作する非常に便利な社内用の単体テストツールを持っています。 コマンドラインの面倒で複雑なセットアップは不要です。 興味のある方がいれば、オープンソースとして公開します。 主に、Ensemble を使ったトランスフォーメーションの単体テストに便利です。
10. そして、ついに、何をやっても効果がない場合は...
コードをステップスルーせずにデバッグするには、グローバル変数が欠かせません。 そこで、私は以下のようなコードを書きます...
Set ^debug($zh,"foovar")=foovar
そして、コマンドラインから zwrite ^debug を実行するか、for loop の監視を実行します。
こうすることで、何行もあるコードをいちいちステップスルーする場合よりも、すばやく問題を発見できます。非同期プロセスの場合はなおさらです。
11. 最後に、少しお恥ずかしいのですが。。。
大したことではないですが、私はよくやっています。 問題を突き止められず困っているときは、ちょっと散歩に出かけて、視野を広げてみます。 戻ってきたら、明らかなものでも先ほどは視野が狭すぎて見えなかったというエラーの存在に気が付くと思います。 個人的には、違うネームスペースにアクセスしているなんてことをよくやらかしています。(オイオイ!)
バグの少ないコードを書くことについて、他のヒントがあれば是非聞かせてください。
最新情報...
12. ラバーダッキング
13. コードレビュー
よく見落としがちだが、重要な提案です。 スタイルガイドが良い補足になると思います。
14. ログの記録
これもまた良い提案だと思います。 Ensemble にはコードに関する情報をログしたり、表示したりできる一連の便利な機能があります。以前は隠れていたエラーを強調表示したり、断続的に発生するため発見しにくいような問題を追跡できます。
Caché デベロッパーの皆さんには、開発者コミュニティに掲載されているログソリューションが重宝するかもしれませんね。
Sean