Skip to content

Latest commit

 

History

History
152 lines (103 loc) · 7.54 KB

coding-standard.md

File metadata and controls

152 lines (103 loc) · 7.54 KB

Autowareコーディング規約

下記に従うようコーディングを行ってください.

ROS開発ガイド

初めに一読しておいてください.

コーディング規約

新規にコードを書くときは ROS標準のコーディング規約に従うようにしてください.

ROS C++コーディング規約

clang-formatを用いた自動フォーマット

https://github.com/davetcoleman/roscpp_code_format

上記のサイトに ROS C++コーディング規約のための, .clang-formatファイルがある. このファイルを利用することで, インデントサイズ, カッコ位置等のスタイルに 関する規約については自動で準拠することができる.

利用方法

  • clang-formatをインストールする(Ubuntuだとパッケージあり). 新しいバージョンが良い
  • プロジェクトのトップディレクトリに .clang-formatファイルを置く
  • clang-format -i filenameとすると .clang-formatに従いフォーマットしてくれる

clang-format -iだとファイルは上書きされるので, 実行前に "git commit"を しておくと安全である.

システム全体に適用するには以下のようなシェルスクリプトを実行すればよい.

for file in $(git ls-files | \grep -E '\.(c|cpp|h|hpp)$' | \grep -v -- '#')
do
    clang-format -i $file
done

ROS Pythonコーディング規約

PEP8準拠をチェックするツールは pep8などで機械的に行えばよい. 現状の ROSは Python2.5をターゲットとしているようだが, Ubuntu 16.04以降では デフォルトの Pythonのバージョンが 3になるので, 今後の保守を考えると, Python3準拠で書いておいた方が良いと思う.

ライブラリ化における注意点

  • パッケージ間の依存関係を不必要に増やさない. 循環依存は絶対作らない
  • そもそもライブラリ化する必要があるかを検討する
  • 他パッケージの msgファイルから生成されたヘッダファイルを includeしない
  • テストしやすいように書く

パッケージ間の依存関係を不必要に増やさない

パッケージ間の依存は少ない方が望ましい. 特に循環参照が発生してしまうと, ビルドができない状態に陥ってしまう.

そもそもライブラリ化する必要があるかを検討する

汎用的なもの以外は切り出さない方がいい. パッケージ間の依存を返って高めてしまう可能性がある. 別パッケージにするほど有用かをまず考える. 単に関数の切り出しなら, 同じパッケージ内にライブラリを 作成した方が良い.

他パッケージの msgファイルから生成されたヘッダファイルを includeしない

msgファイルから生成されたヘッダファイルを includeすると, ライブラリがその msgを持つ パッケージに依存してしまう. 結果そのライブラリをリンクするパッケージも, その msgを持つ パッケージに依存してしまうことになってしまう.

メッセージとして受け取ったデータの処理をライブラリに切り出したい場合は, メッセージに含まれるデータ型(std::vector等)を渡すようにする. もしくは別途定義したメッセージの型に依存しない class, structに移し替える.

現在のライブラリの実装で気になったところ(2016年 3月 30日現在)

下記のような設計, 実装は推奨されない.

グローバル変数の多用しすぎている点

ライブラリ側でグローバル変数で状態を保存するのでなく, classや構造体に状態を持たせた 方がよい(errnoのように真に大域的なグローバル変数は例外であるが, そのような変数が 必要になることはほとんどない).

C++であればメソッドとして実装, C言語であれば引数でポインタを渡すように実装すればよい.

またグローバル変数を使う関数の場合は, 複数スレッドを使った場合, 値の取得, 更新に おいて問題が発生する可能性がある(スレッドセーフ). ROSではユーザの見えないところで スレッドが使われる可能性もあるため, 極力グローバル変数を使わないことが望ましい. 必要な場合は複数スレッドからのアクセスがあるかを考慮し, その可能性がある場合は 排他制御を行う必要性を検討する.

ライブラリ関数の引数がない or 戻り値が void型

ライブラリ関数の引数がない or 戻り値が void型ということは副作用のために 関数呼び出しを行うことになる. このような関数はテストしづらく, 理解もしづらい. ライブラリ関数(not クラスメソッド)については副作用のない関数型スタイルで あることが望ましい. つまり引数が同一であれば結果が一意になる関数.

ネーミング

現在のライブラリ関数のネーミングには以下の問題がある

  • 名前が単純すぎて理解が難しい
  • 名前が単純すぎてシンボル名重複が発生しうる

例えば fusionライブラリには init, destroyと名前付けされた関数が存在するが, これだけ見ると何に関する初期化, 終了処理なのかがわからない. また名前が ありふれているためシンボル名が重複してしまう可能性も高い.

解決案

  1. ライブラリの prefixを使う
  2. namespaceを使う
ライブラリの prefixを使う

上記で挙げた fusionライブラリの場合, fusion_init, fusion_destroyとする. こうすることで少なくとも fusionに関する処理ということはわかる.

namespaceを使う

全体を namespace autoware::fusion {}(もしくは autoware)でラップする. 利用するときは autoware::fusion::init, autoware::fusion_init等になる. システム全体が namespaceを 使っているのであればこの方法が望ましいと思う(特に Autowareのパッケージを一部だけ 切り出し, 別プロジェクトで使うというケースがある場合).

export, 非 exportシンボル

exportするシンボルを明確にする. 現在の実装では不必要に多くのシンボルが export されている. 他パッケージから参照しない関数は exportしないようにする.

C++言語, 無名 namespaceでラップする(ファイルローカルの static指定は非推奨). class, structであれば privateにする. C言語では staticを指定し, スコープをファイルローカルにする.

参考文献

C++11(14, 17)には型推論等便利な機能が多く加わっているので, C++11以降の内容が 記載されている本を一読することを推奨する.