随時加筆修正予定。
殴り書きレベルのものが多いけど、可能な限り修正していきます。
前提
小さいシステム程度ならフルスクラッチで書けるようになってきた人向け。
老害おじさんの極論
詳細は随時加筆修正していきます。
1. 命名には魂を込めよう
持論の展開を始めると1つの記事になってしまう。
英語にする場合は変数名は名詞、メソッドは動詞を使うようにする。
日本語の場合はハンガリアン記法を使うことで、わかりやすい。
- fnc検索
- fnc登録
システム内で辞書を持ち、同一の意味で複数の単語を使うのはやめよう。
- search
- find
などなど・・・
変数のスコープが広い場合は、意味のある単語にしよう。
いつまでも複数のブロックをまたいて、data、list、indexなど汎用性の高い名前を使わない。
data2みたいなのを作りたくなったら、dataも名前変更して意味のある単語に変えよう。
2. スタイルは統一しよう
他人のプログラムをメンテする場合は自分のスタイルを我慢する。
一番の悪はスタイルの混在だ。
キャメルケース or スネークケース、ヨーダ記法、ハンガリアン記法、日本語の可否、カッコの場所、三項演算子、それぞれメリット/デメリットはある。
統一されていれば、可読性は大きく向上する。
すでに色々なスタイルが取り込まれている場合は、言語公式推奨のスタイルを取り込む。
3. コメントは不要
変数名、メソッド名が適切であれば、9割のコメントは不要。
コメントが必要なのは、メソッドの宣言部に書くコメント。
ここには、仕様を明記する。
こんなコメントはすべて変数名、メソッド名で解決できる
アンチパタン
int updateStoreStatus() {
// 検索をする
List<Store> stores = dao.searchStores();
int count = 0;
// リストの数だけループする
for (Store store : stores) {
// isPreOpen() == false または store.isPreOpen() == true かつ store.isOpen()の場合
if (!store.isPreOpen() || (store.isPreOpen() && store.isOpen())) {
continue;
}
// Openフラグをtrueにする
store.isOpen(true);
// OpenDateに今日の日付を入れる
store.openDate(new java.util.Date());
// データを登録する
count = count + dao.update(store);
}
return count;
}
理想
int updateStoreStatus() {
List<Store> stores = dao.searchStores();
int count = 0;
for (Store store : stores) {
if (!store.isPreOpen() || (store.isPreOpen() && store.isOpen())) {
continue;
}
store.isOpen(true);
store.openDate(new java.util.Date());
count = count + dao.update(store);
}
return count;
}
4. コメントを書け
メソッドのコメントには魂を込めて仕様を書く。
プログラムレベルの動作だけではなく、システムの仕様を書く。
全部は難しいかもしれないが、せめてpublicメソッドだけは仕様レベルで書いておく。
なんのためにこのif文が必要で何をやっているか。を、プログラムレイヤーの話ではなく、仕様レベルで書いておく。
自分がクソコードを書いていても、他の人がメンテナンスやリファクタリングするときの道標になる。
アンチパタン
int updateStoreStatus() {
List<Store> stores = dao.searchStores();
int count = 0;
for (Store store : stores) {
if (!store.isPreOpen() || (store.isPreOpen() && store.isOpen())) {
continue;
}
store.isOpen(true);
store.openDate(new java.util.Date());
count = count + dao.update(store);
}
return count;
}
理想
/**
* 店舗の開店情報を更新する。<br />
* プレオープン済でグランドオープンしていない店舗のステータスを開店にする。
* @return 開店状態に変更した店舗数
*/
int updateStoreStatus() {
List<Store> stores = dao.searchStores();
int count = 0;
for (Store store : stores) {
if (!store.isPreOpen() || (store.isPreOpen() && store.isOpen())) {
continue;
}
store.isOpen(true);
store.openDate(new java.util.Date());
count = count + dao.update(store);
}
return count;
}
5. 異常値は落とそう
6. テストコードを書く
7. その他
連想配列やタプルは狭いスコープで使い、極力使わない。
プログラミングアンチパタン
時代にとらわれないアンチパタン
ネストを深くさせるアンチパタン
1. メソッド内でループさせるな
メソッドの1行目でループ開始して、途中抜けることもなく最後までループさせる処理は無駄にネストを深くする。
アンチパタン
private void hoge() {
Foo foo = new Foo();
List<String> list = foo.bar();
fuga(list);
}
private void fuga(List<String> list) {
for(String s : list) {
// 処理
// 無駄に100行くらいある処理
}
}
理想
private void hoge() {
Foo foo = new Foo();
List<String> list = foo.bar();
for(String s : list) {
fuga(s);
}
}
private void fuga(String s) {
// 処理
// 無駄に100行くらいある処理
}
2. continueやreturnを使え
if内の処理が終わった後に処理が続かない場合は、最初に判定してcontinueやreturnをしてしまいましょう。
アンチパタン
private void hoge() {
Foo foo = new Foo();
List<String> list = foo.bar();
if (list != null && list.size > 0) {
for(string s : list) {
// 処理
// 無駄に100行くらいある処理
}
}
}
理想
private void hoge() {
Foo foo = new Foo();
List<String> list = foo.bar();
if (list == null && list.size < 1) {
return;
}
for(string s : list) {
// 処理
// 無駄に100行くらいある処理
}
}
隠ぺいするな
3. 異常値は落とせ
過剰なnullチェックは不要。I/Fとして定義されていない値の場合は躊躇なく落とした方がよい。
バグの隠蔽はよくない。
アンチパタン
public void hoge(String arg0) {
Foo foo = new Foo(arg0);
List<String> list = foo.bar();
if (list != null && list.size > 0) {
// 適当な処理
}
}
// class Foo
/**
* 正常系なら要素数0以上のリストが返却される。
* @return 要素0以上のリスト。異常が起きた場合はnull
**/
private List<String> bar() {
try {
List<String> result = new ArrayList<String>();
// 何か適当にresultに詰める
return result;
} catch (Exception e) {
log.error("", e);
return null;
}
}
理想
public void hoge(String arg0) {
Foo foo = new Foo(arg0);
List<String> list = foo.bar();
// ヌルポの処理は上位に任せる
// ヌルチェックして、異常を隠蔽してはダメ。
if (list.size > 0) {
// 適当な処理
}
}
// class Foo
/**
* 正常系なら要素数0以上のリストが返却される。
* @return 要素0以上のリスト。異常が起きた場合はnull
**/
private List<String> bar() {
try {
List<String> result = new ArrayList<String>();
// 何か適当にresultに詰める
return result;
} catch (Exception e) {
log.error("", e);
return null;
}
}
無駄処理
4. 無駄処理はしない
無駄な処理は余計な思考が割り込まれ、可読性を落とす。
アンチパタン
public void hoge(String arg0) {
Foo foo = new Foo(arg0);
List<String> list = foo.bar();
// nullチェック、サイズチェック
if (list == null || list.size() < 1) {
return;
}
for (String s : list) {
// 何か処理
}
return;
}
理想
public void hoge(String arg0) {
Foo foo = new Foo(arg0);
List<String> list = foo.bar();
// 0件ならループしないので、件数チェックは不要
if (list == null) {
return;
}
for (String s : list) {
// 何か処理
}
return;
}