Edited at

引き継いだソースコードを改変する前に

引き継ぐことになったソースコードを改変する前に、そのバージョン管理とドキュメンテーションコメントとを勧めます。

以下、その理由とどのような部分に気をつけているかを示します。

自分が新たに加わったことで、バグを埋め込んでしまうことは避けなければなりません。引継ぎを開始した時点のソースコードに戻れること、引継ぎを開始して改良する前のコードが何をしているのか理解を高める作業が、プログラムの実装を変える前に必須の作業です。


SVNでバージョン管理する。

SVNの導入の仕方は、web上に各種ドキュメントがあるので検索してください。

バージョン管理してあれば、何か問題を生じたときでも、問題発生前のコードに戻れます。

変更を登録する際には、意味あいの異なる改変を複数同時には登録せず、分けて複数回登録(コミット)することです。

たとえ1人で開発する場合でも、ローカルリポジトリを作ってSVNを使うことを推奨します。

[svn] ローカル環境で Tortoise SVN を使う

もちろんGitを使うのもありです。


Gitを使うべき。SVN にすべき理由がない(2018年追記)

まずは、オープンソースをgithubから fork してみて、個人的に練習するのがてっとりばやいだろう。

以下のような記事もあるから、外部のサービスを利用できない人でもgit を利用することができる。

qiita 個人ユースGitのススメ(その1)


Doxygenを導入する。

DoxygenとGraphvizとをインストールしてhtmlファイルのドキュメントを生成します。

Doxygenならびにgraphvizについても、web上に各種ドキュメントがあるので検索してください。

>doxygen

と打ち込んでhtmlファイルを生成するようにします。

関数のcall tree を出力させるようにしているDoxyfileを書いているつもりなのに表示されないときは

コマンドラインで

> dot

と入力してみます。

dotが見つからないときは、

graphvizのインストール先のディレクトリが環境変数PATHに含まれていることとを確認します。また、dot.exeという名の別プログラムが環境変数の前の方に記述されていないことを確認します。


Doxygen用にドキュメンテーションコメントを書く。

コードの可読性を高めていくことが

C++で既に開発が進んでいるコードを理解するのを助けてくれます。

・Javadocスタイルのドキュメンテーションコメントで可読性を改善します。

@param[in], @param[out], @param[in,out]などで入出力を明確にします。

 引数に構造体のポインタが渡されている場合には、

 関数内部で、構造体のデータメンバーの値が書き換えられているのかいないのかを知るのは手間がかかります。入れ子になった関数で、その構造体のポインタ渡しが続いていれば手間がかかります。


const修飾子が指定可能なものには指定する。

先に@param[in]に分類できた引数が構造体やクラスのインスタンスだった場合には、const 修飾子を追加します。

そして、ソースコードからビルドして、プログラムが動作することを確認します。もし、const修飾子のある変数には、書き込めないという主旨のエラーメッセージが出たら、@param[in]だと思っていたのは間違いだと判明します。


global変数の値がどこで変更になるかを確認する。

Doxygen用のドキュメンテーションコメントで、そのglobal 変数に説明を付けておこう。


構造体の初期化関数、解放関数、値を変更する関数をわかりやすく

構造体という意味のまとまりを作ったときには、

たいがい、それに関連する操作があります。

それを見やすくすることで、メンテナンスをしやすくしておきます。

クラスを定義せず、構造体のままにしておくのも、部署の方針からありえます。


マクロ関数の記述をチェック

部署の方針によりマクロ関数が残っている場合があるかもしれない。その場合、「演算子を含むマクロは、マクロ本体とマクロ引数を()で囲む。」こと。現時点のソースコードがたまたま誤動作していなくても、マクロ引数に負の値が入ったとき、1+2のような式が入ったときにエラーを生じる。そのような地雷は予めつぶしておこう。

 もちろん、マクロ関数よりはインライン関数を使う方がより安全であるのはご存知のとおりである。


列挙型を使ったほうがよいマクロ定数はあるか?

#define LEFT 0

#define RIGHT 1

などとするよりは、

enum Direction = {LEFT, RIGHT};

とする方がよい。

「関連する定数を定義するときは、#defineやconst定数よりenumを使用する。」 [1]

とある。

これらの値と比較する変数を上述のenumの型にしておくと、型の異なる変数が関数の引数に与えられたときには、コンパイルエラーを生じる。このことで、勘違いによるコーディングエラーを予防できる。


改変する必要がある範囲を明確にする

自分の担当の作業では、何を実現する必要があるのか、

その前の版では、何を実現しているのかを十分に理解することを進める。


改変の前後で共通するインタフェースとなる関数を見極める。

Graphvizに含まれるdotコマンドを使ってcalltreeを生成するようにDoxyfileを設定しておくと、その関数を見つけやすくなります。

HAVE_DOT = YES

CALL_GRAPH = YES

CALLER_GRAPH = YES


改変後のインタフェースとなる関数についての改訂の仕様をドキュメント化する。


改変の後でテストするテストベンチを明確化する。

担当する改変の部分だけの動作チェックをする方法を考えて

必要なデータもそろえます。


Redmineを使い始める(もし導入が面倒でなければ)

チームで開発する際に、Redmine(日本語情報サイト)が利用できれば利用しましょう。

何が課題としてあって、何をどう作業を進めていくのかが、チームとして利用可能になります。

「今の作業状況をExcelにまとめて。」などというのは、開発の速度を落とすことにしかなりません。

Redmineは、チケットを発行し管理することで、どういう課題が残っているのか、それぞれが何に従事しているのかが見やすくなります。

十分な考察をしないまま、アルゴリズムの根幹にかかわるような改変をしてはならない。

まとめ


  • SVNでバージョン管理する。

  • Doxygenを導入する。

  • Doxygen用にドキュメンテーションコメントを書く。

  • const修飾子が指定可能なものには指定する。

  • global変数の値がどこで変更になるかを確認する。

  • 構造体の初期化関数、解放関数、値を変更する関数をわかりやすく

  • マクロ関数の記述をチェック

  • 列挙型を使ったほうがよいマクロ定数はあるか?

  • 改変する必要がある範囲を明確にする

  • 改変の前後で共通するインタフェースとなる関数を見極める。

  • 改変後のインタフェースとなる関数についての改訂の仕様をドキュメント化する。

  • 改変の後でテストするテストベンチを明確化する。

参考文献

[1]「組込みソフトウェア開発向けコーディング作法ガイド[C++言語版]」

http://www.ipa.go.jp/files/000005142.pdf

追記;

 ある機能を置き換える書き換えをする場合、その改変範囲がどこまで及ぶのかが自明でない場合には、その機能を新たなnamespaceにおいて、記述しなおすと、変更の及ぶ箇所が明確にあるのではないかと考えている。その新たなnamespaceの中で本当に外部から参照されている部分を特定するという方法がある。

Redmineと書いているけれども

JIRAを用いてチケット関することや

BitBucketなどで、PullRequestでコメントのやり取りなどで

置き換えることができる場合もあるだろう。

この文章を読んだ人が使える環境にある使いやすいツールを使ってください。