仕事としてソースコードを書く以上、ソースコードを利用する人、ソースコードを書く本人がともに幸せになるようなソースコードの書き方をすべきだと私は考えている。Doxygen(日本語による解説サイト)を使って、詳細の実装の仕様書を作成するように推進している理由の一つは、ソースコードとは別のドキュメントを作成する手間を減らして、負担を減らすことも目的の1つだ。
とりわけ若手エンジニアのみなさん、
仕事としてソフトウェアを書くのだから、仕事を通じて自分が幸せになるようなソフトウェアの書き方をしてください。もし、ここに例示してあるような書き方をしている場合には、ソースコードの書き方について学んでみてください。
- 浮動小数点を==や!=で比較する。
- マジックナンバーを埋め込む。
- 対話的な使い方だからといって、全ての部分を単体テストで再現性を可能にしないインタフェースだけで実装する。
- 分岐の必要のない内容をif文で書く。
- なんでもかんでもtry() catchでまとめて(例外の種類を気にせずに)例外を捕捉する。
- Not a Number を利用可能なライブラリで、NaNの値を通常の有限の値に必要もなく置き換える。
-
if(false){ dosomething();}
で十分なところを#if 0 #endif
を用いて書く。 - 作業の分析が間違っていて、べた書きのソースコードの方がよほどうれしいレベルのクラス実装
- 物理量の単位の一貫性を不必要な理由で損なう。
- 役に立たないコードを多数埋め込む。
- よく知られた実装であり、べたで書いても問題がない意味の明確な簡潔な記述を、不自然なまとまりで関数化する。
- 関数のインタフェースの設計において、参照渡しが可能なのにもかかわらずポインタ渡しで設計する。
- 関数のインタフェースの設計において、const 修飾子をつけることが可能なのにもかかわらず,つけない設計にする。
- std::vectorやstd::mapで十分なことを実装するために、わずかばかりの速さのためにswitch文やif ()else if()文を書くこと
- 単一責務の原理を実行していないコードを書くこと。
バグ修正した際に、一方のコードは修正したのに、もう一方の同様なコードがあることを見逃し、バグを残してしまうことや、保守性が低下してしまうコードになって、後で苦しむことになる。
- C/C++ 至上主義を信奉し、他の言語によそ見をしないこと。
C/C++言語を使いこなしてこなしているのは、すばらしいことです。C/C++言語は、他の言語の処理系を作るための基本になっている言語です。C/C++言語は、とても小さな組み込みチップから、ほとんど全てのコンピュータで利用可能な最強な言語です。
だからといって、「他の言語によそ見をしない」をしないのはもったいないことです。C/C++言語を上手に開発するためには、他の言語でツールを作って開発を楽にすることが可能です。
快適なC++生活のためにスクリプト言語を使おう
は、そのために書いた記事です。
付記:
個人的なお勧めは次の本です。
「プログラミング作法」
若手へのOJTが不十分な職場にいる場合には、自分で気づいて自分自身の書き方を改善していくしかありません。
自分自身を守っていくのは、自分自身の力しかありません。このサイトにたどり着いている人は、
ここに書いた「べからず集」など不要な方々であることでしょう。しかし、このアドバイスが役立ちそうな人には
ぜひ、この記事を紹介してくださることを期待します。
###追記:なぜ、それぞれの「べからず」なのか
作業の分析が間違っていて、べた書きのソースコードの方がよほどうれしいレベルのクラス実装
・見えるべきインタフェース
説明しやすく、聞いた人も理解しやすいインタフェース。
正しく動いている、間違っているが判定しやすいインタフェース。
単機能であって余計なことをしていないインタフェース。
依存性が少ない(=直交性がよい)インタフェース。
テストがしやすいインタフェース。
見えるべきインタフェースが見えないと、テストがしにくくなる。
・private属性のメソッドを単体テストの自動化ツールでテストしようとした時点で、
public属性に変更したことがある。
・メソッドの属性をどうすべきは、アルゴリズムの実装時点ではよく理解しきっていないことが多い。
このメソッドがpublic 属性であればよかったのにと、自分の編集権限がないソースコードをみて苦しい思いをする。
実装担当者は、その実装を利用する人でないので、どの変数がどのようにテストされる必要があるかを理解していない。
浮動小数点を==や!=で比較する。
「数値計算を理解していない人」、そのようなコードを出荷している会社は「人を育てることが出来ていない会社」とみなされます。そのことは、いい仕事が入って来にくくなる状況を作り出します。
対話的な使い方だからといって、全ての部分を単体テストで再現性を可能にしないインタフェースだけで実装する。
単体テストを重視していないことがばればれです。
「我々の環境ではうまくいった。」とだけ(=テストコードやテスト結果なしに)言われても、納品物を受け取る側ではうまく言っている裏づけをもらえない限り、手続きを進めることはできません。検収処理後、その部分で問題が発生すると、受け取りの側の担当者は何をやっていたのかということになりかねません。受け取り側の担当者の今年の評価が下げられてしまって、給与が減るということさえおこります。
対話的な使い方の場合、再現テストでデグレード 【 degrade 】、劣化が生じていないことを確認するのがやりにくくなりがちです。対話的な使い方をしている関数でも、その内部の中で対話的でない部分を取り出せる部分はあるはずです。まずそこから始めてみましょう。
対話的な使い方だからといって、全ての部分を単体テストで再現性を可能にしないインタフェースだけで実装する。
自分の作ったライブラリを使う部分でバグが発生したということになると、自分の作ったライブラリが疑われます。
そうなると、その部分のデバッグに自分がかりだされることになります。そしてさんざん四苦八苦したあげくに、エラーを発生させていた部分は、自分の作ったライブラリではなかったことを示すことになります。そのためには、他の部分で生じていることを証明する証拠が必要になります。
ですから、「対話的な使い方だからといって、全ての部分を単体テストで再現性を可能にしないインタフェースだけで実装する。」ことは、不幸の元になります。
物理量の単位の一貫性を不必要な理由で損なう。
単位の一貫性の問題は、このような結果をもたらします。
[~単位系の取り間違いで火星探査機が行方不明~]
(http://www.sydrose.com/case100/287/)
「この探査機を使って論文を書くんだ。」、「その探査機からのデータを受け取って処理するシステムを開発・運用するんだ。」とはりきっていた人たちの人生に大きな変化を生じたことは間違いありません。
関数のインタフェースの設計において、const 修飾子をつけることが可能なのにもかかわらず,つけない設計にする。
一見、変数の値を変えないことを期待する関数の引数のならびにおいて、constをつけておかないと次のようにして、バグに苦しむことになる。
その関数とはまったく別な場所で、妙な挙動をすることを見つけます。
その部分のソースコードをよむとおかしそうな挙動がないように見えます。しかし、実際におかしいのです。
そこで、それらの「 関数のインタフェースの設計において、const 修飾子をつけることが可能な」はずの引数にconst属性をつけていきます。
そうすると、constをつけてビルドに失敗するのがでてきます。そのすると、その関数がその引数の値を変えてしまっていたことが分かります。
constをつけた状態で、目的の動作をするように修正します。そうすることによって、バグを見つけ解決することができます。
そのように強力なツールであるconst修飾子を使わないことは、あまりにももったいないのです。
若手エンジニアを不幸にしないための開発の「べからず」集
を書きました。