StackPHPを使ってみる(Twitter認証)

StackPHPというのが正式名称なのかわからないけど。

http://stackphp.com/

ひな形

  1. HttpKernelInterfaceを実装した$appを準備する。
  2. スタックを作る。
  3. $stack->resolve($app);
  4. $appを実行する
<?php
$app = ...;  // 1.
$stack = (new Stack\Builder())  // 2.
    ->push(...)
    ->push(...);

$app = $stack->resolve($app);   // 3.

// 4.
$request = Request::createFromGlobals();
$response = $app->handle($request)->send();
$app->terminate($request, $response);

Hello, world

1のHttpKernelInterfaceを実装は、SymfonyやLaravelのアプリケーションでも良いのだけれど、 より簡単に作るためにstack/callable-http-kernelというのが用意されている。

また、4の部分を簡単に書くために、stack/runというのが用意されているので一緒にインストールしておく。

$ php composer.phar require stack/builder stack/callable-http-kernel stack/run

ちなみに最近、composer requireでバージョンを指定しなくても良くなったらしい。

<?php
// index.php
require "vendor/autoload.php";

use Stack\CallableHttpKernel;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

$app = new CallableHttpKernel(function (Request $request) {
    return new Response("Hello, world");
});

$stack = new Stack\Builder();

Stack\run($stack->resolve($app));

何もstackにpushしてないけどとりあえずこれで動く。

$ php -S localhost:9000

Twitter認証してみる

stack/sessionとigorw/stack-oauthをインストールする。

$ php composer.phar require stack/session:dev-master igorw/stack-oauth:dev-master
<?php
require "vendor/autoload.php";

use Stack\CallableHttpKernel;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
$app = new CallableHttpKernel(function (Request $request) {
    $token = $request->attributes->get('oauth.token');
    if (!$token) {
        return new RedirectResponse('/auth');
    }

    $params = $token->getExtraParams();
    return new Response("Hello, " . $params['screen_name']);
});

$stack = (new Stack\Builder())
    ->push('Stack\\Session')
    ->push('Igorw\\Stack\\OAuth', [
        'key' => getenv('OAUTH_KEY'),
        'secret' => getenv('OAUTH_SECRET'),
        'callback_url' => 'http://localhost:9000/auth/verify',
        'success_url' => '/',
        'failure_url' => '/auth',
    ]);

Stack\run($stack->resolve($app));

一応動くけど多分このigorw/stack-oauthバグってるな。

続くかも。

Introducing Modelling by Example - BDDの新しいアプローチ

@everzet氏のブログ記事より。例によって翻訳は無理なので気になったところだけ要約。

http://everzet.com/post/99045129766/introducing-modelling-by-example

  • Cucumber、Behat、SpecFlowなどのGherkin-based BDD toolのシナリオをユビキタス言語で 書くといいんじゃない?

つまり、

Scenario: Showing delivery cost for a product on the basket page
  Given there is a product:
    | name  | White Marker |
    | price | £5           |
  And I am on the "/catalogue" page
  When I click "Buy" in the "White Marker" product block
  And I go to the "/basket" page
  Then I should see a list with 1 product
  And the overall price should be shown as £9

ではなく、

Scenario: Getting the delivery cost for a single product under £10
  Given a product named "White Marker" and priced £5 was added to the catalogue
  When I add the "White Marker" product from the catalogue to the picked up basket
  Then the overall basket price should be £9

こう書く。

  • そしてUIやインフラストラクチャー層を除く、ドメインモデルだけのstep definitionから実装を始める。 一部のシナリオをピックアップして、同じフィーチャーに対してエンドツーエンド用のstep definitionを書く。 つまり、1つのシナリオに対して2種類のstep definitionを書くことになる (このフィーチャーに対してはこのstep definitionを使ってね、ということを定義する"suites"という 機能をBehat v3に実装した。CucumberやSpecFlowを使っている人は中の人におねだりしよう)。

  • こうすることで、インフラストラクチャ層がコアドメインをするのを素早く発見できるようになる。

  • BDDとDDDは共にTranslation Costを排除しようとしているがレイヤーが異なっている。 BDDは対話、DDDはコードにフォーカスしている。二度翻訳するのは無駄だし間違うかもしれないよね。

  • インフラストラクチャー層はシナリオをパスするための手段だ。 全てのアプリケーションがMySQLへの接続を必要としているからではなく、 永続化レイヤーが欠けていることによってシナリオがパスしなくなったから永続化レイヤーをアプリケーションに追加するんだ

"Design How Your Objects Talk Through Mocking"を見た

Konstantin Kudryashov - Design How Your Objects Talk Through Mocking at Laracon EU 2014 - YouTube

