moduleFakeNodemoduleValuedef[](key)
key.to_s
endalias:fetch:[]enddef[](key)
value = superif value.nil? && !self.mash.has_key?(key)
case key
when:http_proxynilwhen:rspectrueelse
key.to_s.tap do |v|
v.extend(Value)
endendelse
value
endendendItamae::Node.prepend FakeNode
# spec_helper.rbrequire'infrataster/rspec'%w( cookpad.com xxx.cookpad.com).each do |server|
Infrataster::Server.define(server, server)
RSpec.shared_examples "#{server} normal response"do
it 'returns 200'do
expect(response.status).to eq(200)
end
it "accesses #{server}"do
expect(request_uri.fetch('host')).to eq(server)
endendend
# cookpad_spec.rb
describe server('cookpad.com') do
let(:body_as_json) { JSON.parse(response.body) }
let(:request_uri) { body_as_json.fetch('uri') }
describe 'normal'do
describe http('https://cookpad.com') do
it_behaves_like 'cookpad.com normal response'
it_behaves_like 'https'
it "doesn't cache"do
expect(response.headers).not_to have_key('cache-control')
endendend
describe 'error pages'do
describe http('https://cookpad.com/error', headers: {'X-Test-Status' => 500}) do
it "return front 500 page"do
expect(response.status).to eq(status)
expect(response.body.strip).to eq("fw_errors/500.html")
endendendend
end
iOS 10 で実行してみると Parsed JSON number <1000000000000000070> does not fit in Int64.というエラーが出ます。 1000000000000000080でも起きますが、 1000000000000000071では起きません。
このエラーって何だろう… Swift がオープンソースなので、コードに grep してみましょう。これっぽい。エラーが発生する条件をもう少し見てみましょう。
guardletnumber= value as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else {
throw DecodingError._typeMismatch(at:self.codingPath, expectation:type, reality:value)
}
letint64= number.int64Value
guard NSNumber(value:int64) == number else {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath:self.codingPath, debugDescription:"Parsed JSON number <\(number)> does not fit in \(type)."))
}
NSDecimalNumberと遊んでみると挙動が分かりにくいところがありますが、上記の大きい数字でも NSDecimalNumber(value: int64) == numberが満たされるので、 Swift 本体は条件を以下のにすれば直りそうです。
letint64= number.int64Value
letrecreatedNumber= number is NSDecimalNumber ? NSDecimalNumber(value:int64) :NSNumber(value:int64)
guard recreatedNumber == number else {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath:self.codingPath, debugDescription:"Parsed JSON number <\(number)> does not fit in \(type)."))
}
iOS クックパッドアプリはどうしたかと言いますと、Swift.Decodableを使っていて、サーバーからとても大きい ID が来そうな箇所だけを Himotoki に戻すことにしました。 iOS 10 対応をやめたら、再度 Swift.Decodableに戻す予定です。
$ openssl s_client -connect m.cookpad.com:443 -quiet
depth=3 C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root
verify return:1
depth=2 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert High Assurance EV Root CA
verify return:1
depth=1 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert SHA2 Extended Validation Server CA
verify return:1
depth=0 businessCategory = Private Organization, jurisdictionC = JP, serialNumber = 0104-01-071872, C = JP, ST = Tokyo, L = Shibuya-ku, O = COOKPAD Inc., OU = Infrastructure Division, CN = m.cookpad.com
verify return:1
Web アプリケーションの把握を手助けするための手段としてまず最初に挙がるのがドキュメンテーションだと思います。
しかしながら、人間が入力した情報は構成変更等があったときに必ず古くなり誤った記述になります。
README に書かれていたジョブを探したけど見つからなかった、ドキュメントに書かれていない別のデータベースにも実は接続していた、みたいな経験はよくあると思います。
これを解決するには「人間が入力しない」ということが重要だと考えていて、AWS のように API で情報を取得できるインフラを使っていたり、hako の定義ファイルのように機械的に読み込める情報があるので、これらの実際に使われている実態と乖離していない一次情報を自動的に集めることを念頭に置いて設計しました。
react_native_root = File.absolute_path('../../')
desc "Install dependencies"
lane :setupdoDir.chdir react_native_root do
sh "yarn install && yarn run build"end
cocoapods(use_bundle_exec: true, try_repo_update_on_error: true)
end
▼android/fastlane/Fastfile
react_native_root = File.absolute_path('../../')
desc "Install dependencies"
lane :setupdoDir.chdir react_native_root do
sh "yarn install && yarn run build"endend
また次のような npm-scripts でシミュレータでの実行スクリプトを定義しておくと、開発者はリポジトリをクローンしてから yarn run ios:setupと yarn run startと yarn run ios:run:debugを実行するだけで iOS アプリをシミュレータ上で実行することができて便利です。(Android も同様)
「クックパッド MYキッチン」ではサービスの高速な検証のために、バンドルの配信に Microsoft 製の CodePushという仕組みを利用しています。CodePush を利用すると React Native アプリの JS バンドルのみをユーザーの端末に配信することができ、App Store / Google Play Store でアップデートを配信することなくアプリを更新することができます。この特徴はとにかく高速に仮説を検証したいサービス開発者にとって魅力的で、React Native を採用する大きな理由のひとつになると思っています。
CodePush は一つのプロジェクトに対して複数のデプロイ環境を作ることができ、「クックパッド MYキッチン」では Production, Production-test, Stagingの3つの環境を用意しています。Productionは App Store / Google Play Store で配信されている本番のアプリが JS バンドルを取得する環境、Production-testは社内のみで配信しているアプリが参照している環境、Stagingはチーム内でデザインや動作を確認をするためのアプリが参照している環境です。Production-testアプリと Stagingアプリの違いとして、前者は API サーバーや DB も本番環境を参照しているに対し、後者はバックエンドが本番環境とは切り離されているため、コンテンツの投稿・公開といった動作テストを行うことができるアプリになっています。それぞれの社内配信の方法とデプロイのタイミングについては CI の項で説明します。