TECH PLAY

株式会社ZOZO

株式会社ZOZO の技術ブログ

937

こんにちは、VASILYエンジニアの塩崎です。 今回はiQONを支えているクローラーの並列処理について紹介したいと思います。 並列処理の効率化をする過程でresqueを見限りsidekiqに移行した理由、移行時に書き換えた部分などについてもお話ししたいと思います。 iQONのクローラーの並列処理の仕組み iQONでは毎日数100万点のアイテムのクローリングを行っています。 一度クローリングしたアイテムも毎日1回再クロールし在庫や値下げをiQON内のDBと同期しているため、大量のアイテムを効率良くクロールする仕組みが必要です。 クロールの処理は「ダウンロード」と「スクレイピング」の2つに大きく分けることができます。 このうち、ダウンロードの部分については、提携ECサイトに対して負荷がかからないようにスケジューリングをする必要があります。 この部分の効率化についてVASILYでは分散MutexとResqueを使った並列処理システムを使っています。 ResqueでECサイトごと個別のキューを作り、キューからジョブを取り出し処理をするワーカーもサイトごと個別に作ります。 そして、ダウンロードワーカーは処理を行う前にmutexのロックを行うことによって、1つのECサイトに対して同時に大量のGETリクエストを投げることを防ぎます。 これによって、ECサイト毎に一定の速度でリクエストを発行することができます。 この機能を実現するためにRubyのメタプログラミングを活用し、クラスの動的な生成を行っています。 ダウンロードワーカーは複数のサーバーに分散しているため、このmutexはredisで管理しています。 この辺りの詳細については、以下の記事に詳しく書いてもあります。 Redis::DistMutex - 時限付き分散ロックで効率良くサイトクロールをしよう Resqueで複数サイトにまたがるクローリングを最適化しよう ECサイトが増えた時に問題発生 しかし、クロールするべきECサイトが増えた時に問題が発生しました。 前回の記事でもお伝えしましたが、クローリングするECサイトの数を80から400に増やすという施作を実施しました。 その結果クロールする速度が全然スケールせず、サーバーを増やしても増やしてもクロールしきれないという問題が発生しました。 ECサイト数の増加に合わせてサーバー数も5倍に増加させてみましたが、全くクロールしきれませんでした。 ボトルネックの計測 問題解決のためには、ボトルネックの計測をしなければいけません。 以下のような実行時間測定用のメソッドを作成し、怪しそうな部分全部にこのメソッドを適用しました。 ログ集計用のバックエンドにはfluentdとBigQueryを利用しているためデータのスループットについては特に考えずに、少しでも怪しそうな部分全部で実行時間の測定を行いました。 その結果、ダウンロードや解析の処理そのものは決して遅くないことが分かりました。 Resqueue内部でRedisからジョブをデキューしている部分でほとんどの時間を費やしていることが分かりました。 Resque内のボトルネック Resqueのソースコードを見てみると、デキューをする時にキューを1つ1つ順番にチェックしていました。 Redisには複数のリストから1つのデータを取得するためのAPIである BLPOP があるため、このループの実装はムダです。 iQONのクローラーではクロールするECサイトの数だけ動的にキューが作られるので、キューの数も80から400に増えました。 そのため、この部分が大きなボトルネックになっている可能性があります。 sidekiq移行 というわけで、Resqueはキューの数が増えた時にスケールしないのでsidekiqに移行することにしました。 移行にあたっては以下のことを重要視しました。 ・キューの数が多い時にスケールするかどうか ・Resqueからの移行が簡単か ・キューやワーカーを動的に生成することができるかどうか 開発環境でこれらのことを検証した結果、sidekiqが最有力候補に残りました。 ソースコードを読んでみても、BRPOPを使ってdequeueをしていることが確認できましたので、キューが増えた時でも効率的にdequeueしていることがわかります。 また、sidekiq移行をすることで以下のようなメリットも期待できました。 ・並列化がプロセスレベルではなくスレッドレベルであるため、forkのオーバーヘッドがない ・キューからジョブを取得するときに、キューのpriorityを毎回shuffleできる ・web UIがキレイ 最終的には 公式 に書かれていた What if 1 Sidekiq process could do the job of 20 Resque or DelayedJob processes? という挑発的な文言に煽られて導入を決意しました。   移行にあたって Resqueからsidekiqへの移行は https://github.com/mperham/sidekiq/wiki/Resque-Compatibility を参考にしました。 ワーカー、キューの動的な生成 基本的にはほとんどいじる部分がなさそうですが、iQONのクローラーはECサイトごとにキューやワーカーを動的に生成しているため、その部分を考慮する必要があります。 以下のようにしてECサイトごとのワーカー、キューを動的に生成しています。 エンキューするときには次のようにします。 このときにhoge-1, hoge-2, hoge-3という3つのキューが動的に生成され、それぞれに対して1つずつジョブがエンキューされます。 また、エンキューされたジョブを処理するためのワーカーは以下のようにして起動します。 キュー名の後ろに",1"をつけることによってdequeueをするときのpriorityをランダムにすることができます。 これを指定しないとdomain_idの小さいキューが毎回最優先でdequeueされ、分散mutexの競合が頻繁に発生してしまいます。 移行した結果 resqueを捨て、sidekiqに移行したことによってRedisからのdequeueのオーバーヘッドが大幅に減り、クロール速度が大幅に向上しました。 また、forkのオーバーヘッドが減ることによって1サーバーあたりのワーカー数を4から18に増やすこともできました。 そのほかにも諸々の改修を行うことによって、クローラー用サーバー管理費を1/10にすることも達成しました。 後日談 Resqueの最新版ではBLPOPを使用しているみたいでした。 ですが、最新版でもforkのオーバーヘッドは依然として存在しているので、やはりsidekiq移行はしてよかったと思います。 まとめ クロールするECサイトが増えるに従って、Resqueではスケールしないような状況になってしまいました。 そのため、dequeueが効率化されているsidekiqを導入しました。 結果としてクロール速度の大幅な向上とサーバー管理費を1/10にすることを達成しました。 最後に VASILYでは一緒に働くことができる優秀なエンジニアを募集しています。 世界一のファッションデータベースを作ることに興味のある方は是非 ご応募 ください。
アバター
VASILYの自動化大好きAndroidエンジニア堀江( @Horie1024 )です。今回、GitHubとCircleCIを利用したAWS Device Farmでのテストの自動化ついてご紹介しようと思います。 概要 Calabash で書いたAndroidアプリのE2Eテストを AWS Device Farm で実行する GitHub + CircleCIでAWS Device Farmでのテストの実行を自動化した Hubotを利用して実行中テストの監視とSlackへの通知をやってみた Cloud Test Lab を早く試したい Bazelのロードマップに Cloud Test Labのサポート が記載されている サンプルプロジェクト サンプルプロジェクトは こちら です。サンプルアプリはLogin画面とHello world!と表示されるだけの画面を持つアプリで、このアプリをテストするCalabashのfeatureはとても簡単に書けます。 以下はローカルでテストを実行した様子です。これをAWS Device Farmで実行します。 GitHub + CircleCIでAWS Device Farmでのテストを自動化 以下の図のような流れで自動化してみました。 1. GitHubへPush 2. GitHubへのPushを検知してCircleCIがビルド開始 3. AWS Device Farmでのテストを実行 4. Slackへテストの開始とHubotへの監視依頼を通知 5. Hubotがテストの監視依頼に反応 6. AWS Device Farmで実行中のテストを監視 7. テストが完了後その結果をSlackに通知 8. 結果を確認 以下各項目の詳細です。 1. GitHubへPush 開発したコードと追加したCalabashのfeaturesをcommitしGitHubへPushします。 2. GitHubへのPushを検知してCircleCIがビルド開始 CircleCI上でAndroidプロジェクトをビルドしAPKを作成します。Androidのプロジェクトをビルドするには以下のようなcircle.ymlを用意し、プロジェクトのリポジトリに追加します。今回はmasterブランチに差分がPushされた場合にビルドされるよう設定します。 これでmasterブランチへ差分がPushされると ./gradlew assembleDebugが実行されAPKが作成されます。 CircleCIの設定などより詳しい内容は こちらの記事 をご覧ください。 3. AWS Device Farmでのテストを実行 AWS Device Farmでのテストを実行するまでの流れは以下のようになります。 1. DevicePool情報の取得 2. APKのアップロード 3. テストパッケージのアップロード 4. テストのスケジューリング これらをAWS SDKを使用して実現します。 APIドキュメントと使用するSDK ドキュメントは以下を参照しました。 http://docs.aws.amazon.com/sdkforruby/api/Aws/DeviceFarm.html また、SDKには AWS SDK for Ruby - Version 2 を使用します。 AWS SDK Clientの作成 clientを作成します。IAMでAWSDeviceFarmFullAccessのポリシーをアタッチしたユーザーを用意し、そのAccessKeyIdとSecretAccessKeyを使用します。また、regionには us-west-2 を指定します。AccessKeyIdとSecretAccessKeyは環境変数に登録したものを使用するのが良いでしょう。 Device Farmのプロジェクト情報を取得 まず試しにDevice Farmで作成したプロジェクトの情報を取得してみます。プロジェクトを作成していない場合Device Farmのコンソールから「Create a new project」をクリックしプロジェクトを作成しておきます。 プロジェクト情報は以下のコードで取得できます。 devicefarm.get_project({ arn: "プロジェクトのARN" }) ここで、プロジェクトのARNは以下のようになります。 arn:aws:devicefarm:us-west-2:{ユーザーID}:project:{プロジェクトID} プロジェクトIDは、Device Farmでプロジェクトを開いた際のURLの以下の部分を使用します。 /devicefarm/home?region=us-west-2#/projects/この部分/runs DevicePoolの取得 デバイスプールについて テストを実行するデバイスの種類は、デバイスプールと呼ばれる単位で管理されています。デバイスプールをAWS SDKから作成することは出来ますが、コンソールから作成した方がわかりやすいです。 コンソールのプロジェクトページに表示される「Create a new run」をクリックすると新しいRun(テスト対象APKやデバイスの種類、テストケースを紐付けたもの)を作成することができます。そのStep3で任意のDevicePoolを作成できます。 デフォルトで「Top Devices」というDevicePoolが用意されていますので、今回はこちらを使用します。 AWS SDKでのDevicePoolの取得 以下のコードでDevicePoolを取得できます。レスポンスにはDevicePoolのARNなどの情報が含まれます。ドキュメントは こちら です。 APKのアップロード アップロードは2段階の手順を踏みます。 ・ devicefarm.create_upload()でのinitialize ・ Pre-Signed URLを使用したAPKアップロード initialize 以下のコードで初期化し、Pre-Signed URLを取得します。また、アップロードするオブジェクトのARNを取得しておきます(実行をスケジューリングする際に使用します)。ドキュメントは こちら です。 create_uploadのレスポンスのシンタックスは以下のようになっています。ドキュメントは こちら です。   { "Upload": { "Arn": "string", "ContentType": "string", "Created": number, "Message": "string", "Metadata": "string", "Name": "string", "Status": "string", "Type": "string", "Url": "string" } }   statusは、 FAILED 、 INITIALIZED 、 PROCESSING 、 SUCCEEDED の4種類があり、create_uploadを実行した直後は、 INITIALIZED になり、この状態ではDevice Farmから利用できません。Pre-Signed URLを利用してAPKをアップロードすることで PROCESSING となり、その後 SUCCEEDED へ変化します。ここで PROCESSING の際に不具合が起きると FAILED になります。 upload こちら を参考に、以下のようなコードでAPKをアップロードできます。 テストパッケージのアップロード 今回テストにはCalabashを使用するので、Calabashのfeaturesを圧縮後テストパッケージとしてアップロードします。アップロードの手順はAPKのアップロードと同じです。create_uploadのtypeに CALABASH_TEST_PACKAGE を指定します。 テストの実行 実行のスケジューリング 実行のスケジュールは以下のように行います。ドキュメントは こちら です。 app_arnには、APKをアップロードした際に取得したARNを、device_pool_arnはDevicePoolの取得で取得したARNを、test_package_arnにはCalabashのfeatures.zipをアップロードした際に取得したARNを使用します。 APK、テストパッケージのアップロード完了を待つ APK、テストパッケージをアップロードした直後では、それぞれのstatusが SUCCEEDED になっているとは限りません。このため、定期的にstatusが SUCCEEDED かどうか確認する手順が必要になります。 get_uploadを使用すると、uploadしたオブジェクトの状態を取得できるので、それを定期的に取得しstatusを確認します。そして、APK、テストパッケージ両方のstatusが SUCCEEDED ならschedule_runを実行します。 これでスケジューリングされ、Device Farm上でCalabashのテストが実行されます。 CircleCIからのスクリプトの実行 CircleCIからここまでで作成したRubyのスクリプトを実行し連携させます。circle.ymlは以下のように設定します。 ここでdeploy.shは以下のようになります。 これにより、GitHub上のmasterブランチへ差分がPushされると deploy.sh が実行され、以下の流れでDevice Farmでのテストが自動実行されます。 1. ./gradlew assembleDebug (APKの作成) 2. zip -r features.zip features (テストパッケージの圧縮) 3. ruby scripts/devicefarm.rb (APK、テストパッケージのアップロードとテストのスケジューリング) 4. SlackにHubotへの監視依頼を通知 スケジューリングしたテストは、テスト終了まで時間がある程度かかるためHubotにテストの進捗を監視させます。Hubotへの指令はSlackを経由して行い、Slackへの通知にはSlackの Incoming WebHooks を利用します。 Incoming WebHooksの設定はSlackの「Configure Integrations」からIncoming Webhooksを選択します。 選択すると以下のような画面に遷移しますので、Incoming WebHooksをpostするchannelを選択し、「Add Incoming WebHooks Integration」をクリックします。 これでWebhook URLを取得できるので、そのURLに対してPOSTでHTTPリクエストを送ります。また、Device Farm上でのテストの実行状況を監視するには、実行中のテストのARNが必要になります。 このため、RubyスクリプトからスケジューリングしたRunのARNをSlackに通知します。 今回、Hubotに監視依頼するフォーマットを @vasilybot ARN と決定します。 以下SlackにIncoming WebHooksで通知を送るコードです。 このSlackへの通知のコードを含めた最終的なスクリプトのサンプルは こちら になります。 5. Hubotがテストの監視依頼に反応 CircleCIからSlackのIncoming WebHooksで送られてくるメッセージにHubotを反応させます。 Incoming WebHooksで送られてくるフォーマットは @vasilybot ARN になるので、Hubot側のコードは以下のようになります。これでSlackに @vasilybot ARN と投稿された際にHubotが反応するようになります。 6. AWS Device Farmで実行中のテストを監視 AWS SDKを使用し、定期的にテストの状態を確認します。SDKには AWS SDK for JavaScript を使用します。 Access Key IdとSecret Access Keyについては、 Configuring the SDK in Node.js を参考に環境変数にそれぞれ  AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY として登録します。これでSDKが自動的にAccess Key IdとSecret Access Keyを参照してくれます。 getRun を使用することで実行中のテストの状態を取得できますので、Hubot側のコードは以下のようになります。 7. テストが完了後その結果をSlackに通知 getRunでテストの実行状態を監視し、statusが COMPLETED ならSlackへ結果を送信します。また定期実行を clearInterval でキャンセルします。 最終的なHubot側のコードは以下の通りです。Slackに送信する内容については、 Advanced Message Formatting を利用してテスト実行結果詳細へのリンクを付けるなど、より見やすくする工夫をしても良いと思います。 8. 結果を確認 Slackにテストの結果が表示されるので確認します。 Device Farmのコンソールを確認するとテストがパスされています。 まとめ GitHub + CircleCIを利用してAWS Device Farmでのテストの実行を自動化しました。AWS Device Farmは便利なサービスですが、プロジェクトやRunの削除が出来ない、実行中のRunのキャンセルが出来ないなどまだまだ発展途上と感じる部分も多いです。 AWS Device Farmのようなモバイルアプリのテストをクラウド上で実行する環境を提供するサービスは複数あり、AWS Device Farmも、今年7月にAmazonが AppThwack を買収して始めたサービスです。同様なサービスには、 Scirocco Cloud や Testmunk があります。さらに今年のGoogle I/Oでは、Googleが恐らく同様なサービスと思われる Cloud Test Lab の発表を行っています(事前登録に申し込みましたが今のところ連絡無し)。 Cloud Test LabはAndroidStudioとの連携も考えられているようですし、Bazelのロードマップに Cloud Test Labのサポート が入っており、非常に楽しみです。利用可能になり次第試してみようと思います。 最後に VASILYでは、自動化や新しい技術が大好きなエンジニアを募集しています。少しでもご興味のある方は是非 こちら からご応募よろしくお願いいたします。
アバター
こんにちは。VASILYに入社して、オシャレぶるようになったと周りにイジられているデータサイエンティストの金田です。 VASILYでは、プッシュ通知の開封数を上げるために様々な施策を行っていますが、その一つとして、多腕バンディット問題を応用し、複数の異なるタイトル文の配信比率を動的に最適化することで、開封数を高めるといった取り組みを行っています。今回は、なぜプッシュ通知配信の最適化に多腕バンディット問題を応用したのか、アルゴリズム選定にあたりどのようなポイントを考慮したか、また実用にあたってどのような問題に直面し、それをどう克服したのか、といった点について紹介したいと思います。 プッシュ配信最適化の背景 iQONでは、新着の雑誌記事やコンテストのお知らせをユーザーへ通知するため、1日に数回プッシュ通知を配信しています。プッシュ通知は、どのようなタイトル文を配信するかによって、開封率が大きく異なってきますが、プッシュ配信最適化の取り組みを行う以前は、担当者がそれまでの定性的な知見を基にしてタイトル文を作成し、全てのユーザーに同じタイトル文を一斉に配信するといった運用をしていました。 そのため、日々のプッシュ通知の開封率にバラツキがあったり、また仮に、開封率が高かったとしても比較対象がなく、他の条件を一定にするという"実験"の条件を満たしていないために、なぜそのプッシュ文言の開封率が高かったのか、といった定性的な知見が蓄積されにくいという課題がありました。 従来、インターネットにおける広告やコンテンツの改善にあたっては、一般的にA/Bテストと呼ばれる手法を用いて、無作為に文言やクリエイティブの出し分けを行い、仮説検定を実施して実績の高かった方だけを採用するといった施策を行うことが多いかと思います。 しかしながら、広告やコンテンツと違い、プッシュ通知のタイトル文は賞味期限が短く、その日限りしか使えないことが多いため、仮にどのタイトル文の開封率が高いかという結果がわかっても、その結果を次に活かすことができません。そのため、プッシュ配信の最適化を行うにあたって、多腕バンディット問題に目をつけました。 多腕バンディット問題とは? 多腕バンディット問題に関しては、既に日本語でも広告やコンテンツの最適化への応用が様々なブログ等で紹介されていますが、機械学習の強化学習の手法の一つです。 問題の設定としては、当たり確率の異なる複数のスロットマシンがあり、手持ちのお金が限られているという状況を想定します。また、マシンは1回ごとに変更ができ、アームを引くごとに当たりかハズレかの結果が確率的に得られるとします。このような条件下で、スロットマシンから得られる報酬を最大化するために当たりやすいマシンの見極め(探索)と、当たりやすいマシンにお金を掛けること(活用)をどううまくバランスをとったらよいかという問題になります。 直感的には、各々のスロットマシンに少しずつお金を掛けていき、その過程で他よりも当たりやすそうなスロットマシンがあれば、そこへ他のマシンよりも多めにお金を掛けていくことで、報酬を最大化させるといったイメージになります。 今回は、多腕バンディット問題をプッシュ通知の配信に応用して、開封数をリアルタイムに取得し、開封率が高そうなタイトル文へ配信比率を寄せることで、開封数を増やすことができるのではと考えました。   システム構成 従って、多腕バンディットを適用するためには、配信途中にタイトル文の比率を変えていく必要があるため、リアルタイムに開封数を取得する必要があります。そのため、VASILYではプッシュ通知の配信に下図のシステム構成をとっています。具体的には、プッシュ通知を配信後、デバイスからの開封情報をAPIサーバーで受け、Fluentdを介してGoogle BigQueryへストリームインサートで送っています。そして、配信サーバーからBigQueryへクエリを発行することで、リアルタイムに開封数を取得しています。この仕組みによって、タイトル文の配信比率を動的に変更しています。 また、Tableauサーバーを活用することで、配信結果が自動的にレポートに反映されるような仕組みも作っているため、エンジニアの手を介すことなく、担当者が結果を参照できるようになっています。   プッシュ通知配信に係る問題とその解決策 しかしながら、実際にプッシュ通知の配信に多腕バンディットを適用しようとした場合、通常の多腕バンディット問題とはいくつか問題設定が異なる点があり、実装にあたりいくつか試行錯誤がありました。ここでは、その問題と解決策について説明します。 ステップごとの一括送信 相違点の一つは、アームを一回ずつ引くのではなく、結果をまとめて計算する必要があることでした。なぜなら、VASILYのプッシュ通知配信の仕組みでは、プッシュ通知を何ステップかに分け、まとめて送信をする仕組みになっているためです。例えば、仮に10万通の通知を送信するのであれば、20時半から1万通づつ、5分間隔で10ステップに分けて送信するといった仕組みになっています。 アルゴリズムの実装にあたっては、O'Reillyから出ている下記の書籍を参考にしましたが、通常の多腕バンディット問題では一回づつスロットマシンのアームを引くことを前提としていてるため、実装にあたっては、新たにbulk_update() という一括で更新ができるメソッドを独自に追加することで対応しました。また実装はRubyで行い、Gemパッケージとして導入できるようにしました。 なお、今回ご紹介したRubyでの実装は、GemとしてGitHub上で公開をしていますので、要望、質問、プルリクなどありましたら歓迎いたします。 https://github.com/vasilyjp/multi_armed_bandit 報酬の遅延 また、多腕バンディット問題とのもう一つの違いは、報酬が遅れて支払われるということでした。プッシュ通知の配信の場合、実際にプッシュ通知を送信してから、それが開封されるまでにタイムラグがあります。 そのため、あまり最初の方から配信比率が大きく変化するようにパラメーターを設定してしまうと、配信数が安定せず、1ステップごとに配信比率が大きく振れてしまうということがわかりました。下の図は、ステップごとの配信数の割合を色分けして表したものですが、左側のグラフでは1ステップごとに配信比率が大きく変化してしまっていることが分かるかと思います。 従って、最初の方のステップでは、探索の方に比重を多くし、ステップが増えるに従って、探索の割合を減らし、活用の方に比重が移るようにステップごとのパラメータを調整しました。それにより、配信比率が安定し、適切に開封率の多いタイトル文の配信比率が高くなるようになりました。   アルゴリズムの選定 多腕バンディット問題のアルゴリズムにはいくつか種類がありますが、上記に記載した通り、実装にあたっては、 一括で報酬のアップデートができる 配信ステップごとにパラメータを変更できる 設定すべきパラメーター数が少ない といった条件を満たすことが重要であったため、ε-Greedy と Softmax というの二つのアルゴリズムを候補としました。 この二つのアルゴリズムの大きな違いは、どのアームが成果が高いか"探索"を行う際に、アームを等確率で引くか(ε-Greedy)、過去の期待値に応じて、期待値の高いアームを引く確率を高くするか(Softmax)に大きな違いがあります。 両方のアルゴリズムを実際に運用してみた結果、Softmaxの方が、他よりも特に開封率の低いタイトル文があった場合に、早い段階でそのタイトル文に振り分けられる配信数を減らせることから、最終的にはSoftmax アルゴリズムを採用することにしました。 結果と今後の課題 上記の取り組みの結果、プッシュ配信のタイトル文の配信比率を動的に最適化することで、全ての文言を等配分で配信した場合に比べて、平均して約5%開封数をリフトさせることに成功しました。 また同一の条件で、複数のタイトル文を配信し、その結果を簡単に検証できるようになったため、タイトル文にモデル名を入れた方がよいのか?「〜なコーデ5選」といった具合に数字を入れた方がよいのか?といったタイトル文を作成する上での定性的な仮説の検証が容易になり、PDCAを早く回せるようになりました。 今後は、年齢やユーザーの嗜好といったコンテキスト情報を入れることで、更なる最適化を実現したいと考えています。また、広告やコンテンツの出し分けといったプッシュ通知の配信以外にも多腕バンディットアルゴリズムを適用し、さらにユーザーに感動体験を与えられるようなサービスにしてきたいと思っています。 最後に VASILYのデータサイエンスチームでは、これ以外にも、トピックモデルという文章分類に使われる手法をユーザーのLikeデータに適用し、ユーザーの隠れた嗜好を推定してレコメンドに応用するといったことや、ユーザーの口コミをネットワーク分析によって明らかにすることで、ファッションに関する情報伝播がどのような構造になっているのか解明するといったことを行っています。 また、ここには書ききれないこともたくさんありますので、こういった取り組みに少しでも興味があるという方がいれば、ぜひ一度VASILYに遊びに来てください。VASILYでは一緒に働ける優秀なデータサイエンティストを募集しています。一緒に「ファッション×ビックデータ」という未開の分野を一緒に開拓していきましょう! データサイエンティスト募集要項  
アバター
こんにちはVASILYエンジニアの塩崎です。 iQONでは提携先ECサイトからアイテム情報をクロールしています。 クローラーの仕組みを大幅に変更することによって、1ヶ月間で400サイト分のクローラーを製作することができるようになりました。 今までの仕組みですと、2年間で80サイト分ですので、製作速度は100倍になりました。 今回はその仕組みをざっと紹介したいと思います。 ユーザーさんの欲しいアイテムがない! そもそも、なんでこんなにアリエナイスピードでクローラーを作る必要があったんでしょうか? iQONにはブランドLIKEという機能があり、ユーザーさんが特定のブランドをお気に入り登録することができます。 しかし、ユーザーさんに人気のブランドにも関わらずアイテム点数がほとんどないブランドが多かったです。 中にはTOP10に入っていながらもアイテム点数が数十点しかないブランドもありました。 ユーザーさんにもっとiQONを使って貰うためには、この部分の改善が必要です。 そのため、ブランドLIKEの上位1000ブランドの全アイテムをクロールするためのタスクフォースが組まれました。 1000ブランドのアイテムを集めるために 課題1 400サイトのクローラーを作成し、運用しないといけない このタスクフォースにはエンジニアが5人いたため、各人が1日あたり2サイト分のクローラーを製作すれば期限に間に合います。 しかし、そんなことをしてしまうと、膨大な数になったクローラーのメンテナンスが非常に大変になってしまいます。 仮に1つのサイトが1年間に1回リニューアルをするとしても、1日に1.5サイト分のクローラーの修正をする必要が出てしまいます。 (ちなみにこれは楽観的な想定)今まで通りの仕組みでクローラーを作成した場合は、クローラーの修正コストが馬鹿になりません。 課題2 アイテム情報の自動判定 また、当時はクロールしたアイテム情報の画像判定(iQONのコーディネート作成用の画面に出す or 出さない)やアイテムのカテゴリ判定(トップス or ボトムス or etc.)を人力で行っていました。 なので、たとえ大量のアイテムをクロールしたとしても、その判定の速度がボトルネックとなることが目に見えていました。 人力判定では1日あたり最大で3000点しか判定できませんでしたが、この程度のスピードですとアイテム情報判定の部分で新規アイテムの追加の滞留が起きてしまいます。 解決策 そのため、プロジェクト期間の前半1ヶ月で判定の自動化と、クローラーを簡単に製作するためのツール作りをすることになりました。 その後の1ヶ月を使いチーム全体でクローラーの作成をすることとなりました。 チームの約半数はビジネス職でしたので、エンジニアじゃなくてもクローラーを製作できるようなツールが必要です。 このクローラー作成ツールと自動判定機を使うことによって、今までとは比べものにならないスピードでクローリングを行い、常に最新のアイテムの情報をユーザーさんに届けられるようになりました。 クローラーの構成 まずは、今のiQONのクローラー全体の構成の紹介をしたいと思います。 クローラー作成ツールによるサイト固有パーサーの生成 ECサイト上のアイテム情報は、まず各「サイト固有パーサー」によって解析が行われます。 商品名や価格などの商品名が書かれているHTML要素はECサイト毎に異なります。 このサイト毎の差異を吸収しクローラー共通基盤に対して統一させたフォーマットでデータを提供するのがこのサイト固有パーサーの役割です。 従来の方法では、この「サイト固有パーサー」はエンジニアがrubyコードで書いていました。 しかし、その方法ではエンジニア以外の人がサイト固有パーサーを書くことができません。 さらに、ECサイトにわずかな変更があった場合でもrubyのソースコードを変更する必要があり、エンジニアが行う必要のあるメンテナンスのコストが非常に大きいです。 そのため、エンジニア以外の人でもサイト固有パーサーを簡単に製作できるようなツール、クローラー作成ツールを作りました。 このクローラー作成ツールの画面でXPATHや正規表現を入力するとその結果がDSLとしてDBに書き込まれます。 サイト固有パーサーはこのDSLをDBから読み込み、それに応じてECサイトの情報をパースします。 また、どうしてもツールでは対応できないような複雑なパースを行う必要のある商品情報(非同期なAPI通信を含むもの、詳細ページによって要素のxpathが変わるものなど)を含むECサイトもあります。 そのような要素については「エンジニアに依頼」にチェックを入れると、エンジニアがその要素のパーサーだけrubyコードで実装することができます。その後、エンジニアが書いたrubyコードとツールが生成したDSLをマージしサイト固有パーサーを生成することができます。 このツールを使用することで、エンジニア以外の人でもクローラーを高速に作ることができるようになりました。また、ECサイトのHTMLの構造が変わった場合でもエンジニア以外の人が対応することができるようにもなり、メンテナンスのコストを大幅に減らすことができました。 中には1つのサイトのクローラーをわずか3分で作ってしまうような猛者も登場してしまいました。 いままではエンジニアが1日に1つくらいのペースで作っていたため、エンジニアの間で戦慄が走るようなことにも繋がってしまいました。 アイテム情報判定の完全自動化 未判定アイテム情報テーブルに格納された情報は、自動判定機によって判定済みアイテム情報テーブルに移動されます。 自動判定機は、アイテムの画像判定とアイテムカテゴリーの判定を行います。 アイテムの画像判定 iQONというサービスの大きな特徴の一つに、ユーザーがファッションアイテムを組み合わせてコーディネートを作り、それを投稿できるという機能があります。 そのため、クロールした画像の中から、ユーザーさんがコーディネートを作りやすい画像を判定する必要があります。アイテムが単体で写っている画像がコーディネートに使われやすい傾向にあるため、その判定を行っています。 この処理は従来ではクラウドワーカーさんによる人力判定が行われていましたが、現在ではプログラムによる自動判定が行われています。 この処理の詳細は以下の記事に詳しくまとまっています。 iQONでクロールしたアイテム画像がコーディネートに使われるまで アイテム情報のカテゴリー判定 商品名や商品の説明文などのテキスト情報からアイテムのカテゴリー(Tシャツ、ブラウス、ワンピース、etc)を判定します。 この判定機内部はMeCabで形態素解析を行った結果から、アイテムのカテゴリーを最も判定している可能性の高い単語をピックアップします。 その単語をアイテムカテゴリー辞書と照会することによってアイテムのカテゴリーを自動判定します。 この処理も、クラウドワーカーさんによる人力判定から、プログラムによる自動判定に移行しました。 これら2つの自動判定によってアイテムの判定速度が大きく向上しました。 いままでは最大でも1日に3000アイテムの判定しか行えなかったのが、1日に10万点ものアイテムを判定できるようになりました。 まとめ 今回の記事では、まだクローラーの全体構成を説明するだけに留まってしまいました。 ソースコードなどもなく、図も概念的なものに限っているため、まだまだこれで本当に100倍になるのかという部分に疑問をお持ちの方も多いでしょう。 次回以降の記事で製作速度を100倍にするためにしたことをより具体的に説明していきたいと思いますので、 好ご期待ください。 クローラーそのものは直接ユーザーさんの目に触れることはありませんが、iQONというサービスの根幹を支えていると自負しています。 今回、数多くのクローラーを製作したことにより、「自分の好きなブランドのアイテムが増えた!」という意見をユーザーさんから頂くこともできました。 VASILYでは一緒に働くことができる優秀なエンジニアを募集しています。 100倍なんて生温いという方がいらっしゃいましたら 是非ご応募 ください。
アバター
こんにちはVASILYエンジニアの松本です。VASILYが運営しているiQONというサービスの大きな特徴の一つに、ユーザーがファッションアイテムを組み合わせてコーディネートを作り、それを投稿できるという機能があります。それを実現するために、iQON内では様々な画像処理が行われているのですが、それらを最近大幅に改善したのでその内容を紹介したいと思います。 iQONのコーディネートに使われるアイテム画像について コーディネートを作る過程 下の図のようにユーザーは検索画面からアイテムを検索し、それをキャンバスに配置してコーディネート画像を作っていきます。 iQON内の画像のほとんどは提携先ECサイトからクロールして取得している画像なので、コーディネートに使う画像については以下の2点を実現する必要があります。 ・アイテムを検索するときはコーディネートに使いやすいアイテムに限定して表示する必要がある ・アイテム画像の背景は綺麗に透過されている必要がある コーディネートに使いやすいアイテムの選定 iQON内では アイテム単体のみ で写っている画像がコーディネートによく使われていることが統計的に分かったので、そのようなアイテム画像のみが表示されるようにしています。   この選定ですが、iQONには現在月間60万点以上のアイテムが追加されているので、人力では処理しきれずアイテムの追加に滞留が起こっていました。 そこで、今回はその選定を自動化することに踏み切りました。 アイテム画像判定の自動化 ECサイトからクロールされるアイテム画像には膨大なパターンがあります。その中からアイテム単体の画像のみを取り出すために独自の検出器を実装することで判定を自動化しました。 画像処理ライブラリとしてOpenCVをどうしても使いたかったので、iQONのバックエンドはRubyで実装されていることから ruby-opencv を使用しました。 以下に代表的な画像のパターンについての検出器を紹介します。(赤枠が検出に用いた領域です) 複数アイテム画像の検出器  物体領域のみを抽出した mask画像 を生成し、その領域の個数をカウントして判定しています。アクセサリなどカテゴリによっては複数アイテムが入っても良い場合もあるので、その場合を考慮してフィルタリングしています。 モデル画像の検出器 ECサイトの場合、モデル画像のほとんどが顔が写っているものであることと、人物認識よりも顔認識のほうがあるかに精度が高いことから顔認識による判定を採用しました。参考にしたのはruby-opencvの サンプルコード です。 しかし、この方法をそのまま採用しても精度は低く、多くの誤検出を生み出してしまいます。そこで、ECサイトのモデル着用画像の顔の位置、大きさ、色についてさらに分析を行い誤検出を最大限減少させました。 マネキン画像の検出器 これについてはECサイトによっていろいろな種類のマネキンが存在したので一番苦労しました。上図のように首元の領域を検出してマネキンだと判定したものもありましたが、それでも全部のマネキンを検出することはできません。 そこで、過去に人力でアイテム判定を行ってきたログを解析してみることにしました。iQON内には過去すべてのアイテムについての判定結果のログがBigqueryに保存されていたので、そのデータから各ブランドごとにアイテム画像判定の結果を分析しました。その結果から特定カテゴリにおいてマネキン画像しか入らないブランドをリストアップして判定を行いました。  そのほかにも様々なフィルターを実装し、現在ではこの判定精度は95%以上の精度を保っています。 アイテム画像の背景の透過方法 上記の方法でアイテム単体が写っている画像の判定が出来たので、次はコーディネートを作るためにアイテム画像の背景透過をする必要があります。 一般的な背景透過手法 以前はこの処理を画素の明度値に対してしきい値を設けて行っていたのですが、この場合2つの問題点があります。 1. 上の図の真ん中のように背景とアイテムがほぼ同色の場合にしきい値選定が困難。 2. 上の図の右のようにしきい値を調整しても画像の端をスムーズにできない そこで、今回は1を解決するためには背景色に応じて適切なしきい値で透過処理をかけるようにしました。また、2を解決するために画像にフィルタリングとクラスタリングの処理をかけて、画像のノイズを低減しました。以下ではその概要を説明します。 手法の概要 動的に背景画像を生成 画像によって背景色は変わるため、まず最初に背景画像を入力画像から生成する必要があります。背景画像は入力画像の端をスキャンして線形補完することで生成しています。   γ補正で背景色とアイテム画像のコントラストを上げる γ補正 をかけると画像のコントラストを調整することができます。以下がサンプルコードです ここでのgammaの値は直前に行った背景画像の生成処理から得られた背景画像の明度値によって動的に変化させています。この処理によって画像のコントラストを上げることができ、しきい値選定が容易になります。   画像のノイズをフィルタリング処理で除去 ノイズ除去の最も一般的な手法に BILATERAL FILTER があります。これはエッジの情報を失うことなくフィルタングができる方法として有名です。しかし、これだけでは画像の端の境界部分にブラーが残ってしまいます。そこで mean shift クラスタリングという手法で画像のエッジ部分を滑らかにしました。 こちらの 論文 から引用した以下の画像が最も分かりやすい例でしょう。 meanshiftクラスタリングによって各領域の境界がはっきりすることがわかるとおもいます。(特に背景の海と空の境界部分) 変換処理の結果 これらの処理をさきほどの画像に適用してみます。 ruby-opencvには以下のように関数が用意されています。   背景透過処理 最後に背景画像との差分をとってmask画像を生成し、入力画像とのANDをとることで背景透過画像を生成します。   まとめ 今回はiQON内の特に画像処理にフォーカスして全容を書きました。今回の改善では人力で画像を判定していたのを自動化したことによって、多くの工数を削減できたことと、一日のアイテム追加数の大幅な増加ができたことが大きな成果だったと考えています。アイテム追加数は人力では1日最大3000点程度だったのですが、今回の自動化で1日最大10万点のアイテム追加を実現することができました。 また、画像の透過処理の改善では特に白のアイテムの背景透過処理が改善されたのが大きかったです。やはりファッションの基本となる色がコーディネートに使えないのは残念という声が多数のユーザーから上がっていたのでそこを改善できたことが大きかったです。 かなり専門性の高い処理が多く、ここでは書ききれなかったことがたくさんあるので、詳しいことに興味があればぜひ一度VASILYに遊びに来てください。VASILYでは一緒に働ける優秀なエンジニアをお待ちしています。一緒にファッション業界を変えていきましょう! VASILYのRECURUIT情報はこちら
アバター
4月ということで、先日VASILYでも 入社式 をとり行い、エンジニア/デザイナーの計6名が新たに加わりました。 やる気に満ち溢れたフレッシャーズを見ると、我々も気の引き締まる思いです! 今回は、自分が新卒デザイナーだった頃に読んだ本、読んでおけば良かったなと思う本をご紹介したいと思います。 1.  欧文書体―その背景と使い方 [ 欧文書体―その背景と使い方 ] 欧文タイポグラフィの 入門書 として最適な一冊。 著者である小林章さんは、日本人でありながらドイツのフォントベンダー「ライノタイプ」にて、タイプディレクターを務める人物。日本人で最も欧文に精通していると言っても過言ではない著者による解説は、 入門書でありながら非常に実用的です 。 従来の解説書にありがちだった、あまり実践では使わない知識(書体の細かな分類や、各パーツの名称など)を必要最小限にとどめ、 「こういう雰囲気を出したいときにはどの書体を選べば良いか」「記号類の本当に正しい使い方はなにか」 など、すぐに現場で役立つ知識が数多く掲載されています。 新卒デザイナーに限らず、フォントにちょっと詳しくなりたいディレクターさんやエンジニアさんも気軽に読める内容だと思います。続刊の『 欧文書体 2 』をあわせて読むのもおすすめです。   2.  タイポグラフィ・ハンドブック [ タイポグラフィ・ハンドブック ] 欧文書体・タイポグラフィの 専門書 として最適な一冊。 小林さんの『欧文書体』が入門書なら、こちらは豊富な情報量で手元にあると重宝する 辞書のような存在 です。 そういえばあの用語の意味はなんだっけ? この書体の歴史は? など、毎日使うわけではないけれど知らないと困る基礎〜応用の情報が数多く掲載されています。 欧文に関する情報はウェブでも簡単に入手可能ですが、情報が多すぎるがゆえに誤った情報も氾濫しています。デザイナーとして最高の「提案」を行うためにも、 常に正しい情報をインプットすること は重要です。 手元に置き、困ったときに見られるようにしておくのがおすすめです。   3.  Balance in Design [ Balance in Design ] プロポーションや構図など、美しいデザインのなかに必ず存在する 「数学的美しさ」 について解説された一冊。 ル・コルビジェの建築やバウハウスのポスターを例に挙げ、そのなかに黄金比や幾何学的な解析など 「数学的補助線」 が存在することを、半透明のシートを重ねて解説しています。 一般的にデザインは「感覚的なもの」と思われがちですが、歴史上でも著名なデザインを題材にすることで、 デザインが決して感覚的なものではない ということを分かりやすく示してくれています。 「目を引くようなデザイン」「斬新なデザイン」「オリジナリティのあるデザイン」を求める前に、まずは 美しさの基礎 を知ることはとても重要です。   4.  エモーショナル・デザイン [ エモーショナル・デザイン ] ノーマンと言えばアフォーダンスについて書かれた『誰のためのデザイン?』が有名ですが、内容がやや古いため2004年に書かれた近著であるこちらの方をおすすめします。 なぜ良いデザインは気持ちが良いのか? 数値だけでは決められない感情的なものとはなにか? など、プロダクトにおける 「認知」と「感情」 を中心に語られています。 製品やロボットを「インターフェース」と捉えると、ノーマンの語る「エモーショナル・デザイン」がUIにも通ずる思考法 であるということが良く分かります。 まずはとりあえず読んでみて、3年後、5年後にもまた読み返してみると新たな発見がある、味わいのある一冊です。   5.  デザイン思考が世界を変える [ デザイン思考が世界を変える ] デザインをするための技術ではなく、 「デザイン的思考」 について書かれた一冊。 著者は世界的に有名なデザイン・コンサルタント会社「IDEO」の代表ティム・ブラウン。 デザイン=ビジュアル的な成果物を連想しがちだが、会社における組織問題や社会問題など、「デザイン的思考」を用いることで多くのイノベーションを起こすことは可能です。 従来の「デザイン」から一歩外に出た思考法、「なにを?」ではなく「なぜ?」に応える姿勢の重要性 を教えてくれます。 ただ、考え方や思想を中心に語られており、具体例がやや不足気味。同じくIDEOについて書かれた『 The Art of Innovation 発想する会社 』をあわせて読むと、よりイメージが掴みやすくなると思います。   最後に 以上、新卒デザイナーにおすすめしたいデザイン本5選でした。 VASILYでは、豊富なデザイン知識とイノベーティブなデザイン思考で、UIにとどまらない問題解決をしてくれるデザイナーを絶賛募集中です! ご応募お待ちしております! https://www.wantedly.com/projects/5485 連絡先:info[at]vasily.jp
アバター
最近ではFASHION×ITという話題がネットや雑誌などで注目され、ファッションアプリも増えてきている印象を受けます。 ファッションアプリも、日々のコーディネートをサポートするアプリや、使わなくなったアイテムを売ることのできるものなど様々です。 今日はVASILYデザイナーチームが3月に インスピレーションを受けた ファッション アプリ をいくつかご紹介したいと思います。 1. MODA OPERANDI   モーダ・オペランディは、世界のトップ デザイナーズ ブランドのアクセサリー、ジュエリーなど 最新コレクションを、 ランウェイ後にプレオーダーできるファッションサービス のアプリです。 購入したい最新のコレクションの商品がある場合、 商品価格の50%を先払いし、残りを商品の生産が完了された次点で支払いをするという決済システム になっています。 コレクションの商品は高額なものが多いため、一度に支払うには負担が大きく、手が伸ばせない人も多いと思います。そんな人でも商品価格の半分を先に支払い、生産が完了するまでの間に残りの半分の金額を準備できる期間もあるので、コレクションアイテムを購入できる機会が増えると思います。 2. ASAP54 ASAP54はカメラはアイテムを写真に撮ることで その服がどこのブランドなのかなど詳細な情報を知ることができる アプリです。撮影したアイテムに該当するものがない場合は、そのアイテムと類似した複数のアイテムを表示してくれます。 例えば、テレビや雑誌でいいなと思っったら撮影するだけで、そのアイテムと同じもの、または類似したアイテムを提示し購入画面に繋げてくれるため、店舗に行く手間や、複数のECサイトで探す手間がなくなります。    3. 29CM 29CMは韓国にあるセレクトショップのアプリです。 このアプリは、ドイツレッドドットデザイン賞とIFデザインアワードウィナーを受賞しています。 アイテム写真のセンスが良く、コンテンツも豊富で、見ていて飽きないアプリです。   4. Canopy CanopyはAmazon.comから デザインの 優れた 商品を人の手で厳選し、カタログにしているプロダクト です。 キュレーションされている商品はどれも魅力的で、値段も手頃なものが多く、このデザインでこの値段なら欲しい!と思う商品ばかりです。また、アプリ内全体に「間」があり、商品画像をあまり大きく表示させないところなど、商品とアプリのリッチ感を引き出していると感じました。 5. Spring 以前、 こちらの記事 でもご紹介させていただきましたが、 Apple Design Award 2014にも選ばれている、NY発の新コマースファッションアプリ。Harper's BAZAARの ダウンロードするべきファッションアプリの記事 でも取り上げられていて、ファッション業界からも注目されています。 ユーザー発信のコンテンツをブランドが上手に活用するという手法を取り入れています。買い物本来の楽しさを味わってもらえるよう、あえてシンプルな構成になって、全体的に繊細で上品な印象のファッションアプリです。 ホームから直接注文でき、送り先住所などの入力画面も画面遷移やスクロールしなくとも、そのまま入力できるためシンプルに注文できるのがいいと感じました。  6. Threadflip Theredflipは 使わなくなったファッションアイテムを自由に売り買いができるフリマアプリ です。 自身で写真を撮って売ることもでき、申し込むと無料で梱包セットが届き、30点までまとめて出品することが可能で、 アイテムの撮影は運営側が撮影してくれる とのこと。また、自身で梱包し、必要な手続きの書類をまとめさえすれば、30点以上のアイテムを出品することも可能。 自身で出品する場合、アイテムの撮影の仕方によって見え方が異なり、商品価値を下げる場合もあることや、手間だったりするので代行して撮影して出品してくれるサービスはとてもいいと思いました。 7. ClosetSpace   ClosetSpaceはそれぞれのユーザーに合わせたコーディネートを、毎日提案してくれるファッションアプリです。主な特徴は 天気、気温、シチュエーションを細かく絞り込む ことができます。天気だけでのコーディネート提案はありますが、天気とシチュエーションで絞り込みができるのは、ユーザーごとでライフスタイルに違いがあるところで、それぞれのニーズにうまく応えられているコンテンツだと感じました。  最後に VASILYデザイナーチームがインスピレーションを受けたファッションアプリまとめはいかがでしたでしょうか。 iQONのUI、UXデザインをもっとよくしたい!デザインによってユーザーの課題を解決したい!というデザイナーの方々、絶賛募集中です! ご応募お待ちしております。 https://www.wantedly.com/projects/5485 連絡先:info@vasily.jp  
アバター
Functional Ruby
Modern Ruby: Functional Ghost in an imperative shell Ruby is a language designed in the following steps: take a simple lisp language (like one prior to CL). remove macros, s-expression. add simple object system (much simpler than CLOS). add blocks, inspired by higher order functions. add methods found in Smalltalk. add functionality found in Perl (in OO way). So, Ruby was a Lisp originally, in theory. Let's call it MatzLisp from now on. ;-) matz. Buzzwords such as "Functional Programming", "Curried Functions", "Partial Function Application" and "Lazy Evaluation" have been filling forms and tech blogs, mostly in a pure academic sense and also spoken about in the realm of purely functional languages. It turns out that ruby has its roots in functional programming, even blocks one of the most prominent features of ruby comes from higher order functions. Functional programming ideas can be implemented and exercised in non purely functional languages to produce better testable, readable and less error prone code. Purely functional languages don't own these ideas but merely borrow from them, they belong partially to lambda calculus a branch of mathematics. What ideas can be taken away from the realm of purely functional languages? As far as I know a consensus as to what functional programming is has not been reached in as strong a way that object oriented programming is defined by: Inheritance Encapsulation Objects may carry both state and behaviour Functional Programming has the qualities of: Immutability & Stateless Functions - No Surprises! Once a variable is defined its state may never change. (i.e only named constants, not variables) A function provided the same input will always produce the same output, no internal function state is allowed to change between calls. (The desired effect of having immutable variables.) Higher Order Functions - Functions in Functions out. Functions take functions as input and return new functions return as output. Partially applied functions: Lazy Evaluation - ...should really be called Programatic Procrastination. Values are calculated only when needed and not before. State v.s No State [ruby] #A function that carries external state def numberUniq!(inptLst) return inptLst.uniq!.length end #Stateless Implementation def numberUniq(inptLst) input = inptLst.dup.freeze return input.uniq.length end inputList = [1,1,1,2,3,3,3,3] puts "Input Before Execution:#{inputList}\n Function Output:#{numberUniq!(inputList)} Input After Execution:#{inputList}" puts "Input Before Execution:#{inputList}\n Function Output:#{numberUniq(inputList)} Input After Execution:#{inputList}" [/ruby] Analysis After running the above program the output was as follows: Input Before Execution:[1, 1, 1, 2, 3, 3, 3, 3] Function Output:3 Input After Execution:[1, 2, 3] Input Before Execution:[1, 1, 1, 2, 3, 3, 3, 3] Function Output:3 Input After Execution:[1, 1, 1, 2, 3, 3, 3, 3] In imperative programming there is no contract between the compiler and the author of the software about ensuring the output of a function will always be the same for the same input. If we call "numberUniq!" in conjunction with other functions that operate on the same array as input it can easily be seen that interference may easily occur. In the second implementation we can guarantee immutability by first making a duplicate and then calling freeze to virtually turn the value into a constant. By calling these two functions we can promise to the caller of the function that A: The function will not modify the input(.dup) and B: The same data passed to this function for N times will return the same result N times (.freeze). Higher Order Functions - Ground Zero Basics The concept of higher order functions is just as easy to grasp as functions that work on scalars and lists. First before getting into the discussion of what currying and partial function application are and how we can put them to work in everyday production code, lets get a mathematical definition of exactly what a function is. "A function f takes an input x, and returns a single output f(x). One metaphor describes the function as a "machine" or "black box" that for each input returns a corresponding output." - Wikipedia So the two requirements are that in order to be a function it must not only accept input but always return some form of output otherwise it is only a procedure or a block instructions. Currying and partial function application The process of currying is very simple, instead of one function that takes N arguments, a curried function is a series of N functions that take one argument each. For example if we define a function 'f' to be a function that takes four arguments and returns their sum: f (x, y, z, w) = x + y + z + w we define a function f{x,y,z,w} = f{ x + g {y + h{z + i {w}} } } In reality the curried function runs considerably slower compared to its simpler one dimensional implementation that takes N arguments since we now have four times the overhead of calling the function, but there is great merit to this approach. By writing our functions this way it allows us to reuse the curried definition of the function to easily define new variations (partial application) and for testing purposes we now have four smaller functions we can write tests for rather than one large function we need to cover. Partial Application of functions Say we wanted to write a function that multiplies a variable x by a constant K. We could write: [ruby] def mul8(x) x * 8 end [/ruby] But what if we wanted to define a bunch of functions like this? Do we need to formally write the definition each time? Partial function application to the rescue! [ruby] mulXY = lambda{|x,y| x * y} curriedMulXY = mulXY.curry 25 == curriedMulXY.(5).(5) #true mul3Y = curriedMulXY.(3) #returns Partially Applied Function equivalent to lambda{|y| 3 * y} mul9Y = curriedMulXY.(9) #returns Partially Applied Function equivalent to lambda{|y| 9 * y} [/ruby] This use of Proc#curry is more or less syntactic sugar that can be used in place of writing mulXY manually as: [ruby] def mulXY(x) Proc.new do |y| x * y end end [/ruby] The key idea to take away here is that inside the body of the proc we define x's value is fixed to whatever we initially passed in, so from a functional perspective calling mulXY(3) is nearly identical to writing the following proc directly: [ruby] Proc.new do |y| 3 * y end [/ruby] As you can see partial function application is really just another way to view writing closures and the process of currying simply transforms a single function that takes N parameters to N functions that take one parameter each successively calling the next. If a curried function is called with all of the parameters that it takes passed in, then the normal output of the function is returned. If that same curried function taking N values as input is called with less than N values the returned result is a function with its behaviour partially defined. Why hasn't Currying been adapted yet despite having been introduced since the release of Ruby 1.9? There are a few opinions as to why curried functions in ruby are still not in widespread use but after using Proc#curry it may appear a little obvious. Currying is an after thought, an addition to Proc that got merged into trunk later. You have to take a Proc and then run .curry on it which means a curried state is not a natural state for functions to exist in. Currying most likely isn't in production code for the main reason still being a non-standard way of doing things that many rubyists haven't touched yet for fear of being called out for splitting from the herd. I personally think this is a bad reason not to apply currying where it makes sense and hope this little article is enough to spark your interest. If you want to write ruby with our team please contact: info@vasily.jp WE ARE HIRING!! Till Next time, Nick
アバター
前回の記事 で、アプリデザイン効率化のためのツールのご紹介をさせていただきましたが、VASILYではその他にも Keynoteによるプロトタイピング を取り入れています。 プロトタイピングを効率的に進めるにあたって、どの段階でどのツールを取り入れるかはとても重要な判断になってきます。 Keynoteによるプロトタイピングは導入コストが低いこともあり、話題にあがっているひとつでもあるので試してみたところ、やはりメリットデメリットはありますが、取り入れる段階によってはとても効率的なツールの一つでした。 今回は、実際VASILYではKeynoteによるプロトタイピングを どういう過程で取り入れてみたか を(失敗も含めて...)ご紹介をしたいと思います。 1.企画段階はペーパープロトタイピングから まずはじめにVASILYではどのように進めているかというと、 アプリの改善を進める場合以下のような段階に分かれます。 デザイナーは要件定義の段階から加わって、KPIの設定や要素の洗い出しもエンジニアやハスラーとともに進めていき、プロジェクトメンバー内の共通意識や方向性にズレが無いように プロトタイピングによるアウトプットで可視化 していきます。 要件定義→アイディア拡散&収束→設計まではとにかくスピード重視で素早く回していくので、ペーパープロトタイピングでの簡単なラフから始まり、要素や遷移、使用感などを確認するときは Invision などのツールを使っています。 2.設計から実装依頼までのコミュニケーション 問題は、その先の 設計から実装までのコミュニケーションをどううまく回していくか が、デザイナーにとっての一番の肝です。 ペーパープロトタイピングだけではなく実際にビジュアルに起こし、意図やニュアンス、動きを表現し伝えていかなければなりません。 Keynoteによるプロトタイピングを取り入れることで、エンジニアやテストユーザー、プロジェクトメンバー全員が、より分かりやすい形で、企画やデザインの意図を理解してもらえるのではと思い立ったのがきっかけで、まず以下のようなかたちで実際に取り入れてみました。 3.Keynoteを3つのフェーズでとりいれてみた ①設計フェーズ:全体の流れを把握してもらうためメンバーに共有する(対 プロジェクトメンバー) -状況 チュートリアルの改善プロジェクト。ペーパープロトだけでなく、伝わりづらい部分もあるのでKeynoteを使って全体の流れや動きを共有したい -作成したプロトタイピング -結果 × Keynoteでは端末でのインタラクションは適用されず、決められた動きしか見せることが出来ません。手描きラフで別途遷移の説明が必要になるほどの伝わりづらさだったので、設計フェーズでのKeynoteプロトタイピングの導入はあまり効果的とは言えませんでした。 このフェーズだと、メンバーからフィードバックをいただき、更なる修正も加わる場合が多いので、ことさらペーパープロトタイピングでスピード感もって回していく方が最適だと思われます。   ②ユーザーヒアリングフェーズ:テストユーザーに実際の動きや流れを見てもらう(対 テストユーザー) -状況 同じくチュートリアルの改善プロジェクト。実際に使ってもらうユーザーなので、よりニュアンスの伝わるもので試してもらいたい -作成したプロトタイピングは①と同様 -結果 △ 実際の端末で確認が出来て、より明確な指摘をもらえたことに対しては○と言えますが、やはり②と同様、決められた動きしか見せられないことや、説明を交えながら何度も繰り返し見てもらわないと状況が把握できずで、テストユーザーにとってかなりのストレスであったと言えます。 テストユーザーに触ってもらうには、ビジュアルを作成しInvisionで遷移確認のためのモックを作成するか、インタラクション型プロトタイプをつくれる Pixate や Framer などの方が完成度高いので、より良質なフィードバックをもらえると思います。(後者はデザイナーにとってはかなり習得コストかかりますが...)   ③実装フェーズ:画面スクロール時のアニメーションをエンジニアに伝える -状況 ある画面のデザインは完成したが、複雑な動きが存在するのでエンジニアにアニメーション実装を依頼したい -作成したプロトタイピング -結果 ○ 今までは、デザイナーが「スクロール時にユーザー情報がウィーンって左上に縮小して、タブもある一定の場所でFIXしつつ、タブ以下の情報はスルスル潜り込みながらスクロールしていく」というような擬態語で表現したり、類似したアプリを参考に身振り手振り伝えても伝わりきれなかった動きが、一瞬でエンジニアに理解してもらえました。 デザイナーもエンジニアにとっても完成図を共有しやすく意図が伝わりやすいので、普段の指示書とデザインデータにプラスして少しのひと手間加えてあげることで、実装スピードが一段と上がります。   まとめ 今回は、Keynoteプロトタイピングの効率的な取り入れ方を、事例を含めて紹介しました。 まとめると、 ①Keynoteプロトタイピングが一番活躍するのは実装フェーズ ②一定の動きしか見せられないので、遷移や使用感をテストするには不向き ③ペーパープロト+Keynoteプロトのセットでよりスピード感ある開発を実現できる という結果になり、開発の最終段階でコミュニケーションを円滑にする一つの手段として取り入れるにはとてもおすすめのツールでした。 ツールが色々あるのは知っているけれども、実際取り入れてみるとなるとどこでどう使ったら良いのかと模索状態でしたが、失敗することで課題も見えて次に試す術が見つかるので、様々なツールを試す価値は存分にあると思います。 デザイナーの役割によって、アプリ開発でのスピードは段違いに変わるので、もちろん個々人の経験やコミュニケーション力、知識力の差で変わることもありますが、その差を補うためにも ツールを積極的に取り入れていくことはデザイナーとしての成長を加速させる一つ になります。 VASILYでもまだまだ模索段階なので、一緒により良い開発の進め方を研究していける方を募集していますので、以下よりご応募お待ちしております。 https://www.wantedly.com/projects/5485 連絡先:info at vasily.jp
アバター
VASILYでインターンをしている茨木です。 3月9日に発表されたGoogle Chromeの最新ベータ版v42.0.2311.22でPush APIがサポートされニュースになりました。ブラウザからスマホにプッシュ通知が送れるというものです。 スマホ向けウェブサービスをやっている方ならみんな気になるこの機能、早速試してみました。かなりシンプルなので皆さんもぜひ触ってみてください。 以下のサンプルやサイトを参考にしました。 サイト http://updates.html5rocks.com/2015/03/push-notificatons-on-the-open-web サンプルプログラム https://github.com/GoogleChrome/samples/tree/gh-pages/push-messaging-and-notifications 実行環境 Windows8.1 (64bit) Google Chrome 43.0.2327.5 dev-m (64-bit) 必要なもの SSLサーバー(github.ioなど) バージョン42以上のGoogle Chrome (私は http://getgooglechromeoffline.net/tag/google-chrome-42-download/ から入手しました) 導入手順 Google Developer Consoleでのプロジェクトの作成 今回のサンプルではPush通知にGoogleのAPIであるGCM(Google Cloud Messaging)を使うので、まずGoogle Developer Console ( https://console.developers.google.com/project )でプロジェクトを作成します。画面にある「プロジェクト作成」をクリックするとモーダルウィンドウが出てくるので、「プロジェクト名」に好きなプロジェクト名を入力、「~利用規約を~同意」にチェックをしてください。プロジェクトIDはそのままで結構です。入力後、「作成」クリックするとプロジェクトが作成されます。 プロジェクトを作成すると画面上部にプロジェクトIDとプロジェクト番号が表示されます。今回使うのは「プロジェクト番号」ですので、これをメモしておきます。 APIのkeyの作成 左のメニューで「APIと認証」→「API」と選択します。そうするとAPIの一覧が出てくるので、「Google Cloud Messaging for Android」と「Google Cloud Messaging for Chrome」をONにします。 次に左のメニューで「APIと認証」→「認証情報」と選択し、「新しいキーを作成」をクリックしてください。モーダルウィンドウが出てきたら「サーバー キー」を選択します(間違えると動かないので注意してください)。 次に、許可対象IPアドレスを入力するテキストボックスが出てきますが、入力しなくても大丈夫です。モーダルウィンドウ下の「作成」をクリックすると、keyが生成されます。 Keyを生成すると表が出てくるので、その中の「APIキー」をメモしておきます。 サンプルプログラムの設定 アップロード サンプルプログラムは先ほど取得した「プロジェクト番号」と「APIキー」を設定するだけで動かすことができます。 main.jsの3行目の <YOUR API KEY> にメモしたAPIキーを入力します。 'use strict' ; var API_KEY = '<YOUR API KEY>' ; var curlCommandDiv = document .querySelector( '.js-curl-command' ); var isPushEnabled = false ; manifest.jsonの10行目の <YOUR PROJECT NUMBER> にメモしたプロジェクト番号を入力します。 設定が終了したら、用意したSSLサーバー(github.ioなど)に https://github.com/GoogleChrome/samples/tree/gh-pages/push-messaging-and-notifications 内のファイルをアップロードします。 プッシュ通知を登録 index.htmlにアクセスすると、問題なければ「Enable Push Messages」ボタンが有効になっており、これをクリックすると「cURL Command to Send Push」の下にコマンドが出てきます。これがPush通知のPOST送信用のコマンドになるのでコピーしておきます。結構長いですが、これで一つのコマンドです。上手く行かない場合は、ブラウザのバージョンを確認してください。 コピーしたコマンドをコマンドラインに貼り付け、実行します。成功した場合には { "multicast_id" :<数字>, "success" :1, "failure" :0, "canonical_ids" :0, "results" : [{ "message_id" : "<数字>" }]} と表示され右下にプッシュ通知が表示されます。 Androidの場合も、端末のChromeから同様の手順でコマンドを取得するところまで行ってください。それから取得したコマンドをPCに移して実行することでPush通知を実現できます。Androidの場合もやはりGoogle Chromeのバージョンは42以降が必要ですので、注意して下さい。 簡単な説明 main.jsはロード時、serviceWorker.registerでサーバー上のservice-worker.jsをService Workerとして登録します。そして、ボタンが押された場合に関数subscribe内のserviceWorkerRegistration.pushManager.subscribe()でsubscriptionの登録を行い、そのsubscriptionとAPI Keyを用いてcURLのコマンドを生成しています。 あとは、サーバー上でcURLを実行してpushサーバにPOST送信することで、登録を行った端末にPush通知が送られます。 問題点 現状ではPOST送信する側からメッセージなどのデータを送れず、service-worker.js内に予め書いたstaticなメッセージしか通知できません。仕様にはデータの送信も含まれているので、今後の実装が期待されます。 Google Cloud Messaging for Chromeは個人の場合10000リクエスト/日の制限があります。 備考 このサンプルではindex.htmlでAPIkeyの設定が必要ですが、それはコマンドの生成の為であり、クライアントサイドへのAPIkeyの記述は本来不要です subscriptionIdは署名が行われる毎(「Enable Push Messages」のクリック毎)に発行されます。当然クライアントごとに異なります。 サーバーサイドでservice-worker.jsを書き換えても、クライアントサイドのservice-worker.jsにはすぐには反映されません。ですので、service-worker.js を書き換えてメッセージを更新、といった使い方は難しいです。 VASILYではインターン生を募集しています。 ちょっとでも気になった方は是非一度来てみてください! https://fresh2016.vasily.jp/
アバター
はじめに iQONではアニメーションなどのアプリとしての演出の部分にこだわりを持っています。 突然ですが皆さんiQONでコーディネート画像をタップしたことはありますか? 実際のアニメーションの動き こんな感じでコーディネートに含まれる商品がバラバラと広がって行くアニメーションを実装しています。 今回はこのアニメーションの裏側をAndroidアプリでの実装を例に少しご紹介させて頂きたいと思います。 まだこの動きを見たことがない方はダウンロードして確認してみてくださいね! iOSアプリ Androidアプリ 仕組みの概要 構成 一枚の画像が分解されて商品(以下アイテムと表現します)画像に分解されているように見えますが、実は少し違います。 最初にユーザの目に入るコーディネートのサムネイルは一枚のImageViewで実装していますが、その下に分解後の各アイテム画像のImageViewを含むRelativeLayoutが用意されていて、その中で各アイテムのImageViewがアニメーションするという構成になっています。   ユーザの操作と分解の動作 ユーザがどんな操作をして、分解が動作して行くかをもう少し細かくみてみましょう。 1.コーディネートのサムネイルをタップ 2.コーディネートのサムネイルをGONE 3.下のRelativeLayout内でアイテム画像のImageViewがアニメーション開始 4.分解後に☓ボタンを押して元に戻す 5.元の位置に戻るアニメーション開始 6.アニメーション完了後コーディネートのサムネイルをVISIBLE ユーザがタップする度にこの1〜6を繰り返して分解したり、もとに戻したりしています 実装の紹介 ではもう少し具体的な実装の内側を大きく2つのステップに分けて紹介していきたいと思います。 1. 初期配置とバラバラにする時の移動先の決定 2. バラバラにするアニメーションと元に戻るアニメーション 初期配置とバラバラにした時の移動先の決定 コーディネートのサムネイルがユーザに見えている時には、以下のようなアイテムの配置情報(layout)をサーバから取得して、コーディネートのサムネイルと同じ位置関係でアイテムのImageViewが配置されています。 余談ですが、もちろんコーディネートのサムネイルもこのlayout情報をもとにサーバサイドで生成され、画像サーバにアップロードされています。 layouts:[ { item_id: 4249463,// アイテムID index: 1,// Z-index x: 1.0356848767906093,// X座標 y: 0.9997999119799084,// Y座標 width: 238,// 横幅のサイズ height: 194,// 縦幅のサイズ }, { item_id: 4249463, index: 2, x: 240.99108292274144, y: 0, width: 238, height: 194, },... ] サーバから上記のような情報を取得して各アイテム画像のImageViewを配置する時点で、アニメーションで移動する先も決定しています。 コーディネートのサムネイルと同じサイズの正方形を4×4に分割したセルが移動先だと思ってもらえれば大丈夫です。 移動先のイメージは以下のような感じです。   コードの一部を紹介すると以下のような感じになります。 class SplitItem { private ImageView imageView; private String itemId; private int index; // 移動する前の位置とサイズ private float orgWidth, orgHeight; private float orgX, orgY; // 移動先の位置とサイズ private float dstWidth, dstHeight; private float dstX, dstY; public SplitItem(JSONObject layout) { itemId = layout.getString("item_id"); orgWidth = layout.getDouble("width"); orgHeight = layout.getDouble("height"); orgX = layout.getDouble("x"); orgY = layout.getDouble("y"); index = layout.getInt("index"); // 移動先の情報を算出 initDstData(); } // 移動先の情報を算出するメソッド private void initDstData() { // 4*4のセルに分割した時の移動先のサイズと座標を算出 int cellLength = thumbnailWidth / 4; int xIndex = index % 4; int yIndex = index / 4; float sizeRatio; if (orgHeight > orgWidth) { sizeRatio = cellLength / orgHeight; dstHeight = cellLength; dstWidth = orgWidth * sizeRatio; } else { sizeRatio = cellLength / orgWidth; dstHeight = orgHeight * sizeRatio; dstWidth = cellLength; } dstX = cellLength * xIndex + (cellLength - dstWidth) / 2; dstY = cellLength * yIndex + (cellLength - dstHeight) / 2; } public void open() { // 初期位置から移動先の位置にアニメーションする処理(後述) } public void open() { // 移動先の位置から初期位置にアニメーションする処理(後述) } } バラバラにするアニメーションと元に戻るアニメーション 初期配置情報とアニメーションで動く先が決まったので、実際にコーディネートの画像をバラバラにするアニメーションを紹介していきます。 private ArrayList items; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); items = new ArrayList (); // サーバから返却されるJSONのlayoutsから各アイテムを初期化する処理 JSONArray layouts = coordinate.getLayoutJSONArray(); for (int i = 0; i < layouts.length(); i++) { JSONObject layout = layouts.getJSONObject(i); SplitItem splitItem = new SplitItem(layout); items.add(splitItem); } // 省略 // サムネイルのタップイベントの設定 thumbnailImageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { v.setVisiblity(View.GONE); for (SplitItem item : items) { item.open(); // 各アイテムを移動先へアニメーションする } } }); // 一度バラバラに移動したアイテム画像を元に戻すボタン closeButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { for (SplitItem item : items) { item.close(); //各アイテムを移動元へアニメーションする } } }); } バラバラにするアニメーション class SplitItem { // open時のアニメーションの実行 public void open() { PropertyValuesHolder holderX = PropertyValuesHolder.ofFloat("translationX", 0f, dstX - orgX); PropertyValuesHolder holderY = PropertyValuesHolder.ofFloat("translationY", 0f, dstY - orgY); PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1f, dstWidth / orgWidth); PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1f, dstHeight / orgHeight); ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(imageView, holderX, holderY, scaleX, scaleY); objectAnimator.setInterpolator(new DecelerateInterpolator()); objectAnimator.setDuration(duration); objectAnimator.start(); } } 上記のようにObjectAnnimatorを使って、移動先のセルに向かってサイズを変えながら移動するというアニメーションを実装しています。 元に戻る時のアニメーション 移動した後に☓ボタンを押せば元の位置に戻ります。もとに戻るときのコードもご紹介します。 class SplitItem { // close時のアニメーションの実行 public void close() { PropertyValuesHolder holderX = PropertyValuesHolder.ofFloat("translationX", dstX - orgX, 0f); PropertyValuesHolder holderY = PropertyValuesHolder.ofFloat("translationY", dstY - orgY, 0f); PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", dstWidth / orgWidth, 1f); PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", dstWidth / orgWidth, 1f); ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(imageView, holderX, holderY, scaleX, scaleY); objectAnimator.setDuration(duration); objectAnimator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { // コーディネートのサムネイルを表示VisiblityをVISIBLEにする処理(今回は省略) } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); objectAnimator.start(); } } 先ほどのopenメソッドとは反対の処理ですが、ポイントはAnimationListenerのonAnimationEndの部分です。今回は省略しますがアニメーションが終了したらGONEにしていたサムネイルのvisiblityをVISIBLEにもどして最初にユーザ見ていた状態に戻す処理を実装しています まとめ 配置情報の管理はチームで協力 この機能の肝とも言える部分ですが、ユーザが作ってくれたコーディネートをどんなフォーマットでデータ管理するかをバックエンドチームと協力してDBで管理しています。 アニメーションの処理自体はそこまで複雑ではない ご紹介したとおり配置情報の仕樣さえしっかりチームで共有できてれば、アニメーションの処理自体はそこまで複雑ではありません 実際に大変なところ 今回はかなり省略しましたが、実際には画像をネットワーク越しに取得してImageViewに設定しなければなりません。 そうなるとListViewなどで同じ表現を実装する場合、スクロールをスムーズにしてもらうためにはアイテム一つ一つの画像の処理を相当工夫する必要があります。(1つのコーディネートにつきアイテムが約15個あるため全部、その都度素直に処理してしまうと高速にスクロールされると大変なことになります) このあたりぜひ聞いてみたいという方いらっしゃいましたら気軽にオフィスに遊びにきてください。 大変だった点、この機能の誕生の裏話などたくさんご用意してお待ちしております。 最後に ユーザがつい押したくなってしまうような表現を求めてアプリ、バックエンドに関わらずチームで実装の壁を超えて日々挑戦しております。 アイデアをどんどん形にしてユーザに届けたい方、ユーザにワクワクしてもらえるようなアプリを一緒に作りましょう。 興味のある方はこちらでお待ちしております! https://www.wantedly.com/projects/7595  
アバター
プロダクト開発においてスピードも重視するVASILYでは、 効率的・効果的に デザインを行えるよう様々なツールを活用しています。 今回は、これまで使ってきた中で オススメのアプリやサービス をいくつかご紹介したいと思います。 プロトタイピングをつくる アプリ制作は、 - どこからどこへ遷移するのか - どのようなアクション・アニメーションで遷移するのか など、実際に動いているものを検討してみないとわからないケースが多いものです。 実装後、「やっぱこれって変じゃない?」とならないためにも、VASILYでは プロトタイピングでの確認・検討を必ず行う ようにしています。    POP https://popapp.in/jp/ [iPhone / Android] ※2015年3月12日現在 POP(Prototyping on Paper)という名前からもわかる通り、 ペーパープロトタイピング に特化したアプリです。紙に書いた手書きワイヤーを「スマホで撮影」「リンクを設定」するだけで、画面遷移をするモックが簡単につくれます。 プロト制作に必要な最低限の機能で構成されているので、 アプリデザインの初期段階 や、 はじめてペーパープロトに挑戦したい方 、 ノンデザイナーの方 にもオススメです。   Prott   https://prottapp.com/ja/ [iPhone] ※2015年3月12日現在 基本機能はPOPと同じですが、 機能やUIをさらにリッチ にしたアプリです。 リンクや画面遷移の指定がより簡単で直感的に行え、アクションやアニメーションの種類もPOPよりやや豊富。プレビューの際にステータスバーの色が変えられるのも、かゆいところに手が届いている感じでグッドです。 また、Slackとの連携も可能なので、社内でSlackを導入している場合はより効率的な開発が可能になるかと思います。 ただ、2プロジェクト以上つくる場合は有料版への登録が必要なので、 ノンデザイナー含め複数人でプロトタイプを制作 したり、Slackなど 外部サービスとも連携させたい 場合にオススメです。    InVision http://www.invisionapp.com/ [iPhone / Android] ※2015年3月12日現在 ペーパープロトからちょっと進んで「 ラフデザインで動きも確認したい 」というときには、InVisionがオススメです。 POPやProttと同様のプロト制作機能を備えつつ、 縦スクロール可能なモックもつくれる ため、 より実際の使用感を意識したプロトタイプ がつくれます。もちろん、ペーパープロトをつくるだけでもまったく問題はありません。 ペーパープロト〜ラフデザインという 幅広い制作段階で使用できる ことから、VASILYデザインチームではInVisionでのプロトタイプ制作を積極的に取り入れています。     デザインを手軽に実機で確認する 実際のデザイン制作を進めていくと、マージンや文字の可読性など、どうしてもスマホで実機確認をしたくなる場面がやってきます。 画像を書き出してメールに送ったり、あるいはサーバにアップしたりと、スマホでデザインを確認するのはなかなか大変な作業です。 そんなときは、Macの画面をiPhone上に リアルタイムプレビュー してくれるアプリがオススメです。   Skala Preview http://bjango.com/mac/skalapreview/ [iPhone / Android] ※2015年3月12日現在 まずは、MacとiPhoneの両方に専用アプリをダウンロード。同じLAN内に接続することで、 PhotoshopのキャンバスをリアルタイムにiPhone上で見る ことができます。 もちろん修正もリアルタイムで反映されるため、細かな微調整を実機で確認しながら行えます。 都度書き出して、サーバにアップして、実機で確認…というわずらわしさをカットできるので、作業効率がぐっと上がります。   Live View [iPhone] ※2015年3月12日現在 Skala PreviewがPhotoshopとのリアルタイムリンクなのに対し、Live Viewは PCに表示されている画面ならどこでもリンク させることが可能です。 デザインはIllustratorじゃなきゃ。という方にはこちらのアプリがオススメです。   アプリのモーションを録画する デザインをするにあたり、みなさんも参考になりそうなアプリを日々キャッチアップしているかと思います。このメニューの表示の仕方が素敵だなとか、スクロール時のぬるぬるした動きが気持ち良いなとか。素敵な表現はぜひとも参考にしたいですよね。 とはいえ、アプリの細かな動きを言葉で表現するのはなかなか難しいものです。そんなときは、 実際にモーションを録画 してしまうほうが早いかもしれません。    Reflector [iPhone] ※2015年3月12日現在 まずはMacにReflectorをインストールし、iPhoneをAirPlayでミラーリング。すると、iPhoneで表示されている画面が、Macでも同時に見えるようになります。iPhone内の動きや音もきちんと同期されるので、 Mac上でリアルタイムに録画 することが可能になります。 動画はMP4形式で保存されるので、チーム内で情報共有をしたい場合はもちろん、Evernoteに蓄積して自分専用のモーション・アーカイブをつくるのもオススメです。    Telecine https://play.google.com/store/apps/details?id=com.jakewharton.telecine [Android] ※2015年3月12日現在 Androidアプリのモーションを録画したいという場合には、Telecineがオススメです。 ReflectorのようにPCをミラーリングデバイスとして使用する必要がなく、 録画・保存までAndroid内で手軽に行える ことが大きなポイントです。 ただし、Android 5.0以上でないと使えないのでご注意ください。   最後に 以上、VASILYデザイナーチームが選ぶ、アプリデザインを効率的に行うためのツール紹介でした。 VASILYではこのようなツールを最大限に活用し、 スピーディなプロダクト開発に貢献してくれるデザイナー を絶賛募集中です! https://www.wantedly.com/projects/5485 連絡先:info[at]vasily.jp  
アバター
VASILYでは、より良いアウトプットをするためにも デザインインプットの時間を週1回設けています。 画面遷移であったり、ちょっとしたアニメーションなど優れたUIをチームで共有し、 実際にiQONのUIやUXという部分に反映しようと日々、試行錯誤しております。 今回はその中で、VASILYデザイナーチームが2月に デザインインスピレーションを受けたアプリ をいくつかご紹介したいと思います。 1. Spring Apple Design Award 2014にも選ばれている、NY発の新コマースファッションアプリ。 ユーザ発信のコンテンツをブランドが上手く活用する という手法を取り入れています。 買い物本来の楽しさを味わってもらえるよう、あえてシンプルな構成 にしているそうで、全体的に 繊細で上品なアプリ というイメージを受けました。 2. Storehouse 写真、映像、テキストを織り交ぜながら1つのストーリーを作ることができます。 自由にレイアウトやトリミング可能なため様々な見せ方が可能です。 CEOが元AppleのUXエバンジェリスト ということもあり、公開されているストーリーは、どれも美しく、 思わず自分も投稿したくなるのがこのアプリの魅力 です。 また、ローディングアイコンの見せ方もきちんとデザインされていました。 Storehouseは Apple Design Award 2014 にも選ばれているアプリ でもあります。    3. Nat Geo View National Geographicが新しくリリースしたダイジェストアプリです。 曜日ごとに厳選されたNational Geographicの高画質な写真や映像を紹介してくれます。 厳選されているということもあり、見入ってしまう作品ばかりで、スクロールしたときの パララックス感や、フォント選び、マージンの取り方などとても参考になります。 また、動画のサムネイルの見せ方もただの静止画ではなく、 キャプチャー画像をアニメーションで見せ、再生しなくても映像の内容が楽しめる という部分は他のアプリではあまりない手法だと感じました。   4. YPlan 直近にある楽しそうなイベントを紹介してくれるアプリ。気になるイベントがあれば詳細情報を見ることができ、その場でチケットも購入可能。 デザインは 操作系のボタンまでアニメーションを使用 していたり、アクションシートまでもきちんとデザインされていて細かい部分のデザインにもこだわりを感じるアプリでした。 5. Timeline 歴史をたどることでコンテクスト(文脈)がわかるニュースアプリで、さまざまなジャンルのニュースを年表でたどっていけるのが特徴です。 最近目にするカード形式のデザインを採用しているアプリ でもあります。また、ローディングアイコンのアニメーションや、 コンテンツ間の切り替わりなどなめらかで使っていて心地よいと思うアプリ でした。   6. August  音楽、写真、動画、テキスト、などをシェアできるアプリです。 プルダウンで簡単に自分のお気に入りにストックすることができるUIが特徴 です。また、ユーザー画面をスクロールした際に背景画像がただ上に流れて消えるのではなく、奥に沈んでいくようなフェードアウトをしていて少し変わった表現でした。 7. Vurb    コンテキスト型検索エンジンアプリ。検索した情報が、検索エンジンを離れることなく見ることができます。検索カテゴリは、「場所、映画、テレビ、音楽、映像、イベント」などに大きく分かれいて、映画のカテゴリを選択すると、「公開中、近日公開予定、オンラインで観れるものなど条件を絞ることが可能です。映画の詳細画面に入ると、予告編、上映時間、レビューなども見ることができます。 また、 写真を全面に使用しながらカード形式のデザインを取り入れているのが特徴 です。iQONもカード形式のデザインのため、 カードごとでどのように情報が分けられているかなど参考になるアプリ でした。   8. FastCompany   米国ビジネス誌「Fast Company」のコンテンツアプリ。 FastCompanyが提供するwebサイトのコンテンツをすべて閲覧することができます。 コンテンツ間の動きがなめらか で、コンテンツを移動していてもストレスなく見続けられると感じました。またレイアウトでは写真に見出しがかかっていたり、 カテゴリを大胆にデザインして区切っていることなども他のアプリにはあまりみられない点だと感じました。 また、コンテンツの最後にいくと次のコンテンツの見出しと写真があり、 次のコンテンツに遷移したくなる仕掛けがされているデザイン でした。 最後に VASILYデザイナーチームがデザインインスピレーションを受けたアプリまとめ(2015年2月)はいかがでしたでしょうか。 ご紹介したアプリのように iQONのUI、UXデザインをもっとよくしたい!というデザイナーの方々、絶賛募集中です! ご応募お待ちしております。 https://www.wantedly.com/projects/5485 連絡先:info[at]vasily.jp  
アバター
  「iQON AD」 VASILYでは2014年10月から、インフィード型ネイティブ広告「iQON AD」をiQONのiOSとAndroidアプリ、スマートフォンサイトに向けて配信しています。 国内最大級のファッションアプリ「iQON」、 女性向けネイティブ広告「iQON AD」を開始。 「iQON AD」は、iQON内に配置された独自広告ユニットに対して広告を配信できるサービスになります。本プロジェクトでの開発要素は主に以下の3つです。 1. ネイティブアプリ内の広告ユニット(SDK) 2. 広告管理ツール 3. アドサーバー サービスインしてから少し間があいてしまいましたが、広告配信システムについて簡単に紹介したいと思います。 「iQON AD」のシステム構成 広告管理ツールとアドサーバーはともにRubyで書いており、ミドルウェアも含めてすべてAWS上で運用しています。 広告管理ツール 広告の入稿、レポートの閲覧、配信データの生成と配信ログを使った集計などを行います。社内外の限られたユーザーが利用するシステムです。 Ruby2.0 + Rails4.0で書いています。 ツールから入稿される広告データはRDS(MySQL5.6)に貯めて、広告配信に必要な形に変換してRedisへと同期します。アドサーバーからS3に蓄積される各種計測ログを定期的に集計して、これもRDSに貯めます。広告の画像はS3にあげて、CloudFrontから配信しています。 アドサーバー 主に広告配信と各種イベントの計測を担当します。HTTPリクエストに対してJSONを返すWebAPIです。 コアとなるEC2インスタンスではSinatraベースのWebアプリケーションをunicornに載せ、unixドメインソケットでnginxとつないでいます。広告データはRedisから取得し、各種計測イベントは同じインスタンス内にあるfluentdを経由して集約用のfluentdからS3に蓄積。memcachedには消えてもクリティカルにはならないもの(かつ配信には必要なもの)を入れています。アドサーバーでは基本的に静的コンテンツ配信は行っていません。 配信ロジックを最適化しつつ高いスループットを確保することが要件であるため、Railsのような高機能はフレームワークは使わずRuby2.0 + Sinatra1.4で書いています。 アドサーバーの処理性能 ピークタイムでサーバー1台あたり30リクエスト/秒くらいの広告リクエストを受けていて、それを平均30~40msec程度で処理しています。 各種計測イベントなども受け付けるので、それも含めると実際にはもう少し多いリクエストを処理することになります。 広告配信の規模としても(一般的なアドネットワーク等と比べると)それほど大きいわけではないので、今のところ必要十分な性能となっています。 Ruby2.0? 現在のRubyの最新版は2.2なのに2.0を使っている理由はいくつかありますが、時間的制約が主な理由です。 プロジェクトの初期開発期間が非常に限られていたため、既存プロジェクトで運用実績のあるものを使うことでインフラ構築コストや未経験による運用リスクは最小限に抑えつつ、時間の大半をアプリケーション開発に最大限あてることでひと通りの機能を揃えることを優先しました。(VASILYではインフラ構築にはAMI+Chefを使っています) Rubyのコードについてもあまり凝ったことはせずにわりと愚直に書いてあります。そのため、設計やパフォーマンスにもまだまだ改善の余地はあります。Ruby2.1以後GCまわりの改善によってパフォーマンスを改善できそうですし、今後はRubyバージョンアップも含めて色々と改善を図っていく予定です。何かしら成果があった時にはまた本ブログで紹介したいと思います。 以上、iQONの広告配信システム構築の紹介でした。 VASILYでは、広告配信システム開発だけに限らずエンジニアを募集しています。 https://www.wantedly.com/projects/7595 連絡先:info[at]vasily.jp
アバター
  社内にデザイナーが複数人在籍する場合、チーム内でのデザインクオリティの担保やスキルアップはどのように行われていますでしょうか?VASILYでは、デザインレビューや、インプット、セミナー参加など、チームでも個人レベルでも常に積極的に行いながら制作しています。 デザインレビューやインプットの仕方などは、デザイナー間でもよくあがる話題の一つだと思いますが、今回は弊社 デザイナーチームがスキルアップのために実際に行っている効果的な方法を3つ ご紹介したいと思います。 1. デザイナー全員でのデザインレビュー   ■チームとしての課題 スタートアップでは、制作と開発を速いサイクルで回していきながらも、デザインの質と量はどちらも担保していかないといけません。 これまでは、エンジニアへ依頼までの細かい確認と、実装後の確認をデザイナー1~2人や担当者内で進めていましたが、デザイナーが増えたこともあり、クリエイティブのクオリティアップと共通認識やルールの意識合わせは課題としてより重く認識するようになりました。   ■目的と効果 それにより 「週に各自どれだけの量を制作したか確認、そして制作物に対してもう一度見直して改善点を洗い出し、次制作のクオリティアップへつなげる」 ことを目的とした、週に1回30分〜1時間ほどのデザインレビューMTGを現在行っています。 制作物を完全に「見える化」し意識することによって、デザインレビュー開始初期に比べ 制作量は約2倍 となり、プロジェクト全体やチーム間での方向性を確認、修正、改善を行っていけるので、デザイナー全員が 自分のデザインに対して目的と意図をしっかりとプレゼン出来る ようになります。   2. 制作物をPinterestのシークレットボードで管理 ■実現、継続させるために デザイナーとして1番フォーカスすべきである「制作」のためにも、デザインレビューの運用方法は負担なく続けれるようにしたいものです。 「短い時間で確認出来るには一覧性も欲しい、1週間ごとに区切って誰が投稿しているかも確認したい」 を叶える最適な方法は Pinterestのシークレットボードでの管理 でした。 他にも、Slackでレビュー用のチャンネルを作成する、WikiやQiitaへのアップなども検討しましたが、情報が流れてしまい一覧で管理出来ない、編集コストがかかってしまうなどでデメリットが多く、今のところPinterestが一番ストレスなく実践出来ておすすめです。   ■実践方法とメリット 方法は以下の通りでとっても簡単。 1. 共有するPinterestのアカウント を作成し、 週ごとにシークレットボードを作成 2. チームメンバーをボードに招待し、 各自のアカウントで1週間の制作物をアップ 3. デザインレビュー時にプロジェクターで大きく映し出し、全員で確認し 出た意見はコメントに記入 上であげた要件以外でのメリットは、 どの端末でも簡単に実機で確認出来る ことです。 唯一デメリットとしてあげるなら、「1週間ごとにボードを作成して、その度にメンバー招待する」ということがあげられますが、週に一回の1分もかからない作業なので現在5人ほどのチームで運用してますがそこまでの負担はありません。   3. タスク確認とインプットの時間を全員で作る ■緊急では無いが重要なことをする 次から次へと降ってくるタスクの波に溺れてしまい、ついつい人は緊急なことから手を付けてしまいがちになります。 そのためVASILYでは、 週の初めにタスクの優先度を全員で確認 し合い、問題があれば調整してインプットの時間を捻出しています。 日々のインプットがないと引き出しも無くなるので、いいアウトプットに繋がるためにも強制的に時間を全員で作るようにしました。   ■実践方法とメリット 1.  タスクを週末にまとめて、全員での確認は 週始めの始業時間前 に行う 2.  インプットは 週1で担当者を変え 、事前にテーマを決めてメンバーにシェア 3.  時間は2時間ほど確保し、その日のテーマに沿った発見、学んだことを後で 各自Qiita:teamにまとめて共有 する メリットは、まだ人が少ない始業時間前にタスク確認を行うことで、焦ることなくささっと終わることができ、1週間を余裕もって気持ちよくはじめることができます。 また、インプットでは自身が主催者になることでさらに世間のトレンドや情報にアンテナを張り ファシリテーション能力も鍛えれる ようになります。 Qiita:teamにまとめて共有することもポイントです。作品に対しての評価を自分の意見として記録することで、 デザインの善し悪しを判断する習慣 となっていきます。   ■過去に実践して良かったインプット 代官山蔦屋で書籍から取り入れた新しい発見をまとめる 写真展を全員で鑑賞 ツールの勉強会 課題やテーマに合わせて、10分でデザインを探し出し、プレゼンしドット投票で一番よかった人を決める etc... 今後はエンジニアの方にも協力を得て、技術的なインプットもしていければと予定していますので、インプットの内容については、今後詳しくブログでまとめていきます。   番外編. UIデザインアドバイザーからのフィードバック 弊社では、 THE GUILD代表の深津貴之(fladdict)さん をUIデザインアドバイザーとして迎えており 、週1でUI改善や新規機能開発についてのMTGを行っています。 MTGでは、体験や機能を実現するためのUIを導きだすために、たくさんのプロトを作成し、デザイナーだけでなく、エンジニアや、ディレクター、プロデューサーも参加し、全員で確認してデザイン検討しています。 社内の人間だけで開発を進めていると分からなかった気付きや発見はとても貴重で、 社外からのフィードバックを盛り込む ことでよりスキルアップにも繋がります。 ■DesignSprintの実践 最近では、Googleのワークショップで参加した DesignSprint を深津さんとともに社内でも実践し、サービスアイディアを数時間で拡散&収束させ、ペーパープロトまで落とし込んで発表するという勉強会も開きました。 デザイン思考で開発していく文化 を会社に根付かせていくのもデザイン力アップのための大事な要素の一つとなりますので、開発手法も積極的に取り入れていけるようにしましょう。 終わりに 以上、VASILYのデザイナーがスキルアップのためにチーム内で取り入れている方法をご紹介しましたが、いかがでしたでしょうか。 「うちの会社ではこういう方法でデザインレビューしてるよ!」「もっと良いツールあるよ」といった意見などあれば是非情報交換させていただきたいので、オフィスにも気軽に遊びに来てください。 また、今すぐにでもこの環境でデザインスキルアップしたいというデザイナーの方々、 絶 賛募集しておりますのでご応募お待ちしております。 https://www.wantedly.com/projects/5485   連絡先:info[at]vasily.jp  
アバター
多くのiOSエンジニアが愛用していたβテスティングサービスのTestFlightですが、2015年2月26日をもってtestflightapp.comが閉鎖になるという 公式アナウンス がありました。 TestFlightを運営するBurstly社がApple社に買収され、現在ではiTunes Connectから TestFlightが利用出来るようになっています。今後は後継となる TestFlight Beta Testing の使用が推奨されていますが、従来のTestFlightと異なる制約が多々あるため、別サービスを検討している方も多いのではないでしょうか。 今回はTestFlightに変わるβテスティングサービスを紹介したいと思います。    TestFlight Beta Testingの問題点 TestFlight Beta Testingには、公式で提供されているからこそのメリットも多々あります。 しかし、多くのプロダクトでネックになるとても重要なことがあります。それは「 iOS 8以上のデバイスでなければTestFlight Beta Testingのアプリを使えない 」ということです。 まだまだiOS 7をサポートしているプロダクトは多いはずです。この理由だけで代替サービスを探そうと思う方は多いと思います。 代替サービスの選定基準 代替サービスに移行するのであれば、より自分たちのプロダクトに適したβテスティングサービスを選定したい気持ちがあります。今回は「 TestFlight Beta Testing 」「 Fabric Beta 」「 DeployGate 」の3つのテスティングサービスを比較してみました。比較の観点は6つあり、50名程度の社内テスターに、アプリケーションのバージョンアップ毎に配信することを想定しています。   ・ iOS7をサポートしているか ・ 導入が容易か ・ テスターの追加が容易か ・ 安価であるか ・ 配信時に手間がかからないか ・ CIとの連動が容易であるか 上記結果だけを見ると「TestFlight Beta Testing」については時期尚早だと感じて頂けると思います。 しかし、メリットが無い訳でもありません。次に各サービスのメリット・デメリット、使用感についてまとめます。 TestFlight Beta Testing ・ https://itunesconnect.apple.com/ 本記事でも何回も登場しているオフィシャルのテスティングサービスです。 【メリット】 ・ Releaseビルドでアプリを確認できる ・ 最大1000人まで外部テスターを招待でき、フィードバックを得ることができる ・ SDKが不要 【デメリット】 ・ iOS 7に対応していない ・ 外部テスターの登録に手間がかかる ・ 内部テスターの権限に融通がきかない ・ 端末のAppleIDと紐づくため、TestFlightアカウントの切り替えが非常に面倒 ・ CIとの連動が簡単ではない Releaseビルドでアプリが確認出来るのは素晴らしいメリットだと思います。 少なくとも開発者数名がテストを行うという意味では積極的に使用するべきだと感じました。 DeployGate ・ https://deploygate.com/ 国産の配信サービスです。元々はAndroidアプリのテスティングサービスでしたが、今ではiOSもサポートされています。mixi社が運営していましたが、2015年2月28日を持ってデプロイゲート社に事業譲渡されます。 【メリット】 ・ 国産なので日本語のドキュメントがしっかりしている ・ 配信だけならSDK不要 ・ CIとの連携もしやすい 【デメリット】 ・ 有料 弊社の場合はAndroidでDeployGateを使用しているため、テスティングサービスの統一や、すでに知見があるというのは大きなメリットです。Androidですでに使っている企業も多いと思うので、料金面が問題無いのであれば選定されるプラットフォームだと思います。 SDKを導入すればテスティング以外にも活用できます。 Fabric Beta ・ https://get.fabric.io/ Crashlytics, Twitter , MoPubが統合されたプラットフォームです。Tiwtter社が運営しています。Crashlyticsがテスト配信機能(Beta)をもっており、Crashlyticsを使っているアプリケーションは導入の手間をかけずにそのまま使えます。 【メリット】 ・ Crashlyticsを使用しているプロダクトであればBetaの導入が楽 ・ ビルドから配信までシームレスであり、グループ機能により配信範囲の選択も楽 ・ APIが公開されており、CI連携も可能 ・ ダッシュボードが見やすい 【デメリット】 ・ Crashlyticsを使用していない場合はSDKの導入が面倒 CrashレポートサービスにCrashlyticsを採用していたため、非常に簡単に「Fabric Beta」を使うことができました。ダッシュボードがとても優れており、テスターのインストール状況など直感的に分かりやすいUIが提供されています。 まとめ 今回は元々Crashlyticsを使っていたこともあり「Fabric Beta」を採用しました。 Crashレポートサービスとしても非常に優秀なので、未導入のサービスはこのタイミングでSDKの導入を検討してはいかがでしょうか。 先日TestFlight Groupsが発表されたりと、βテスティングサービスの選定は時代とプロダクトによって柔軟にしていく必要がありそうです。今回は比較対象に上げませんでしたが、以下のようなサービスもありますのでご紹介します。 HockeyApp http://hockeyapp.net/features/ 昨年Microsoft社が買収しました。 HockeyAppをMicrosoft社の製品に統合する計画らしいですが、引き続きサービスは提供される予定のようです。今後に流れに注目です。 EMLauncherv https://github.com/KLab/emlauncher http://www.klab.com/jp/press/140304.html KLab社が公開しているオープンソースです。 Burstly社が買収された際に、Androidエンジニアが試していることが多かったようです。 終わりに 今回のエントリをみて「こんなサービスもあるよ」「それでも◯◯というメリットがあるから××に乗せ変えた方がオススメ!」といったご意見もあると思います。そんな方、ぜひ情報交換させてください。 ご興味があればVASILYに遊びにきて頂ければと思います。 また、VASILYではエンジニアを募集しておりますので応募お待ちしております。 https://www.wantedly.com/projects/7595 連絡先:info[at]vasily.jp  
アバター
  先日 ThoughtWorks社 から最新の技術動向をまとめた Technology Radar の2015年1月版が発表されました。 このTechnology Radarですが毎回、 『技術』 『ツール』 『プラットフォーム』 『言語・フレームワーク』 と4つの領域に分けて紹介しており、絶賛流行中もしくは今後注目されるテクノロジーなどが紹介されています。 今回はそんな 『言語・フレームワーク』 の領域から厳選した11の注目テクノロジーを紹介します。 はじめに 各テクノロジーは 『Adopt』 『Trial』 『Assess』 『Hold』 という4つの階級のどれかに属しており、各階級は以下の意味を持っております。 ・ 【Adopt】 企業での使用が推奨されるレベル ・ 【Trial】 使用する価値はあるが、低リスクのプロジェクトで使用すべきレベル ・ 【Assess】 使用する価値があるか、使用方法やポテンシャルを検証すべきレベル ・ 【Hold】 先行きがわからないので取り扱いには注意すべきレベル 以下、多くの素晴らしいテクノロジーが登場していますが階級の意味はあくまでも参考程度に考えたほうが良さそうです。 Adopt 1. Go language まず最初は言わずと知れた「 Go 」。 VASILYのエンジニアでも個人プロジェクトで使用している人も多く、まさしく今一番流行っているプログラミング言語だと個人的にも感じています。 国内スタートアップでも導入実績が増えており、先日開催された dots. Summit で メルカリ や Gunosy で使用しているという話がありました。   2. Java 8 続いては「 Java 8 」。 ラムダ式 や Stream API など強力な機能追加で話題のJava最新バージョン。 残念ながらAndroid開発に関して現時点ではJava 8を使うことはできませんが、Java 8の新機能は今後Android開発者を含むすべてのJavaプログラマーが必須の知識になってくると思うので今から抑えておくと良いと思います。 *現時点のAndroid開発でも「 Retrolambda 」と「 RxJava 」を持ち込めばJava 8っぽく記述することができます   Trial 3. AngularJS Googleとオープンソースコミュニティによって開発されているJavaScriptの有名なフレームワークである「 AngularJS 」。 ちょっと前までは至るところで名前を聞きましたが最近は少し React.js に押され気味だと個人的に感じています。JS界隈はホントに動きが激しい。 少々取り上げるか悩んだのですが、現在 v2.0 が開発中らしいので今後盛り返しにちょっとだけ期待です。 ちなみに弊社開発アプリの iQON において裏の運用ツールの一部に使用しています。   4. Dashing イケてるダッシュボードが簡単に作れるRubyのフレームワーク「 Dashing 」。 この サンプル みたいなダッシュボードが、Ruby, HTML, Sass, CoffeeScriptを少し書くだけで作れてしまいます。 Ruby 1.9以上が入っているマシンで以下の数行を書くだけで始められるので、チーム内でのKPIの共有などに活用してみると面白いと思います。 $ gem install dashing $ dashing new sweet_dashboard_project $ cd sweet_dashboard_project $ bundle $ dashing start   # localhost:3030 にアクセス 5. Django REST Pythonの有名なフレームワークである Django をベースとしているRESTfulなAPIを開発するに適しているフレームワーク「 Django REST framework 」。 昨年末に大きな変更を加えた v3.0 がリリースになりましたが、多くの機能が追加されているため興味がある方は リリースノート を読んでみてください。 PythonでAPI開発を行う場合に候補に入れてみてはいかがでしょうか。   6. Ionic framework HTML5でハイブリッドなモバイルアプリが作れるフレームワーク「 Ionic framework 」。 このフレームワークは Apache Cordove をベースに AngularJS と Sass が標準で使えるように構成されています。 テンプレートが用意されているため、自動でコードが展開されすぐにビルドすることができます。 HTML5でクロスプラットフォームを意識したアプリが作りたい方は導入してみてはいかがでしょうか。   7. Retrofit AndroidとJavaのRESTクライアントライブラリとして有名な「 Retrofit 」。 開発は、Android界隈の神JakeWharton氏が在籍するSquare社。 非常に使い勝手が良いライブラリなので導入している会社はちらほらあるんじゃないかと思います。 ちなみにiQONのAndroid版においては Retrofit は使っていませんが『Otto』や『Butter Knife』などは使っています(この辺はまた別の機会にご紹介します)。   Assess 8. Lotus この1年で突如現れたRubyの最新フレームワーク「 Lotus 」。 Github を見てみると非常に面白いんですが、モジュールがすべて入ったフルスタックなプロジェクトもある一方、フレームワークをモジュールごとに分けたプロジェクトも存在しています。 このコードをある単位で分割が容易に行うことができる点がLotusの特徴になっています。 Sinatraみたいな軽量なアプリを作ることができ、かつRailsみたいなフルスタックなアプリも作ることができる柔軟なフレームワークになっています。   9. React.js 最近話題のFacebook製JavaScriptライブラリ「 React.js 」。 ざっくり言うとMVCでいうViewの部分をコンポーネント化して開発できると言ったUI周りに特化したライブラリになります。 この1年で急に盛り上がってきたと感じているんですが Facebook, Instagram はもちろんのこと Netflix, Yahoo, Airbnb, Atlassian などでも使われているそうです。 React.jsの一番の特徴は 仮想なDOM をJavaScript内に持っていることです。これにより従来の実際のDOMをこねくり回してた状態と比べ、必要最低限の更新のみで済むのでパフォーマンス改善に繋がるわけです。 他にもデータを子に渡していくという一方向なデータの流れのためコードも追いやすいという利点があったり、JSXが使用できたりといろんな特徴なあるライブラリです。   10. Rust Mozillaによって開発中のプログラミング言語「 Rust 」。 1月に 1.0.0 Alpha がリリースされ、来週には beta 1 がリリース予定になってたりと、そろそろ正式版がリリースされそうなこのタイミング。せっかくなのでRust触ってみてはいかがでしょうか。 Rust本体と、Rustのパッケージマネージャである Cargo を入れて、 このイントロダクション に沿って行けばRustの入り口を学ぶことができます。 言語としては、純粋関数型、手続き型、オブジェクト指向をサポートしている高機能な言語になっています。   11. Swift 昨年、突如として現れたiOS、OS Xのための新言語「 Swift 」。 つい先日も最新バージョンである Swift 1.2 が 発表 され盛り上がりを見せていますが、iPhoneアプリの開発者は今後絶対に抑えておかないといけない言語であることは間違いないです。 2つ前のエントリー でも紹介しましたが、まだ弊社も iQON には投入できていないものの新しいプロジェクトでは既に使い始めております。 以下のエントリーをまだ読まれていない方はぜひとも読んでみてください。 Swiftで会社の受付アプリを作った話とCADisplayLink まとめ 流行中のテクノロジーをいくつか取り上げましたが、最近はホントに流行り廃りが早いため来年にはいくつか消えているんじゃないかと思います(既になくなりつつあるものもありますが)。 そんな中ではありますが自分が好きだと思えるプロダクトを見つけて愛していくのはエンジニア冥利に尽きると思います。 今回いろいろと調べている際に、最近触っていない言語が気がついたらいろいろと進んでいてショックを受けたので定期的にいろんな言語に触れないとダメだと感じました。 VASILYに遊びに来ませんか? 今回のエントリーに言及したい方、最新テクノロジーが好きな方はぜひ一度VASILYに遊びに来ませんか? info[at]vasily.jp や @yoichinishimura などで気軽に連絡いただければと思います。 またVASILYではエンジニアを大大大募集しておりますので応募お待ちしております。 https://www.wantedly.com/projects/7595  
アバター
  iQONはAppStoreのレビュー4.5, GooglePlayのレビュー4.3と、嬉しいことにユーザーから高い評価を受けています。しかし、実際にユーザーが日々感じているアプリの良い点だったり不満点などの本音の部分は、レビューやTwitterなどのユーザーが投稿する文章の中に含まれています。特にサポートにお問い合わせをしてくださったユーザーからいいただくような改善を訴えるメッセージとは違い、Twitterやレビューに投稿している文章には現状ユーザーが感じている改善してほしい点やバグ等が、より意識せずに書かれている可能性が高いと考えられます。そのテキストの内容を解析できれば、開発者が認知している問題の中でもより多くのユーザーが改善してほしいと感じている点であったり、我々開発者が気づけていなかったバグの発見等が可能になると考えられます。 そこで今回、「評判分析はじめの一歩」と題して、iQONについて書かれている文章の評判分析を実験的におこなってみましたので、その内容と結果を紹介したいと思います。 評判分析とは?   評判分析とは様々なテキスト情報をテキストマイニングや機械学習の技術を用いて、肯定的な評価をしている記述と否定的な評価をしている記述に分類したり、実際にそのテキストを書いている人がどのような事を考えて記述しているか分析し、理解する事を言います。 ブログやSNSの発展や、AmazonなどのECサイトのレビュー機能が充実した現在、評判分析はユーザーの生の声を把握する事ができると期待されているため、研究分野でも盛り上がりを見せています。 実験概要 対象データ ・書かれている内容の精査等にコストをかけないため。 ・すでに評価の点数が振られている点。 評判分析とは様々なテキスト情報をテキストマイニングや機械学習の技術を用いて、肯定的な評価をしている記述と否定的な評価をしている記述などに分類したり、実際にそのテキストを書いている人がどのような事を考えて記述しているか分析し、理解する事を言います。 ブログやSNSの発展や、AmazonなどのECサイトのレビュー機能が充実した現在、評判分析はユーザーの生の声を把握する事ができると期待されているため、研究分野でも盛り上がりを見せています。 mattlawer/appstat の様なコマンドラインからアプリのapp_idを指定してレビューを取得する便利なサービスもあるのですが、今回は200件以上を取得したかったので、AppleのAPIのレスポンスをスクレイピングする形で取得しました。 評判分析ツール 「独立行政法人情報通信研究機構 旧知識処理グループ 情報信頼性プロジェクト」で作られているツールを使用して分析を行いました。(詳細はこちら :  http://alaginrc.nict.go.jp/opinion/ ) こちらは1行につき1文が書かれたテキストファイルを入力すると、① その評価情報を表す表現の抽出② その評価情報の意味的な分類③ ポジティブ / ネガティブ の様なその文章が表す「評価」に関する情報を抽出してくれるスクリプト群です。 以下のものが動く環境で、こちらのツールを使用する事ができます。 ・CRF++(Version 0.54 で動作確認) ・iconv (Version 2.5で動作確認) ・gawk(Version 3.1.6 および 4.0.0で動作確認。3.1.5ではエラーが発生します) ・gcc(Version 4.1.2で動作確認) ・perl(Version 5.8.8 および 5.10.1で動作確認) ・JUMAN(Version 6.0 および 6.01で動作確認。Version 7.0には対応していません。) ・KNP(Version 3.01 で動作確認。Version 4.0には対応していません。) 分析結果として表示される、評価タイプの種類と各タイプが持ちうる極性は以下の表の様になります。(+はポジティブ、-はネガティブを表します) 実験内容 ・スクレイピングで取得したレビュー300件を取得 ・アプリのバージョン × レビューの点数 ごとにファイルを分割 ・レビューの点数ごと/バージョン別に評価分析の結果をまとめる 取得した文章は一つのレビューの中で肯定的な意見と否定的な意見を混ぜて記載しているものが存在する理由から、分析スクリプトに流してもどのような意見を述べているか判定できない可能性が高いため、文ごとに区切って分析を行いました。 実験結果 全体の評価内容数 感情+        : 6 感情-         : 0 批評+        : 200 批評-         : 77 メリット+ : 150 メリット-  : 56 採否+         : 8 採否-          : 0 出来事+     : 0 出来事-      : 0 当為           : 28 要望           : 0 レビューという事もあり、「批評+-」「メリット+-」に関する意見が多い結果となりました。また、「当為」が多くレビューに書かれている事からアプリに何を求めているかを知る事ができそうです。 レビュー点数ごとの評価内容 レビュー5のコメント内で 評価内容 レビュー5のユーザーのコメントとしてはポジティブな意見が多く、特に ・コーデを作ることの楽しさ / 可愛さ ・買い物に便利 ・探していたものが見つかる 等の意見を多くいただきました。 レビュー1のコメント内で 評価内容 レビュー1をいただいたユーザーのコメントにはやはりマイナスな意見が多く存在しています。今回試してみたツールの結果のままでは、マイナスな意見に関してもいくつかプラスの意見として判定されてしまっているモノがありました。 大きく分けると バグ報告系 と 改善要望系 の2種類に分けられます。こちらが認知して今後改善を進めて行くバグや機能改修についても多くの意見をいただいていますが、「機能改善をする事自体に対する不満のご意見」がある事もわかりました。 最新バージョンのレビューでマイナス評価のもの 一番直近のレビューの中でマイナスの評価になったものとしては上記のお知らせに関してですが、お知らせを消す仕組みは現在のアプリにも実装されているので、そちらがユーザーにきちんと伝わっていない事がわかります。   結果からの考察と今後の話 今回は特に分析に関してカスタマイズ等をしていないので、評判分析の精度を上げる事には言及していませんが、ユーザーが投稿している文書を解析する事で ・ ユーザーが何に喜んでいるかがわかる ・ ユーザーが何に不満を感じているかがわかる 普段見逃してしまっているレビューの中にあるユーザーの意思をつかんでサービスに落とし込む事は確実にメリットがあります。 他にも、私たち開発者が気づけていないバグについて把握ができ、ユーザーがどこの機能を楽しんで、自分たちのアプリを使ってくれているか、自分たちのアプリの強みを知る事にもつながります。 今後進めたいこと 辞書/分析アルゴリズムの最適化 今回は「評判分析導入のはじめの一歩」という事で、分析ツールに特に学習データを与えて学習させたり、辞書をアプリをテキストマイニングするのに最適化するようなことはせず、一般的な評判分析用の辞書を使っています。 そのため、プラス/マイナスの評価の部分などでおかしいものが多々ありました。 ・分析がおかしい例 このように人間がみれば一発でマイナスの感情な意見でも、プラスな評価に判定されてしまっている解析結果が多々あります。今後はアプリの批評に関する言葉を学習させて辞書に追加していくなどして、より精度を上げた評判分析ができれば、アプリの改善等にプラスになるので進めて行きたいと考えています。 冒頭でもテキストマイニングを用いた評判分析の分野は研究で盛り上がっていると記載しましたが、調べている中で次に試せそうな面白い研究があったのでいくつかありました。ぜひ参考にしてみてください。 レビューの語の重みを考慮したテキストマイニングによるゲームソフトの評判分析   構文片を用いた意見・評判情報抽出手法 ツールによるビジュアライズ   今回はローカルのバッチを単発で回して処理をし、テキストファイルをアウトプットとしていました。今後は ・定期的に最新のレビューの分析結果を更新 ・ ツールでエンジニア以外も見れるように ・各アプリのバージョンごとでレビューにどのような変化が現れているかを見える化。 ・ レビューだけで無くTwitterなどに投稿されている文章も解析する ・プラス/マイナスそれぞれの評価の中で頻出な単語を形態素解析で分解しツールで見れるようにし、ユーザーが何かしらの媒体にポストしている内容でホットなワードは何かを見える化 等を進める事で、日々ユーザーに向けた改善をとれるような体制を作りたいと考えています。   最後に 今回はレビューに関する分析の実験内容をあげましたが、レビューやTwitter以外にも弊社アプリには様々なテキストデータや画像データがあり、ファッションに関するデータという意味では日本最大級のデータがたまっています。VASILYでは現在、これらのデータを使って今迄にない新しい価値を世の中に生み出して行きたいというエンジニアを大募集しています!ぜひ一緒にテクノロジーの力でファッション業界にインパクトを与えてきましょう! 募集要項 連絡先:info[at]vasily.jp
アバター
iQONのiOSアプリはまだ全てObjective-Cで記述されています。 Swiftへの移行については「たいしてパフォーマンスが上がるわけでもないし…」と思って渋っていました。 そんな中、オフィスの移転をきっかけに来客の受付システムをiPadアプリで作ることになりました。 スクラッチでアプリを作るのならSwiftで、ということでSwiftで作りました。 今回は、受付システムの社員を呼び出すデータ通信と、トップページの時計に使ったCADisplayLink実装を紹介します。 完成品 www.youtube.com 呼び出したい社員を選択すると、twilioから各個人の携帯電話に自動音声の電話がかかってきます。 電話呼び出しと同時にSlackにも通知が飛ぶようになっています。 実装 データの流れは下記のようになっています。 アプリからはherokuのAPIをリクエストするだけなので、エラーハンドリングも簡単に済みました。 データ通信 iPadから呼び出したい社員を選択すると、アプリからHerokuのAPIにリクエスト HerokuのAPIがSlackとtwilioにリクエスト 社員のケータイに電話(自動音声)とSlackの通知が飛びます アプリの実装 ネイティブ側では下記のようなことをやっています。 ・ Swift製通信ライブラリのAlamofireを使用 ・ CAGradientLayerでiPhoneのロック解除のようなシマーアニメーションを実装 ・ 時計のアニメーションをCADisplayLinkを使って正確に描画 ・ UICollectionViewFlowLayoutをオーバーライドして、セル追加アニメーションを実装 ・ 呼び出しリクエスト中にAudioToolbox.frameworkで効果音を無限ループさせる ・ 通信中の波形アニメーションにCADisplayLinkを使ってアニメーション ・ アプリアイコンは基本的に見せないので、identiconでデザイン工数ゼロ その中の一つ、今回はCADisplayLinkの実装を紹介します。 時計のアニメーションとCADisplayLink アナログ時計のような無限に動き続けるアニメーションを実装するとき、NSTimerやdispatch_afterを使って0.01秒ごとに位置を修正する処理を実行するような実装が考えられます。 受付システムの時計のアニメーションの実装には、CADisplayLinkを使用しています。 CADisplayLinkは画面のリフレッシュレートと同期して描画させるタイマーオブジェクトです。 vs NSTimer NSTimerを使ったり、dispatch_afterをループしても同じような処理を実装できます。 例えば、NSTimerのインターバルを1秒に設定して、その処理の実行時間が1.5秒だった場合、処理実行中は次のタイマー処理がスキップされ、処理が実行されるのは2秒間隔になってしまいます。(いわゆるフレームスキップ) これはCADisplayLinkでも同じことです。CADisplayLinkの場合でもスキップはありますが、あくまでも呼び出されるタイミングは画面の更新に同期するのでアニメーションを使うには効率が良いのです。 CADisplayLinkの実装 CADisplayLinkオブジェクトを生成時にターゲットとメソッド名を登録します。 生成したCADisplayLinkオブジェクトをNSRunLoopのメインループに追加すると、画面描画のリフレッシュごとに登録したメソッドが呼ばれます。 let displayLink = CADisplayLink(target : self , selector : Selector ( "update:" )) displayLink.addToRunLoop(NSRunLoop.currentRunLoop(), forMode : NSRunLoopCommonModes ) 円を描く実装 実装の一部を一つのViewControllerにまとめました。 GitHubにサンプルプロジェクト を置いてあるので動かしてみてください。 こんなアニメーションが動きます。 import UIKit class ViewController : UIViewController { private let secondLayer = CAShapeLayer() override func viewDidLoad () { super .viewDidLoad() // 円のレイヤー let frame = view.frame let path = UIBezierPath() path.addArcWithCenter( CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame)), radius : frame.width / 2.0 - 20.0 , startAngle : CGFloat ( - M_PI_2), endAngle : CGFloat (M_PI + M_PI_2), clockwise : true ) secondLayer.path = path.CGPath secondLayer.strokeColor = UIColor.blackColor().CGColor secondLayer.fillColor = UIColor.clearColor().CGColor secondLayer.speed = 0.0 // ※1 view.layer.addSublayer(secondLayer) // 円を描くアニメーション let animation = CABasicAnimation(keyPath : "strokeEnd" ) animation.fromValue = 0.0 animation.toValue = 1.0 animation.duration = 60.0 secondLayer.addAnimation(animation, forKey : "strokeCircle" ) // CADisplayLink設定 let displayLink = CADisplayLink(target: self, selector: Selector("update:")) displayLink.frameInterval = 1.0 // ※2 displayLink.addToRunLoop(NSRunLoop.currentRunLoop(), forMode : NSRunLoopCommonModes ) } func update (displayLink : CADisplayLink ) { // timeOffsetに現在時刻の秒数を設 let time = NSDate().timeIntervalSince1970 let seconds = floor(time) % 60 let milliseconds = time - floor(time) secondLayer.timeOffset = seconds + milliseconds // ※3 } } secondLayer.speed = 0.0 CALayer のspeedを0にして、自動でアニメーションが動かないようにする displayLink.frameInterval = 1.0 1フレームごとに処理を実行する secondLayer.timeOffset = seconds + milliseconds アニメーションの進捗具合を設定する CALayerの speed = 0.0 の状態で、 timeOffset を操作しているので、円が一周しても、また最初から描画が始まって無限に動き続けます。 Swiftで書いてみて思ったこと メリット コード量が減る    .h/.m → .swift 一つになります    型推論 Objective-Cでの不便なことが改善    文字列の扱い、Switch、enum Optional Value (?, !)   ビルドせずに静的解析でバグに気付くことができます iOSエンジニアに以外の可読性向上   Objective-Cの独特な記法がなくなって、iOSエンジニア以外でもなんとなく理解できるぐらい読みやすくなりました これがきっかけでAndroidエンジニアがplaygroundを触るようになりました 普段アプリをObjective-Cで作っている人には、たいして難しくない (簡単というわけでもないですが) 何より書いていて楽しい デメリット Xcodeでメソッドの定義に飛ぶショートカット(Cmd+Ctrl+J)があまり効かない   optionキーを押しながら、コードをクリックして回避しています ライブラリの利用が面倒    Alamofireをgitのsubmoduleを使ってインストールしましたがかなり面倒でした    CocoaPodsでSwiftライブラリが扱えるようになるのは、0.36以降の予定です     正式リリースが待たれます メリットの方が大きいと思ったのでiQONのコードも新しいものからSwiftで書いていこうと思います。
アバター
  みなさんはAndroidアプリのリリース作業を自動化していますか? 2014年GooglePlayベストアプリを受賞した弊社のファッションアプリ「iQON」では、リリース作業をCircleCIとDeployGateで自動化しています。今回、どのように自動化したのかを、昨年11月からVASILYで働き始めた堀江( @Horie1024 )がご紹介しようと思います。 概要 iQONの開発フローは、PullRequestベースで行われており、開発が完了したコードをreleaseブランチに随時PullRequestを送りながら開発を進めています。 releaseブランチを作成 releaseブランチにPullRequest 問題が無ければPullRequestをマージ 1~3を繰り返す そして、リリース作業は以下のような手順で行っていました。 releaseブランチをmasterブランチへPullRequest PullRequestをマージ masterブランチからAPKを作成 メールでAPKを社内配布 最終確認 GooglePlayにアップロード リリース完了  作業手順としては難しくないのですが、頻繁にあるリリースの度に作業が発生するのでとても面倒でした。 実現したいこと 今回、自動化することで以下の2項目を実現したいと思います。 APK作成の自動化 社内への配布の自動化 どう実現するか サンプルプロジェクト 解説用にサンプルプロジェクトを用意しました。 https://github.com/horie1024/CircleCISample 全体の流れ GitHubへ差分をPush CircleCIがビルドを開始 Slackへビルドの成否を通知 DeployGateへAPKをアップロード 検証端末にDeployGateアプリ経由でAPKを配信 APKをインストール APK作成の自動化 コマンドでのAPK作成 AndroidStudioでのプロジェクトのビルド iQONの開発には、AndroidStudioを使用しています。AndroidStudioでは、IDEとビルドシステムが疎結合になっているため、コマンドでのビルドが容易に行えます。 ビルドシステムには、Gradleが使われており、Android Gradle Pluginを使用してAndroidプロジェクトのビルドを行います。Gradleについてのより詳しい情報は、 Gradle 日本語ドキュメント 、Android Gradle Pluginについては、 Gradle Plugin User Guide をご覧ください。 ビルドスクリプト AndroidStudioでプロジェクトを新規作成すると、以下の2つのbuild.gradleがあります。 Project直下のbuild.gradle app module内のbuild.gradle app module内のbuild.gradleにAndroidプロジェクトをビルドするための設定が含まれています。 assembleタスク 新規作成したAndroidStudioでプロジェクトには、gradlewという実行形式ファイルが含まれており、gradlewを使いGradleのビルドを実行することが推奨されています。 gradlewでビルドを実行する場合、Gradleが自動でダウンロードされ、それを使用してビルドが実行されます。より詳しい解説は こちら をご覧ください。 Gradleによるビルドは、プロジェクト単位で一つ以上のタスクで構成されており、プロジェクトが実行可能なタスクの一覧は、tasksで表示できます。 $ ./gradlew tasks タスク一覧の中に、Build tasksがあり、APKを作成するには、assembleタスクを実行します。 Build tasks ----------- assemble - Assembles all variants of all applications and secondary packages. assembleDebug - Assembles all Debug builds assembleDebugTest - Assembles the Test build for the Debug build assembleRelease - Assembles all Release builds build - Assembles and tests this project. buildDependents - Assembles and tests this project and all projects that depend on it. buildNeeded - Assembles and tests this project and all projects it depends on. clean - Deletes the build directory. Androidプロジェクトは、デフォルトでdebug APKとrelease APKの2種類の出力を持っていて、assembleタスクを実行すると両方を出力します。出力を分割するには、 assembleDebug 、 assembleRelease タスクを利用します。今回は、GooglePlayへアップロードできる状態でAPKを作成したいので、assembleReleaseタスクでAPKを作成します。 ターミナルからのAPK作成 実際にターミナルからassembleReleaseタスクを実行すると、app/build/outputs/apk以下にAPKが出力されるのが確認できます。このassembleReleaseタスクを自動的に実行することで、APKの作成を自動化します。 $ ./gradlew assembleRelease 署名の設定 サンプルプロジェクトでは、設定していませんが、本来であればassembleReleaseでAPKを作成する場合には署名を付けます。Releaseビルドで署名を付けるには、app module内のbuild.gradleのコードを以下のようにします。詳細は こちら をご覧ください。 リリース作業手順の確認 リリース作業の手順を確認し、自動化する箇所を洗い出します。 releaseブランチをmasterブランチへPullRequest PullRequestをマージ masterブランチからAPKを作成 メールでAPKを社内配布 最終確認 GooglePlayにアップロード リリース完了 目的はAPK作成の自動化ですので、1~3の手順に注目すると、 「PullRequestのマージによってmasterブランチに変更が生じたらAPKを作成する」 とまとめられます。これを CircleCI を利用して自動化します。 CircleCI CiecleCIのようなCI as a Serviceでは、GitHubとの連携が前提になっているので、GitHubに差分がPushされたのをトリガーに、任意のコマンドを実行するといったタスクを簡単に定義できます。実際にCircleCIにどのような挙動をさせるかの設定は、 circle.yml という設定ファイルに書き、CI対象のリポジトリに設置します。 circle.yml circle.ymlの構造は6つのセクションに分かれており、上から順に実行されます。また、これらのセクション全てについて設定を書く必要はありません。 machine  : VMの設定の調整 checkout  : gitリポジトリからのclone dependencies  : ビルドの依存関係の解決 database  : テストのためのdatabaseの準備 test  : テストの実行 deployment  : デプロイの実行 各セクションは、bashコマンドのリストを持て、実行したいbashコマンドを指定していきます。もし特にコマンドを指定しない場合、CircleCIがリポジトリのコードから推測したコマンドが実行されます。コマンド実行時のオプションとして、以下3種類を選択できます。 pre  : CircleCIが推測したコマンドより前に実行 override  : CircleCIが推測したコマンドを独自に定義したコマンドで上書き実行 past  : CircleCIが推測したコマンドより後に実行 これら6つのセクションと3種類のオプションを覚えておけば、circle.ymlは問題なく書けると思います。より詳しい解説は、 Configuring CircleCI をご覧ください。 次に、実際にAndroidプロジェクトをビルドするcircle.ymlを書いてみます。 Androidプロジェクトのビルド Test Android applications を参考に書いていきます。 checkout セクションと database セクションについては、必要が無いので設定を書きません。 ▪︎VMの設定 ビルドを実行するには、 ANDROID_HOME の定義が必要になるため、circle.ymlのmachineセクションで定義します。environmentセクションで環境変数を定義でき、VMの /usr/local/android-sdk-linux にAndroid SDKが用意されてるので、そのPathを指定します。また、Javaのバージョンをopenjdk7に指定します。 machine: java: version: openjdk7 environment: ANDROID_HOME: /usr/local/android-sdk-linux ▪︎sdkのアップデート VMに用意されているAndroid SDKは初期状態のため、必要に応じてアップデートします。例えば、CI対象Androidプロジェクトのbuild.gradleの設定が、以下のようになっていた場合 android { compileSdkVersion 21 buildToolsVersion "21.1.2" } circle.ymlにSDK 21とBuild-tools 21.1.2をインストールするよう追記します。overrideとしてるのは、CircleCIが推測して実行する、gradle dependenciesによってビルドが失敗するためです。 machine: java: version: openjdk7 environment: ANDROID_HOME: /usr/local/android-sdk-linux dependencies: override: - echo y | android update sdk --no-ui --filter "android-21,build-tools-21.1.2" サポートライブラリや、GooglePlayServicesライブラリを使用する場合、filterに以下のidを追加します。 "extra-google-m2repository,extra-android-m2repository" また、filterに指定できるidは、以下のコマンドで確認できます。 $ android list sdk --all --extended ▪︎testセクション testセクションは、必ず実行されてしまうため、overrideでダミーの処理を行うようにします。 machine: java: version: openjdk7 environment: ANDROID_HOME: /usr/local/android-sdk-linux dependencies: override: - echo y | android update sdk --no-ui --filter "android-21,build-tools-21.1.2" test: override: - echo "Nothing to do here" Robolectric Gradle Plugin を導入している場合、testセクションでテストを実行します。 test: override: - ./gradlew test ▪︎APKの作成 deploymentセクションでAPKを作成します。deploymentセクションは、複数のサブセクションを持てます。サブセクションは、branchセクションを持ち、差分が生じたブランチが、指定したbranchにマッチした場合に、commandsを実行します。より詳しい解説は、 こちら を参照してください。 machine: java: version: openjdk7 environment: ANDROID_HOME: /usr/local/android-sdk-linux dependencies: override: - echo y | android update sdk --no-ui --filter "android-21,build-tools-21.1.2" test: override: - echo "Nothing to do here" deployment: master: branch: master commands: - ./gradlew assembleRelease ▪︎ビルドできるか試す CircleCIで実際にAndroidプロジェクトをビルド出来るか確認します。 CircleCIにログイン・サインアップ   GitHubのアカウントでログインもしくはサインアップします。 Add Projectsをクリック   左側のメニューのAdd Projectsをクリックします。 CIの対象とするプロジェクトの選択   1でアカウントを選択し、2でCIの対象とするプロジェクトを選択します。 初回ビルドの実行   プロジェクトを選択すると初回のビルドがスタートします。初回ビルドでは、circle.ymlが不正だったためビルドが失敗しました。 masterブランチに変更をPush masterブランチでcircle.ymlを修正し、再度Pushするとビルドがスタートします。circle.ymlが正しく修正されたため、無事ビルドが成功しました。 成果物 Androidプロジェクトがビルドでき、APKを作成できました。次にAPKをGooglePlayにアップロードできるよう、作成したAPKをダウンロードできるようにします。 CircleCIでは、ビルドを実行した結果発生する成果物は、 Build artifacts としてビルド毎にダウンロードできます。Build artifactsとしてダウンロードするには、ビルド成果物を保存する必要があります。 成果物を保存するには、generalセクションのartifactsセクションに成果物のパスを指定します。generalセクションは、6つのセクションとは別に、特定のセクションに属さない、ビルド全体に関する設定を書くことができるセクションです。 general: artifacts: - "app/build/outputs/apk/app-release-unsigned.apk" machine: java: version: openjdk7 environment: ANDROID_HOME: /usr/local/android-sdk-linux dependencies: override: - echo y | android update sdk --no-ui --filter "android-21,build-tools-21.1.2" test: override: - echo "Nothing to do here" deployment: master: branch: master commands: - ./gradlew assembleRelease masterブランチでのみタスクが実行されるようにする ここまでで、GitHubでPullRequestをマージもしくは変更をPushすることで、CircleCIのタスクが実行されるようになりました。ですが、master以外のブランチへPushした場合でもビルドが実行されてしまいます。そこで、masterブランチへのPushでのみビルドが実行されるようにします。 Specifying branches to build を参考に、circle.ymlに設定を追加します。generalセクションにbranchesを追加することで、masterブランチへのPushでのみビルドが実行されるようになります。 general: branches: only: - master artifacts: - "app/build/outputs/apk/app-release-unsigned.apk" machine: java: version: openjdk7 environment: ANDROID_HOME: /usr/local/android-sdk-linux dependencies: override: - echo y | android update sdk --no-ui --filter "android-21,build-tools-21.1.2" test: override: - echo "Nothing to do here" deployment: master: branch: master commands: - ./gradlew assembleRelease 以下のように、testブランチをPushしても 「Not Run」 となります。 Slack連携 Slackと連携させることで、ビルドの成功・失敗を通知させることができます。 SlackのConfigure IntegrationsからCircleCIを選択 通知したいchannelを選択 channelを選択するとWebhook URLが得られます。 CircleCIのProject SettingsでWebhook URLを登録 Notifications > Chat NotificationsからSlackを選び、Webhook URLを入力後、Saveをクリックします。 OOM問題 自動化してしばらく運用した中で実際に起こった問題なのですが、build-toolsのバージョンを21に上げたタイミングでOut Of Memoryでビルドが頻繁に失敗するようになりました。これは既知の問題のようで、CircleCIのドキュメントにも OOM killer ran として載っています。 Androidプロジェクトで発生した場合の対策ですが、プロジェクトによって原因が異なる可能性があるので確実ではありませんが、Gradleのバージョンを2系に上げることで改善できました。 社内への配布の自動化 DeployGateの利用 社内へのAPKの配布には、 DeployGate を利用します。DeployGateは、APKをアップロードすることで、専用アプリを介して開発中のアプリを簡単に配布できるサービスです。 DeployGateでのアプリの配布方法 DeployGateでのアプリの配布方法は、サインアップ後のチュートリアルがわかりやすく、すぐに理解できました。また、 こちらの資料 も参考になりました。 DeployGate APIの利用 社内への配布を自動化するにあたり、 DeployGate APIのPush API を利用することで、cURLコマンドで簡単にAPKをアップロードできます。 $curl -F "file=@sample.apk" -F "token=YOUR_API_KEY" -F "message=sample" https://deploygate.com/api/users/YOUR_USER_NAME/apps APIキーの取得 APIを利用するには、APIキーが必要になります。APIキーは、DeployGateへ新規登録することで発行されます。新規登録後に、 https://deploygate.com/settings#apiKey にアクセスすることで確認できます。 ターミナルでの実行 Macのターミナルから実行し、DeployGateにアップロードされることを確認します。DeployGateのダッシュボードにアップロードしたアプリが表示されれば成功です。 $ curl -F "file=@PATH_TO_YOUR_APK" -F "token=YOUR_API_KEY" -F "message=sample" https://deploygate.com/api/users/YOUR_USER_NAME/apps CircleCIでのビルドから社内配布までの流れの詳細 実際の配布の流れは、以下の通りです。 CircleCIがAPKを作成 CircleCIがDeployGateへAPIを使いAPKをアップロード DeployGateがDeployGateアプリへ配信 検証端末でDeployGateアプリを起動し、APKをダウンロード・インストール DeployGateからの配信を受けるには、DeployGateアプリをインストールしておく必要があります。 CircleCIとの繋ぎこみ CircleCIからコマンドを実行し、APKをDeployGateへアップロードします。masterへのPushからAPKがDeployGateへアップロードされるまでの流れは、以下のようになるはずです。 masterへ差分をPush CircleCIが検知し、APKを作成 DeployGateへのアップロードを実行 したがって、circle.ymlを以下のように記述します。 general: branches: only: - master artifacts: - "app/build/outputs/apk/app-release-unsigned.apk" machine: java: version: openjdk7 environment: ANDROID_HOME: /usr/local/android-sdk-linux dependencies: override: - echo y | android update sdk --no-ui --filter "android-21,build-tools-21.1.2" test: override: - echo "Nothing to do here" deployment: master: branch: master commands: - ./gradlew assembleRelease - curl -F "file=@app/build/outputs/apk/app-release-unsigned.apk" -F "token=YOUR_API_KEY" -F "message=sample" https://deploygate.com/api/users/YOUR_USER_NAME/apps deploymentのcommandsで、APKを作成とAPKのDeployGateへのアップロードを実行しています。ここで、APIキーが直書きになってしまっているので、CircleCIの環境変数に登録し、それを参照するようにします。 CircleCIの環境変数への登録 Project SettingsのTweaks > Environment variablesから設定します。NameとValueというformがあるので、NameにDEPLOY_GATE_API_KEY、ValueにAPIキーを入力し、Save variableをクリックします。するとDEPLOY_GATE_API_KEYとして環境変数が登録されます。 登録した環境変数を使用するように書き換えます。 general: branches: only: - master artifacts: - "app/build/outputs/apk/app-release-unsigned.apk" machine: java: version: openjdk7 environment: ANDROID_HOME: /usr/local/android-sdk-linux dependencies: override: - echo y | android update sdk --no-ui --filter "android-21,build-tools-21.1.2" test: override: - echo "Nothing to do here" deployment: master: branch: master commands: - ./gradlew assembleRelease - curl -F "file=@app/build/outputs/apk/app-release-unsigned.apk" -F "token=${DEPLOY_GATE_API_KEY}" -F "message=sample" https://deploygate.com/api/users/YOUR_USER_NAME/apps このように、登録した変数は、circle.ymlから参照できます。 コマンドの別ファイルへの切り出し circle.ymlを見やすくするために、コマンドを別ファイルにまとめてしまいます。 ./gradlew assembleRelease curl -F "file=@app/build/outputs/apk/app-release-unsigned.apk" -F "token=${DEPLOY_GATE_API_KEY}" -F "message=sample" https://deploygate.com/api/users/YOUR_USER_NAME/apps その結果、最終的なcircle.ymlは、以下のようになります。 general: branches: only: - master artifacts: - "app/build/outputs/apk/app-release-unsigned.apk" machine: java: version: openjdk7 environment: ANDROID_HOME: /usr/local/android-sdk-linux dependencies: override: - echo y | android update sdk --no-ui --filter "android-21,build-tools-21.1.2" test: override: - echo "Nothing to do here" deployment: master: branch: master commands: - ./deploy.sh 動作確認 うまくいけば、DeployGateアプリにビルドしたAPKが配信されます。 また、ArtifactsからAPKをダウンロードできます。 自動化した結果 APKの作成から社内配布まで自動化することができました。PullRequestのマージが行われるとAPKが配布されるようになり、リリース作業がかなり効率化されました。 自動化前 releaseブランチをmasterブランチへPullRequest PullRequestをマージ masterブランチからAPKを作成 メールでAPKを社内配布 最終確認 GooglePlayにアップロード リリース完了 自動化後 releaseブランチをmasterブランチへPullRequest PullRequestをマージ CircleCIがAPKを生成するタスクを実行 DeployGateを介して社内配布 最終確認 CircleCIからAPKをダウンロード GooglePlayにアップロード 7. リリース完了 まとめ CircleCIとDeployGateを利用して、リリース作業を自動化してみました。昨年11月から実際のリリース作業に組み入れ運用していますが、思っていた以上にストレスが減り、快適に開発を行えるようになりました。チームメンバーからの評判も良く、やってみて良かったと思います。 しかし、まだまだ改善できる点があり、継続して改善していこうと考えています。現在、GooglePlayへのAPKのアップロード自動化を組み込んだ開発フローおよびリリース作業手順をテスト中です(実験した内容は Qiitaに上げました )。また、今回紹介出来なかった内容もありますので、近日中にご紹介できればと思います。 最後に VASILYでは、自動化や新しい技術が大好きエンジニアを大募集しています!少しでもご興味のある方は是非オフィスに遊びにいらしてください! また、1月28日にSmartNewsさん、Wantedlyさんと ベストアプリ勉強会 という勉強会を開催します。私も会場にいますので、お気軽にお声掛けください! 募集要項 連絡先:info[at]vasily.jp
アバター