コーディング規則「優しいコードを書こう」

  • 9
    Like
  • 0
    Comment
More than 1 year has passed since last update.

はじめに

「優しいIT」という理念のもとITコサルタントをしている。亀井亮介で〜す
システム開発する上で、品質・保守性の向上を考えると、コーディング規則や命名規則などの「ルール」が必要です。
「資格試験勉強すればするほど社会貢献ができるe-lerning(開発中)」で利用しているコーディング規則の例です。
ソースのプログラミング言語はPHPで、フレームワークはFuelPHPを使っています。

●コーディング規則「優しいコードを書こう」

1. テストファースト(ユニットテストを先に書く)

はじめに失敗するテストを書きます。理由は、成功するテストから書いた場合にバグに気がつかないためです。

※例は実践JUnitより

2. 1関数1機能にすると、コードが短く簡潔になり、テストがしやすくなる

皆さんも「スパゲッティ・コード」を見て、ソースを見るのが嫌になったことがありませんか?
「スパゲッティ・コード」とは、関数同士が複雑に絡み合い、お互いがお互いと依存しているようなコードです。
これを極力排除するのが「1関数1機能」です。
下記は、HTMLタグと指定したタグに囲まれた中身を削除する関数で、1機能しか実現していません。

question.php
    public static function removed_tag_and_contents($body, $tag_name) {
        return
            preg_replace(
                      '{<'.$tag_name.'>(.*)</'.$tag_name.'>}'
                    , ''
                    , $body
            );
    }

上記に対するテストは下記の通りです。
実際の振る舞いは

    タグを除去するために作成しました。
    そのため、
      タグが除去できるかテストをしています。
question_Test.php
    public function test_removed_tag_and_contents() {
        /*
         * beforequestionから値を取得
         */
        $questions = Controller_Question::get_before_question(2);

        /*
         * 選択肢を除去
         */
        $conveted_question_body
            /*
             * ●コーディング規則「優しいコードを書こう」
             * 3. 横幅は80文字以内とし、縦の線をまっすぐにする意識をすると、ソースの可読性が向上する
             */
            = Controller_Question::removed_tag_and_contents(
                      $questions['question_body']
                    , 'ul'
            );
        /*
         * 選択肢が除去されていれば、除去前と比較して異なる
         */
        $this->assertNotEquals(
                  $conveted_question_body
                , $questions['question_body']
        );
    }

このように1関数1機能にすると、疎結合となり、他の関数に依存せず、「スパゲッティ・コード」を回避できます。
故にソースの可読性が向上し、メンテナンスがしやすくなり、品質が高かくなります。

3. 横幅は80文字以内とし、縦の線をまっすぐにする意識をすると、ソースの可読性が向上する

下記のように横に長いと見にくくありませんか?

question.php
    $conveted_question_body = Controller_Question::removed_tag_and_contents($questions['question_body'], 'ul');

人間の目は、横に流れるのが苦手だそうです。縦に流れるのは得意だそうです。
確かに、スマートフォンは縦に流れる仕組みですよね?
プログラム・ソースのように謎の文章が羅列されていれば、なおのこと読みやすさが必要です。

question.php
    $conveted_question_body =
        Controller_Question::removed_tag_and_contents(
              $questions['question_body']
            , 'ul'
        );

読みやすさが向上していませんか?書く方は面倒ですが、3ヶ月後に自分で書いたプログラムを読むときに、「昔の俺は優しいな〜」と思えるはずです(笑)。

4. コメントは「意図を相手に伝えること」なので、簡潔に例となる値やToDo、欠陥を書く

コメントは必要最低限が望ましいです。全く書かないのも問題ですが、余計な情報があるのも問題です。
必要な情報とは?関数の引数にどういう値が入るか?
このような場合、ソースを追うと思うのですが、下記のように実際に入る値の例や役割があると「優しいな」と思いませんか?

question.php
    public static function get_question_keywords (
              $round_id        /* = 14 平成27年度応用情報技術者試験 */
            , $question_number /* = 1  問題の番号 */
    )
    {
    // ... 略
    }