BehatやPhpSpecの作者である@everzetによるLaracon EU 2014での講演です。 英語が苦手なので翻訳することはできませんが印象的かつ聞き取れた部分を要約して紹介します。


  • モックはデータベース接続等の遅い部分をテストから分離して速くするためのものだと思われているが、それは誤解だ(そのような目的ではFake Implementationを使う)。

  • モックは、結果や状態に注目したクラシカルなTDDでは隠されていたオブジェクト間のメッセージングをさらけだし、設計の問題を明らかにするデザインツール

  • メッセージングではなく、結果をさらけ出そうとするのなら、コードにさらにgetterを追加することを強いられるだろう

  • 存在しないメソッド、インタフェース、クラスをモックしたことを知らせてくれないような壊れたMocking Frameworkを使わない

  • 自分が所有していないオブジェクトをモックしない

  • (QAより)

    Q:例えばS3のようなサードパーティー製のAPIを使う場合はどうすべきか。

    A:インターフェースを作り、それを実装したS3と通信するクラスを作る。そのクラスのインテグレーションテストを書き、インターフェースをモックする。

    インテグレーションテストはPHPUnitや他のテスティングフレームワークで書き、実際にS3にファイルが保存されるかをテストする。


感想。

サンプルコードはPHPUnit+Prophecyという構成で書かれています。説明のためにより広く知られている記法を選んだのではないかと思いますが、PhpSpecで書けばより簡潔なコードになるでしょう。

Mockを使った開発の問題として、Mockと実装が食い違ってしまうという点が挙げられる場合があります。しかしそれはMocking Frameworkがチェックすべきだと@everzetは指摘しています。多くのMocking Frameworkでは存在しないクラスやメソッドをMockすることができますが、PhpSpec/Prophecyではエラーとなります。

個人的な経験としては、PhpSpecを学ぶことで、Mock、システム境界、Hexagonal Architecture が一つの線で結ばれ、The GOOS bookに書かれていることが初めて理解できたように思います。

最初にThe GOOS Bookを読んだときは、「モックするのは自分の持っている型だけ」の意味が理解できなかったのですが、PhpSpecでコードを書いてみると、そもそもモックを書くのは次に実装しようとしているコラボレーターの場合が多く、モックは設計なんだ、既に存在しているものをモックする意味は無いんだということが自然に理解できたように思います。

The GOOS Bookって良い本だけどちょっと難しいので、同じようなテーマでPhpSpecで書かれたものがあればいいなあ。

実践テスト駆動開発 (Object Oriented SELECTION)

実践テスト駆動開発 (Object Oriented SELECTION)

学習のためにGithubを徘徊する

ちょっと間が空きましたが前回の補足。

プログラミング初心者が中・上級者になるためには、GithubのリポジトリをWatchすればいいんじゃないかな - iakioの日記

  • 自分で問題を解決しようとするだけだと、自分の発想にとらわれがちなので、他人のコードも参考にした方が良い
  • だけど、コードを0から読むのは大変なので、興味のあるところからつまみ食いするのが良い
  • そこで、GithubのPull RequestをWatchするのはどうか。興味の持てそうな話題以外は読み飛ばしても良い(数十件に1つくらいを真面目に見てみるくらいの感覚で良いと思う)

という話でした。

さて実際、僕がGithubを徘徊していてなるほどなと思った体験を1つ挙げてみます。

Gitlistは、PHPで実装されたGitのリポジトリビュワーで、Silexというフレームワークを使って実装されています。SilexはSymfonyコンポーネントを使った軽量Webフレームワークで、Symfonyの開発者でもあるfabpotことFabien Potencier氏が開発しています。

で、このGitlistを見ていたら、fabpotからのPull Requestがありました。

Refactoring by fabpot · Pull Request #74 · klaussilveira/gitlist · GitHub

例えて言うなら、RailsのアプリケーションをGithubで公開していたらDHHからPull Requestが来たみたいな話です。まさに「Silexを使うならこう使え」と言わんばかりの内容でした。

特に今まで何のためにあるのかわからなかったPimpleのextendメソッドの使い方はなるほどなと思いました、という話は以前にも書いたので詳しくはこちらをご覧ください。

Pimple 2.0がリリースされたのでPimpleについて復習してみる - iakioの日記

さて、そういったことを思い返してみると、人に注目してみるのはGithubを徘徊する1つの方法かもしれません。あのライブラリを書いた作者は他にはどんなものを作っているのだろう。どんな他のプロジェクトに注目しているのだろう、といった具合に。

あるいは、Most active GitHub users (by contributions). http://twitter.com/paulmillrで、お気に入りの言語からアクティブなユーザーを見つけて、そこからたどってみるのも良いかもしれません。

