読者です 読者をやめる 読者になる 読者になる

Xcode7にしてちょっと困ったこと

アプデ作業がようやく落ち着いたので、Xcode7を入れて実験中のアプリを動かそうと思ったら、ハマったのでメモ

PromiseKitがコンパイルエラー

Swift2になった影響で、PromiseKitのコンパイルがエラーになってしまいす。現在対応中のようでCocoapodsには対応バージョンが無い様なので、対応済みブランチを使うようにPodfileを修正しました。

pod 'PromiseKit', :git => 'https://github.com/mxcl/PromiseKit.git', :branch => 'swift-2.0-minimal-changes'


執筆時点の最新バージョンは2.2.1です。近いうちに対応されたら普通に最新版にあげればいけると思います。

iOS9でHTTP通信をドメイン指定で許可する方法

実験アプリでは、外部のテストサイトにアクセスするんですが、iOS9で追加されたApp Transport Security(ATS)の影響で以下のようなエラーが出てアクセスできませんでした。

App Transport Security has blocked a cleartext HTTP (http://)  resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.

対応方法としてはATS自体を無効にする方法もあるのですが、以下のようにInfo.plistに設定することでドメイン指定で許可することができます。

f:id:kaz_29:20150926180152p:plain

example.comの部分をアクセス対象のFQDNに変えればOKです。

僕が作っているアプリでも細かな問題が起きて色々対応した(してる)んですが、メジャーバージョンが上がる時はなかなか大変ですね(^^;。

2015/9/28追記

スクショが切れちゃってたんでplistの該当部分を貼っときます。

<key>NSAppTransportSecurity</key>
<dict>
	<key>NSExceptionDomains</key>
	<dict>
		<key>labo.decr.jp</key>
		<dict>
			<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
			<true/>
		</dict>
	</dict>
</dict>

CakePHPでもChatOps

ここ2週間ほど、追い込みで自宅に引きこもっていたわたなべです。

ChatOps

去年の夏ころから弊社でもSlackを使っていて、いま開発中の案件でも開発中の様々なイベントがSlackに流れてくるようになっています。いま連携してるのはこんな感じ。

  • Github
  • Pivotal Tracker
  • Jenkins
  • Trello
  • Crashlytics

あとは、増井さんが作った「チャットで勤怠管理する「みやもとさん」」とかも使ってます。

blog.masuidrive.jp

アプリからもSlackへ

で、いま開発中のアプリはとあるスケジュールに従って自動的にインスタンスが立ち上がったり、落ちたり(破棄まで)する機能があります。この状態もSlackに流したいなーとおもって調べらた、PHPでSlackのIncoming WebHooksを使って連携させるライブラリが山ほどありました。

Community-built Integrations - Slack

どれか選んで使ってもよかったのですが、CakePHPのHttpSocketクラスを使えばサクッと実装できそうだったので、Pluginを作りました。

CakeSlack


READMEにも書きましたが、bootstrap.phpなりに設定を書いた上で、以下のような感じ。

<?php
App::uses('Slack', 'CakeSlack.Lib');

....

Slack::send('CakePHPからこんにちわ');

これで、以下のように簡単に連携できます。

f:id:kaz_29:20150319114452p:plain

Packagistにも登録したのでインストールは以下一発で。

$ composer require "kaz29/cake_slack":"dev-master"


簡単に連携はできますが、確かSlackにも流量制限(1秒1リクエスト?未確認です)があったはずなので大量に流れる可能性がある場合はキューに溜めるなりの工夫が必要かと思います。


ということでproduction環境に仕込んだこのプラグインが動くまで(あと30分)の待ち時間に久々の更新でした(^^;。

13:05追記

ということで無事起動して一安心(^^。

f:id:kaz_29:20150320081922p:plain

「CakePHPで学ぶ継続的インテグレーション」- CakePHPを使って継続的インテグレーションを実践するながれを解説した書籍が出版されます

一部の方には事前にお話していましたが、わたしも共著で執筆に参加した「CakePHPで学ぶ継続的インテグレーション」という、CakePHPを使って継続的インテグレーションを実践するながれを解説した書籍が9/19にインプレスから出版されます!

f:id:kaz_29:20140903081908j:plain

CakePHPで学ぶ継続的インテグレーション

CakePHPで学ぶ継続的インテグレーション

既にインプレスさんのサイトやAmazonにも掲載されています。まだ、書影が反映されていませんが、予約受付中です!是非ポチッとお願いします(^^。

今年頭頃のミーティングから約9ヶ月、途中本業が忙しくなかなか執筆がすすまなかったりもしましたが、なんとか書き上げることができました。今回、初めて僕自身の企画+執筆のとりまとめをすることになり、段取りが悪く、他の執筆陣や編集担当にはいろいろと心配や迷惑をかけましたm(__)m。

今回も、原稿のmarkdownはgithubで管理してたのですが、追い込みだった7月、8月はなかなかすごい状況でした。

f:id:kaz_29:20140902164813p:plain

執筆陣

  • 渡辺 一宏
  • 吉羽 龍太郎
  • 岸田 健一郎
  • 穴澤 康裕

私はともかくw、今回の執筆陣かなり豪華です。強力な執筆陣のおかげで、継続的インテグレーションやテストに関して、私自身、執筆を通してたくさん勉強させてもらいました!

目次

まだ多分どこにもでていませんが、目次はこんな感じ。

  • Chapter 1 概論
  • Chapter 2 導入
    • 2-1 バージョン管理
    • 2-2 テストの自動化
    • 2-3 インスペクションの自動化
    • 2-4 ドキュメント生成の自動化
    • 2-5 デプロイの自動化
    • 2-6 フィードバック
  • Chapter 3 使用ツール
  • Chapter 4 環境構築
    • 4-1 環境の説明
    • 4-2 環境設定
    • 4-3 サンプルアプリケーションの環境構築
  • Chapter 5 開発工程(1)
    • 5-1 開発の進め方
    • 5-2 ユーザーストーリーの定義
    • 5-3 機能実装
  • Chapter 6 開発工程(2)
  • Chapter 7 デプロイと運用
    • 7-1 デプロイ
    • 7-2 継続的な機能追加
    • 7-3 継続的なテスト実行
    • 7-4 ソースコード品質の維持

継続的インテグレーション自体の解説から始まり、使用する各種のツールの解説、実際の環境構築方法、ユニットテストの効率的な書き方、Behatを使った受入テスト、そして、実際に継続的インテグレーションサーバに全てを組込む方法の解説、はたまたデプロイの自動化方法の解説とかなり盛りだくさんな内容になっています。

私は、Chapter 1,2と3,7の一部を担当させて頂きました。

まとめ

今回も恒例(?)のように、脱稿直前にCakePHPとJenkinsのバージョンアップのおかげでスクリーンショット取り直すことになったり、composerのバージョンアップで挙動がおかしくなったりなどなどなどなど...。色々ひやひやすることもたくさんありましたが、最終的にかなり読み応えがある書籍に仕上がっているのではないかと思います。

私自身、2年くらい前に初めて継続的インテグレーションを始めたばかりときに持っていた疑問や、たくさんのはまりどころが、この書籍を読むことでスムースに理解、解決できるように...。との思いで執筆しました。これから継続的インテグレーションを始めようとしている人、検討している人、そして今の開発現場を少しでも改善したいと考えている人の手助けになったら嬉しいです。価格はちょっと高めですが、その価値はあると思います。是非、一度手に取って(そして是非購入して(^^;)みてください!

あと、もしチャンスがあればこの書籍を題材にハンズオンとか出来たら面白いかなと思ってます!興味のある方はお声掛けくださいー。

最後に、共著者の @ryuzeeさん、@sizuhikoさん、@hampomさん、編集の丸山さん、本当にお疲れさまでした!

CakePHPで学ぶ継続的インテグレーション

CakePHPで学ぶ継続的インテグレーション

あわせてどうぞ。

CakePHP2 実践入門 (WEB+DB PRESS plus)

CakePHP2 実践入門 (WEB+DB PRESS plus)

クラウドセキュリティ クラウド活用のためのリスクマネージメント入門

クラウドセキュリティ クラウド活用のためのリスクマネージメント入門

「mongoDB datasource for CakePHP」 を composerでインストールする

超久々のブログですが、小ネタです。

何周か遅れでいま開発中の環境をcomposerを使って構築してるんですが、ちょっとはまったのでメモ。

id:cakephper さんの作ったmongoDB datasource for CakePHPPackagistに登録されていないのでcomposer.jsonを以下の様な感じにするとgithubから直接インストールできます。

{
    "name": "cakephp",
    "repositories": [
        {
            "type": "pear",
            "url": "http://pear.cakephp.org"
        },
        {
            "type":"package",
            "package": {
                "type" : "cakephp-plugin",
                "name": "ichikaway/cakephp-mongodb",
                "version": "2.2.x-dev",
                "dist": {
                    "url": "https://github.com/ichikaway/cakephp-mongodb/zipball/master",
                    "type": "zip"
                },
                "source": {
                    "url": "https://github.com/ichikaway/cakephp-mongodb",
                    "type": "git",
                    "reference": "cake2.2"
                },
                "require":{
                   "composer/installers": "*"
                },
                "extra": {
                    "branch-alias": {
                        "dev-cake2.0": "2.0.x-dev",
                        "dev-cake2.2": "2.2.x-dev"
                    },
                     "installer-name": "Mongodb"
                }
            }
        }
    ],
    "require": {
        "pear-cakephp/cakephp": "2.4.4",
        "cakedc/migrations": "*",
        "ichikaway/cakephp-mongodb": "2.2.x-dev"
    },
    "require-dev": {
        "cakephp/debug_kit": "2.2.*@dev"
    },
    "config": {
        "vendor-dir": "Vendor/"
    }
}

composer.jsonの書式がよくわからなかったので、このPRを参考にしました。

以上で。

2014/2/20 11:30 追記

id:cakephperさんが音速でこのPRをマージしてくれたので、以下の様な普通か方法でインストール出来るようになりました〜!

{
    "name": "cakephp",
    "repositories": [
        {
            "type": "pear",
            "url": "http://pear.cakephp.org"
        }
    ],
    "require": {
        "pear-cakephp/cakephp": "2.4.4",
        "cakedc/migrations": "*",
        "ichikaway/cakephp-mongodb": "2.2.x-dev"
    },
    "require-dev": {
        "cakephp/debug_kit": "2.2.*@dev"
    },
    "config": {
        "vendor-dir": "Vendor/"
    }
}

「CIを半年間まわしてみて」というお題でLTをしてきました

大分時間も経ってしまい今更ではありますが、先日行われた第67回 PHP勉強会で「CIを半年間まわしてみて」というお題でLTをしてきました。

昨年の11/30に、当時ちょうど開発が始まった案件の開発環境に関して「今時なCakePHPでの開発環境!?」というエントリーを書いて、初のホッテントリ入りしました。4月末でこのプトジェクトが始まって半年という事で、実際にCIをまわしている中で起こった事や、試行錯誤しつつどうやって解決したかなどを簡単にまとめてお話ししました。

LT用に作った資料ではちょっと伝わりにくいので、以下にまとめ直しました。

成長の軌跡

Jenkinsサーバーを立ち上げた時は、UnitTestのテストケースが10個だけだったのですが、4/30現在 UnitTestのテストケースが467件、受入れテストのシナリオ数が292件とものすごい成長っぷりです。

f:id:kaz_29:20130430122241p:plain

f:id:kaz_29:20130430120730p:plain

この半年間に起こった事

テストコードはいつ書くか?

今回のプロジェクトはUnitTestやBDD Plugin(BeHat)を使用しての受入れテストは書きましたが、TDD/BDDで開発していた訳ではありません。私自身もプロダクションのコードを書きながらテストコードを書いて、一通りブラウザ上で動作する所まで進んでから、受入れテストを書いていました。

年末〜年始にかけて手伝ってくれるメンバーが3名増えたのですが、実際にコードを書き始めて起こったのが...

プロダクションコードとテストコードが一緒にコミットされない!

折角CIしているのにこれでは全く意味がありません。という事で「テストコードが無いコードはmasterにマージしません!」と宣言して実際にマージしませんでした。masterにマージされなければ当然ステージング環境にも反映されませんので、ストーリ(チケット)が完了しません。という事で(おそらく(^^;)渋々テストコードを書いてくれたんではないかと思います。

自動テストに40分かかる

開発も順調に進み、テストコードが増えてくると皆さん直面するスローテスト問題が発生しました。当初は、インスペクション(静的解析)/UnitTest/BDD(StoryTest)を順番に実行していたため、各処理を分割して、インスペクションとUnitTestは並列に実行する様にしました。また、ビルドパイプライン化してUnitTestが正常に完了した場合のみStoryTestを実行する様に変更しました。この変更ですべてが完了するのに20分台まで時間が短縮しました。

ステージングへの自動デプロイがエラー

今回のプロジェクトではビルドパイプラインを作って、masterブランチで受入れテストが正常に完了すると自動的にステージング環境にデプロイされる様になっています。もちろん、テーブルの変更/追加時も自動でデプロイする為に、Migrations Pluginを使って自動でマイグレーションしています。そして、自動デプロイの際にこのマイグレーションに失敗してしまいました...。

原因は単純なミスだったのですが、ステージング環境のDBがつじつまの合わない中途半端な状態になってしまいクライアントさんにごめんなさいして、再度構成し直しました。これがプロダクション環境で起きたら...と思うと冷や汗がでました。

では、なぜこんな問題が起こったかというと、Jenkins上のUnitTestやBDD環境でテストを実行する際のマイグレーション手順がステージング環境と違っていたためでした。

この辺りにも書かれている通り、原則なはずの「すべての環境で、同じ手順でデプロイするべし」をしっかり守る事で、開発環境やテスト環境などで繰り返しデプロイ(この場合はマイグレーションですが...)が実行され、問題がある場合にも事前に発見出来る様になりました。

selenium-standalone-serverが落ちる

githubのcommit時に自動でテストが実行されるので、CIサーバーはもちろん24時間動作しています。継続して運用をしていると、突然ストーリテストに失敗する様になってしまいました。原因を調査すると、selenium-standalone-serverが落ちていたり、メモリ不足が発生していました。メモリーリークが発生しているのだろうと予想して、ストーリテスト実行時に自動的にselenium-standalone-serverを再起動する様に設定したところ改善しました。

ストーリーテストで時々エラーになる

単独で実行したり、開発環境で実行すると問題なく動作するのにある特定のテストケースが時々エラーになるという謎現象が発生しました。色々と調べた結果原因は簡単で、とあるモデルのアソシエーション先のorderが指定されていないため、環境/状況により並び順が変わってうことが原因でした。

アソシエーション先のデータの並び順は通常の処理では問題にならない事もあるので、注意が必要かもしれません。

スローテスト再び...

ビルドパイプライン化して、30分を切っていたストーリーテストがまた40分程度かかる様になってしまいました。色々と悩んだ結果、ストーリーテストを2つに分割して、同時に実行する様に修正しました。今回利用しているBDD Plugin(BeHat)ではシナリオにタグを振る事ができるので、以下の様にJavaScriptを使っていてSeleniumServerを利用するシナリオと、それ以外のシナリオに分割しました。実際にタグで実行するストーリーを切り替えるには以下の様に実行します。

$ ./app/Console/cake Bdd.story --tags=javascript // javascriptタグが付いているもの
$ ./app/Console/cake Bdd.story --tags=~javascript // javascriptタグが付いていないもの


複数のタグを付ける事も出来るので、機能毎にタグを付けておくとテストの実行範囲を絞り込むことが出来てとても便利です。この修正で、実行時間はほぼ半分の20分程度まで改善しました。

UnitTestがセグフォ

通常のUnitTestを実行する分には、全件テストを実行しても256M程度割り当てていれば問題ないのですが、CodeCoverageを取得しようとすると、膨大なメモリが必要で、プロジェクト開始から半年経過した4月にはとうとう2G割り当ててもセグフォで落ちる様になってしまいました。CI用サーバーのメモリは4Gと立ち上げ当初は多めのものを用意したつもりだったのですが、厳しくなってきました。

試行錯誤した結果、全件一括のテストを諦めてControllerのテストとそれ以外のテストの2つに分割して順番に実行する様にしました。カバレッジ自体は、Jenkinsが複数の結果をまとめてくれるのですが、詳細なhtmlレポートは今のところ統合出来ていません。ちょっと不便なのでなんらか改善策を打ちたいなと思っています。

テストケースが増えてくるとこの問題は必ず打ち当たる問題だと思います。皆さんがどんな風に解決しているかとても興味のあるところです!

またしてもスローテスト…

プロジェクトも終盤にはいって、JavaScriptをガンガン使う大きめの機能が複数完成したのに伴ってまたしてもストーリーテストの実行時間が30分を超えて、40分に迫りつつあります。これに関してはまだ対策は実施していません。4月末で、ひとまず開発作業にめどがつくので、時間を見つつテスト用のデータベースをインメモリ化してみようと思っています。

今回のCIサーバーは、さくらのVPS 4Gを使用しているのですが、UnitTestにしても、ストーリーテストにしても、Fixtureなどを利用してデータベースへの操作が多いテストを実行するとIO負荷が高くなりがちです。VPSにしてもIaaSにしてもHDDのアクセス性能はオンプレミスのサーバーに比べてかなりおそいので、ここがボトルネックになる事がありそうです。最近はSSDを使えるサービスなどもある様なので、色々と試してみたいと思います。

まとめ

今回クライアントさんの理解のおかげで、開発初期からCI環境を用意して進める事が出来、とても貴重な経験を出来ました。CI(continuous integration)は、日本語では継続的インテグレーションと訳されます。半年間継続してきて実感するのは、まさに継続していく事が肝だなと思いました。

今後、このプロジェクトに限らずプロジェクトが進んでいく中で、色々と厳しい状況が発生する事があると思いますが、今回の取り組みを継続していきたいと思っています。

FileFixture Plugin for CakePHPを作りました

皆さんテスト書いてますか?

という事で、必要に迫られて「FileFixture Plugin for CakePHP」を作りました。

Fixtureのデータを外部ファイルから読込む

プロジェクトの規模が大きくなってくると、整合性の取れたテストデータを手動でFixture形式にするのは結構大変です。Excel等の表計算ソフトでテストデータをまとめて作成して、CSVで出力したファイルをFixtureから利用する事が出来ます。

FileFixture Plugin for CakePHP」で出来る事は以下の通りです。

  • CSVファイルからFixtureデータを読み込む
  • TSVファイルからFixtureデータを読み込む

今のところ、対応しているフォーマットはCSV/TSVの2つですが、一応複数のフォーマットに対応出来る様に作ったつもりなのでそのうちXMLとかYamlとかも作るかもしれません。

他にも幾つかアイデアがあるので、しばらくはメンテナンスしていく予定。

使い方

使い方はとても簡単です。

データファイルを準備

下記のディレクトリにCSVファイルを用意します。

app/Test/Fixture/Data/posts.csv

1行目のフィールド名は、実際のテーブルのフィールド名と一致している必要があります。

title,body,created,modified
"The title","This is the post body.","2011-06-20 23:10:57","2011-06-20 23:10:57"
"A title once again","And the post body follows.","2011-06-20 23:10:57","2011-06-20 23:10:57"
"Title strikes back","This is really exciting! Not.","2011-06-20 23:10:57","2011-06-20 23:10:57"

テストデータファイルをFixtureで指定

Fixtureを以下の様に、親クラスを変更し、テストデータファイルを指定するだけです。

<?php
App::uses('FileTestFixture', 'FileFixture.TestSuite/Fixture');
class PostFixture extends FileTestFixture {
	public $fields = array(
		'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => 11, 'key' => 'primary'),
		'title' => array('type' => 'string', 'null' => true, 'length' => 50),
		'body' => array('type' => 'text', 'null' => true, 'length' => 1073741824),
		'created' => array('type' => 'datetime', 'null' => true),
		'modified' => array('type' => 'datetime', 'null' => true),
		'indexes' => array(
			'PRIMARY' => array('unique' => true, 'column' => 'id')
		),
		'tableParameters' => array()
	);

	public $importRecords = array(
		// 'path' => [path to Fixture File Path], // Optional(default is 'app/Test/Fixture/Data/')
		'file' => 'posts.csv',
	);
}

デフォルトでは、'app/Test/Fixture/Data/' にあるファイルを利用しますが、パラメータを指定する事で別のディレクトリに配置する事も可能です。

多分、来月くらいから実戦配備する事になると思うので必要な機能が出来たら随時アップデートする予定です。

「入門Chef Solo - Infrastructure as Code」のおかげでChefデビューできました!

入門Chef Solo - Infrastructure as Code

入門Chef Solo - Infrastructure as Code

 

去年、会社をやめて最初にサーバーを設定する時に、この本に書かれている理由そのまんまで挫折した経験があります。
その時はcapistrano+shellスクリプトでそこそこのレベルで自動化させてお茶を濁したのですが、ことあるごとにChefを調べては挫折...の繰り返しでした。
 
昨今のChefの盛り上がりを横目に眺めつつ、今月に今進んでいる案件のプロダクション環境を構築する予定があったので、SDの特集を読んでそろそろ手を付けようと思っていた矢先に「入門Chef Solo - Infrastructure as Code 」が発売されました!
 
速攻購入して、通勤中にiPad miniで読みふける事数日...。この週末にようやく纏まった時間が取れたので実際に手を動かしてみました。
 
手元の開発用MacのRuby環境がなんだかカオスな状態だったので、rvmを入れるところからはじめて、何とか一日がかりでいつも設定する基本的な設定までをChefで設定する事ができました。
 
普段、ニフティクラウドを使う事が多いのですが、ニフティクラウドはインスタンス立ち上げ直後は、rootでログインしないといけないのでひとまず以下の様な流れで設定出来る物をつくりました。
 
  1. Webコンソールからインスタンス立ち上げ
  2. capistranoでアカウント作成、sudo出来る様に設定
  3. chef-solo(knife solo)で諸々設定

 

1,2の部分も含め、どこまでをどのツールで設定するかは今後試行錯誤が必要そうです(サーバーの設定に関しては、出来るだけChefによせたいと思ってます)

 

しかし、コマンド一発でいつもの設定が終わって、なおかつ状態が管理されているのは感動ものです!

 

すばらしい本を書いてくれた id:naoyaに感謝!