PHPのTraitをやたらと使って感じたこと

以前、php5.4のプロジェクトに関わっていて、
そこのプロジェクトの方針でやたらとTraitを作っていたが、Traitの多用は「鬼門」だと正直思った。

class MyModel extends BaseModel
{
    use User;
    use Photo;
    use Album;
    use Relation;
    //....
    //....

    public function getData($id)
    {
        $tmp = $this->getFriendList($id); //どのTraitに実装されているか
        return $this->getPhotoSet($tmp); //調べるのが結構たいへん!
    }
}

NetBeansの場合はtraitのコード補完・関数ジャンプの機能があるからまだ楽だけど、
それでも実装があちこちに飛んでしまうのは階層の深い継承と同じストレスがあるし、
Traitの関数名を迂闊に変えて、他のTraitの関数と名前が衝突してしてコンパイルエラーが起こるので、多重継承と同じストレスもある

しかし、継承を使わずにプロパティにアクセス出来る実装を使いまわせるのは便利だった。

例えば、SPLにあるArrayAccessインターフェイスとかはTraitにしたほうが便利なのではないかと思う。

/**
 * ArrayAccessで典型的な処理をTraitで実装
 */
trait ArrayAccessHelper
{
    public function setProerty($offset, $value)
     {
        if (!empty($offset)) {
            $this->$offset = $value;
        }
    }
    public function proertyExists($offset) {
        return property_exists($this, $offset);
    }
    public function unsetProerty($offset) {
        unset($this->$offset);
    }
    public function getProerty($offset) {
        return property_exists($this, $offset) ? $this->$offset : null;
    }
}

/**
 * 上記をArrayAccessインターフェイスと合わせて使う
 */
class ArrayObj implements arrayaccess
{
    use ArrayAccessHelper;

    public function offsetSet($offset, $value)
    {
        return $this->setProerty($offset, $value);
    }
    public function offsetExists($offset)
    {
        return this->proertyExists($offset]);
    }
    public function offsetUnset($offset)
    {
        return $this->unsetProerty($offset);
    }
    public function offsetGet($offset) {
        return $this->getProerty($offset]);
    }
}

まぁこのやり方でも、インターフェイスの実装は必要なだけど、幾つものクラスにインタフェイスを実装するときはこの方法でタイプの量をかなり減らせる。
(※1)

あと、以前のプロジェクトではCodeIgniterのModelにTraitを使っていた。

コネクションを保持するのはCI_Model の$db
特定のテーブルのアクセスはメソッドはTraitにまとめる
アプリ内で使用するModelは上記2つを合わせて構築する
上記のルールでテーブルへのアクセス処理をかなり共通化出来たのですが、
その代わり最初に書いた問題も露呈指摘たのでTraitの使い処は難しい。


(※1) ArrayAccessを実装したクラスをを継承したほうが手っ取り早い事に気づいた、、、

複数環境でPHPを動かすときに気をつけていること。

ほとんどのサーバー再度開発は Local→ステージング→本番の様に コーディングからリリースまでに複数の環境で動かすことが多いと思います。

この時に問題になるのが"Localでの環境設定がそのまま本番にUPされてしまった。"といった環境依存コードの管理ではないでしょうか?

今回自分が環境依存コードの管理で気をつけている事をまとめてみました。

1. 環境の設定をSCMに入れない。

subversionやgitにどの環境を判定・設定するコードを入れずに、サーバーの設定や、デプロイ時のコマンドで対応するようにします。

下記の様なコードをSCMに上げていると"Localの環境が本番に上がってた。" といった危険が増えます。

#本番では下をコメントアウトする。
define(DEBUG, true);


上記を防ぐために環境切り替えのためのコードはSCMで管理している場所以外に置くようにします。

よく使う場所としてはApacheのconfです。


<localhost *:80>
...
SetEnv APP_ENV development
...
</localhost>

上記で設定した環境変数PHPではgetenv関数で取得する事が可能です。


$env = getenv('APP_ENV');

switch($env) {
case: 'production'
include('prod_conf.php');
break;
case: 'development'
include('dev_conf.php');
break;
case: 'test'
include('test_conf.php');
break;
}


上記の様な工夫により環境の設定ミスを起こす可能性がかなり減らせます。

2. 非機能要件は抽象化する。

非機能要件→キャッシュ、ログ、セキュリティなどは必ず何らかのラッパーを入れて
環境により切り替えられるようにしないと、「テストのためだけにコメントアウトしたコードが本番に上がる」
といった事態が起こります。


//windows環境で動かせないので下をコメント(といった一時的なコードがそのまま本番に上がってしまう。)
// $settings = $memcache->get('setting');


