榊原昌彦

2015/10/11

Codeigniterでwebアプリをつくる時にやらかしちゃった5つのアンチパターン

記事のアイキャッチ画像

気づいたら、私が「CakePHP」ではなく「CodeIgniter」を選んだ3つの理由を書いてから早1年。ということは、Codeigniterを使い出してから1年経ってました。本当、時間が流れるのは早い・・・。
そこで、この1年間にやらかしちゃったアンチパターン(そして、リファクタリングに無駄に時間をかけてしまった)を5つご紹介します。
 

1.Modelでデータ処理をしない(sql関連のみにしちゃう)

最初、Modelはデータベースと接続するソケット的イメージをしていました。そうなるとどうなるかというと、例えば生徒の「名簿」と「成績」を取得する時に、Modelを以下のように用意して、それをControllerでforeachで回してくっつける、みたいなことをしちゃうのです。

モデル
[php]
function 名簿(){
$sql = "SELECT * FROM 名簿";
$query = $this->db->query($sql);
return $query->result_array();
}

function 成績(名前){
$sql = "SELECT * FROM 成績 WHERE 名前 = ?";
$query = $this->db->query($sql,名前);
return $query->row_array();
}
[/php]
 
コントローラー
[php]
$名簿 = $this->モデル->名簿();
foreach($名簿 as $名前){
$成績 = $this->モデル->成績(名前["名前"]);
  $生徒[] = $名前 + $成績;
}
[/php]
 
もう馬鹿かと(LEFT JOINを使えという話じゃないです。説明用に単純化してるだけでwコントローラーでデータ処理をしてしまっていることが問題なだけで)。
結果的にContorollerを肥大化させてしまう。そもそもの話、Modelってデータ処理を司るところでphp処理を書けたらいけないわけじゃないので
 
[php]
function 生徒(){
$sql = "SELECT * FROM 名簿";
$query = $this->db->query($sql);
$名簿 = $query->result_array();
foreach($名簿 as $名前){
$sql = "SELECT * FROM 成績 WHERE 名前 = ?";
$query = $this->db->query($sql,名前["名前"]);
  $生徒[] = $名前 + $query->row_array();
}
return $生徒;
}
[/php]
 
コントローラー
[php]
$生徒 = $this->モデル->生徒();
[/php]

ってシンプルに処理しちゃえばいいのです。ミスった。当時何も考えてなかった。
“SELECT COUNT(*) 〜”で取得したものをそのままreturnして、Controllerで”$count = $result[‘count’];”ってわざわざ一行付け足すようなことも平気にしてた。黒歴史。
 
 

2.Controllerにhtmlを書いちゃう

そして、そのままControllerにhtmlを書いてしまう。多分、その時の心情でいうと「どうせforeachするなら、一緒にしてしまったらコードダイエット!」的な。馬鹿だ。
さっきのコントローラーで例えると
 
コントローラー
[php]
$名簿 = $this->モデル->名簿();
foreach($名簿 as $名前){
$成績 = $this->モデル->成績(名前);
  $テーブル .= "<tr><td>${名前["名前"]}</td><td>${成績["国語"]}</td>";
}
[/php]
 
みたいな感じ。そして、それをviewに引き渡して、素知らぬ顔してechoで表示するという。ここまで書いてて、Codeigniterのアンチパターンというよりも、MVCの基本的な知識な気がしてきました・・・。
 
 

3.複雑なviewになるのにpurserを使ってより複雑に

そして、purser機能をみて「おー!これは使わなくては!!」と思った当時の私、よく考えろ。
purserは強力な機能だと思うし、変数部分を
 
[php]
<?php echo 変数; ?>
[/php]
 
じゃなくて任意の文字列に変えれるので、例えば
 
[php]
<!– 変数 –>
[/php]

で置き換えることもできる機能です。つまり、テンプレートとphpを完全に分離できる。デザイナーに出す時に、ハードルが下がる!(実際下がった)と無邪気に喜んでたのですが、冷静に考えると今わたしは結構複雑な処理をするアプリを作っているわけです。
つまりは、置き換えとせいぜいforeachしかできないpurserでは対応できない部分が出てくるわけで。で、Controllerで表示に関わる条件分岐をはじめてしまうから、余計に複雑になっていくわけです。
viewが複雑化するかどうか、それはpurserでカバーできるかどうかは最初にまじめに考えないと手痛い目にあいます(load->viewに置き換え途中。面倒・・・)
 

4.Composerを使わずライブラリからrequire

Codeigniter3は、Composerに対応しています。なのに、どうして私はaws.pharをLibraryに直接入れて、requireしたんだろう。使えるものは使う。素直にComposerしたほうが、見渡しいいです。
 

5.validationを同一Controllerに書いちゃう

ひとつ前のエントリーで書いたのですが、validationを同一コントローラーに書いちゃうとメンテナンスが重いです・・・。
以下、パスワード再発行のControllerなのですが、短い目のやつを選んでも1methodが長い。もっとvalidationと分岐が激しいものだと、1methodで100行いきます。
スクリーンショット-2015-10-06-10.56
 
とりあえず、別でvalidation用Controller群を作ると、かなりメンテナンスは楽になるので、今、私はそうしてます。validationの時はそのControllerに別でアクセスするか、もしくは呼び出しをかける。以下のアドバイスをいただいた通り、PHPフレームワーク的には、API的に叩くよりも、validation用Controllerを呼び出して実行する方が筋はよさそうです。
追記:Codeigniter的には筋悪らしいです。やっぱり私は今まで通り、Ajaxで叩き続けると思います。
  

//platform.twitter.com/widgets.js

 
ちょっとここあたりは試行錯誤中なのですが、同一Controllerに書くのはないな、と。
 
 
以上。
実はまだまだajax用Controllerを呼び出し元・呼び出し先で同じControllerに書いちゃったり、1つのLibraryにほとんどのmethodを集中させてるから保守性が悪かったり、configファイルの使いどころ考えろよ!とかいろいろあるけど、多分そういうことをしちゃうのは私ぐらいな上に、黒歴史をほじくり回すみたいで辛いので、これぐらいにしておきます。
それでは、また。

Cookieを利用します

このWebサイトでは、Google Analyticsをアクセス解析のために導入しており、個人データであるCookieにアクセスします。引き続き利用する場合はCookieの利用への同意が必要です。

同意する