プログラミング初心者が中・上級者になるためには、GithubのリポジトリをWatchすればいいんじゃないかな

よく、プログラミングを学ぶ方法として「まずは何か作りたいものを見つけて、、、」といったアドバイスを見かける。たしかに何かを作り上げることで学ぶことも多いのだけれど、どちらかというとそれは実装方法よりもデプロイだったりライブラリやツールの使い方といったところの方が大きいように感じる。

一方で、実装方法については、自分で問題を解決しているだけだとどうしても自分の考え方にとらわれてしまう。

プログラミングの上達のためにきっと一番大切なことは環境で、近くに良い師匠がいるのであれば様々な問題の解決方法を学ぶことができるだろう。

そうでない場合は、インターネット上でお手本を見つけるのが良いと思う。

f:id:iakio:20140903122012p:plain

あまり大きすぎず、ある程度活発なお気に入りのプロジェクトをGithubで見つけてWatchする。毎日届くNotificationをざっとで良いので目を通す。最初はほとんど意味がわからないだろうけどかまわない。でも見続けているうちにこんな風に思うかもしれない。

  • このライブラリ、こんな機能もあったんだ
  • 次のバージョンではこんな機能が入るのか
  • バグだって指摘されたけどそれバグじゃねーよって言われてる。あ、ドキュメントがわかりづらいということで直すことになったようだ
  • 新機能提案したけどそれこのライブラリでやることじゃねーからって却下されてる
  • リファクタリングでがっつり行数減ってるけど、なんかあらたなライブラリを導入したんだろうか

といった感じで、理解も深まるし親しみももてるようになる。ある程度の規模の開発のリズムみたいなものも知ることができるだろう。

そして、ある程度の規模のソースコードを読むのは初心者には大変だけれど、Pull Requestだけざっと見て面白そうなとこから読んでいった方が、飽きないし発見も多いんじゃないかな。

プログラミング初心者が中・上級者になるための近道

#mozaicfm #7 REST を聞いた

#7 REST - mozaic.fm

RESTの引力に惹かれたREST人達を、RESTの伝道師たる@yoheiが粛清する話。だったと思う。

APIバージョニングの話を聞きながら、/api/v1/fooじゃなくいっそ/api/v1.2.*/fooとか/api/>=v1.3.4,<v1.4/fooとかだったらどうなるだろう。とか想像した。APIのセマンティックバージョニング。まあマイナーバージョンは必要無いかな。

とはいえ、もともとはURLの設計としてどうかというよりサーバー側をどう実装するかの話だったので、そういう意味ではほぼ無理ゲーな気がする。たとえバージョンごとに別々のサーバーがあったとしても、最終的には永続化レイヤーが問題になるんだろうなあ。

Goのバージョンの話が出てたけど、最近TypeScriptを勉強していて、あの.d.tsもなかなか大変なことになってるなと思った。

伊勢神宮の話が面白かった。昔(多分十年以上前)、どこかで「工場のようなソフトウェア」という話を読んだのを思い出した。もう元ネタは探し出せなかったけど。

PHPUnitでGrowl通知する方法を書いた件

PHPUnitの実行結果をGrowlに通知する方法 - Qiita

  • 事の発端は、去年の年末あたりからRails Tutorialをやっていて、GuardのGrowl通知いいなーと思い始めたことだった

  • PHPUnitの実行にguardやglupを使うという方法もあったけど、ちょっとした用途には大げさかなと思ったのと、その手のやつはPHPUnitの標準出力をパースして結果を取得しているのがイケてないなー、PHPUnitを拡張するような方法でできないだろうかと思っていた

  • まず最初にPHPUnit_Framework_TestListenerを思いついたけど、これは個々のTestやTestuSuiteに対して呼び出されるのでちょっと頻度が多すぎる。で、次にprinterClassを見つけた

  • 次にどうやってGrowlに通知する方法、gntpnotifyやgntp-sendといったコマンドを実行させるという方法はあまり好きじゃなかったのでGNTPを実装したモジュールを探したけど、イマイチ良いのが無かったので結局自分でGNTPを実装することにしたんだけどインターフェースを決めきれずに数か月放置

  • なんやかんやでPackagestにも登録して、Qiitaに投稿しようかなと説明を書き始めたところでphar版PHPUnitでテストしてないことに気が付いて、まさにRebuild: 52: TLDR Driven Development (Naoya Ito)でやっていた「先にREADMEを書く」ことの効果を気づかされることになった

  • 書いたコードはわずかでもリリースするところまでやると色々学ぶことがあるなーと思った。PHPUnitを調べたりComposerを調べたり。あとTravisのMatrixを使ってPHPPHPUnit複数のバージョンでテストする方法を試せたのが良かった