SymfonyやSpringなど、DIコンテナが使えるのであればそれを使ってキャッシュやログ管理を抽象化するようにしましょう。
そういったものが使えない場合もライブラリを導入するか自作するかして、他のプログラマが、キャッシュ機構やログ機構を意識しないような設計にするのは重要です。

以上です。
こういうのはユニットテストなんかを書くと早めに気づけるので、テストコードを書きつつ設計を見直すことをおすすめします。

closureを使ったLazyLoad(PHP)

Devshedで紹介されていたclosureの使い方が面白かったので紹介する。

3ページに渡る記事だけど、最後のサンプルを見るだけでも十分。

テンプレート

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Using closures in PHP</title>
</head>
<body>
<header>
<h1>Header section</h1>
<h2>Welcome! You're accessing this page from : <?php echo $this->clientIp;?></h2>
<p><?php echo $this->header;?></p>
</header>
<section>
<h2>Main section</h2>
<p><?php echo $this->content;?></p>
</section>
<footer>
<h2>Footer section</h2>
<p><?php echo $this->footer;?></p>
</footer>
</body>
</html>

PHP

<?php

use MyApplication\View,
MyApplication\Serializer,
MyApplication\FileHandler;

// include the autoloader and create an instance of it
require_once __DIR__ . '/Autoloader.php';
$autoloader = new Autoloader;

// create a view object
$view = new View;
$view->header = 'This is the content of the header section';
$view->footer = 'This is the content of the footer section';
$view->clientIp = $_SERVER['REMOTE_ADDR'];

// lazy load contents from a remote file and assign them to the 'content' field
$view->content = function() {
$fileHandler = new FileHandler(new Serializer);
return $fileHandler->read();
};

// render the view template
echo $view->render();

コレのポイントはテンプレートの

<p><?php echo $this->content;?></p>

PHP

$view->content = function() {
$fileHandler = new FileHandler(new Serializer);
return $fileHandler->read();
}

上記部分、

closureがなかった頃は一度ファイルを読み込んで、それを変数に入れるという2度手間が必要だったけど、

closureによりそれを1箇所にまとめ、かつ「ファイルの読み込み」というコストのかかる処理をそれが必要なタイミングギリギリまで遅らせている。

勿論、上記処理はクラスを使うことによって同等の事が行えるけど、

テンプレートエンジンによってはメソッドの扱いが面倒だったりするし、「クラスの宣言が不要」と言うのも有難い。

今のところ、closureはarray_walk/set-error-handlerなど、callable引数に使うことが多いけど

こういう使い方も直ぐに思い出して使えるようにしたい。

Macのeclipseにsubclipseを入れても使えずに困った。

MacBook Pro(Lion)にPHPの開発環境を作るために、eclipsesubclipseを入れてチェックアウトしようとしたら

変なエラーが出て進めない、、、

なんだかJavaHLライブラリがないと言うエラーのようで検索してみるとMac Portsでインストールできる事が判明。

$ sudo port install subversion-javahlbindings

これでようやく使える様になった。手こずってしまった、、、

ForkwellのおおかゆかさんとStartup Datingで話した。

興味本位で登録していたFacebookグループ"Startup Dating"でForkwellの話を聞くことが出来るというので、初めて参加してみた。

http://www.startup-dating.com/2012/01/startupdating-salon/

ココでForkwellディレクターのおおかゆかさんや、アメリカのスタートアップの環境に詳しい方々から非常に濃い話を聞いたのでまとめてみる。

Forkwellの話

  • 最初からシリコンバレーで使われる事を念頭に置いているので、デフォルトの言語は英語・サーバーはAWSの西海岸リージョンを使用している。
  • スキルのあるエンジニアが一つの会社に縛られることなく、プロジェクトを渡り歩ける様にしたい。
  • 登録者のスキルに+1出来るのはFacebookで友達になってる人だけなのでレピュテーションの信頼性が高い。
  • スキルのロゴに自動的にフォントを適用するなどデザインには相当こだわってる。
  • 将来の求人サービスは、あまり「求人スパム」的なものが来ないような仕組みを作りたい。

おおかゆかさんから聞いた話

  • 今、Slerの若い優秀なエンジニアがどんどんWeb系の起業に転職している。
  • 最近、SI案件で大きな失敗の事例が増えているのは、優秀なエンジニアが逃げ出してるのもひとつの要因では?
  • PG/SE/PMみたいに職種分けされる事にエンジニアが嫌気を感じている。
  • 私はドリコムでソーシャルゲームの開発も手がけていたが「自分のサービスが億単位の金を動かしている」のを体感するのは一度経験する価値がある。
  • 「日本のデザインはアメリカではうけない」とか言われているけど、私はそうは思わない。nintendoのコンテンツなどアメリカでヒットしている日本のデザインはある。

