twitterで下記のようなコメントがあり、弊社も新卒採用などやっていることから、Matzさんに新卒エンジニアの給料について伺ってみました。 質問 新卒エンジニアの適正給料はこれだとするならいくら位だと思いますか?ざっくり。 Matz 日本ということ考えて…理系大卒で600万くらいかなあ でもねぇ、大卒はだいたい粒ぞろいだと言っているのと同じ。個人差は無いものとしているってことなので、それだとおかしいよね。 ただ、コンピュータサイエンスの学科を出て、プログラミングできるっていう学生が300万とか400万とかしか貰えないと、彼の持ってる技能はあまり評価されてないってことじゃないかなと。特殊技能を持っていると思われてないってことじゃないかな。 プログラミングするのに国家試験はいらないので誰でもなれるって思われてるんだけど、実際はプログラムかける人とかけない人の差ってものすごいあるじゃないですか。 プログラミングを好きで、ものすごい苦労して特殊技能として伸ばしてきた訳だから。かつ、それを仕事で使って会社に貢献するはずなのに、普通に大学出て、プログラミングできません、これから仕事ですから勉強しますって人と同じ扱いをされると、全然評価されてないってことで、どういうことなんだろなって。 スタープレーヤーだと大学卒業してすぐでも1000万超えるくらいじゃないと夢がないんじゃないかなって。 逆に、使えなかったらバッサリ切る。凄い大学出てたとしても。 新卒みんな丸ごと高いっていうのはおかしいけど、スタープレーヤーに対して普通の給料しか出していないと、「俺、普通の人と同じに働いていれば良いのかな」ってなる。できない振りするのは簡単なので。 だいたいプログラマって、野球選手が野球にかけるのと同じくらいの時間かけてるじゃないですか。優秀な人は。 野球もそうなんだけど、頑張った人がみんなプロ野球の選手になれる訳じゃないんだけど、少なくともトップの人は凄い成功して、あの人みたいになりたいっていう憧れの存在って、プログラマーだとあんまりないよね。 経営者の方では凄いエンジニアがいればそのエンジニアの開発能力をお金にかえて欲しいし、エンジニアの方は自分の能力を正当に評価してくれるところに行ってして欲しいし。 VASILYの皆様にも、持ってるテクノロジーをお金に換えるってところは頑張ってほしいよね。 ---------- 新卒の皆さん・採用担当の皆さんは就職活動がヒートアップしてきたと思いますが、是非是非参考にして見てください。 VASILYもテクノロジーをお金に換えるところ、頑張ります。 VASILYでは2016年の新卒採用を行っています。自分こそがスタープレーヤーだと思う方は是非是非ご応募ください! 2016年度 新卒採用
質問 RubyKaigi、楽しみにしていますが、これをもっと楽しむためにはどうしたら良いですか? 参加者として楽しむには勉強しておくといいことなどあれば教えてください、登壇者を事前にネットストーキングすると楽しいとか。 Matz まあそれもいいかも(笑) カンファレンスの内容って、殆どのものってネットを調べればわかる情報なんですよね。 わざわざ会場に行ってっていうのは、スピーカーで話を聞くことよりもむしろネットワーキングっていうか、人と人とが繋がることのために行くんだと思ってるんですよ。 でも、それってあんまり言われないので、多くの人たちってただ行って話を聞いて「ああいい話を聞いた」って帰ってしまうことがかなり多いので、ちょっともったいないなと。 この業界の人はあんまり積極的に知らない人と交流する人ばかりじゃないんだけど。そこはちょっと置いといてですね、人と人のつながるみたいなことを主眼に置いたらいいんじゃないかなと思うんですよ。積極的にスピーカーに話しかけるとか、休憩室で隣に座った人に「あなた何やってんの」みたいに話しかけるとかいうことをすると120%か、まあ200%かもしれないけど、カンファレンスを有効活用できるんじゃないかと思うんですよね。 有料になってるので、せっかく行った分を取り返すためにはどうしたらいいかっていうと、そうやって人と話すっていうのが大事なんじゃないかなと。 質問 RubyKaigiでは、人と話せるチャンスはどこら辺なのでしょうか。 Matz 一番やりやすいのは懇親会ですよね。そこはあまり苦労しなくてもできるので、頑張った方がいいと思うのはコーヒーブレイクが途中にあるじゃないですか。あれをいかに有効活用するのかっていうのが狙い目じゃないかと思うんですよね。 そういった時間は知った人とつい喋ってしまう。VASILYの人とか、元々知ってる人とばかり集まって、「あの話はどうだったね」みたいな話をしがちだけど、それはオフィスに帰ってからもできるから。 そうじゃなくて、色んな人と喋るみたいなのをやるといいかなと。 まあ私にやれと言われても結構辛いんですけどね。性格上(笑) 質問 MatzさんはRubyKaigiで非常に多くの人と話すと思うのですが、どういった話をしている時が楽しいですか? Matz RubyKaigiの場合は来てる人みんなRubyに関心があるか好きな人なので、そういう意味で言うと誰と話してても楽しいのは楽しいんですね。 あと言うと新しいアイディアの話をするのは結構好きなので、「こんなことやってみたんですけど」みたいな話をするのは楽しいですね。それはいろんなレベルだけど、Rubyそのものに対してどうしたいみたいなアイディアもウェルカムだけど、「Rubyでこんなことやってみました」みたいな話も面白いですよね。特に「今までやったこと」みたいな話ばかりではなくて、新しいこと、「こんなこと試したい」とか「試してるんですけど」みたいな話を聞くのはすごい好きですね。 質問 Matzさんは今年もKeynoteがありますよね。外にも様々なプレゼンをされているんですが、エンジニアとしてのプレゼンのコツって何かありますか? Matz 心当たりあるのは数ぐらいしかなくて、やっぱり数をこなすと聴衆が何を期待しているのかとかが大体把握できて、だいぶ楽になりましたよね。 あとは、エンジニアなのでテクニカルな話はするんだけど、テクニカルのレベルを上げすぎちゃうと8割9割の人は付いて来れなくなるので、そこは「もっと詳しく知りたい人はあとで来てね」みたいな感じで抑えとくっていうのはエンジニア向きの話としても結構大事な気はしますね。 ジェネリックな話っていうか一般論の方がみんな好きなことが多いみたいで。だから詳細には立ち入らないんだけど「こんなことが今大事なのでこれちょっと頑張ろう」みたいな。いろんなのがあるんだけどここが大事、みたいな戦略的な話をするのは結構重要かなと思います。 あと、大体のことって一次元では決まらないじゃないですか。バトルもののランキングとかとは違って、このことは得意なんだけどこっちは苦手みたいなのは常にあるので、そういうトレードオフを意識した話をするようには心がけています。 一つのアイディアがどこでもオールオッケーみたいなケースってエンジニア的にはほとんどないんですよね。こういう前提条件があればこのアイデアはいいけど、前提条件が成立しないときはまた別のという風なことになるので、こういうトレードオフでこれを選んだんだけど、前提条件が成立しないときはそうでもないよねっていう話はよくしますね。 まあ、フェアでありたいと思ってますね。マーケティングの話とかだと、この技術で何でも解決みたいな、「これさえあればなんでも解決」みたいな話をしがちなんだけど、現実はそうではないのでそこはちゃんと言うようにしてます。 ---------- RubyKaigi 2014は9/18〜19。MatzさんのKeynoteは19日9:30〜です。 盛り上げて、楽しみたいですね! (弊社VASILYもGold Sponsorとして参加&Matzさんの衣装コーディネートもしますので、楽しみにしていてくださいませ!)
こんにちは、バックエンドエンジニアのBoBです。 今回は皆様にお知らせがあります。 弊社VASILYと、株式会社ハースト婦人画報社共催で、日本初のファッションをテーマとしたハッカソン 「THE FASHION HACK in TOKYO powered by Hearst Fujingaho & VASILY」 (以下、THE FASHION HACK)を 2014年9月6日(土)~9月7日(日) に開催する事となりました! 「THE FASHION HACK」は、エンジニアやデザイナーなどのクリエイターが1~3人1組のチームで、与えられた24時間で新たなアイディアのもと、実際に動くプロダクトを開発するハッカソンイベントです。 今回はファッションに普段から興味があるエンジニアの方にとっても、そうでないエンジニアの方にとっても、このハッカソンイベントがいかに魅力的かを伝えたいと思います。 1. ファッション×テクノロジーはまだまだ未開拓 今回のハッカソンイベントのテーマは、「ファッションとITテクノロジーを掛け合わせて、新しいものを作る」です。それ以外に特に縛りはありません。 近年、弊社iQONをはじめ、インターネットのファッションメディアがユーザー数をどんどん増やしたり、ハースト婦人画報社の様なファッション業界の会社がデジタル戦略を加速させたりと、テクノロジーでファッション業界にイノベーションを起こそうという企業が増えています。しかし現状、まだまだ開拓されていない領域です。 また、ウェアラブル端末であったりIoT(Internet of Things)の分野が盛り上がりを見せており、ファッション業界からも大きな注目を浴びています。メガネ専門店「JINS」を運営する株式会社 ジェイアイエヌが発表した、JINS MEMEは記憶に新しいかと思います。これらの分野は今後確実に伸びて行く分野であり、かつファッションとは切っても切り離せない分野となっています。 今回のこのイベントをきっかけに普段気になっている新しいテクノロジーに触れ、このチャレンジングな分野に興味を持ち、イノベーティブなものを形にしてもらえればと思います。 2. 普段はさわれない、国内最大級のファッションアプリ「iQON」のAPIを使った開発ができる ファッションコーディネートアプリ「iQON」は、投稿されたコーディネート数は100万件を超え、掲載されているファッションアイテムも400万件以上と、国内最大級のファッションコンテンツが集まるアプリに成長しています。 そのiQONのAPIを今回のイベント限定で、参加者に公開する予定となっています。 またハースト婦人画報社が所持している、ファッション記事に関するAPIも当日公開される予定となっています。 もちろんその他、ファッションに関わらず様々なAPIを使って開発していただいてかまいません。 ぜひ普段さわれないiQONやその他のAPIを自由に使って開発を楽しんでいただきたいと思います。 3. 通常のハッカソンでは出会えないような人との出会い ハッカソンの醍醐味としては、普段話さない人たちとの新しい出会いがあると思います。 特に今回のハッカソンに関してはエンジニアやデザイナーだけでなく、審査員やスタッフも含め、ファッション業界の方にも参加していただく予定となっております。詳しい審査員の情報は専用サイト( http://www.thefashionhack.com )をご覧下さい。 イベント後の懇親会も予定していますので、今ファッション業界ではどのようなテクノロジーに注目しているのか、今後どのようにファッション業界とテクノロジーの関係は変わって行くのかなど、普段なかなか聞けない話を聞く事ができるイベントとなっています。 4. 採用につながる可能性も。。。 私たちVASILYは、テクノロジーで世の中にインパクトを与えたいエンジニアを常に募集しています。 弊社エンジニアも当日会場にいますので、VASILYに興味がある方はぜひぜひ参加して話してみてください。 詳しいイベント概要の確認、ハッカソンへの申し込みは専用サイト( http://www.thefashionhack.com )からお願い致します。 皆様からのたくさんのご応募、お待ちしております!
VASILYではエンジニアが海外で行われるカンファレンスに参加できる制度があり、毎年iOSアプリのエンジニアが WWDC に、Androidアプリのエンジニアが Google I/O に参加しています。 今年もAndroidアプリのエンジニアである私、 @yoichinishimura が6月25日、26日に行われた Google I/O に参加してきました。 今年のI/Oでは、 Material Design やAndroid関連の多くの発表がありましたが、その中で私が一番に関心を持ったのが Android Wear でした。 半年ほど前に公開されたPreview版のSDKにはさほど興味は湧かなかったのですが、正式なSDKが公開されたのと、会場で参加者に配られた Samsung Gear Live を身につけていたら急に興味が湧いてきました。 今回は Android Wear とはいったいなんであるのか ということをI/Oのセッションや公式ドキュメントで学んだことと、私の考察を混ぜながら紹介したいと思います。 1. Android Wearとは I/Oに行く前は 『 Android Wear とはGoogleが提供するOSを取り入れた時計、つまりスマートウォッチのこと』と勝手に思っていたのですが、どうやらスマートウォッチのことだけじゃないと Wearable computing with Google というセッションで知りました。 セッション内で Google Glass が Android Wear に対応するという発表があったのですが、つまり対応後は Google Glass も Android Wear という扱いになるそうです。 つまり Android Wear とは Androidと通信することができるウェアラブル端末すべて を指すのです。Androidが起こすIoTの時代がやってきたと感じました。 Android Wear イメージ的には以下の画像の下部にあたると思います。 2. 既存アプリのAndroid Wearの使いどころ Android Wear の開発をはじめる方は Googleが出している公式ドキュメント を一読することをオススメします。 Android Wear の一番の基本機能は Context Stream と呼ばれるカードリストを表示させるところです。 「Google Nowに似たもの」とイメージすればわかりやすいと思いますが、1画面に1カードAndroidから送られるNotificationなどの情報を表示します。 デバイスの操作は、スマートフォンと同様にタップやスワイプ、Yes or Noなどの簡単な操作、音声入力などが行えます。 実際に使ってみるとよくわかりますが、スマートフォンに比べて行えることが限りなく少ないですし画面も非常に小さいです。 そのため既存アプリを上手く対応させようと思うとかなり苦労すると思います。 話は戻りますが Wearable computing with Google のセッションで以下の図が出てきました。 Wearableの開発をするにあたっては従来の デザイン・開発・デバッグ(テスト) の工程に加えて UXイテレーション が重要になるそうです。 開発者が意図するUXを実現してもらうため、Webやスマートフォン以上にWearableの開発にはUXに関わる時間を使う必要がありそうです。 iQONでも Android Wear 対応をするには既存機能の中で何の機能を実装するのが最適であるのかを考えてみたのですが、定期的にユーザーにGCMで送っている以下のような情報を Android Wear に最適な形で対応すると効果が高いと考えました。 Likeしているブランドのアイテム追加情報 アイテムが割引になった際のセール情報 Likeしているアイテムが売り切れ間近の在庫情報 常に見たい オトクでタイムリーな情報 を配信するのは Android Wear 冥利に尽きると思いますし、使い方としては間違っていないと思います。 先日 Android Wear 対応するのに必須な Google Play Services のバージョンアップも済ませたので、近日 Android Wear 対応したバージョンを配信する予定です。 3. Android Wear開発のはじめ方 最後に、簡単にはじめられる Android Wear 開発のはじめ方を紹介します。 Hello World!出力 まずは Android Studio をインストール 、もしくは v0.8.0 以上にアップデートしてください(SDKの更新も忘れずに)。 https://developer.android.com/sdk/installing/studio.html New Project を立ち上げて、 Select the form factors your app will run on まで進んで、 Phone and Tablet と Wear にチェック を入れてください。あとはポチポチとNextを押下してプロジェクトを作成してください。 プロジェクトが出来上がると mobile wear と見慣れないディレクトリ構成でプロジェクトが立ち上がります。 mobile の Configuration を選択し Android のスマートフォンの 実機 or エミュレータにビルドを行い、 wear の Configuration を選択し Android Wear の 実機 or エミュレータ にビルドを行うことで、各デバイスに Hello World! を出力することができます。 サンプルコードで学ぶ SDKマネージャーから Android 4.4W のパッケージをインストールすると以下のパスにいろんな利用シーンを想定した17個サンプルのプロジェクトができています。 それをビルドしながら実際に動かし、コードを読み進めていくと Android Wear でどういうことができるのかを効率良く学ぶことができます。 $ /samples/android-20/wearable/ 併せて 公式の開発ドキュメント を読みながら Android Wear から新しく登場したクラスを探ってみると更に理解が深まると思います。 4. まとめ ざっくりと Android Wear について紹介しましたが、実際に手にとって使ってみないと良さがわからないと思うので興味のある方は発売開始したスマートウォッチを手に入れてみてください。 時計や眼鏡は常に身体に身につけているものなので、手に取って操作しないといけなかったスマートフォンでは提供できなかった新しい体験が Android Wear では提供できると思います。 最後の最後に現実の話をしますと Android Wear と連携できるのは Android 4.3 以上の端末のみ です。 2014年7月14日現在、世界全体の25%のユーザーしか対応OSを使っていないですし、iQONに至っては12%のユーザーのみです。そこから Android Wear 端末を購入して使うユーザーがどのくらいいるかを考えるとかなり少ないと思います。 Android Wear 対応を急ぐことはありませんが、前述の通りシンプルそうに見えても効果を最大限に対応するにはかなり難しい印象です。 そのため今からスタートダッシュで開発を進めノウハウをためるのがベストだと思います。iQONも先陣を切ってウェアラブル対応を進めていきます。 iQONを開発しているVASILYでは先陣を切って世界にインパクトを与えたい Androidエンジニア を大募集しております。 【Android】世界で勝ちたいAndroidアプリエンジニア募集 また情報交換なども随時行っていきたいと考えているので勉強会などの開催、参加についても気軽に相談頂ければと思います。 info[at]vasily.jp や @yoichinishimura などで気軽に連絡いただければと思います。
VASILY新入りエンジニアのEricと申します。 フィラデルフィアから来ました。好きな漫画はHUNTER x HUNTERです。 今回は使える英語コミットコメントを10個紹介します。 Fix, Change, Reviseなど、日本人の方には違いが分かり辛いものも、実際の使い所が分かるようにしてみました。 是非知って、使ってみてください! 1. Fix 意味: 直す, 修理する 使い方: バグなどが出たためコードを書き直す必要があう場合に使います。何か問題を直して、正確な操作に戻すニュアンスが強いです。 例: Fix inequality in LinesComponent 訳: LinesComponentにおける不等式を書き直す 2. Revise 意味: 変更する、修正する 使い方: バグは出ていませんが、不十分なところや修理が必要としたところがあって、コードをよりよくする時に使うことが多い。考え直して、改善するというニュアンスを持っています。 例: Revise User class variable types 訳: Userクラスにおいている変数の種類を修正する 3. Change 意味: 変更、変える 使い方: 前もっていた状態を変えるというニュアンスが強い。ある値を持っていた変数に別の値をつけたり、クラスなどの造りを変更したりする時に良く使います。 例: Change var names for consistency 訳: 一貫性のために変数名を更新する 4. Update 意味: 更新する、新しくする 使い方: 最新の情報などに対応するためにコードやドキュメントを変更する時によく使います。最近変化した別のものにマッチするというニュアンスが入っています。 例: Update documentation to show new methods 訳: ドキュメントを新しいメソッドを反映するようにアップデートする 5. Upgrade 意味: 更新する、改善する 使い方: プロジェクトなどの部分やライブラリーのバージョンを更新する時によく使います。Updateとの違いは微妙ですが、バージョン番号などが変わる時に使うことが多いです。 例: Upgrade to markdown-preview@0.74 訳: `markdown-preview`をバージョン0.74に更新する 6. Clean up 意味: 片付ける、奇麗にする 使い方: 分かりにくかったり、無駄があったりしたところを片付けて、分かりやすくする時に使うことが多いです。 例: Clean up specs based on feedback. 訳: フィードバックに従ってスペックを片付ける 7. Remove 意味: 削除する、取り除く、除去する 使い方: 以前コードに入っていたものを取り除く時に使います。 例: remove decoratorType instance var `decoratorType`というインスタンス変数を削除する 8. Revert 意味: 取り消す、元に戻す 使い方: プロジェクトなどを元の状態に戻す時に使います。 例: Revert to version 1.0.9 訳: バージョン1.09に戻す 9. Add 意味: 追加する、加える 使い方: 今までなかったものを追加する時によく使います。 例: Add `has-selection` class to the editor div 訳: `editor` div に`has-selection`というクラスを追加する 10. Implement 意味: 実装する 使い方: ある追加したい機能やフィーチャーがあって、実際にコードを書いてプロジェクトに入れる時に使います。 例: Implement removeDecorations class 訳: `removeDecorations`というクラスを実装する 英語でコミットコメントが書けると、githubなどで世界中のプロジェクトに参加して多くのエンジニアと一緒に仕事ができるので刺激的です。 挑戦してみてください! VASILY iOSエンジニアによるApple WWDC報告会を開催します! ・日時:6月27日(金)20:00〜22:00 (20:00〜21:00 Apple WWDC報告会、21:00〜22:00 オフィスで懇親会) ・場所:東京都渋谷区恵比寿3-42-13 1F 株式会社VASILY( http://bit.ly/1mQQMDs ) ・参加費:無料 ・定員:15名 ※ご参加は学生、社会人問わず Apple Developer Programs に加入していらっしゃる方のみとさせて頂きます。 ※定員制のため、応募者多数の場合は抽選とさせていただきます。ご招待する方のみ 6/20(金)にメールにてご連絡いたします。 VASILY iOSエンジニアによるApple WWDC報告会のお申し込みは こちら から
VASILY iOSエンジニアの庄司です。 同じくiOSエンジニア荒井とチーム全員(2名)でサンフランシスコで開催中のWWDCに来ています。 今回のKeynoteは既にご存知の通り、「OS X Yosemite」、「iOS 8」、新言語「Swift」など盛りだくさんの内容でした。 SwiftはRubyと似たような記法があり、 Rubyを使っている会社 の一員としてはとっつきやすくていい感じです。 さて、WWDCの開催期間は5日間ありますが、大きく報道されているKeynote以外にも たくさんのセッション が開かれています。 そのセッションの様子は WWDC2014の公式サイト で見ることができます。 Keynoteもセッションも現地に行かずに見れるのに、なぜ高い参加費を払って現地に来るのでしょうか。 今回は「現地に来るべき理由」をいくつか紹介します。 WWDCの現地に来るべき理由 1. Labs WWDCの会場にはAppleのエンジニアが直接技術的な相談に乗ってくれるブースがあります。(基本的に英語。一部日本語のわかるエンジニアもいるそうです) 日本にいるとAppleのエンジニアと話す機会はなかなかありません。英語に自信がなくてもコードでなら会話ができます。 僕達も実際にLabに行ってみました。英語が苦手でも一人ひとりに理解できるまで丁寧に教えてくれて、抱えていた問題が解決しました。 2. Bash WWDC期間中の一通りのセッションが終わった後、会場の隣の公園でWWDC参加者が一同に会するBash(打ち上げ)が開催されます。 去年はここで「こんなに日本人来てたのか」というぐらい、多くの日本人エンジニアと話すことができて、帰国後も交流が続いています。 毎年有名なアーティストが招待されており、企業のお祭の域を超えた盛り上がりを見せます。 3. Stump the Experts 毎年WWDC期間中に開催されるイベントで、ステージ上のAppleエンジニアvs観客のエンジニアのクイズ大会です。 クイズの問題はAppleに関する超マニアックなもの(例: 粉々になったプラスチック片を見せて、これは何年のmacのどのパーツ?)が多く、僕なんかはさっぱり答えがわかりません。 Keynoteと同じ会場で席は半分ほどしか埋まっていませんでしたが、Keynote以上の歓声と熱気がありました。 4. 現地で開催されているイベントに参加 AltConf WWDCのチケットの抽選に外れてしまったエンジニア達が有志で開催しているイベントです。WWDC期間中、会場の近くで開催されています。 僕が見に行った時は、ベルリンから来たエンジニアがXcode Pluginについて語っていました。 当然WWDCのように最新技術については触れられませんが、デザイン関連のセッションやマーケティング関連のセッションもあり、WWDCのチケットを持っていても行ってみる価値はあると思います。 おまけに、無料なのにTシャツまでもらえました。 AppAdviceのパーティー WWDC開催の前日、会場の近くでAppAdviceというアメリカのレビューアプリのメンバーが主催するパーティーに行ってきました。 日本人は僕達だけでしたが、WWDCのジャケットを着たエンジニアがたくさんいたので、積極的に交流してきました。 お互いに自身のアプリを紹介し合い、エンジニア同士貴重な情報交換が出来る場であったと思います。 パーティーの趣旨はよくわかりませんでしたが、iQONの宣伝も忘れずにしてきました。 こういったイベントはこの時期よくやっているようです。 5. 現地の企業に行く 知人の紹介でYahoo! inc.で「Yahoo! News Digest」のPMを担当している方とお知り合いになりました。 WWDCが落ち着いた後、Yahoo! Inc.のオフィスにお邪魔してくる予定です。 6. とにかく話しかける 正直なところ僕は英語が苦手です。英語だと会話のキャッチボールがうまくできませんが、自分からボールを投げ始めることはできます。 セッションに並ぶ行列中に話しかけたり、隣の席に座った人のmacを覗きこんで話しかけたり… この行動のおかげで去年あった外国人と現地で再会することができました。 7. 話しかけられる 写真にあるようにVASILYのメンバーに借りた着物を着て行きましたが、効果抜群でした。 みんなが笑顔でこっちを見てくれるし、多くのエンジニアに声をかけられました。話しかけてくれた人の中には「Oh, Jedi...」とオビ=ワン・ケノービと勘違いしている人もいました。 チャイナドレスのエンジニアがいたら僕も話しかけたくなるので同じ心理だと思います。 まとめ 5. については、たまたまいい人を紹介していただけたのでラッキーだったとは思いますが、それ以外のことはチケットを購入できれば自分の努力でどうにかなります。 また来年WWDC参加を狙っている方は全力で楽しむために、今回紹介した内容を試してみてはいかがでしょうか? 惜しくも抽選にもれてしまった方は、現地に行った方から話を聞くと何かしら発見があるかもしれません。 さいごに この記事を読んで来年こそはWWDCに行ってみたいと思ったあなた、一緒にiOSアプリを開発してWWDCに行ってみませんか? (もちろんチケットが取れればの話ですが) WWDC仕込みのメンバーとNo.1のアプリを作るiOSエンジニア募集
まつもとゆきひろさんが弊社の技術顧問に就任する事となりました。せっかくなので、「ベンチャーの重要性」「世界での勝ち方」「sierのヤバさ」「モルモン教とエンジニアリング」など、まつもとさんに色々聞きたかった事をぶつけてみました! vasily officeにて 質問 我々は、小さい会社ながらも技術によって世の中にインパクトを与えようと頑張っています。 他にもそういった会社が増えていますが、思う所など教えてください。 まつもと その逆は大企業とかだけど、関わっている人が多くなればなるほど、辛くなりますよね。 僕はビジネスマンじゃないので、エンジニアが幸せかどうかしか分からないけど、自分で決められないエンジニアは不幸なんですよね。 この技術の方が絶対いいのに、「上司が説得できないから従来のやり方で頑張りましょう」みたいな空気で腐りながらやるのは、エンジニアにとっては不幸なんですよね。 小さなとこだと自分で何をするか決められるじゃないですか。それはエンジニアにとっては幸せなことだと。 あとは、ネットのスピード感を維持するっていうのはむしろ、小さな組織でなければできない。 「大企業があります。ビジネスがあります。大企業がそのシステムが欲しいから発注します。」みたいな構図はもう、なくなっていくかなと。 テクノロジーを担うのは動きの速い小さな組織しかないんじゃないかな、と思いますね。 質問 我々はテクノロジーを足がかりにして世界と戦おうとしています。 rubyは世界進出に成功したプロダクトだと思いますが、その経験を踏まえて成功するのに必要な事は何だと考えますか? まつもと なんでも人間が相手なので、人気が出るとか広く使われるとかは人が決める。一人一人がサイトだったりサービスだったり、あるいは言語だったりを選ぶ事によって決まるわけですよね。 それを選ぶかどうかっていうのは、好きかどうかとか、便利かどうかで、それって文化に依存する。 rubyの場合はプログラマーのマインドとか、ハッカー文化みたいなものに寄り添って、そこに最適化していて。そこが特定の国に依存してないものだったので、上手く行ったと。 現状、本当に世界規模で何かをやるには、国に依存しない共通な何かの文化を見つけ出して、それに最適化しないと難しいんじゃないかと思いますね。 iqonは成功するために日本の文化・ファッションの文法によりそっているわけですが、これを海外に持っていくためには、この日本への最適化そのものが障害になる可能性が出てきますよね。 あるいは、この日本のファッションという文化ごと世界共通語を目指すといいのかもしれないけど。 質問 エンジニア、プログラマーの幸せって何だと思いますか。 まつもと 満足しているかどうかってことかな。 自分の待遇だったり境遇だったりに対して、満足しているかどうかっていうのは一番大事だと思っていて、プログラマーとして満足なのは何っていうと、 一つは面白いものを作っているかどうか。 テクニカルもエキサイトできるかだし、もちろん収入もそうだし、忙しいかどうかも。時間の使い方だとか。 あとは自由とか裁量。 自分がほんとうに素晴らしい、正しいと思う事を聞いてもらえるか、説得できる余地があるかどうか。 エンジニアが何を言っても駄目だって諦めていると、そこは違うだろうみたいな。 で、最後にそれに繋がるものっていうのは、自分がエンジニアとして、技術を持っている人として、テクノロジーを使ったパワーを持っている人としてリスペクトされているか。 「お前の持っている技術だったら俺のやりたい事ができるかもしれない。一緒にやってくれないか」って言われたら、リスペクトされている気になるじゃないですか。そうするとすごい力が出てくる。 逆に「お前がどう思ってようが関係ない、俺の言った物作れ」っていうのはリスペクトされないわけですよね。 質問 リスペクトされていない状態の人達もいると思いますが、そういう人はどうしたら良いですかね? まつもと やめる。 すごく我慢する人が多くて、景気がすごく悪いのは続いていて、ここにいないと僕はニートになってしまうかもしれないっていう恐怖感はあると思うんだけど、そのリスペクトしない人に対して奉仕しちゃうと、どんどん立場が下がっていく。 最終的には奴隷になっちゃう。it奴隷に。 それはダメだと思うので、どうするかっていうと、昔からそういう時は反乱を起こす。そういうエンジニアをリスペクトしない連中は見捨てるっていう。 どうせエンジニアがいなけりゃシステム作れないんだから。 そういうのをみんなでやって、技術者を大切にしないと自分の事業は立ちいかないっていう状態に追い込まないと、良くならないと思うんですね。 例えば、金山さんが「ファッション界に変革を起こしたい、itは単なる道具」という態度であればvasilyと共感できなかったと思います。 しかし、実際には金山さんも魂はエンジニアで、「テクノロジーが世の中を変えることができる、我々のフィールドはファッションだ」というテクノロジードリブンな発想だったので、これならお手伝いできるなと思いました。 質問 ちなみに、「こういう会社は気をつけた方が良い」っていう物はありますか? まつもと 「si」っていう単語が使用されている会社は8割9割ダメ。 siの、お客様の為にシステムを作るっていう構造が、win-winになりにくい。 顧客は出来るだけ安く、出来るだけ良い物を作ってもらいたい。作る方は出来るだけ少ない仕事で出来るだけ沢山お金を貰いたい。一緒の方向を向いていないんですよ。 作る方も最初に作りますって言った仕様を満たす最低ライン出せば良くて、納めてしまえば終わりで、お客様が成功したかなんて関係ないんですよね。 ほとんどの会社はシステムを売ってはいないから間接部門なのでコスト部門なんですよ。 社内でも切れ切れって言われていて、ちょっとでも安くしないとって物なので買い叩かれるのですけど、それだとエンジニアは幸せになりませんよね。 最悪のビジネス構図です。 なので、siはもう見捨てるしかないかなと。 システムインテグレーションっていう業種が壊滅したらもうちょっとマシになるんじゃないかな。 大企業にいて苦しんでいる人には「辞めたらいいんじゃない」って毎回言っているんですけど、やっぱ怖いんですね。フリーランスになるとか小さな会社に行くとかは。 心理的な障壁が大きいんですね。「頑張って大企業に入りました。それを辞められますか」と。 心理的な障壁に甘えて、siみたいな幸せにならない構造を維持していくのはどうかというのはありますね。 質問 まつもとさんはモルモン教の宣教師だったのですが、それがプログラミングやエンジニアリングに与えている影響ってあるのでしょうか? まつもと 相対化できないので、同じ条件でそういう経験のない私と今の私とは比べられないので、なかなか難しいですが。 大学生の時に2年間宣教師として奉仕したんですけど、人と凄くたくさん話をしたんです。何万人と。 その時割と人間を見たんですね。そういうのが役に立っているかもしれないなと思う時はありますね。 itってテクノロジーなんだけど、最後のファクターは人間なんですよね。 テクノロジー的にはトレードオフを提供できる。このボリュームをこっちにあげるとこうなって、こっちをあげるとこうなってっていうのはできるけど、じゃあ、そのトレードオフのボリュームをこうしますっていうのは人間が決めるんですよ。 絶対的な真理はなくて、100人が100人納得する意見っていうのはないので、テクノロジーを人間に合わせる部分が大事なんですね。 そこは多くの人と話をしたのが役に立っているかもしれないですね。 あとは2人1組で活動する事が多くて、だいたい僕の相棒はアメリカ人とか外人が多かったので、英語を使っていましたね。 今、僕が英語を喋っているのも基礎みたいなのはそこでできたと思いますね。 この2つは影響があったんじゃないかと。 質問 ざっくりとした質問で恐縮ですが、プログラミングの将来ってどうなるのかをお伺いしたいです。 まつもと 近い未来だと、ソフトウェアの規模はどんどん小さくなるんじゃないかな。小さいのをたくさん作るみたいな感じになるんじゃないかと思います。 それは何かというと、フレームワークであるとか、ライブラリであるとかが充実してきて、それを組み合わせるだけで一通りの事ができるという。 その時にrubyみたいな言語ってのはクラスライブラリとかを提供していって、プログラマーはスコアリングの調整やapi取り込めば良いだけみたいになって。 ターンアラウンドタイムがだんだん短くなっていくんじゃないかと思います。 遠い未来だと、コンピュータが人間の言葉を理解して、人間に変わってコンピュータが計算してくれてとか、いい感じにビジュアライズまでして出してくれるとかっていう感じになると思うんですけど。 そうするとプログラミングの楽しみがなくなるんだけど、僕はちょっとおじいさんになってもプログラミングしていて、「おじいちゃんがまた年寄りの趣味やってるよ」とか、「もう何十年前のやり方なんだろうね」っていうのをプログラムやりながら言われてそうな気がします。 今でも現実に普通の人はいろんな事を探すより先にgoogleしますよね。 あれがどんどん自然言語に近づいていって、「何かが知りたい」とかいうと、今でも普通に文章を打ち込む人結構いるんだけど、適当に出てきて用が済んじゃうみたいな。あれがどんどん進んでいくんじゃないかな。 あとはフロントはsiriみたいになって、どんどん自然に。 質問 その仕組みを作る側にも人はいるんですよね。 まつもと もちろん、当面はいますね。 でも、それもどっかから自動化されて。コンピュータの知能が十分高まっていくと、聞いただけで言葉を理解して、持っている情報からそれっぽいのを作り出してくれるような気がしますけどね。 プロプログラマーの仕事は2極化して、アカデミックな最先端のことやるのと、本当に簡単な事をやるのと。 個別のニーズに合わせて、「この業種だからこういう組み合わせをする」というのをやるエンジニアは当面はいると思います。 でもそれは誰でも出来ちゃうんで、何を差別化するかっていうところはキーポイントですね。 まつもとゆきひろ氏を囲んで 以上、当日話した内容のごく一部ですが紹介いたしました。 他にもエンジニア同士で言語や仕事、マネジメントについてなど、踏み込んだ話で盛り上がりました。 vasilyでは、一緒に切磋琢磨できるエンジニアの仲間を探しています。 まつもとさんを迎え、vasilyはエンジニアにとってさらに成長できる環境になりましたので、ご興味ある方は是非是非↓こちらまで! 世界を変えたいエンジニア募集
VASILYのiOSエンジニアは今年もWWDCへ参加しています。 同時に、WWDCへ参加する世界各国のエンジニアたちとの交流も深めています。 和服で来ています WordPressのエンジニアと ものすごい熱気です iOSエンジニアとしてノウハウや今後の動向を学ぶだけでなく、文化や魂など、色々お土産を持って帰ってくる予定です!
Androidエンジニアの村田です。チームメンバーが増えてきてますますテストコードの必要性を感じています。 ということでAndroidアプリの開発でユニットテストを導入しました。 挫折しないでユニットテストを始めるための3つのポイントを紹介していきたいと思います。 なぜ始めたか? まずはじめにそもそもなぜ始めたのかの理由を3つ紹介します。 プロダクトの品質を仕組みとして保ちたかった コードレビューはしてるが、あくまで人の目の確認となり抜け漏れが生じてしまいます。クラスやメソッド単位での品質は仕組みとして担保したいと思いました。 チーム内でクラス、メソッドの仕様についての共通認識を高めたかった そのコードは何を受け取ったらエラーとするのか?テストコードを書けばわかりやすくなると思います。自分のためにもチームメイトのためにもなると思います。 仕様変更によるバグ発生の回避 たくさんの機能をハイスピードで開発、改善、廃止などしていくうちにちょっとしたコードの変更が思わぬバグを生むことがあります。 予めテストが書かれていればコードを微妙に変えても異変にすぐ気がつけると思います。 このように始める理由は結構ありきたりな理由でした。 それでは本題に入っていきます。挫折しないようにユニットテストを始めるための3つのポイントを紹介していきます。 1.現状分析&シンプルな導入 2.自分のコードは完璧じゃないと疑う 3.メリットを明確に納得する 現状分析&シンプルな導入 始めるにあたってアプリケーションのどの部分から始めるかを決めるのは大事です。 どこから始めるかをしっかり絞って優先付けをしていくことで迷わずにユニットテストを導入することができます。 iQONではクラス単位でざっくりどういう役割があるのかを把握することから始めました。 iQONのAndroidアプリのクラス数 Activityクラスの数:73 Fragmentクラスの数:32 Adapterクラスの数:15 View関連の共通クラス数:30 モデルなどのデータ処理系のクラス数:45 iQONの機能のほとんどはバックエンドのAPIサーバ+画像サーバとhttp通信をすることで実現しています。 この処理を担当するのが1番下のデータ処理系のクラス(45クラス)になります。 ユーザから見えにくい処理はユニットテストにうってつけ ViewとかActivityとか表面に見える部分のバグは実機テストするときに人の目でも検知できますが、データ処理系は目視では検出しにくく、本当にその挙動が正しいのか正確に判断できないことがあります。こういった処理はユニットテストでバグを検知するにはうってつけだと思います。 処理の重要度で優先付け データ処理関連はアニメーションなどの表現に関する処理に比べるとシビアなのでまずはテストすべきだと思います。どんなにすごいアニメーションで表現しても肝心の処理がうまく行ってなければ本末転倒です。 導入は簡単に、シンプルなものから始めてまずは文化づくりから ユニットテストを始めるときに、あんまりいろんなことを最初からやってはいけません。気持ちの問題ですが、最初からあれこれやり過ぎて導入、開始までで疲れてしまって挫折してしまうこともあるかと思います。まずは簡単な仕組みから始めてテストをかく習慣、文化を作ります。 実際に導入するテストツールはいろいろ検討しましたが、Javaで書かれたコードをユニットテストするのにもっともメジャーでシンプルなJUnitを採用しました。弊社ではAndroidStudioを使用しているので、実際かなり簡単に始めることが出来ました。 具体的な導入については次回以降のエントリーで紹介していきたいと思います。 という3つの理由からJUnitによるユニットテストを開始しました。 自分のコードは完璧じゃないと疑う ちゃんと動いていると信じていたメソッドも意外とまともに動いてない テストコードを書くとなると容赦ないパラメータをメソッドに投げるわけですが、変な値を投げると意外とうまく動いていないことがあります。 設計を見直す良いチャンス テストコードを書き始めると、「あれ?テスト書きにくいクラスがあるな」と思うことが出てきます。これはテストが書きにくいクラスなのではなく、設計があんまりよくないクラスの場合が多いと思います。ちょっとiQONであった実例を紹介します。 public void setJSON(JSONObject json) { try { if (!json.isNull("category")) { String category = json.getString("category"); if (2 < category.length()) { // 省略(categoryを適当に変更する処理) this.category = category; } else { // 省略(categoryを適当に変更する処理) this.category = category; } } else { // 省略 } // 省略(他のインスタンス変数に対する処理がこのあとも多数続く) } catch (JSONException e) { e.printStackTrace(); } } バックエンドのAPIから返ってきたJSONのレスポンスを上のようなメソッドに渡して、 インスタンス変数の値を設定する処理がありました。 このメソッドは300行近くに達し、とても見通しの良いコードではなかったです。本来ならsetterを実装してそこで値の検証をして、インスタンス変数に値を設定するのがいいと思います。 public void setJSON(JSONObject json) { try { if (!json.isNull("category")) { String category = json.getString("category"); setCategory(category) } else { // 省略 } // 省略(他のインスタンス変数に対する処理がこのあとも多数続く) } catch (JSONException e) { e.printStackTrace(); } } public void setCategory(String category) { try { if (2 < category.length()) { // 省略(categoryを適当に変更する処理) this.category = category; } else { // 省略(categoryを適当に変更する処理) this.category = category; } } catch (JSONException e) { e.printStackTrace(); } } このようすればsetCategoryメソッドでいろんな値を設定してインスタンス変数の変更に関するテストがかけるようになります。 ちょっと設計を改善すれば、テストが書けるようになります。逆にテストを書こうと思ったので設計の見直しができたと思います。(今回の例だともともと処理を切り分けたいと思っていた気持ちがより強くなりました) メリットを明確に なぜテストをやるのか?そのメリットを明確にしてやるべきだと思います。 私自身もテストを書くのに挫折したことがありましたが、挫折する理由の一つとしてメリットを納得できてなかったからだと感じています。 自分なりに納得したポイントをざっくり上げたいと思います。 1. コードの品質があがる 言わずもがな、テストをかけばその分コードの品質は上がります。これは保守するコストを下げるメリットがありますね。 2. テストを意識した、きれいな設計を保てる きれいな設計を保てるということは保守するコストもそれなりに下がっていきます。これもメリットですね。 3. テストが用意されているので思い切った開発ができるようになる テストが用意されているので、ちょっと処理の内容を変えてもテストを流せばおかしいところはすぐに検出できます。 この処理を変えたらあちこちに影響ないだろうか?と開発時に迷う気持ちを抑えられると思います。不安ならテストを流せばいいわけです。 あれこれ影響範囲を調べたりする開発時のコストを下げることもできそうです。これもメリットと言えるでしょう。 4. テストコードが仕様書になる どんな値を受け取って、どんな場合にエラーを返すか。みたいな仕様はテストコードを見れば一目瞭然なので、仕様書の代わりになります。ドキュメントとして細かい仕様をまとめるのも大事ですが、テストコードを代わりにしてみるといろいろ無駄が省けるかもしれません。 まとめ 現状分析&導入はシンプルに 現状のアプリの中でテストを書き始められる箇所がどこか見極める。大掛かりなしくみを最初からやろうとしないで小さなことから始めてみる。最初から飛ばし過ぎると導入の時点で疲弊して続きません。 自分のコードを疑う 自分が書いたコードは完璧じゃないと疑う。テストコードを書いてみて初めて気がつくことはよくあります。 メリットを明確に メリットを明確にして、きちんと納得して始める。 次回は実際の導入の紹介やTravisCIとの連携などを紹介していきたいと思います。 しばらくテスト関連のエントリーが続きますが、楽しみにして頂けたらと思います。 さいごに iQONではエンジニアを募集しています。一緒に世界を目指すAndroidアプリの開発をしませんか? 【Android】世界で勝ちたいAndroidアプリエンジニア募集 情報交換なども随時していきたいと思いますので勉強会などの開催、参加についても気軽に相談頂ければと思います。
iOSエンジニアの庄司です。 先月2月20日、『【第2回】iQONエンジニアセミナー ~進化し続けるiQONを支えるグロースハック的エンジニアリング手法とは?~』と題して、エンジニアセミナーを開催しました。 会場となった弊社オフィスにたくさんのエンジニアの方々に集まっていただきました。 当日は、弊社エンジニアが『グロースハック』をテーマに各プラットフォームがどのようにiQONのグロースハックに取り組んでいるかを発表しました。 当日の発表資料をSpeaker Deckにアップしたのでぜひ御覧ください。 グロースハックを支えるエンジニアリング CTO 今村 Androidファースト/より早く提供するための開発手法 Androidチーム (西村/村田) グロースハックさせるためのiOS開発手法 -ログ収集編- iOSチーム (荒井/庄司) iQONを支えるバックエンド バックエンドチーム (吉田/大貫) グロースハック的開発 最初の一歩 LT枠 (かとあつ) まとめ グロースハックにフォーカスしての各プラットフォームで発表しましたが、時間の都合上紹介できたのはグロースハックに関して取り組んでいることの一端にすぎません。 この他に取り組んでいることをどんどんこのブログで紹介していきたいと思います。 各資料の最後でも触れていますが、今回のセミナーや発表資料でiQON面白そう!と思っていただけた方をお待ちしております。 日本最大級のファッションサービスiQONをぶっちぎりにするエンジニア募集!
ウェブサービスに限らず、アプリの継続率を上げるためには離脱率や離脱ページの計測は重要です。 離脱率の高いページを知り、改善することでアプリの継続率やコンバージョン率の向上につなげることができます。 特に新規ユーザーの離脱ページを改善すると継続率への影響は大きいでしょう。 今回は、iOSアプリの離脱ページ計測について3点にわけて紹介します。 iOSアプリにおける離脱とは 最前面のUIViewの特定 最前面のViewController (離脱ページ) の特定 iOSアプリにおける離脱とは iOSアプリにける離脱とは、ホームボタンを押したり、かかってきた電話に出たりなど、そのアプリケーションの利用が終了することと同義です。 このタイミングは UIApplicationDelegate の applicationWillResignActive: というデリゲートメソッドで検知できます。 このタイミングで最終的に表示していたページ(=ViewController)を取得できればよいのですが、アプリケーションの実装によっては同時に複数のViewControllerが存在するため特定が困難です。 ここでは applicationWillResignActive: が呼ばれた時点で最前面にあるViewControllerを離脱ページとして計測すればよいでしょう。 最前面のViewControllerを取得するには、下記の2ステップです。 最前面のUIViewを特定 そのUIViewが属するUIViewControllerを特定 Google Analyticsなんかでもやってることでしょ? Google Analyticsでも画面ごとの離脱率を計測することができます。 ですが、今回は新規ユーザーについてのみ、どの画面で離脱したかを計測するために実施しました。 最前面のUIViewの特定 最前面のUIViewを取得するには UIWindow から始まるsubviewsツリーの最後のViewを再帰的にたどって行くことで最前面のUIViewが取得できます。 最終的に applicationWillResignActive: で取得するので、UIApplicationDelegateのクラスでメソッドを実装します。 アプリケーションの最前面のUIViewを取得する処理の実装例 @implementation MyAppDelegate - (UIView *)foregroundView { // UIWindowから始まるView階層を再帰的にたどる UIView *foregroundView = self .window; while ( 1 ) { UIView *tmpView = nil ; for (UIView *subview in foregroundView.subviews.reverseObjectEnumerator) { // 非表示のviewは除く if (!subview.hidden && subview.alpha > 0.f ) { tmpView = subview; break ; } } if (tmpView) { foregroundView = tmpView; } else { break ; } } return foregroundView; } @end 最前面のViewController (離脱ページ) の特定 さきほど取得した最前面のUIViewのレスポンダチェーンをたどって行くと、そのUIViewが属するUIViewControllerが取得できます。 UIResponderクラスのカテゴリのメソッドを実装します。 UIViewのレスポンダチェーンから自身が所属するUIViewControllerを取得する処理の実装例 @implementation UIResponder (Addition) - (UIViewController *)belongingViewController { UIResponder *responder = self ; while ( 1 ) { if (!responder) { return nil ; } else if ([responder isKindOfClass:[UIViewController class]]) { return (UIViewController *)responder; } else { responder = responder.nextResponder; } } } @end 最終的に最前面のUIViewControllerを取得して計測する処理は下記のようになります。 最前面のUIViewControllerを取得して計測する処理の実装例 @implementationMyAppDelegate - (UIViewController *)foregroundViewController { // 表示されている最前面のViewControllerを返す UIViewController *vc = self .foregroundView.belongingViewController; if ([vc isKindOfClass:[UINavigationController class]]) { // UINaviagtionControllerの場合はtopViewControllerを返す return ((UINavigationController *)vc).topViewController; } else { return vc; } } - ( void )applicationWillResignActive:(UIApplication *)application { // 会員登録から24時間以内のユーザーのみログを落とす if ([[NSDate date] timeIntervalSinceDate:USER.createTime] <= 60 * 60 * 24 ) { UIViewContrller *vc = self .foregroundViewController; // ロギング処理 } } @end 再帰処理をたくさんやってるけどパフォーマンスは? 計測処理が遅くてアプリケーションの使い勝手が悪くなるような事態は避けなければなりません。 今回は再帰処理を使っていますが、実機で確認してみたところ、1msecかからず返ってきました。 subviewsのツリーとレスポンダチェーンをたどるだけの処理なので、大した負荷はないようです。 まとめ 離脱率を計測するために、アプリケーション終了時に最前面のViewControllerを取得する処理を紹介しました。 レスポンダチェーンをたどることで、UIViewのサブクラスからView自身が所属するViewControllerを取得することもできますが、ViewがViewControllerの存在を意識する必要はないのでおすすめしません。 計測をすることはサービス改善の第一歩です。計測結果を解析してサービス改善に役立ててください。 最後に 今回の記事に物申す!という方はこちらまで↓ 【iOS】Appleも認めたiQONにさらに磨きをかけるエンジニア募集
近年O2O(Online to Offline)が販売促進のマーケティングなど様々な分野で脚光を浴びていますが、O2Oを絡めた機能をアプリで提供するために不可欠な要素として 位置情報サービス があります。 今回はAndroidアプリで位置情報サービスを効率よく使うための2つのTipsと実装例を紹介していきます。 1,『最新の位置情報サービスの罠』を対策しアンインストールを回避 2,最新機能『Google Play ServicesのLocation API』を使って効率UP Tips1:『最新の位置情報サービスの罠』を対策しアンインストールを回避 Android4.4(KitKat)から位置情報サービスの設定画面が変更されました。大きな変更は以下の2点になります。 高精度・バッテリー節約・GPSのみ の3つのモードから選択できるようになった 位置情報サービスを直近で利用したアプリが一覧表示されるようになった 特に後者の「アプリが一覧で表示される」変更に関しての対策は、今後の位置情報サービスを使うアプリ開発においては非常に重要な要素になってくると考えております。 実はこのアプリ一覧の各アプリの項目はタップすることができ、タップするとアプリ情報の詳細ページにIntentされる仕組みになってます。 ご存知の通り、このページに来るとアプリのアンインストールができてしまいます... 電池の減りの早さに悩んでいるときに「高い電池使用量」という文言を見かけ、アンインストールできるページにIntentしたら普通ならどうするでしょう? 位置情報サービスを使う際には 仕様にあわせて最適な選択をし、必要以上に位置情報サービスを使わない ということが今後は鉄則になってきます。 そうすることで アンインストールのリスクを回避 することができます。 iQONでの位置情報サービスを利用した事例 先日iQONでは、Androidで先行して天気コーデ機能をリリースしました。設定したエリアの天気予報と、天気予報にマッチしたコーデが見れる機能になっています。 当たり前な話ですが天気は地域によって全く異なってくるものです。そのためユーザーに自分が住んでいる場所を選択してもらう必要があります。 ただ、膨大な地域情報から自分が住んでいる地域を選択していく操作は手間がかかり、機能の利用率向上の足かせになります。 そこでiQONでは手動での位置情報設定に並行して、位置情報サービスを使った自動位置情報設定の機能を提供しました。位置情報の取得に関しては従来の仕組みである android.location.LocationManager android.location.LocationListener を使っています。 先ほども記載しましたが、位置情報サービスは 仕様にあわせて最適な選択をし、必要以上に位置情報サービスを使わない という鉄則が大事になってきます。 これを頭に入れた上で、以下の2つのポイントに気をつけて実装を行いました。 天気エリアは大まかな位置情報が取得できれば十分な機能を提供できるため精度は多少落ちても良い 一度位置情報が取得できれば機能に利用できるので位置情報を継続して取得し続ける必要はない public class WeatherSpotAutoSetActivity extends Activity implements LocationListener { LocationManager locationManager; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.weather_spot_auto_set); locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); String gpsStatus = android.provider.Settings.Secure.getString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED); if (gpsStatus.indexOf(LocationManager.NETWORK_PROVIDER) > 0) { // 位置情報の取得処理開始 // 大まかな位置情報が取得できれば要件を満たせるのでネットワークで取得する処理を走らせる(省電力) locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this); } else { // 位置情報サービスがOFFの場合は処理を終了 finish(); } } @Override protected void onDestroy() { locationManager.removeUpdates(this); super.onDestroy(); } @Override public void onProviderDisabled(String provider) { } @Override public void onProviderEnabled(String provider) { } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onLocationChanged(Location location) { String latitude = String.valueOf(location.getLatitude()); String longitude = String.valueOf(location.getLongitude()); // 【重要】緯度経度が1度でも取得できた時点で処理を終了 locationManager.removeUpdates(this); // 取得した緯度経度を使って処理を行う(処理の詳細は省略) } } iQONではネットワークからの取得に絞っているため、位置情報サービスの設定画面には「低い電池使用量」としか表示されません。 Tips2:最新機能『Google Play ServicesのLocation API』を使って効率UP 前項でiQONは現状 android.location.LocationManager android.location.LocationListener を利用して位置情報を取得していると紹介させていただきましたが実はこれは古い仕組みで、2014年3月現在では Google Play ServicesのLocation API を利用するのが最も新しい形になります。 昨年のGoogle I/Oで新しく発表された機能です。 OSのバージョンがAndroid2.2以上、「Google Play 開発者サービス」がユーザーの端末にインストールされている必要がありますが、リアルタイムで位置情報を取得しないといけないアプリに関してはLocation APIを使用した方が圧倒的に効率が良くなります。 iQONにおいても今後の展開を考えて、近日中にLocation APIに乗り換える予定です。 Location APIは従来の仕組みと比べていくつか優れた仕組みがありますが、その中でも実際に使ってみて一番良いと思った仕組みは Fused Location Provider というものになります。 従来の仕組みでは位置情報を取得する際には LocationManager.GPS_PROVIDER や LocationManager.NETWORK_PROVIDER と指定する必要がありました。 Criteriaクラスをオプション的に用いて精度や消費電力を指定して組み合わせる方法もありましたが正直使い勝手はあまり良くありませんでした。 Fused Location Provider は、従来の仕組みとCriteriaクラスが統合されたような仕組みになっていて、精度と消費電力のどちらを優先させるかを選択するだけでProviderの指定は行う必要がなくなりました。 利用シーン1:高精度でリアルタイムに位置情報を取得したときの実装例 public class TestActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener { /* * implementsするLocationListenerはcom.google.android.gms.locationのもの * 既存の仕組みから移行する場合にはこれに気をつけないとハマります */ private LocationClient mLocationClient; private LocationRequest mLocationRequest; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.test_activity); // Google Play Services が利用できるか確認 int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); if (ConnectionResult.SUCCESS == resultCode) { mLocationClient = new LocationClient(this, this, this); } else { // 従来の仕組みで代用するなりのプランを考える } } @Override protected void onStart() { super.onStart(); mLocationClient.connect(); } @Override protected void onStop() { mLocationClient.disconnect(); super.onStop(); } @Override public void onConnectionFailed(ConnectionResult connectionResult) { // 接続が失敗したときの処理はここに記載 finish(); } @Override public void onConnected(Bundle bundle) { mLocationRequest = LocationRequest.create(); mLocationRequest.setInterval(5000); // 5秒ごとに位置情報を取得 mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); // 高精度で取得 if (mLocationClient.isConnected()) { mLocationClient.requestLocationUpdates(mLocationRequest, this); } } @Override public void onDisconnected() { // 切断したときの処理はここに記載 if (mLocationClient.isConnected()) { mLocationClient.removeLocationUpdates(this); } } @Override public void onLocationChanged(Location location) { String latitude = String.valueOf(location.getLatitude()); String longitude = String.valueOf(location.getLongitude()); // 取得したLat,Lonを使って処理を行う(詳細の処理は省略) } } } 利用シーン2:ある程度の精度で常時位置情報を取得したいときの実装例 public class TestActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener { ... /* 他の箇所は利用シーン1と同様のため省略 */ @Override public void onConnected(Bundle bundle) { mLocationRequest = LocationRequest.create(); mLocationRequest.setInterval(3600000); // 1時間ごとに位置情報を取得 // setIntervalはあくまでも目安のため、状況によって間隔が変わる // そのため長時間取得取得する場合はsetFastestIntervalも設定する mLocationRequest.setFastestInterval(300000); // 取得の頻度は最低でも5分は空ける mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); // 精度と消費電力のバランス取って取得 if (mLocationClient.isConnected()) { mLocationClient.requestLocationUpdates(mLocationRequest, this); } } ... } 利用シーン3:大まかな位置情報を1度だけ取得したい場合の実装例 public class TestActivity extends Activity implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener { ... /* 他の箇所は利用シーン1と同様のため省略 */ @Override public void onConnected(Bundle bundle) { mLocationRequest = LocationRequest.create(); mLocationRequest.setPriority(LocationRequest.PRIORITY_NO_POWER); // 電力を使わない範囲で取得 // PRIORITY_NO_POWER よりも精度が高い PRIORITY_LOW_POWER でもテストをしてどちらを使うか決める if (mLocationClient.isConnected()) { mLocationClient.requestLocationUpdates(mLocationRequest, this); } } @Override public void onLocationChanged(Location location) { String latitude = String.valueOf(location.getLatitude()); String longitude = String.valueOf(location.getLongitude()); // 取得できた時点で処理を終了させる if (mLocationClient.isConnected()) { mLocationClient.removeLocationUpdates(this); } // 取得したLat,Lonを使って処理を行う(詳細の処理は省略) } ... } パラメータの値は実装する機能にあわせて細かくテストして最適な形にする。 まとめ 位置情報サービスは非常に便利ですが、今後は利用するアプリは一覧表示されて晒されることを理解した上で利用してください。 そのため 仕様にあわせて最適な選択をし、必要以上に位置情報サービスを使わない ことを徹底しないとアンインストールのリスクに繋がります。 また位置情報取得は従来の仕組みでもいいですが、 Google Play ServicesのLocation API はより細かい設定ができ使いやすいのでオススメです。 さいごに 日々成長している 日本最大級ファッションサービスiQON を一緒に成長させてくれるエンジニアを絶賛募集しております。 我こそはという方お待ちしております。 【Android】世界で勝ちたいAndroidアプリエンジニア募集 日本最大級のファッションサービスiQONをぶっちぎりにするエンジニア募集!
バックエンドエンジニアのBoBです。 今回はiOSプッシュを最適化するためには必要不可欠な、Apple Push Notification service(以下APNs)のFeedbackサービスについて紹介したいと思います。 はじめに iPhoneやAndroidにはプッシュ通知という仕組みがあることは皆さんもよくご存知かと思いますが、より洗練された、効果的なプッシュ通知を送るために自分たちのプロダクトが送っているプッシュ通知を分析する事はとても重要な事です。 今回はiPhoneのFeedbackサービスを利用して、プッシュ通知を送れていないユーザーを把握する事に関して 1. プッシュ通知の意義 2. Feedbackサービスの説明 という2点から紹介しようと思います。 プッシュ通知の意義 iPhoneやAndroidのプッシュ通知は、ユーザーのRetention(再訪率)を高める効果があります。 弊社グロースハックブログの 広告費0円でもDAU10倍!? ユーザーRetention(再訪率)を最大化する施策10選 の記事にも、Retentionを上げる意義やそのためのプッシュ通知の必要性などが書いてあるのでぜひ参考にしてください。 しかし、ただ闇雲にプッシュ通知をユーザーに送っていてもプロダクトのRetentionを高める事にはつながりません。 プッシュ通知を最適化するためには、実際にプッシュ通知の様々な部分を日々工夫し、その結果どのようなプッシュ通知がユーザーのRetentionを高める効果があるかを分析しなければいけません。 その分析を行うためには様々な数値を正確に知る必要があります。 プッシュ通知改善の為に日々変更を加える部分は大きく分けて以下の2点があるかと思います。 ・タイミング(プッシュ通知を送る時間) ・内容/見た目 これらを変更した際の効果を測定するためには以下のような数値を知る必要があります。 ・ 何人のユーザー(何個の端末)を対象としたプッシュ通知なのか ・ 実際には何人のユーザーに送信されているのか ・ 何人のユーザーがプッシュ通知からアプリを起動したか APNsのFeedbackサービスでは、 「実際にユーザーに届ける事ができなかったプッシュ通知の情報」 を取得することができます。 つまり、上記の例で言うと二つ目にある「実際に何人のユーザーに送信されているか」というデータを知るために必要不可欠な仕組みとなっています。 Feedbackサービスとは? APNsにはFeedbackサービスという、正常に処理できなかったプッシュ通知に関する情報を返す仕組みがあります。 Feedbackサービスに接続したときに得られる情報は、前回Feedbackサービスの情報を取得した以降、配送に失敗した通知に関するものだけで、Feedbackサービスが保持しているリストは読み取り後クリアされます。 Feedbackサービスの導入方法 Feedbackサービスはプッシュ通知の仕組みを実装していれば非常に簡単に導入でき、使い方次第でサービスのグロースに絶大な効果を上げる事ができます。 1. 各種設定 Feedbackサービスを利用する際は以下のサーバー、ポートにSSL接続します。 key, certの設定はプッシュ通知を送る際と同じpemファイルを設定します。 [ruby] require 'socket' require 'openssl' # 開発環境 apns-dev-key-noenc.pem, apns-dev.pem # 本番環境 apns-prd-key-noenc.pem, pns-prd.pem context = OpenSSL::SSL::SSLContext.new('SSLv3') context.key = OpenSSL::PKey::RSA.new(File.read("apns-prd-key-noenc.pem")) # プッシュ通知を送る処理と同じpemファイル context.cert = OpenSSL::X509::Certificate.new(File.read("pns-prd.pem")) # プッシュ通知を送る処理と同じpemファイル [/ruby] 2. 結果取得処理 ssl通信で結果を取得します。 [ruby] # 開発環境: feedback.sandbox.push.apple.com # 本番環境: feedback.push.apple.com sock = TCPSocket.new('feedback.sandbox.push.apple.com', 2196) # Feedbackサービスのポートは2196で固定 ssl = OpenSSL::SSL::SSLSocket.new(sock, context) ssl.sync = true ssl.connect while line = ssl.read(38) # SSLソケットから38バイト取得する # feedbackで取得したデータを用いた処理をここで実装する p line.unpack('N1n1H140') end ssl.close sock.close [/ruby] 3. レスポンス 上記の結果は以下のような形で出力されます。 [ruby] [1392300474, 32, "#プッシュ対象のdevice id"] [1392303094, 32, "#プッシュ対象のdevice id"] [1392295196, 32, "#プッシュ対象のdevice id"] [1392301807, 32, "#プッシュ対象のdevice id"] ........ [/ruby] Feedbackサービスから取得できる情報で利用できるものはプッシュ通知対象のdevice idのみですが、この各レスポンスからどのユーザーのプッシュ通知かを判断し、分析をかける事ができま す。 まとめ 今回APNsのFeedbackサービスによる送信失敗結果の取得方法を紹介しました。しかしここで説明した内容を実装しただけではサービスのグロースには何もつながりません。 ここで取得したデータをいかにうまく使って分析していくかが重要であり、今回紹介した内容はプッシュ通知最適化の入り口でしかないのです。 現にVASILYではFeedbackサービスで取得したデータ以外にも様々なログを用いてユーザーに送るプッシュ通知を分析し、より効果的なプッシュ通知を目指して日々改善しています。 最後になりますが、VASILYでは現在エンジニアを大募集しています! 直近ですとiQONを支えているアグレッシブな技術がどのようなものか紹介する勉強会や、会社での飲み会が予定されています。 【第2回】iQONエンジニアセミナー ~進化し続けるiQONを支えるグロースハック的エンジニアリング手法とは?~ 【2/21】「iQON」急成長を支えるエンジニアと話したい人、WANTED VASILY/iQONに少しでも興味がある方はぜひご参加ください!
理系的素養は有るけれどもウェブ経験が全く無い学生インターンが、9日間で立派なウェブ系エンジニア になったので、そのポイントをまとめました! ざっくり概要 Getting Started with Rails をやる ユーザに届ける体験をする Pull Request のやりとりをする SQLをいじる ウェブで使うミドルウェアとインフラを知る JSFIDDLE を触る ウェブ業界について知る そしたら取り敢えずウェブ系エンジニアとして仕事ができます! インターンで来たのはこんな人 ウェブ系の採用イベントに参加した際に、多くの方が「Twitterの分析をしています!」とか「SNSの実装をしています!」とか「検索で使えるアルゴリズムの研究をしています!」と、ウェブ系のアピールをされている中、ただ一人ウェブとは関係ない、超目立つロボットを持ってきている方がいました。 激しく動き、歌い、光るロボット。 話を聞くと、「ウェブやりたい!でもウェブ良くわからないから作れるもの持ってきた!プログラムは大好き!ファイルシステムくらいなら自分で実装できる!ウェブやりたい!」 ってことだったので、東北と遠方の方ではあったのですが、インターンで2週間だけ来て頂きました。 やった事 インターンまでの宿題 Getting Started with Rails をやる heroku でアカウント作ってデプロイする ウェブの勉強するのにおすすめの書籍は何か?みたいな話になった時に、取り敢えず手を動かすのを優先して欲しかったのと、作った物を自分一人ででも世に出す方法を知って欲しかったので、上記二つを私からの宿題にしました。 初デプロイ(初日) Virtual Box で開発環境構築 Github 開設 Railsで簡単なサイトの修正 ( The NERD Tree 使ってもらった) Capistrano でデプロイ 色々な説明は端折りながらも、スピード優先で実装からデプロイまでを経験してもらいました。内容は簡単なリンクURLの差し替えです。 最初のデプロイ時は手が震え、家に帰ってからは嬉しくてその箇所を何度も見直したそうです。 基本的な開発からデプロイまでの確認(2日間) MVCについてとRailsのMVCについて説明 どんな意図でどのファイルを修正するかシェア RailsでAPIの実装 Pull Request やり取り RSpec でテスト書く 最初に実装からデプロイまでの流れを通しで経験している(=デプロイの怖さ等も理解している)状態だと、Pull RequestやRSpecの必要性やMVCについて、言葉上の理解ではなく体感として理解してもらえたと思います。 バックエンド/インフラの理解(3日間) AWS, MongoDB, Redis, MySQL,memcached の概要と、iQONで何を担っているかシェア MySQLのクエリ最適化 をひたすらやる 障害対応見学 バックエンドとインフラについては、ヨッシーさんに見てもらいました。ハーコーな方なので、私一人からは教われない物を色々学んだはずです。 障害は予期していなかったものですが、彼にとっては幸運だったと思います。普段はチャットでコミュニケーションしつつ各々のペースで開発しているメンバーが、高い緊張感の中でノートPCを寄せ合って密に連携をとりながら各プラットフォーム対応していく状況でした。そこから感じ取るものは有ったと思います。 フロントの実装(3日間) JSFIDDLE 触る HTML書く( zen-coding 使ってもらった) CSS書く スマホ/PCブラウザ対応する JavaScript書く(Chromeの開発者ツール使ってもらった) JSFIDDLE はHTML/CSS/JavaScriptが書けて、メジャーなライブラリのインクルードも簡単に出来るサービスです。気軽に試せるサンドボックスで、初学者にとっては学習速度が必ず上がるものです。 彼の自前のherokuのプロジェクトにGoogle AnalyticsとAdsenseを入れてもらいました。インターン期間中には教えられなかった、計測と改善の楽しさを自分なりに体験して欲しいです。 他 tmuxで画面共有 vimの変な癖があったら治すため、vimlogとった(けどあまり使わなかった) ウェブ業界について、今イケてる(と我々が感じている)サービスとか、IPOとか、元気なベンチャーとか、大企業のウェブについてとかを、みんなで好き勝手教える 取り敢えずfacebookのアカウント作らせる 結果 どれくらいに到達したかを表にしました。レベルは今まで見てきた複数の職場で流通していたチケット(多分難易度はウェブ系では一般的)の内、こなせる率はどれくらいかを示しています。 領域 レベル 対応可能なケース NGそうなケース HTML CSS 40% HTML5でのvalidなマークアップはできる 既存コードを参考にした要素の追加削除とかも出来る 細かいデザイン等はキツい IEががががが。。。 JavaScript 60% 一般的な物はいける 複数の非同期通信が絡むようなのは楽しそうにやっていた CSSのデザインが絡むようなのはキツい Ruby on Rails 60% 一般的な物はいける MongoDBとか、何らかのミドルウェアが絡むとキツい 急ぎ案件はキツい 元は言わずもがな全て0%。9日間でここまで出来るようになるとは思っていなかったので、教えていて非常に楽しかったです。 彼自身の地頭や根性やバックグラウンドもあったとは思いますし、英語が出来ないと宿題の時点で詰んだりする訳ですが、やはり「ウェブをやりたい!」という熱い気持ちが成長を後押ししていたように見えました。 ざっくり概要(再度) Getting Started with Rails をやる ユーザに届ける体験をする Pull Request のやりとりをする SQLをいじる ウェブで使うミドルウェアとインフラを知る JSFIDDLE を触る ウェブ業界について知る そしたら取り敢えずウェブ系エンジニアとして仕事ができます! とは言え、当然まだまだまだまだ覚える事は沢山あるので、あくまでスタート地点に立ったというイメージです。 最後に 弊社は大企業でも官公庁でもないので、それらがエンジニアに与えてくれる物の多くは弊社では得られません(特に今は)。 ただし、「成長」の一点はどこよりも得られます(特に今は!)。 人生変わる程の成長がしたい!と思ったら、是非是非 VASILYサマーインターン へ! (遠方の方でも、旅費・宿泊費は会社で負担しています!)
iOSエンジニアの荒井です。 今回はXcodeプロジェクトのライブラリ依存関係を簡単に管理出来る” CocoaPods ”の紹介をします。 未導入の方はオープンソースの管理が劇的に変わるので是非導入してみてください。 はじめに 最近iOSの勉強会などに参加すると、CocoaPodsを導入していることが前提で話が進む事が多くなりました。また、iOSエンジニアと話す際も「CocoaPodsで管理していますか?」という質問を頂きます。 導入していないことによって不便をきたすことがないようにしたいですね。 もちろん、単に時代の流れの面でだけでなく、メリットの部分が非常に多いと感じています。 今回のエントリでは 1. CocoaPodsのメリット 2. CocoaPodsの導入手順 に焦点を当てて紹介していこうと思います。 Cocoa Podsの導入メリット 冒頭にも書きましたが、CocoaPodsは「 Xcodeプロジェクトのライブラリ依存関係を簡単に管理出来るツール 」です。 iOSの開発をはじめて、オープンソースの利用をする時、GitHubなどからソースコードを持ってきて プロジェクトに入れてという作業を行うと思います。 これは非常に手間であり、特にRubyGemsやyumを使用した経験がある方からすると 「もっと簡単に管理できないか」と考えると思います。 CocoaPodsはこの問題を解決するアプローチの一つであり、コマンドを実行する事によってこれらの 問題を簡単に解決してくれます。 CocoaPodsの導入 CocoaPodsの導入は非常に簡単です。 いくつかのコマンドを実行するだけでインストールが完了します。 では早速流れを見てみましょう。 1. CocoaPodsのgemインストール $ sudo gem install cocoapods ※ CocoaPodsはRubyのgemとして提供されているのでruby環境が必要です。 2. セットアップ 次に~/.cocoapods の作成を行います。CocoaPodsがライブラリ管理を行うディレクトリです。 $ pod setup 3. Podfileの設定 hoge.xcodeprojが存在するディレクトリにPodfileを作成します。 今回はiQONのPodfileをサンプルとして記載します。 iQONではAFNetworkingやソーシャル連携(Facebook)のテストを実施しました。 [ruby] platform :ios, '6.0' #プラットフォームの指定 iOS6.0以上 xcodeproj './iQON.xcodeproj' pod 'AFNetworking', '~> 2.0' #2.x以下のAFNetworkingライブラリを使用 pod 'AFNetworkActivityLogger', '~> 2.0' pod 'Facebook-iOS-SDK', '~> 3.0' [/ruby] CocoaPodsで導入出来るライブラリについてはこちらで検索をすると便利です。 http://cocoapods.org/ 4. インストール $ pod install 5. ライブラリの確認 Xcodeを一旦閉じてライブラリの確認を行います。この際、Xcodeでxcworkspaceを開きます。 上記のようにライブラリが確認出来れば完了です。 通常通りimportして使いましょう。 #import "Facebook.h" まとめ VASILYのiOSエンジニアは元々rubyを使っていたので、rubyのbundler感覚で使えるCocoaPodsの導入は全く抵抗がありませんでしたが、ライブラリ管理ツールの経験が無い方でも簡単に導入出来ると思います。 まだCocoaPodsを導入していない方は、ぜひこの機会に導入を行い、快適なオープンソースライフを過して頂ければと思います。 最後になりますが、VASILYではエンジニアを募集しています。 【2/21】「iQON」急成長を支えるエンジニアと話したい人、WANTED エンジニアセミナーも実施が決まったので、皆様ふるってご参加ください。 【第2回】iQONエンジニアセミナー ~進化し続けるiQONを支えるグロースハック的エンジニアリング手法とは?~
どうも。バックエンドエンジニアの吉田です。 前回は1サイトをクロールする際の最適化戦略としてRedisベースの分散ロック機構を使った実例を紹介しました。 前回の記事:Redis::DistMutex – 時限付き分散ロックで効率良くサイトクロールをしよう 今回は複数サイトに対する処理をResqueを使って最適化した事例を紹介したいと思います。 ※ランダムにキューをlistenする話の予定でしたが、話がとっ散らかるので主題を変更しました。 主なキーワードとしては、「Resqueのキュー分割」、「Rubyでクラス定義を動的生成」といった感じです。 おさらい 前回使った図を使います。 iQONのクローラーは、提携サイトの商品一覧から商品ページのURLを取得し、ページをダウンロードする処理(fetchフェーズ)を必要な数だけWorkerプロセスとして起動しておき、Resqueを使って処理をしています。ダウンロードが終わったら順次解析する処理(processフェーズ)にResque経由で処理を引き継ぎます。これはクローラーによくある設計です。 今回のお題は、このダウンロード処理を複数サイトに対して並列に良い感じに処理させるための最適化事例とその実装例です。 キューの分割 このような設計にした場合、ページのダウンロード処理は複数のWorkerに分散されますが、複数サイトを同時にクロールした場合、enqueueされるURLの順序は予測できません。 このダウンロード処理用のキューが1つしかないと、キューは順番にdequeueされるので1サイトのURLが連続する可能性があります。1サイトに対するHTTPリクエストは時限付きMutexによって処理スピードが制限されるため、他ドメインの処理がブロックされてしまいます。 サイトごとにキューを用意すれば、キューの順序にかかわらず1サイトの処理が他サイトの処理をブロックすることもありません。 キューの状態を図にするとこんな感じです。 ただし、Resqueの場合はキューの指定をクラス変数によって定義する前提であるため、クロール対象数だけその定義を用意しなくてはなりません。dequeして得られたURLをダウンロードする処理はサイトに依らず共通であるのに、クラス定義を複数用意するのは非効率ですし、Workerの起動もサイト数分指定しなくてはいけません。 問題の解決策として、動的にクラス定義を生成する手法を採用しました。 動的にWorkerクラスを生成する ダウンロード処理をするクラステンプレートを用意して、それを設定ファイルに定義されたサイトのリストをもとに複数のクラス定義を動的生成します。 Workerを起動するときは定義されたサイトIDから全部のクラス定義を生成すればよく、enqueするときも同様の戦略で問題解決できます。 実際のコードを見たほうが理解しやすいでしょう。 iQONではサイトをdomainと読んでいるため、コードもそれに倣います。 クラス設計概観 実際のクラステンプレートは以下のように実装しています。 サイト別定義を動的生成するための抽象クラス定義 module Crawler :: Workers class DomainSpecificWorker def self . domain_id= (domain_id) name = "#{ instance_variable_get( :@queue ) } - #{ domain_id }" instance_variable_set( :@queue , name.to_sym) instance_variable_set( :@domain_id , domain_id) end def self . domainify (domain_id) klass_name = "#{ name.split( ' :: ' ).last } _ #{ domain_id }" unless Crawler .const_defined? klass_name Crawler .const_set(klass_name.to_sym, clone) klass = Crawler .const_get(klass_name.to_sym) klass.domain_id = domain_id end Crawler .const_get(klass_name.to_sym) end end end ページをダウンロードするWorkerクラスの定義 module Crawler :: Workers class FetchPageWorker < DomainSpecificWorker @queue = :fetch_page def self . perform (params) # 実際のダウンロード処理は別クラスに定義して、それを呼び出すだけ end end ※今見ると、DomainSpecificWorkerはモジュール化してMix-inしたほうがRubyらしい感じもしますね… Before(静的にクラス定義を用意する場合) enqueする時のコード例 args = { domain_id : 1 , url : ' http://... ' } Resque .enqueue( FetchPageWorker1 , args) Workerの起動スクリプト domain_ids = config.get( :domain_ids ) # ドメインごとのクラス定義を読み出し queues = domain_ids.map { | domain_id | Crawler :: Workers .const_get( " FetchPageWorker #{ domain_id }" ) } # ランダムに並び替えた優先順でワーカーを起動 worker = Resque :: Worker .new(*queues.shuffle) worker.work After(動的にクラス定義を用意する場合) enqueする時のコード例 args = { domain_id : 1 , url : ' http://... ' } Resque .enqueue( FetchPageWorker .domainify(domain_id), args) Workerの起動スクリプト domain_ids = config.get( :domain_ids ) # ドメインごとのクラス定義を動的生成 queues = domain_ids.map { | domain_id | FetchPageWorker .domainify(domain_id) } # ランダムに並び替えた優先順でワーカーを起動 worker = Resque :: Worker .new(*queues.shuffle) worker.work このようにWorker.domainify(domain_id)をコールすると、そのサイト固有のWorkerクラス定義を生成できるので、コードもシンプルに保つことができます。 さらにWorkerの起動スクリプト中で'queues.shuffle'することで、スクリプト実行の度に毎回優先順位の異なるプロセスが起動され、複数サイトの処理ももっとバランスよく並列に処理することができます。 まとめ サイトごとのキューを用意することでクローラー全体として並列度をキープ&処理効率の最適化ができます。さらに、ResqueのWorkerクラス定義を動的生成することで、実処理が共通なクラス定義を複数用意するという実装コスト・管理コストを下げ、コードの簡潔性も保つことができました。 前回はiQONのサービス規模も交えながらの事例紹介でしたが、今回はRubyやResqueの活用方法にフォーカスした事例紹介をしてみました。 ちなみに、VASILYではエンジニア向けのセミナーを近日中に開催を予定しています。。 VASILYというスタートアップがどういう会社なのか、どんなサービスをつくっているのか、技術的にどんな事に取り組んでいるのかということをお話する予定です。 日程・内容が確定しだいお知らせしますので、興味のある方はぜひご参加ください。
はじめまして。バックエンドエンジニアの 吉田 です。 2013年5月末の入社以降、大量のEC2インスタンスのVPC移行を担当した後、今はiQONの商品DBを支えるクローラーの改善に取り組んでいます。今回はその改善の1つとして開発したRedis::DistMutexという分散ロック機構のruby実装を紹介をしようと思います。 Redis::DistMutex 開発の経緯や細かい設計の話は後述するとして、まずはつくったgemの紹介をします。 Redis::DistMutex Redisベースの分散ロック機構 rubyのライブラリにある Mutex 互換 スレッド間だけでなく、プロセス間・ホスト間でも共有できるMutex 時限つきロックの作成が可能(redisのsetnxとexpireを活用) namespaceを指定できるので、特定の処理ごとにロックの作成が可能 redis2.6以上のみサポート(1秒以下のexpireの指定が可能な pexpire 依存するため) サンプルコード sample.rb require ' redis ' require ' redis-dist-mutex ' Redis :: DistMutex .redis = Redis .new mutex = Redis :: DistMutex .new( :test_app , expire : 1 , auto_release : false ) mutex.synchronize { puts ' started ' ; sleep rand( 5 ) } これを5つ以上の複数スレッドや複数プロセスで同時実行すると、'Kernel.sleep(n)'の長さに影響されることなく全体として一定間隔でsyncrhonizeに渡されたブロック内の処理が実行されます。 複数スレッドから使うサンプル スレッドごとにsynchronize内でランダムにKernel.sleepを実行 syncrhonizeに渡すブロック内でRedisにIDと現在時刻を記録 test_mutex.rb require ' redis ' require ' redis ' require ' redis-dist-mutex ' class TestMutex def initialize @redis = Redis .new Redis :: DistMutex .redis = @redis @mutex = Redis :: DistMutex .new :test_app , expire : 1 , autorelease : false end def create_thread (id) Thread .new do now = -&gt; { sprintf( ' %.1f ' , Time .now.to_f) } @redis .lpush( ' hoge_test:start ' , &quot; #{id}:#{now.call}&quot;) @mutex .synchronize { @redis .lpush( ' hoge_test:end ' , &quot; #{id}:#{now.call}&quot;); sleep 2 + rand } end end def start puts ' - ' * 40 @redis .del( ' hoge_test:start ' ) @redis .del( ' hoge_test:end ' ) 5 .times.map { | id | create_thread(id) }.each(&amp; :join ) puts &quot; Start : #{@redis.lrange('hoge_test:start', 0, -1)}&quot; puts &quot; End : #{@redis.lrange('hoge_test:end', 0, -1)}&quot; end end if $0 == __FILE__ test = TestMutex .new 3 .times.each { | i | test.start } end 実行してみると、スレッドのIDは実行順とは無関係に記録されていて、それぞれ約1秒おき記録されています。 $ bundle exec ruby ./test_mutex.rb ---------------------------------------- Start: [ "0:1385368596.6" , "1:1385368596.6" , "2:1385368596.6" , "4:1385368596.6" , "3:1385368596.6" ] End : [ "0:1385368600.6" , "4:1385368599.6" , "1:1385368598.6" , "2:1385368597.6" , "3:1385368596.6" ] ---------------------------------------- Start: [ "0:1385368605.0" , "1:1385368605.0" , "2:1385368605.0" , "4:1385368605.0" , "3:1385368605.0" ] End : [ "4:1385368609.0" , "0:1385368608.0" , "1:1385368607.0" , "2:1385368606.0" , "3:1385368605.0" ] ---------------------------------------- Start: [ "0:1385368613.4" , "1:1385368613.4" , "4:1385368613.4" , "3:1385368613.4" , "2:1385368613.4" ] End : [ "3:1385368617.4" , "0:1385368616.4" , "1:1385368615.4" , "4:1385368614.4" , "2:1385368613.4" ] 実行時に別のターミナルで'redis-cli monitor|grep expire'を実行しておくと、1秒おきにロックが取得されるのがよくわかると思います。 initialize時のオプション 'expire: n'を設定しないとブロックの実行が完了次第、次の処理に移る rubyのMutexと同じ動作 'autorelease'はデフォルトtrueで、'false'を設定しない限り、処理が同期的になる 'true'だとsyncrhonize終了時に必ずロックを開放 今回の要件では、'expire: 1, autorelease: false'を指定 そうすることで、ロック取得から1秒後に必ずロックが開放される サイトクロール時の問題点 iQON掲載商品数 200万件以上 iOONでは大量の商品データを保有しているのですが、それらは提携しているECサイトをクロールしてDBに取り込んでいます。さらに、いったん貯めたアイテムの在庫情報も定期的に再クロールして更新しているので、相当数の商品ページを効率的にクロールする仕組みが必要になります。 クローラー最大のボトルネックはネットワークIO クローラーの処理は、大きく"ダウンロード"と"解析"の2つに分けられます。 ページの解析については、サーバーの性能やコードの見直しで高速化が容易です。一方、ページのダウンロードについては外部サイトの性能に依存するため、効率化が難しくなります。これを効率的に行う設計が必要になります。 既存のクローラーはサイトの性能にかかわらず直列でダウンロードして、一定時間sleepしていました。そのように素直に直列でダウンロードした場合、レスポンスタイムに依存してリクエスト間隔がばらばらになります。1ページ5000msかかると1000ページで5000秒(83分20秒)かかる計算です。逆に、200msで返してくれるサイトの場合は1000ページを200秒(3分20秒)で処理できますが、5req/secの負荷がかかります。 このようなサイトごとのレスポンス性能の差異に関係なく一定間隔でページをリクエストできれば、全体としてクロール効率を向上させ、対象サイトへの負荷も軽減することができます。 今回の新クローラー開発では、そのような問題にも取り組みました。 Resqueによるダウンロード処理の並列化 今回開発したクローラーは、起点となるページから抽出した商品詳細ページのURLをResqueにenqueueし、workerはそのURLのページをダウンロードしてDBに保存し、ページ解析用のworkerに処理を引き継ぎます。この時、worker数を増やせばそれだけ並列度を上げて効率よくダウンロードできるのですが、前述した通り、増やしすぎると対象サイトに負荷をかけることになります。 また、何らかの障害によってworkerがdequeueしていなかった場合、ダウンロードキューが大量に蓄積されます。障害から復旧した後でworkerを起動すると、蓄積されたキューが一気に処理されるため、worker数だけ同時にHTTPリクエストする状態が一定時間継続することになります。これはクロール対象サイト対してDoS攻撃しているようなものです。 そこで、このクロール頻度の制御に有効な手段として、時限付き分散ロック(redis-dist-mutex)を導入しました。 時限付き分散ロック Mutex(=Binary Semaphore) Rubyにも同梱されている"Mutex"は、 wikipedia ではこう説明されています。 クリティカルセクションでアトミック性を確保するための同期機構の一種である。 つまり、複数スレッドやプロセス間の排他制御に使用するロック機構の一種であり、ロックを取得したものだけが処理をすすめられ、取得できなければ開放されるまで待つことになります。 ただし、今回の要件では厳密な排他制御は必要なく、全体として一定間隔での実行を保証できれば十分です。ロック取得から一定以上の時間が経過したらそれ以上の排他制御は必要ありません。 そのような仕組みがあることによって、各worker内のHTTPリクエスト開始のタイミングのみの制御が可能になります。(※スケジューラーに近いイメージですが、スレッドやプロセス同士での協調動作となる点でスケジューラーとは異なります。) このように時限付き分散ロックを用意しておけば、複数のResqueWorkerから特定のサイトHTTPリクエストが集中することを防止できるようになります。例えば1リクエストに3秒かかるサイトに対しては3つのworkerが起動していれば、1秒おきにHTTPリクエストを発生させることができます。仮に1秒間隔でリクエストすることが条件ならば、起動しておくべきworker数は以下の式で算出できます。 worker数 >= 平均レスポンスタイム(秒) + α ちなみに、iQONのクローラーのざっくりした構成は以下の図のようになっています。 実際にはiQONのクローラーは複数サイトをクロールするので、サイトごとにqueueとmutexを用意して、複数のworkerから全サイトに対して効率よく処理されるように設計を工夫しています。各workerはそれら複数のダウンロードキューをランダムな優先順位でlistenすれば、全体のバランスがとれます。このあたりの設計の話については別の機会に紹介したいと思います。 以上、 Redis::DistMutex と、それを使ったクローラー事例の紹介でした。 最後に 今回紹介したものはiQONのクローラーのほんの一部分であり、iQONというサービスを支えるためのサーバーサイド技術は多岐にわたります。クローラーにかかわらずiQONを支えるサーバーサイド技術に興味のある方はぜひ恵比寿にあるオフィスに直接遊びにきてください。VASILYでは現在、一緒に働いてくれるエンジニアを大募集しています。 募集要項 連絡先:info[at]vasily.jp
はじめまして、VASILYデザイナーのこんです。 今までは「Tech Blog」としてエンジニア陣で技術的な発信をしてきていたのですが、 デザイン的な発信もしていける場所を設けたいということになり、 「Developers Blog」と改名し、わたくしめが紅一点()として加わることになりました。 今回の記事はデザイナーとしての簡単な紹介となりますが、 これから有意義な情報をお届けできるようにしますので、 よろしくお願いします! 先週の話になりますが、11/20にアプリやWebサービスのデザイナーを対象にした Designers meetup Vol.2というイベントに参加してきました。 VASILYのデザイナーは現在 常駐私1人と、アルバイト3人で回していて、 普段は、社内の人間としか話さないため、 他社のデザイナーさんと赤裸々な話で盛り上がったり、 自社サービスをやってるデザイナーだからこその話もたくさんできたので、 情報共有としてもとても刺激的で楽しいひとときでした。 そんな中、私も「iQONデザインリニューアルのポイント」というテーマで 今回のiOSアプリリニューアルのお話を発表させていただきましたので、 そちらのスライドを公開したいと思います。 iQON デザインリニューアルのポイント from Kwon Miae 前の記事で、エンジニアの庄司さんが書いてた内容 と少々かぶりますが、 実際のデザイン時にどうゆう意図があって構成や表現を考えたのか、 リニューアル時に行った作業はどんなものかといったことなどを LTだったので5分という短い時間でしたが精一杯発表してきました。 あまり人前に立つこともないし、喋るのは特に苦手意識を持っていたのですが、 「このタイミングでiQONのデザインリニューアルを是非とも伝えたい、自信を持って発表してみたい!」と勇気をだして今回の発表に立候補して本当によかったです。 今まで、デザインのセミナーや勉強会には、目につけば出来る限り参加してきましたが、 発表する側での参加の方がとても有意義なものになるなぁと実感しました。 もちろん、参加者としても得られるものは多いのですが、 他の人はどんな内容を発表してどんな伝え方をしてるのかを強烈に意識して聞くようになり、 懇親会でも”さっき話してた人”で認識してもらえるので、 ただの名刺交換だけでなく、プレゼン内容に対する質問から会話も盛り上がって、 より繋がりが産まれる場となったと思います。 VASILYでデザイナーとして働き始めてもうすぐ2年で、 グラフィック上がりの私は、初期はバナーやLPくらいしか作れなかったのですが、 今では、PC、iOS、Android、スマホページ、タイアップ企画のビジュアル全般等、様々なデザインを担当させてもらえるようになりました。 まだまだ未熟なところだらけですが、そんな私だからこその情報を発信していくこときっと誰かの役に立つのではと願いつつ、一緒にデザインしてくれる仲間を増やしていくためにも、今後もブログ更新していきます。 スライドでも書いてましたが、VASILYではデザイナー絶賛大大大募集中なので、 自社サービスもクライアントワークな仕事もやりたいという欲しがり屋さんデザイナーの方々、 心よりお待ちしてます! VASILYリクルートページ 連絡先:info[at]vasily.jp
はじめまして!2013年7月にVASILYにJOINした西村と申します。VASILYでは主にiQONのAndroidアプリの開発を行っています。 先週からAndroid4.4搭載のNexus5を使っているんですが動きがかなり向上されたため、これからAndroidの快進撃が起こる予感がしてワクワクです。Androidの快進撃といえば最近iQONでも起こりはじめています。少し前まではAndroidアプリよりもiOSアプリの方が評価が高かったiQONですが、この半年でAndroidアプリのユーザーレビューが0.8ほど上がりiOSアプリに追いつきつつあります。先月にはGoogle Playの「今週のおすすめ」枠に掲載していただきました。 今回はそんなAndroidアプリの開発で使用しているツールを紹介します。 Android Studio 現在、IDEは「 Android Studio 」を使用してます。 http://developer.android.com/sdk/installing/studio.html 2ヶ月前まではAndroid開発では一般的なEclipse + ADTの構成で開発してましたが、検証をしたところ大きな手間もかからず移行できることがわかったためAndroid Studioに移りました。 まだ移行して浅いですが、以下のような開発効率が上がる利点がありました。 ・9-patchツールがIDEに組み込まれている (意外と便利) ・Vimプラグインの操作性がEclipseのときより良い (VimmerのためVimプラグインを使用) ・エディタを分割して同一ファイルを表示させることができる (Eclipse4.3 for Macではなぜかできなかった) ・全体的にEclipseのときよりも安定している (IDE自体がクラッシュすることがなくなった) Android StudioはビルドツールがGradleなんですが、まだまだ使い倒せていないので今後はそこの部分にも手を入れていこうと思ってます。 Genymotion エミュレータも2ヶ月前に「 Genymotion 」に移行しました。 http://www.genymotion.com/ Androidアプリの開発をされたことがある方ならご存知かと思いますが、Android SDKの標準のエミュレータはとにかく重くて遅い。エミュレータの起動時間や操作性が開発での大きなボトルネックになっていました。 そんな中で爆速エミュレータであるGenymotionの存在を知り導入したところ、想像以上の爆速でボトルネックだった部分が一瞬で解消され開発効率が何倍にも上がりました。もうAndroid SDKの標準のエミュレータには戻れません。導入して問題がない環境であれば絶対に導入した方がいいツールです。 インストールする際には、Genymotionのアカウントの作成と、VirtualBoxのインストールが必要になりますが、その手間に見合うだけの対価は十分にあると思います。 Localytics iQON内の数値計測、KPI管理を効率化するために「 Localytics 」を使用しており、各ページの表示回数やどの導線を経由して来たかなど幅広く分析できるように細かく数値を落としてます。 http://www.localytics.jp/ AndroidアプリはiOSアプリのような審査がなくリリースできるという利点があるため、施策のABテストや検証を行うには最適な場になります。AndroidアプリでABテストや検証を繰り返して効果が上がった施策をiOSアプリに移植しているケースもあります。 ネイティブアプリでもスピード感を落とさずに精度の高い施策を出すためにはAndroidアプリをうまく利用することが重要になってきます。 Google Analytics Localyticsとは別軸の数値計測をしたり、クラッシュレポートをみたりするために「 Google Analytics 」を使用してます。 クラッシュレポートに関しては、CrashlyticsやBugSenseを使っていた時期がありましたが、現在はGoogle Analyticsに落ち着いております。他に良いサービスがあれば移行したいと考えているのでご存知のかた教えてください。 最後に 現状のAndroidアプリの開発で使用しているツールを簡単に紹介しましたが、Androidチームは新しいモノが大好きなので今後も開発効率が上がるためならアグレッシブに取り入れていきます。なのでオススメのツール等がありましたらぜひとも教えてください。 またVASILYでは一緒にサービスを盛り上げてくれるエンジニアを大募集しております。 興味のある方、一緒にAndroidアプリを作りたい方はご連絡ください。 募集要項 連絡先:info[at]vasily.jp
2013年も終盤にさしかかり、年内に+10kgに到達しそうなiOSエンジニアの庄司です。 先日、iQONのiOSアプリをiOS7にデザインを最適化してリニューアルしました。 今回は新しくなったiQONの新機能とUIについてご紹介します。 まずはあたらしくなったiQON v2.0.0を こちら でインストールしてみてください。 新しくなったiQONの新機能 アプリのデザインをリニューアル iOS7にマッチしたシンプルで明瞭なデザインに変更しました。(あえてフラットデザインとは言いません) iOS7のトーンに合わせるだけでなく、ユーザーインターフェース部分の装飾を最低限必要なものだけにしました。 そうすることで、投稿されるコーディネートや掲載商品などのコンテンツを引き立てるように設計されています。 ↓v1.8.2 と v2.0.0 ホーム 今回新たに追加された「ホーム」は、iQONの利用シーンで多い自宅でのリラックスした時間や平日のちょっとした空き時間など、コンテンツを流して見て楽しむ利用シーンを想定し、ユーザーが主体的に検索する必要なくホーム上に流れる人気のコンテンツや最新の情報を見ているだけでiQONを楽しめるようにしました。 シンプルなナビゲーション よく使われる機能は、メニューを開くことなくいつでもアクセスできるようにタブに集約しました。 また、ナビゲーションバーとタブは透けているため、画面を広く使うことができます。 LIKEリスト 自分がLIKEしたアイテム、コーディネートなどをいつでも見返すことができるように、「LIKEリスト」にまとめました。 ナビゲーションバーの右上にLIKEリストのボタンが常にあるのでここからいつでもアクセスできます。 凝ったUI デザインはかなりシンプルになりましたが、実装においてはiOSネイティブな機能から外れることが多いため色々と凝った実装をしています。 - 全画面表示 iOS7ではデフォルトでフルスクリーンコンテンツを想定していて、ナビゲーションバーやステータスバーが透けることでコンテンツをより広く見せることが出来るようになりました。 これと同じ思想ですが、iQONでは「ホーム」のように縦に長いコンテンツをスクロールしていく時に、よりコンテンツに集中できるようにナビゲーションバーとコンテンツを隠して画面を広く取りました。 メニュー/LIKEリストのスライドジェスチャー ナビゲーションバーのボタンからメニューとLIKEリストを開くことができますが、女性の小さいの手では片手でタップするのは難しいこともあります。 また、ナビゲーションバーが適宜隠れるようになったためボタンが表示されていないこともあります。 こういう場合の補助的な機能として、画面の端からスライドしてメニューやLIKEリストを開くことができます。 アイテムポップアップ ホームなどでアイテムの画像をタップすると、アイテムの画像がズームして詳細情報が表示されます。 このアイテムポップアップではそれまで見ていた画面が透けて見えるため、前の画面に戻って流し見しやすくなっています。 ブラー (ぼかし) メニューやLIKEリストなどいつでも開ける画面は、それまで見ていた画面がわかるように、全画面を覆わずに元いた画面にブラーをかけています。 まとめ 今回は新しくなったiQONのiOSアプリについて紹介しました。 v2.0.0へのリニューアルは基本的にiOS7におけるAppleの思想から大きく外さないように、シンプルなデザインを目指して作ってきました。 また、これらの新しくなった機能はこれまでのiQONのバージョンで計測した数値やユーザーからの声をもとに使いやすく改善してきたこともあり、リリースして一週間の現在ユーザーからのレビューも上々です。 今後はiOS6との共存や具体的な実装についても紹介していきたいと思います。