今日からできる!良いコードを書くための最初の3ステップ

こんにちはー!むちょこです。

いくつかコードレビューをさせていただく中で、初学者の方には大体同じことを伝えているなーと気が付いたのでここにまとめようと思います!

「ただ動くだけじゃなくて、”良いコード”を書いてみたいな、、、」と思ったときの参考になりましたら幸いです:)

“良いコード”を突き詰めるとキリがないので、まずは簡単かつ広範囲で使えるもののみをご紹介しています。

諸先輩方へ。もっと良いのがありましたらTwitter(@aya_lachelier )やリクエストフォームから教えてください!

コーディング規約を守る

良いコードの条件の一つに、コードの読みやすさ(「可読性」といいます)が挙げられます。

可読性を上げるためにまず誰でもすぐできるのが、コーディングスタイルを統一することです。

これは自分の担当箇所だけを統一すれば良いのではなく、プロジェクトのコードすべてが1つのルールに則って書かれることでその真価を発揮します。

コーディング規約にはいくつか選択肢がありますので、どんな場面でどの規約を守ると良いのかを優先度が高い順にご紹介します。

1. プロジェクトのコーディング規約

多人数が参加するプロジェクトでは、予めコーディング規約が定められていることがあります。

その場合は、プロジェクトメンバーの責務として定められたルールに従いましょう。

2. フレームワークのコーディング規約

メジャーなフレームワークでは、コーディング規約が定められていることがほとんどです。

フレームワークの仕様的に、コーディング規約を守らないと面倒な設定が必要になる場合があります。

既存のプロジェクトのルールがなく、利用するフレームワークにコーディング規約が定められていればそれに従うことをオススメします。

3. PSR-2

PHPには標準的なコーディングスタイルのガイドとして、PSR-2があります。

一部のフレームワークではそのままコーディング規約として採用されていたり、PHPerなら知っている方も多いので、特にこだわりがなければこれに従うといろいろと楽です。

IDEによっては、自動でPSR-2に準拠してくれる設定が備わっているらしいです。

4. 自分で決めたコーディング規約

なにかこだわりや理由があれば、自分で決めたコーディング規約で行うのももちろんありです。

大事なのは、プロジェクト内で統一することです。

名前で伝える 

変数ならその変数に何の値が入っているのか、関数ならその関数は何の役割を果たす関数なのかを名前で表現するようことも、可読性の向上に役立ちます。

「変数は値を入れておく箱である」と学んだ方も多いかと思いますが、その理解の仕方の是非は置いておいて、箱に具体的なラベルがついているのとそうでないのとでは、中身を展開する前に把握できる情報に差がつくのは明らかですよね。

はじめのうちはどんな名前にしようか悩むことも多いと思いますので、ここではちょっとした命名のコツをご紹介します。

変数名は名詞

変数名は何の値が代入されるのかを、具体的に名詞で表してあげます。

さらに、それが配列である場合は、複数の値が入ることが前提になるので複数形の名詞をつけると分かりやすくなる場面が多いです。ただの変数のときには単数形の名詞にします。

変数名の例
$fruits = ['apple', 'banana', 'orange'];
foreach ($fruites as $fruit) {
    echo $fruit;
}

関数・メソッド名は動詞

関数やメソッドはなにかしらの処理を行うので、動詞が基本です。

命名するときは、実行する側の立場で役割を表すように意識するとわかりやすい名前をつけることができます。

たとえば年の値を返す関数があるとしたら、実行する側は年の値を取得するために使いたいのでgetYear()とつけるとわかりやすいです。

関数・メソッド名の例
// 「year(年)をget(取得)できる関数なんだな」ということがすぐわかる。
function getYear()
{
    return date('Y');
}

↓

// 役割ベースで名付けているので、処理の中身が変わっても名前に矛盾が生じない
function getYear()
{
    if (isset($_GET['year']) && $_GET['year']) {
        return (int)$_GET['year'];
    }
    return date('Y');
}

重複する処理をまとめる

意図が同じで処理内容もほぼ同じなコードは共通のコードとしてまとめてあげると、後々の変更のしやすさ(「変更容易性」といいます)が上がります。

たとえば、DBのいくつかのテーブルからそれぞれ全てのデータを取得したいとします。下記のように1つにまとめておくと、接続情報が変わったときにも1箇所のみを変更すれば良く、テーブルが増えたとしても実行時に引数として渡すだけでOKなので、漏れなどの人的ミスや工数を減らしてくれます。

(※下記は例用にわかりやすくしたコードです。たくさんの問題を含んでいますので、実際の運用に利用しないでください)

同じ用途のコードを関数化する例
/**
 * テーブルに保存されているすべてのレコードを返す
 * @param string $table
 * @return array|void
 */
function getAll($table)
{
    // 接続
    // 接続情報に変更があってもここだけ変えればOK
    $dsn = 'mysql:dbname=testdb;host=127.0.0.1';
    $user = 'dbuser';
    $password = 'dbpass';
    $dbh = new PDO($dsn, $user, $password);

    // データの取得
    $sql = "SELECT * FROM {$table}";
    $sth = $dbh->prepare($sql);
    $sth->execute();
    return $sth->fetchAll();
}

// 実行
// 唯一違うテーブル名部分は引数として渡す
$users = getAll('users');
$rooms = getAll('books');
$messages = getAll('messages');

ポイントは、処理内容だけでなく意図(用途)も同じかどうかを確認することです。

単に現時点での処理が似ているからと言って、意図(用途)が違うものもまとめてしまうと逆に変更容易性が下がり後で困ることがあるので注意しましょう。