アメリカのエンジニアの環境の話など

  • 日本のエンジニアは優秀な人が多く、アメリカに行けば年収600~900万は見込めるのに日本の仕事に満足しているのはもったいない。
  • 日本のエンジニアの技術力は、米国のエンジニアと比較しても遜色はない。
  • 英語が不自由でも、技術がある人を欲しがってる会社は西海岸にはたくさんある。
  • 日本のエンジニアは「オープンソースのコミッタになった」とか、「〇〇のライブラリを公開した」とか、技術者としての名誉を得ることへの関心は強いが、経済的な成功を得る事への関心が低すぎる。
  • エンジニアはもっと自分のプロダクトや、技術がマネタイズされる事へ関心を持って欲しい。

僕が話したこと、思った事

  • 技術者がマネタイズに関心が薄い理由は、SIerとか長らくシステム部門が「コストセンター」として扱われてきた事が大きいと思う。仕様を削る、人件費を削るなどコスト削減に強いエンジニアは周りにも多いけど、「こういう機能つけたら利用者数増える」とか「アクセスログからしてこの機能は使われてないからテコ入れしたい」みたいな事を考えるエンジニアは少ない気がする。
  • 日本のエンジニアが「アメリカに行って稼ごう」と思わないのは、「日本でもそこそこの給料がもらえる仕事が十分にあるから」と、「プログラミングや開発といった行為が十分楽しいので、その職種につける事に満足してしまうから」かなぁ。。。
  • でもこの前エルピーダが倒産した時の竹内健さんのtweet、これこれを見て、エンジニアももう少しお金ハングリーな方がむしろ技術スキルが上がる様な気がしてきた。
  • 金稼ぎに興味が無いことはエンジニアに限った話でないと思う。 ただ、「ITでお金を稼ぐ」事は「ITエンジニアの雇用を生む」「ITエンジニアのキャリアを積む機会を作る」事に繋がるから、結果的に「IT業界に貢献する」のは間違いない。「OSSに貢献する」とか「〇〇の本を執筆した」以外にもITや社会に貢献する方法はある。
  • おおかゆかさんはディレクターなのにRubyもScalaもPythonも出来てカッコイイ!」と思ってたら、元々エンジニアとして参画してたけど、ディレクション担当になりそのまま今のポジションに落ち着いているようです。(garbsさんは代表取締役以外全員エンジニアなのかな?)

久しぶりにバイトの先輩に会う

大学時代の知人の死があり、10年ぐらいぶりに大学の友だちと集まる機会があった。その集まりの後、僕にずっと親身にしてくれているバイト時代の先輩の元に出かけた。

その先輩は学生時代から人間や時代に対する観察眼が鋭く、話を聞く度に感心させられる事が多い。

