はじめに
「優しいIT」という理念のもとITコサルタントをしている。亀井亮介で〜す
システム開発する上で、品質・保守性の向上を考えると、コーディング規則や命名規則などの「ルール」が必要です。
「資格試験勉強すればするほど社会貢献ができるe-lerning(開発中)」で利用しているコーディング規則の例です。
ソースのプログラミング言語はPHPで、フレームワークはFuelPHPを使っています。
●コーディング規則「優しいコードを書こう」
1. テストファースト(ユニットテストを先に書く)
はじめに失敗するテストを書きます。理由は、成功するテストから書いた場合にバグに気がつかないためです。
※例は実践JUnitより
2. 1関数1機能にすると、コードが短く簡潔になり、テストがしやすくなる
皆さんも「スパゲッティ・コード」を見て、ソースを見るのが嫌になったことがありませんか?
「スパゲッティ・コード」とは、関数同士が複雑に絡み合い、お互いがお互いと依存しているようなコードです。
これを極力排除するのが「1関数1機能」です。
下記は、HTMLタグと指定したタグに囲まれた中身を削除する関数で、1機能しか実現していません。
public static function removed_tag_and_contents($body, $tag_name) {
return
preg_replace(
'{<'.$tag_name.'>(.*)</'.$tag_name.'>}'
, ''
, $body
);
}
上記に対するテストは下記の通りです。
実際の振る舞いは
- タグを除去するために作成しました。
そのため、
- タグが除去できるかテストをしています。
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文字以内とし、縦の線をまっすぐにする意識をすると、ソースの可読性が向上する
下記のように横に長いと見にくくありませんか?
$conveted_question_body = Controller_Question::removed_tag_and_contents($questions['question_body'], 'ul');
人間の目は、横に流れるのが苦手だそうです。縦に流れるのは得意だそうです。
確かに、スマートフォンは縦に流れる仕組みですよね?
プログラム・ソースのように謎の文章が羅列されていれば、なおのこと読みやすさが必要です。
$conveted_question_body =
Controller_Question::removed_tag_and_contents(
$questions['question_body']
, 'ul'
);
読みやすさが向上していませんか?書く方は面倒ですが、3ヶ月後に自分で書いたプログラムを読むときに、「昔の俺は優しいな〜」と思えるはずです(笑)。
4. コメントは「意図を相手に伝えること」なので、簡潔に例となる値やToDo、欠陥を書く
コメントは必要最低限が望ましいです。全く書かないのも問題ですが、余計な情報があるのも問題です。
必要な情報とは?関数の引数にどういう値が入るか?
このような場合、ソースを追うと思うのですが、下記のように実際に入る値の例や役割があると「優しいな」と思いませんか?
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は早めに返すほうが品質が向上します。
下記に例を示します。
/**
* 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+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を使いサーボモータを動かす