Clang-FormatでObjective-Cのコードを整えたらレビュー捗る
最近Objective-C書いてるのでClang-Formatというツールを試してみた。
些末なコードレビュー - naoyaのはてなダイアリー にもある通り、コードレビューするときにいちいちソースコードのフォーマットを指摘し続けるのはアンチパターンで、人間以外がやるべき仕事。
PerlならPerltidyというツールがあるけど、Objetive-C(C, C++)にはclang-formatというコマンドがある。暇なので社内で導入出来るように調べた。
ClangFormat — Clang 3.5 documentation
使い方
CLIの場合は以下のように実行する。-iで指定したファイルを上書き、-styleでフォーマットを指定する。
$ clang-format -i -style=Google Hoge.m
これだけで既存のコードがフォマッターの設定通りに整えられる。
2014年4月6日現在、brewコマンドでインストールすることは出来なかったので以下のブログを参考に自前でビルドしても良い。
blog.hardcodes.de: Building clang-format and friends on OSX Mountain Lion
が、しかしXcodeのプラグインとしてインストールするとバイナリがそのままついてくるのでそれを使うと良いし、実際にコード書くときに反映されたほうが便利。
Xcodeでの設定手順
travisjeffery/ClangFormat-Xcode というプラグインをインストールする。
- XcodeにAlcatrazというプラグインパッケージ管理ツールを入れる http://alcatraz.io/
- ClangFormatをインストールする
- リポジトリ内のトップレベルのディレクトリに.clang-formatという設定ファイルを置く
- Xcode上で Edit > Clang Format > File と Enable Format on Saveを選択しておく
Fileを選択すると自分自身が作った設定を利用できる。 他にも既存のLLVM, Google, WebKit, Mozillaなどのフォーマットを利用できるけど、どれも割りと極端(インデントが空白2つとか1行80文字とか)だったりするので自分たちのチームでいい感じになるようにアレンジすると良いと思う。
以下の様な全く意味は無いコードが、デフォルトで備わってるGoogleのフォーマットに整えるとこうなる。
- (NSNumber*)fooBarWithBaz:(NSObject*)baz fizzBazz:(NSNumber*)fizzBazzFizzBazFizzBazFizzBazFizzBaz { NSArray* array = @[ @1, @2 ]; if ([array objectAtIndex:1]) { return @1; } NSNumber* result; for (NSNumber* element in array) { switch ([element intValue]) { case 1: result = @100; break; default: break; } } return result; }
- (NSNumber*)fooBarWithBaz:(NSObject*)baz fizzBazz:(NSNumber*)fizzBazzFizzBazFizzBazFizzBazFizzBaz { NSArray *array = @[ @1, @2 ]; if ([array objectAtIndex:1]) { return @1; } NSNumber *result; for (NSNumber *element in array) { switch ([element intValue]) { case 1: result = @100; break; default: break; } } return result; }
C++のフォーマットがベースになってる。 * Google C++ Style Guide * Google Objective-C Style Guide
WebKitだとこんな感じ The WebKit Open Source Project - WebKit Coding Style Guidelines
- (NSNumber*)fooBarWithBaz:(NSObject*)baz fizzBazz:(NSNumber*)fizzBazzFizzBazFizzBazFizzBazFizzBaz { NSArray* array = @[ @1, @2 ]; if ([array objectAtIndex:1]) { return @1; } NSNumber* result; for (NSNumber* element in array) { switch ([element intValue]) { case 1: result = @100; break; default: break; } } return result; }
自分たちのチームで使う用のはこんな感じに設定してみた。 基本的には、Googleのコーディングスタイルに沿うけど、行文字数とかインデントとかは適度な値に変更した。
--- BasedOnStyle: Google ColumnLimit: 160 IndentWidth: 4 BreakBeforeBraces: Linux ObjCSpaceAfterProperty: true ObjCSpaceBeforeProtocolList: true AllowShortFunctionsOnASingleLine: false AllowShortLoopsOnASingleLine: false AllowShortFunctionsOnASingleLine: false
設定ファイルはYAML形式で記述していく。カスタマイズ項目は公式ドキュメントを参照すると良い。 Clang-Format Style Options — Clang 3.5 documentation
.clang-formatという名前でプロジェクトのリポジトリ内に置いておくとプラグインが良い感じに参照してくれるはず。
最後に、全ファイルに適用していくには、Project Navigator上でファイルを全選択してEdit > Clang Format > Format Selected Filesを実行すると良い。
あとはmake/rakeタスクなどにしておいてたまにコマンドで実行しても良いし、CIツール等で定期的にClang Formatを実行してプルリクエスト投げるようにしても良い(開発中差分とコンフリクト発生してうざいかも)。
これで、いちいちソースコードの見栄えについて気にすること無くコードレビュー出来るようになったので開発捗る。