その時の3時間ぐらいの雑談も非常に内容が濃かった。

  • 先輩:ポール(僕の事)この前また転職したらしいなこれでお前何社目や?
  • 自分:この前って言っても2年前だよ。えーーっとこれで4社目かな?どうも仕事を続ける根性がなくてね。
  • 先輩:それはすげーな。やっぱりお前にはそれなりのスキルがあるからやろうな。
  • 自分:え、どういう事?
  • 先輩:ポール、バイトの時の厨房のスタッフのHさん知ってるやろ。あの人厨房のスタッフやめた後、青果市場で2年ぐらい働いて、その後はレンタルビデオ屋でバイトやっとるで。あの人みたいに高卒で特に出来ることも無ければ仕事が無いんだよ、今は。4社も会社渡り歩けるのは恵まれてるほうやで。
  • 自分:そうなんだ、、、そういえば大学の同級生でも「リストラにあって今はバイトみたいな事してる」って言ってる人もいたなぁ。まぁ俺人付き合いは苦手だけど、システム開発とかプログラミングは面白いからね。興味本位で本読んだり、色々な勉強会に顔出したりしてれば勝手に技術は身につくよ。
  • 先輩:それは恵まれてる事だよ。「仕事が好き」「仕事が面白い」って言える奴はお前の歳では普通いないぞ。みんな仕事は嫌だけど、辞めても他の仕事はないし、家族を養わなきゃいけないから嫌々働いてるのが大半だぞ。仕事時間以外で勉強するとか普通あり得ないぞ。
  • 自分:そうなんだぁ、まぁこっちはこっちで毎年毎年新しい技術が来て覚えなきゃいけないから大変だけどね。昔はPC用のWebサイトの開発スキルが必要だけど、その後は携帯用のWebサイトの開発スキルが必要になって、今はスマフォ、、、新しい事を覚えるのも大変だけど、今までのスキルが役立たなくなるのが悲しいね。
  • 先輩:そういやぁポールはスマフォなんだな。それどこのメーカーのヤツ?
  • 自分:HTCってメーカーのヤツだね。高くないけど性能はそこそこって感じかな? 仕事柄スマフォは必要だから手頃なヤツを買ったけどやっぱり便利だね、地図とか乗り換えとか、twiterやfacebookも見やすいし。そういえば大学の同級生でスマフォ持ってる奴ほとんどいなかったなぁ。
  • 先輩:そりゃそうだよ。こっちは車社会なんだから。車乗りながらスマフォいじるわけにもいかんだろ。電話とメールができればいいから昔の携帯で十分だわ。
  • 自分:あ、そうか!僕達は電車通勤がほとんどだから、電車の手持ちぶたさを紛らわすにはスマフォは本当に良いけどね。東京だともうスマフォ以外の携帯を見かけるのが珍しいよ。
  • 先輩:東京では車も家も買わないし、買えないから、そういう所にお金がかけるんだろうな。そういえばお前のその服装、同級生の中では気を使ってたほうじゃないのか?
  • 自分:まぁ、ゼミの先生や遺族の方も来るって言うから一応ジャケットと革靴で来たけど、、、スウェットとかジーンズで来てる子もいたからもう少しラフな格好で来れば良かったと思ってるよ。
  • 先輩:それも車社会だからだよ。車通勤になれば服装なんか気にしなくなるよ。だって家からオフィスまでずっと車の中なんだから。寄るとしてもコンビニぐらいだから、服装に気を使う必要もないだろ。職場にユニフォームがあれば仕事時間以外ずーーーと部屋着でも気にならなくなるよ。あと鞄も学生以外は使わないよ。荷物は車の中に置いておけば良いんだから。この前東京行ったらみんなCoachとかTUMIとか高そうなの持っててびっくりしたわ。東京みたいに電車で通勤1時間が普通だと、安っぽい格好で外に出られないと思うんだろうな。
  • 自分:まぁ、、、 「UNIQLO」や「H&M」の様な量販店もそこら中にあるから皆が高価な服を着ている訳ではないし、僕の職業だとリュックとかトートとかカジュアルな鞄のほうが多いけど、電車の中で「服装に気を使ってない」「鞄もってない」人を探すのは確かに難しいかも、、、まぁ僕は昔から「車」より「服」のほうが好きだったからこの生活は気にはならないけど。
  • 先輩:東京がそんなかんじだから、最近のテレビドラマには「車でデート」ってシーンがないよな。最近の若者は車には興味がないし、ファッションも「UNIQLO」とか「H&M」とかで安くてそこそこなのが買えるから、金に執着がないんだよな。どうしても必要なのはスマフォだけらしいよ。連絡も買い物も音楽も映画もゲームもそれで用が足りるからな。スマフォが維持できるだけの金が稼げれば十分みたいだよ。俺んとこのバイトも1ヶ月ぐらいですぐやめちゃうし、勤務時間が6時間超えるだけで敬遠されるから本当に困るよ。

ソフトウェアテストの設計は、ソフトウェアサービスの設計と同じ

今日、「エンジニアが如何にテストに取り組むか」みたいな話を聞きに行ったけど、最初から最後まで何か違和感があった。

勿論テストケースがコケると色々面倒だし、サービスが続けば続くほどテストケースがメンテできなくなってくるけど、
本来、テストケースでエラーが出たときは「テストケースでエラーが出たおかげで、本番リリース前にデグレードが見つかって助かった」と喜ぶべきだし、それを踏まえれば、テストケースのNGが増えてくるのはそれだけサービスが成長してる証として喜んでも良いのではないのだろうか。

そう、「サービスで不具合が起きる事を予防する」のがテストであり、何故それが必要であるかと言えば、「不具合が起きた時のリスク・コストを軽減する」ためだ。

上記を踏まえると「その機能に不具合が起きた時にどれぐらいのリスク・コストがかかるか把握してない」エンジニアがいくらテストを書いてもメンテナンスする価値のあるテストは書けないのではないだろうか。

テストを作る人間、テスト工程を管理する人間がビジネスを理解してなければ、ロクに使われてない機能のためにテストケースのカバレッジを100%にするとか、本番でのバグが検知できない意味のないテストコードとか、無駄なコストや負債が増えるだけではないだろうか。

逆に、エンジニアが「ビジネスモデル」を理解していれば「ほんとうに必要なテスト」というのが自ずと定まってくるはずだ。
「このプロジェクトは仕様が全然定まらないからテストは書けないんだよ」というのは自分が関わってるサービスを真に理解してないエンジニアの言い訳ではないか。

そしてエンジニア以外のサービスに関わってる人達もテストに向き合う方が良いはずだ。ソフトウェア開発は製品と製品の製造ラインを同時につくるものだから、製品のリリースだけに目を向けて、テストを含めた製造ラインを見なければサービスの真のコストは把握できない。