ハンズオンのコーディングポリシー
概要
DBFluteハンズオンやjavatryなどで推奨されるコーディングポリシーを用意しています。
実際の開発現場では違うコーディングポリシーになるかもしれませんが、それぞれの行った先のポリシーにすぐに合わせて実装ができるというのも重要なスキルの一つです。
研修用のコードであっても、全くの自由ではなく、何かしらのコーディングポリシーを意識しながらプログラミングする習慣を付けましょう。
1. レビューしやすいコード
様々なコーディングポリシーの根底にあるコーディングテーマです。
- コードを最初に読む人は?
- ずばり、レビューワー
- レビューしやすいコードだと?
- → レビューが早く抜けが少ない
- → レビューでバグを発見しやすい
- → 経験浅い人のコードもリリースしやすい
- → 経験豊富な人も責任の重いコードを書きやすい
リリース前にバグが発見できれば安全なわけです。 最初からバグのないコードを書く努力も大切ですが、バグを発見してもらいやすいコードであれば、品質の高い状態でリリースできるのです。
レビューがしやすいコードは、ビジネス意識の高いコードと言えます。そしてそれは、開発者自身を助けることにもなります。 レビューしやすいコードとは?それを考えながら実装しましょう。
もっと奥が深いものです。ぜひ参考ブログも読んでみてください。
2. エディター警告の解決
Eclipse や IntelliJ のエディター上の警告が残っている状態でコミットしないように気を付けましょう。 (自動チェックできるものを人間がレビューするのは時間がもったいないです)
警告ではなく提案やヒントのようなものであれば無視しても構いませんが、それらを放置し過ぎて警告ノイズにならないように注意しましょう。 警告ノイズが多くなる場合は、そもそもエディターの設定を調整しましょう。 (特にIntelliJでは、デフォルトで細か過ぎる提案が多い印象です)
低レベルなミスを未然に防げれば、もっと大事なことにレビュー時間を使うことができます。
3. 最低限のクラスJavaDoc
一行だけでも良いので、クラスの内容を表現するコメントを書きましょう。
そして、クラスのJavaDocに @author を付与しましょう。 (Eclipseなら @au => ctrl+space で補完)
e.g. 最低限のJavaDoc, 一行コメントとauthor @Java
/**
* 商品一覧検索画面のAction
* @author jflute
*/
public class ProductListAction extends ... {
...
}
他の人が作ったクラスを (レビューコメント以外で) 修正した場合は、@author を下に追加します。
e.g. jfluteが作ったクラスにstojkovicが修正を入れた場合 @Java
/**
* 商品一覧検索画面のAction
* @author jflute
* @author stojkovic
*/
public class ProductListAction extends ... {
...
}
誰が修正をしたのか?というのは別にgitのHistoryを見ればわかる話ではありますが、クラスファイルを開いたらすぐに目に入ってくるというのがポイントです。
特にインクリメンタルな開発の場合、とある人が途中まで作ったものを別の人が引き継いだりと複数の人が関わることが多く、緊急の場面でのコードリーディングも多いと想定されるので、すぐに「話しかけたい人」がわかるというのが大切だと考えています。
また、複数の人がクラスを修正していると、その場限りで都合のよい無責任実装が積み上がっていきやすいものです。手を動かして記名することで少しでも「自分が関わったクラスなんだ」という意識を高めることも目的の一つです。
4. 空行マネジメント
空行には「区切り」という明確な役割があります。
いい加減に空けたり詰めたりすると 見た目で理解しづらいコード になってしまいます。 必ずこうしなければならないというルールがあるわけではありませんが、まずは統一性を大切に、そして、ひと目で読み手がコードの意図を理解しやすい空行を心がけましょう。
また、ディスプレイは横長のものが多く、縦が短いものです。無駄な空行は削除(Eclipseならctrl+D)していきましょう。もちろん意図のある空行であれば遠慮なく空けていきましょう。
空行マネジメントされてない例 ×
統一感の問題もあるので、必ずしもすべてダメというわけではありませんが、特にindex()メソッドでは処理の意味的な区切りが少々不明瞭です。
e.g. 空行マネジメントされていないコード、LastaFluteのExampleの場合 @Java
/**
* 商品一覧検索画面のAction
* @author jflute
*
*/
@AllowAnyoneAccess
public class ProductListAction extends HarborBaseAction {
@Resource
private ProductBhv productBhv;
@Resource
private PagingAssist pagingAssist;
@Execute
public HtmlResponse index(OptionalThing<Integer> pageNumber, ProductSearchForm form) {
validate(form, messages -> {}, () -> {
return asHtml(path_Product_ProductListHtml);
});
PagingResultBean<Product> page = selectProductPage(pageNumber.orElse(1), form);
List<ProductSearchRowBean> beans = page.stream().map(product -> {
return mappingToBean(product);
}).collect(Collectors.toList());
return asHtml(path_Product_ProductListHtml).renderWith(data -> {
data.register("beans", beans);
pagingAssist.registerPagingNavi(data, page, form);
});
}
}
空行マネジメントされている例 ○
対してこちらは、処理の意味的な区切りと空行が一致しています。
もちろん、意味的な区切りというのは個人差が出るものなので、あくまで参考例ですが、何かしら自分の中で統一感のある空行マネジメントを意識をして欲しいというところです。
e.g. 空行マネジメントされたデモコード、LastaFluteのExampleの場合 @Java
/**
* 商品一覧検索画面のAction
* @author jflute
*/
@AllowAnyoneAccess
public class ProductListAction extends HarborBaseAction {
@Resource
private ProductBhv productBhv;
@Resource
private PagingAssist pagingAssist;
@Execute
public HtmlResponse index(OptionalThing<Integer> pageNumber, ProductSearchForm form) {
validate(form, messages -> {}, () -> {
return asHtml(path_Product_ProductListHtml);
});
PagingResultBean<Product> page = selectProductPage(pageNumber.orElse(1), form);
List<ProductSearchRowBean> beans = page.stream().map(product -> {
return mappingToBean(product);
}).collect(Collectors.toList());
return asHtml(path_Product_ProductListHtml).renderWith(data -> {
data.register("beans", beans);
pagingAssist.registerPagingNavi(data, page, form);
});
}
}
DBFluteハンズオンのコードの例も挙げておきます。
e.g. 空行マネジメントされたデモコード、DBFluteハンズオンの場合 @Java
/**
* DBFluteハンズオンのセクション2のテストクラス
* @author jflute
*/
public class HandsOn02Test extends UnitContainerTestCase {
@Resource
private MemberBhv memberBhv;
public void test_demo() throws Exception {
// ## Arrange ##
String prefix = "S";
// ## Act ##
List<Member> memberList = memberBhv.selectList(cb -> {
cb.setupSelect_MemberStatus();
cb.query().setMemberName_LikeSearch(prefix, op -> op.likePrefix());
cb.query().existsPurchase(purchaseCB -> {
purchaseCB.query().setPaymentCompleteFlg_Equal_True();
});
cb.query().addOrderBy_Birthdate_Desc();
});
// ## Assert ##
assertHasAnyElement(memberList);
memberList.forEach(member -> {
String memberName = member.getMemberName();
log(memberName);
assertTrue(memberName.startsWith(prefix));
});
}
}
5. 背景コメント
まず、コメントを積極的に書きましょう。研修用のコードだと、コメントが忘れ去られがちです。研修用でも本番と同じ気持ちで、レビューワーのために。
そして特に、背景コメント を書きましょう。"なぜ、そのように実装しているか?" を知りたいです。 (コードから読み取れない情報こそ、コメントで補足されてると読み手は嬉しいものです)
ぜひ、参考ブログを読んでください。
DBコメントもコメント
コメントは、コードだけとは限りません。DBのテーブルやカラムにもコメントは書けます。
メソッド名や変数名もコメント
コメントは、コメントだけとは限りません。メソッド名や変数名も重要なコメントの一つです。