そのプログラムの修正点(今は直す必要がないけど、後日直したほうがいいと思う点)を@TODOとして残したり…
「伝えたいこと」を書くを意識すれば自ずと的確なコメントになります。

5. 条件式 左側は調査対象(変化する)右側は比較対象(変化しない)

例は後日

6. if/else 肯定形を使う。単純な条件や目立つ条件を先に書く

例は後日

7. 基本はifとforeach/forを使い、case, whileやwhile doは原則使わない

経験の浅いプログラマでもプログラムが読めるように、記述を統一します。
利便性は犠牲になりますが、分岐はif文のみ、ループはforかforeachに統一します。
Webアプリケーションの開発であれば、十分だと考えられます。
(場面によってはcaseは便利なので悩みどころです。)

8. 早めにreturnし、関数から抜ける

関数のreturnは1つにしたくありませんか?かつて、私も「関数のreturnは1つだけ」と思っていました。
その方がソースの可読性が上がると考えていたからです。
しかし、最近のフレームワークの仕様を見ていると、関数の値は早めに返していました。
理由は簡単で、returnすべき箇所を通過した後は、「どうでもいいプログラム」です。ここでは既に終了している場合の振る舞いも考慮する必要があり、バグの温床になります。
そう考えると、可読性は少々犠牲になるかもしれませんが(思いのほかならない)、returnは早めに返すほうが品質が向上します。
下記に例を示します。

question.php
    /**
     * create_choices
     * 選択肢(4つ)を生成
     *
     * @param int $question_last_id question.id
     * @return boolean
     */
    private function create_choices($question_last_id) {
        /*
         * IPA系の試験は選択肢は4つある
         */
        for($choice_num = 1; $choice_num run())
            {
                /*
                 * 問題を追加するINSERT(もしくはUPDATE)を生成
                 */
                $choice = Model_Choice::forge(array(
                    'question_id'  => $question_last_id,                       // 問題番号(固定)
                    'choice_num'   => $choice_num,                             // 選択肢番号
                    'correct_flag' => $correct_flag,                           // 正解
                    'choice_body'  => Input::post('choice_body_'.$choice_num), // 選択肢
                ));

                if (!($choice and $choice->save()))
                {
                    Session::set_flash('error', '選択肢を追加できませんでした。');
                    /*
                     * ●コーディング規則「優しいコードを書こう」
                     * 8. 早めにreturnし、関数から抜ける
                     */
                    return false;
                }
            } else
            {
                Session::set_flash('error', $choice_validation->error());
                /*
                 * ●コーディング規則「優しいコードを書こう」
                 * 8. 早めにreturnし、関数から抜ける
                 */
                return false;
            }
        }
        return true;
    }

おすすめ本

リーダブルコード
レガシーコード改善ガイド

サイトマップ(未投稿あり)

理念・価値・ビジョン・使命

テスト駆動開発を重点においた規則

コーディング規則「優しいコードを書こう」(FuelPHP)
命名規則「3ヶ月後の自分自身に優しく、チームに優しく、まだ見ぬメンバーに優しく」

Docker+PythonでWebアプリケーション開発

Docker上のCentOSにPython3と、関連ライブラリpip, virtualenvとフレームワークDjango, bottle, Flaskのインストール!これらをまとめたDockerfile付き!

開発しやすい環境構築(Docker+PHP)

Dockerを利用しApacheにPHP環境 + Eclipseを連携
Dockerを利用したFuelPHP開発環境構築
Docker利用したFuelPHP開発環境の初期設定とscaffoldを利用してCRUDスケルトン作成
FuelPHPのデータベースマイグレーション

Raspberry Pi 3 (ラズパイ)とpythonで遊ぼう

Raspberry Pi 3インストール→無線LAN→日本語入出力→Macから操作
Raspberry Pi 3でプログラミングをする Node-REDと普通にプログラミング
Raspberry Pi 3でpythonを使いLEDを光らせる(Hello World)
Raspberry Pi 3でスイッチの状態を検出する
Raspberry Pi 3でpythonを使いサーボモータを動かす