Androidのコード規約について考えてみた


あくまで個人意識のため、内容はほとんど引用メイン
Android開発時のコード規約に関して、自分なりに噛み砕いて理解するために記す

## コード規約の在り方
Androidでもチームで開発する際、開発メンバーが決められたコード規約に基づいて実装しないと、可読性などが失われ単体テストや結合テスト、ソースレビューにも影響が出てくる

PHPやObjective-C、もちろんJavaにもデフォルトのコード規約は存在する
Androidの時はどうすればいいのか

私の結論としては「[Android Open Source Project](http://source.android.com/index.html)」にある [Code Style Guidelines for Contributors](http://source.android.com/source/code-style.html) に従う

例えば会社の場合、ある程度その会社独自のコード規約が存在する
しかしそれは一般的でもなんでもない、私から言わせていただけば「負の遺産」にすぎない
コード規約というものは、開発者全員が共通言語として理解できるものでなくてはならない、と私は考える

## Contributors(コントリビュータ)って何よ？
うれしいことに日本語訳も提供されていた [コントリビュータのためのAndroidコードスタイルガイドライン 日本語訳](http://www.textdrop.net/android/code-style-ja.html) via textdrop
※2010-07-07 時点の日本語訳

ここでいうContributors(コントリビュータ)って何？
自分は最初「オープンソースプロジェクトのコミット権限を持っている人」と言う認識だった
この記事を書くついでに、もう一回調べてみた

例えば [Apache License](http://sourceforge.jp/projects/opensource/wiki/licenses%2FApache_License_2.0) におけるコントリビュータの定義は次の通り
> 「コントリビューター」とは、ライセンサーおよびその代理を務める個人または法人で、自分のコントリビューションがライセンサーに受領されて成果物に組み込まれた者を指します。
> 引用元：Apache License, Version 2.0 via OSG-JP

？　コントリビューション？ライセンサー？
それぞれに関しては、[Apache License](http://sourceforge.jp/projects/opensource/wiki/licenses%2FApache_License_2.0)を参考に

まぁ直訳すると「貢献者」と他のサイトにも書いてある通り、私の中では次の通りで落ち着いた
> 「コントリビュータ」とは、自身で作成したもの（ここでいうとAndroidのソースコード）が、その著作権元（ここでいうとOracleかGoogle）から認められた個人（または法人）のこと

こんな感じかな？

## まずはJavaのコーディング規約
[コントリビュータのためのAndroidコードスタイルガイドライン 日本語訳](http://www.textdrop.net/android/code-style-ja.html)の「Java言語に関するルール」にもあるように
> 標準のJavaコーディング規約に従います

ここで言う「標準」というのはGoogleが出している [Google Java Style](http://google-styleguide.googlecode.com/svn/trunk/javaguide.html) ってことかな？

最初はOracleが公式として出している「Java プログラミング言語に関するコード規約」だと思ったんだけど、リンクどこいったのさ…
まぁ今回はAndroidについてのコード規約を考えるので、素直にGoogleに従う

## Android コーディング規約
[コントリビュータのためのAndroidコードスタイルガイドライン 日本語訳](http://www.textdrop.net/android/code-style-ja.html)を順に追っていく

### 例外処理
#### catchが空のtry-catchは書くな！
Javaの例外としてよく書かれるtry-catch文
そもそも例外処理の中に何も書かないなら、最初からtry-catchなんて使うなと言わんばかりですが

```Java:ダメなコード例
void setServerPort(String value) {
    try {
        serverPort = Integer.parseInt(value);
    } catch (NumberFormatException e) { }
}
```
もちろん、絶対ダメだよ
正しくは次の３つ

```Java:1.メソッドの呼び出し元に例外を投げるタイプ
void setServerPort(String value) throws NumberFormatException {
    serverPort = Integer.parseInt(value);
}
```
```Java:2.抽象化した新しい例外を投げるタイプ
void setServerPort(String value) throws ConfigurationException {
    try {
        serverPort = Integer.parseInt(value);
    } catch (NumberFormatException e) {
        throw new ConfigurationException("Port " + value + " is not valid.");
    }
}
```
```Java:3.きちんとcatchの中も書きましょうタイプ
/** Set port. If value is not a valid number, 80 is substituted. */
void setServerPort(String value) {
    try {
        serverPort = Integer.parseInt(value);
    } catch (NumberFormatException e) {
        serverPort = 80;  // default port for server 
    }
}
```
リファレンスでは、他にも

- Exception をキャッチして、新しい RuntimeException を投げるタイプ
- 最後の手段: 自信をもって例外を無視するのが本当に適切だと言い張るタイプ

という２つがあるが、私はちゃんと上記３点のどれかに落ち着くように徹底する

#### Exception e とか書くな！
これ、学生時代の私でした、今となっては猛省しております

```Java:ダメなコード例
try {
    someComplicatedIOFunction();        // may throw IOException 
    someComplicatedParsingFunction();   // may throw ParsingException 
    someComplicatedSecurityFunction();  // may throw SecurityException 
    // phew, made it all the way 
} catch (Exception e) {               // I'll just catch all exceptions 
    handleError();                      // with one generic handler!
}
```
これをやってしまうと`ClassCastException`や`RuntimeException`といった予期せぬ例外もアプリケーションレベルにあるエラー処理でキャッチしてしまいます
ようは、なんでアプリケーションがクラッシュしたのか分からないことになってしまうからです

この場合は次のように複数のcatchで例外を捕まえましょう

```Java:良いコード例
try {
    someComplicatedIOFunction();        // may throw IOException 
    someComplicatedParsingFunction();   // may throw ParsingException 
    someComplicatedSecurityFunction();  // may throw SecurityException 
} catch (IOException e) {
	ioExceptionError();
} catch (ParsingException e) {
	parsingExceptionError();
} catch (SecurityException e) {
	securityExceptionError();
}
```
どうしても落ちるという人は、それは実装したコードの例外パターンを知らないだけ

### finalize()は使わない
ファイナライザが何？という人は[コチラ](https://www.google.co.jp/search?q=Java+finalize)へ
[コントリビュータのためのAndroidコードスタイルガイドライン 日本語訳](http://www.textdrop.net/android/code-style-ja.html)にも書いてあるけど「オブジェクトがガベージコレクトされるときに実行されるコード」ってこと

> 基本は使わない

どうしても必要なときはclose() メソッド（のようなもの）を定義するらしい
けど、そんなコードはどんな時だろう

### import foo.*;のようなワイルドカードは使わない
めんどくさいときにやるよね

```Java:悪いコード例
import foo.*;
```
けど、これだと際にどのクラスが使われているのかが明確にならないので、やっぱりきちんと書く方が良いらしい

```Java:良いコード例
import foo.Bar;
import foo.Key;
```
Javaの標準ライブラリ（`java.util.*`, `java.io.*`）とか、ユニットテストコード（`junit.framework.*`）はOKらしいのだけど、ここもきちんと書く習慣をつけた方が望ましい

### Javadocコメント
Copyrightちゃんと書こうよ
`package`文と`import`文の順で書こうよ
各ブロックの間は1行空けて
そしたらクラスやインタフェースの宣言を書こうよ

```Java:良いコード例
/*
 * Copyright (C) 2010 The Android Open Source Project 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at 
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 */

package com.android.internal.foo;

import android.os.Blah;
import android.view.Yada;

import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * Does X and Y and provides an abstraction for Z.
 */
public class Foo {
    ...
}
```
ここでも次の一文があるけど
> "setFoo()" といった簡単な get/set メソッドの場合、「Fooを設定する」というだけの Javadoc を書く必要はありません

基本的には、どんなに小さいメソッドでもちゃんと書く習慣をつけることが大事
毎回Javadocを生成するイメージを持つこと

### 1メソッドは40行以内！
メソッドはモニターでスクロールしない大きさのスコープで作ると良いと聞いたことがある

### ローカル変数のスコープは最小に
むやみやたらに変数を宣言したり、長いスコープにしない
ローカル変数の宣言はイニシャライザを入れる

### importの順番を大切に
インポート文は次のような順序でインポート
> 1. Android 関係のインポート
> 2. サードパーティ製ライブラリ (com, junit, net, org)のインポート
> 3. java および javax 関連のインポート

IDE の設定とうまく合わせて、次のようにインポートすべき
> 1. 各グループ内では、アルファベット順にインポート
> 2. 大文字は小文字よりも前にあるものと見なおす（例えば Z は a よりも前にある）
> 3. 大きなグループ分け (android, com, junit, net, org, java, javax) の間には空行を入れておくべき

### インデントはスペース4つ
関数呼び出しと引数を含んだ行の折り返しは、スペース8つでインデント

```Java:良いコード例
Instrument i =
        someLongExpression(that, wouldNotFit, on, one, line);
12345678
```
これは正しくないインデントです。

```Java:悪いコード例
Instrument i =
    someLongExpression(that, wouldNotFit, on, one, line);
1234
```

### フィールド名

#### 非パブリック、非スタティックフィールドの名前は m スタート
```Java:良いコード例
public class MyClass {
    int mPackagePrivate;
    private int mPrivate;
    protected int mProtected;
}
```

#### スタティックフィールドの名前は s スタート
```Java:良いコード例
public class MyClass {
    private static MyClass sSingleton;
}
```

#### それ以外はフィールドは小文字スタート
```Java:良いコード例
public class MyClass {
    public int publicField;
}
```

#### パブリックな static final フィールド（定数）はアンダースコアを含む大文字だけ
```Java:良いコード例
public class MyClass {
    public static final int SOME_CONSTANT = 42;
}
```

### 中括弧 {} で行は初めてはダメ
これはよくあるコードスタイル戦争

```Java:悪いコード例
class MyClass
{ // ×
    int func() {
        if (something) {
            // ...
        } else if (somethingElse) {
            // ...
        } else
            body(); // ×
    }
}
```

条件文にも中括弧を付ける
>ただし、条件文全体（条件と本体）が1行に収まるのであれば、中括弧を付けなくても構いません

とあるけど、ちゃんと統一したほうが良い気がする

```Java:良いコード例
class MyClass {
    int func() {
        if (something) {
            // ...
        } else if (somethingElse) {
            // ...
        } else {
            // ...
        }
    }
}
```

### 1行の長さは100文字まで
これよく80文字を基準にしている所も多いはず、私もそう
ここに関しては、[コントリビュータのためのAndroidコードスタイルガイドライン 日本語訳](http://www.textdrop.net/android/code-style-ja.html)にもあるようにある程度の例外は受け入れるのが吉

> 例外: コメント行に100文字以上のコマンド例やURL文字列が含まれる場合には、100文字を超えても構いません。コピー＆ペーストしやすくするためです。
> 
> 例外: インポートの行はこの制限を超えても構いません。ただし、めったにないでしょう。この方がツールを書くのも簡単になります。

### Javaのアノテーションはきちんと書く
これはそうだね、ちゃんと書こう
それぞれのアノテーションの説明は省く

#### @Deprecated
かならず付けろ

#### @Override
絶対書け

#### @SuppressWarnings
こちらに関しては、これを使わないようにコードをきちんと分離したほうがいいね

### 名前における頭字語（アクロニム）
こちらは、たまにクラス名とかで気持ち悪くてもがんばる

|よい|わるい|
|:--|:--|
|XmlHttpRequest|XMLHTTPRequest|
|getCustomerId|getCustomerID|
頭字語や略語そのものが名前の場合（HTMLなど）にも、このスタイルを適用する

|よい|わるい|
|:--|:--|
|class Html|class HTML|
|String url;|String URL;|
|long id;|long ID;|

### TODOを書く場合には具体的な日付も入れよう

```Java:良いコード例
// TODO: ここは数値における仕様が決定する2014/12/31までに修正
```

### Javatestのスタイルに関するルール
こちらに関しては、使用するツール（JUnitであったり）によって、きちんと決めましょう
大抵は、メソッド名に`test_`みたいな統一ルールになるはず

## まとめ
他にもJavaに関するコーディング規約 [Google Java Style](http://google-styleguide.googlecode.com/svn/trunk/javaguide.html) も再度目を通す必要があると思った
そちらはまた今度