一休.com Developers Blog

一休のエンジニア、デザイナー、ディレクターが情報を発信していきます

ネット断食におすすめ!日帰り温泉・サウナも楽しめるSPA15選

この記事は一休.comアドベントカレンダー2018の7日目です。

こんにちは。スパ事業部 デザイナーの東根です。

約1年かけて10月25日にローンチした一休.com スパ即時予約サービス をご紹介したいと思います。

一休.com スパ

SPAとは?

エンジニアのみなさまは「SPA」と聞いてまず 「Single Page Application(シングルページアプリケーション)」 を思い浮かべたかもしれませんが、罠でした。すみません。

ここでご紹介するのは、 日帰り温浴やサウナのほかリラクゼーションマッサージの施術が受けられる 「デイスパ(Day spa)」や「ホテルスパ」のことです。

最近では「サ道」「サウナー」も増えているそうですが、 温浴施設で身体を温めてからアロマトリートメントなどの施術を受けると、 血行やリンパの流れが良くなりより効果が高まります。

「Day spa」のwiki英語版によると、

A day spa is a business that provides a variety of services for the purpose of improving health, beauty and relaxation through personal care treatments such as hair, massages and facials. A day spa is different from a beauty salon in that it contains facilities such as a sauna, pool, steam room, or whirlpool that guests may use in addition to their treatment. ...

一休 .com スパの特徴・UIUXのポイント

つまり、一休 .com スパが厳選するスパは、
街中にあるリラクサロンやエステサロンとは違い

  • バスサウナなどの温浴施設
  • プールフィットネスジムなどの運動施設
  • バスローブのまま寛げるリラクゼーションラウンジ

などの施術前後に使える付帯施設があったり、

  • 一般には流通しないこだわりの化粧品ブランド

を使っていたり、といった魅力をアピールしていく必要があります。

UIUXのポイント① 施設の魅力を伝える

f:id:higashinek:20181206134036j:plain

・・・

f:id:higashinek:20181206144238j:plain

施設の魅力といえば、何と言っても写真です。
一休.comの他のサービスにも共通しますが、高級感のある美しい写真をできるだけ大きく見れるとユーザーにその施設を訪れたときのイメージを持ってもらえます。

なので、登録するのに写真は必須。また、お部屋のスペック(広さやスパスイートかどうか、完全個室であるかetc)や温浴施設の内容(ホットバス、コールドバス、ドライサウナ、スチームサウナ、温泉、岩盤浴があるか)、プールやフィットネスジムは水着やトレーニングウェアをレンタルできるかどうかをシンプルなテキストアイコンで表現しました。

UIUXのポイント② プランの魅力を伝える

f:id:higashinek:20181206152217j:plain

ここからはスマホ版のキャプチャで説明します。 プラン一覧およびプラン概要では、タイトル・利用できる付帯施設・滞在時間目安・料金がわかるようになっています。ちなみに、タイトルにある分数純粋なトリートメントの時間で、カウンセリングや施術前後に使える付帯施設の利用時間を含んでいません。そのかわりに前後の付帯施設利用時間を含めた全体の滞在目安の時間を別に表示することで、どのくらい時間に余裕があればこのプランをしっかり体験できるかがわかります。

f:id:higashinek:20181206153816j:plain

プラン内容ではトリートメントの詳細とともにどんなお部屋で施術受けるのか、付帯施設はそれぞれいつ(施術前か後か)どのくらいの時間、どんな施設を使えるのかわかります。

UIUXのポイント③ 空き時間・予約時間をわかりやすく

f:id:higashinek:20181206162455g:plain

プランが決まったら「予約時間を確認する」ボタンから空き時間を探してみます。 まずカレンダーで「日付」を選択、次に「施術スタート時間」を選びます。 時間はレストランの予約とは異なり来店時間ではありません。*印で「付帯施設は、施術スタートの○分前から利用できます」と表示していますので、それを参考に15分刻みの時間ボタンを選んで予約フォームに進みます。

UIUXのポイント④ 予約の前に利用条件をしっかり説明

f:id:higashinek:20181206164036g:plain

注意文言に入れて読んでるハズとしてしまうのではなく
女性限定マタニティ不可のプランなどで利用できない条件を選ぶと 予約完了できないようになっています。

その他、施設スタッフから事前にユーザーへ質問・確認ができるようになっています。

おすすめのホテルスパ15選

ということで、 一休 .com スパの中から以下のポイントでおすすめの施設をセレクトして15選ご紹介します。

  • ホテルスパ、旅館・リゾートスパである
  • 温浴施設利用付きプランがある
  • 男性も女性も利用できる

東京のホテルスパ

1. ザ・ペニンシュラ スパ

東京・日比谷/ザ・ペニンシュラ東京 6階 https://spa.ikyu.com/day_spas/660025/?ikac18i ★こちら実際に体験してきました!私の中で満足度1位★

お風呂はなくサウナのみですが、しっかり暑いドライサウナと ほどよい暖かさのスチームサウナ、アロマの香りがするシャワーのほか アイスファウンテンがあるのでサウナーの方も満足いただけるはず。

アロマテラピーの施術がとっても気持ちが良いのはもちろん、 この写真のリラクゼーションルームではよく冷えたグレープフルーツジュースと マンゴージュースがいただけます。 またこのチェアではヘッドホンで音楽を聞くことができたり、読書灯で 雑誌を読むこともできるので、ネット断食にはぴったり。ゆったり寛げます。

2. ザ スパ アット マンダリン オリエンタル東京

東京・三越前駅直結/マンダリン オリエンタル 東京 37階 https://spa.ikyu.com/day_spas/660038/?ikac18i

おそらく一休.com スパで一番お高いプランのあるホテルスパ。 でも、ローンチしてすぐにペアでXmas近くに予約が入りました。すごい。 とても人気なのでいつか行ってみたい!

完全個室の贅を極めたスパスイートのほか、お風呂やサウナからも眺望が楽しめます。

3. アマン・スパ/アマン東京

東京・大手町駅直結/アマン東京 34階 https://spa.ikyu.com/day_spas/660030/?ikac18i

見てください、このプール!左端には富士山が見えます。 迷わずトップページのメインビジュアルに採用してしまいました。

プールのほかフィットネスジム、大浴場、トリートメントルーム毎の リラクゼーションエリアからも眺望が素晴らしいです。

4. AO スパ&クラブ/アンダーズ 東京

東京・虎ノ門ヒルズ/アンダーズ 東京 37階 https://spa.ikyu.com/day_spas/660032/?ikac18i

白を貴重とした洗練された空間。木のぬくもり溢れるトリートメントルームからも高層階ならではの青空や皇居を望む素晴らしい眺望が楽しめます。

全トリートメントルームにはプライベートロッカー、シャワールームがあり他のゲストの目が気になりません。 ロッカーエリア併設の温浴エリアではお風呂、シャワーの他、男性はドライサウナと水風呂、女性はスチームサウナと360°シャワーを完備されています。

5. スイス・パーフェクション スパ キオイ/ザ・プリンスギャラリー 東京紀尾井町

東京・赤坂見附・永田町/ザ・プリンスギャラリー 東京紀尾井町 30階 https://spa.ikyu.com/day_spas/660019/?ikac18i

世界中のセレブから愛されるスイス製植物性セルラー化粧品「スイス・パーフェクション」を使用する国内初の直営サロンで、エイジングケアの先端技術を結集したトリートメントを堪能できます。

写真はスパスイート・ペアルーム。角部屋のパノラマの眺望が素敵ですね。 スパスイートのプランではこのお部屋でアフターティーをいただくことができます。

6. スパ&ウェルネス ジュール/ハイアット リージェンシー 東京

東京・新宿西口/ハイアット リージェンシー 東京 28階 https://spa.ikyu.com/day_spas/660005/?ikac18i

著名デザイナーが手掛けたスタイリッシュな空間は、木などの天然素材の温もりを感じさせながらコンテンポラリーな雰囲気が漂います。

トリートメント前にはプールやフィットネスジムも利用可能。写真のとおり、プールにはジャグジーやウォームルームを備え、プールサイドは居心地のよいデッキチェアとテーブルを配したウッドデッキとなっています。

7. フォルトゥーナ/ホテルニューオータニ

東京・赤坂見附/ホテルニューオータニ ガーデンタワー 3階 https://spa.ikyu.com/day_spas/660003/?ikac18i

100℃前後の乾燥した高温で発汗を促すドライサウナ、50℃前後の温度で肌や体に負担がかかりにくいスチームサウナの2種類をラインナップ。 バイブラとジェットの機能を持つ浴槽や、体をゆったりと休められるラウンジも併設します。

プール・フィットネスジム付きのプランなら水着やトレーニングウェアを無料でレンタルできるので手ぶらで利用できます。

8. SPA THE SAKURA/ザ・プリンス さくらタワー東京

東京・品川/ザ・プリンス さくらタワー東京 B1階 https://spa.ikyu.com/day_spas/660020/?ikac18i

都会のなかにたたずむ静寂と広い空間のなかで、日本古来の伝統的な香りに包まれるトリートメントルームです。

トリートメント後、アフターティーをいただけるラウンジは、竹林にたたずむような静けさに包まれながら、ゆっくりと過ごすことができる空間になっています。

9. 庵スパ TOKYO/ヒルトン東京お台場

東京・台場/ヒルトン東京お台場 5階 https://spa.ikyu.com/day_spas/660015/?ikac18i

レインボーブリッジ、東京湾ビューが楽しめる大浴場は、プールを併設する水着着用エリアにあります。(有料レンタルあり)

海を眺めるテラスがついた開放的なフィットネスセンター。 各種マシーンを備え、ご宿泊者は無料で24時間利用できます。

東京から2時間以内で行ける旅館・リゾート

10. 赤沢スパ/赤沢迎賓館

静岡・伊東市/赤沢温泉郷 https://spa.ikyu.com/day_spas/660047/?ikac18i

壮大な緑に囲まれた赤沢温泉郷内に、美と健康、リラクゼーションの場所として誕生。 フランス発祥の海洋療法「タラソテラピー」の発想をもとに生まれた海洋深層水のプールには、赤沢沖の深海800mから汲み上げた新鮮な海水を温めて使用されています。

エステエリアには、特徴の異なる3つのドーム(サウナ)と温・冷の足湯などを完備。 海洋深層水のプールで代謝をアップさせた後には、完全個室のアロマの香りに包まれたお部屋でトリートメントを受けられます。またご希望のお客様には、プラス料金で生花のバラを100輪浮べたバラ風呂をご用意することも可能です。

11. GINYU SPA(ギンユウスパ)/箱根吟遊

神奈川・箱根・宮ノ下 https://spa.ikyu.com/day_spas/660048/?ikac18i

日本一予約の取れない宿として噂の旅館「箱根吟遊」その静寂な杜の空気に包まれた「Ginyu Spa」

トリートメント前後に ウォーターガーデンの向こうに望む雄大な自然を眺めていただきき源泉から湧き出る大地の力で、五感を解き放つことができます。 セラピストのテクニックにより、体の疲れをとることだけでなく、自分本来のバランスを整え健康や美しさへと導きます。

12. 庵スパ KARUIZAWA/軽井沢マリオットホテル

長野・軽井沢/軽井沢マリオットホテル B1階 https://spa.ikyu.com/day_spas/660017/?ikac18i

こちらのお風呂は「小瀬温泉」泉質はナトリウム-炭酸水素塩泉。 “美肌の湯”とも呼ばれ、肌の不要な角質や毛穴の汚れを取ってくれる女性に嬉しい効能がたくさん。湯上がりがさっぱりするので、スポーツやアクティビティで汗を流した後などにもおすすめです。

和のエッセンスを随所に取り入れたヒーリング空間「庵スパ KARUIZAWA」。 日本人ならではの繊細で丁寧な施術と、日本由来の贅沢な粧材を使用し、心と身体を解きほぐしていきます。

大阪・京都のホテルスパ

13. CONRAD SPA/コンラッド大阪

大阪・中之島・梅田/コンラッド大阪 38階 https://spa.ikyu.com/day_spas/660006/?ikac18i

淀川側を望むトリートメント全室からは、地上200mから望むスカイラインが刻一刻と表情を変える景色を眺めながら、安らぎの時間をお過ごしいただけます。シャワーブース、トイレ、パウダーコーナーが完備された完全プライベートな空間です。

温浴施設はサウナ、ジェットバス完備。
男性:ホットバス / コールドバス / ドライサウナ
女性:ホットバス / スチームサウナ

ロッカールーム内にはダイナミックな景色を眺めながら、ゆっくりとした時間をお過ごしいただけるラウンジも併設。ドリンクコーナーには、季節のフルーツウォーター、温かいお茶が用意されています。

14. MEGURI SPA & WELLNESS/インターコンチネンタルホテル大阪

大阪・梅田・グランフロント大阪/インターコンチネンタルホテル大阪 4階 https://spa.ikyu.com/day_spas/660021/?ikac18i

全室がクローゼット、シャワー、トイレ、ドレッサーを備え、お着替えからトリートメント後のお支度まで、全て個室内で行えるスパスイート。

温浴施設はまるで高級旅館の温泉を彷彿させる日本式浴場。 大都会の中心で味わう、想像を越えた極上のリフレッシュ&リラクゼーションジャーニーを楽しめます。

15. ザ スパ アット フォーシーズンズホテル京都

京都・東山周辺/フォーシーズンズホテル京都 https://spa.ikyu.com/day_spas/660044/?ikac18i

インドアプールは、京都屈指のゆったりとした広さを確保しております。20メートルの広さに加え、2つのジャグジーも完備。リゾート感溢れる雰囲気のなか、贅沢なひとときをお楽しみください。

お風呂(温浴・冷浴)・サウナをお楽しみいただけます。
男性:ドライサウナ
女性:スチームサウナ

入念に選び抜かれた自然の力とラグジュアリーが融合したスキンケアブランドと、深いヒーリング効果をもたらす京都ならではの素材、それらを使用したトリートメントは、本物のくつろぎと新鮮な安らぎをもたらします。

おわりに

みなさん毎日PC仕事やネットサーフィンで目を酷使しているので 肩こり・腰痛持ちの方も多いのではないでしょうか?
(わたしは慢性的な肩こりの解消にアロマテラピーにはまりました。)
たまには自分の身体もメンテナンスしないと高いパフォーマンスを出せません。

一休.com スパではただいまXmasまでのウィンターセールを開催中です。 この機会にぜひ心身を癒やす贅沢な体験をしてみませんか?

https://spa.ikyu.com/specials/timesale/?ikac18i

Rundeck in practice [導入編]

この記事は一休.comアドベントカレンダー2018の6日目です。

qiita.com


一休では、2016年の10月からRundeckを使ってバッチジョブの実行管理を行なっています。
導入からおおよそ2年たちました。
その間にデータセンターからAWSへの移行やいくつかの運用トラブルなどを経験しました。知見が溜まってきたので導入編と運用編の2つの記事に分けて紹介したいと思います。

今回はまず、導入編として、導入の背景と実際の導入作業で工夫した点、苦労した点を紹介します。また、Rundeckを導入したことで得られた改善についても紹介します。

Rundeckとは

f:id:s-tokutake:20181206084400j:plain

  • Rundeck社が提供するOSSのジョブ管理ソフトウェア。有償版もある。
  • ジョブフロー構築、失敗の自動リトライ、開始終了に対する通知フックなど、 一般的なジョブエンジンの機能を持つ。
  • Java + Groovy + Grailsで実装されている。
  • スケジューリングの定義は、cron形式。
  • 管理画面はWebブラウザで操作できる。
  • SSH経由でリモートのコマンドを実行できる。
  • SSHが通るマシンであれば、OSを問わず、どのマシンのプログラムでも定期実行できる。

脱Windows タスクスケジューラ

Rundeckを導入する前、一休ではサービス運用に必要なバッチ処理をWIndows タスクスケジューラで実行していました。登録されたタスクの数は、100を超えていました。
タスクスケジューラで100を超えたタスクを管理するのはとても辛いです。なにが辛いかというと、

タスクスケジューラのGUIは大量のタスクを管理するのに向いていない。

タスクスケジューラのGUIはフィルタや検索ができません。タスクの数が少なければ問題ないのですが、100以上のタスクを管理しようとするとかなり苦労します。例えば、手動でタスクを動かす必要がある場合、タスク一覧を目視で舐めて目的のタスクを見つけるという辛い作業をしていました。

ジョブフローが組めない。

  • 100以上のタスクがあれば、実行順序に依存関係のあるタスクもあります。しかし、タスクスケジューラでは、「タスクAが正常に実行を完了したらタスクBを動かす」というようなジョブフローが組めません。

なぜRundeckを選んだのか

脱Windows タスクスケジューラを目指すため次の4つの要件を満たすジョブエンジンを探しました。

  • ジョブフローが組めること
  • GUIがわかりやすいこと。ブラウザでアクセスできること。
  • WindowsとLinux両方で動くこと。
    • 一休はWindows系の技術スタックをメインに使っていますので、Windowsで動くことが必要ですが、Linuxサーバも使いますので、Linuxもサポートする必要があります。
  • OSSであること。
    • プロプライエタリな製品だと設計や運用でライセンスを気にする必要が出てきます。また、機能検証しにくいこともあるかもしれないので、まずは、OSSで探して、良さそうなものが見つからなければ市場調査をしようと考えました。

この基準で判断した結果、以下のふたつが、候補になりました。

決め手のひとつはGUIのシンプルさでした。SOS JobschedulerもブラウザでアクセスできるGUIを持っていますが、Rundeckの方がわかりやすいです。 また、日本語の情報もRundeckの方が多かったため、Rundeckを選択しました。
そして最大の決め手は、「SSHさえ疎通すれば、どんなマシンのどんなコマンドでもcron実行できる」という柔軟さです。これによって、ジョブ管理をするサーバとジョブを実行するサーバを分離できます。ジョブ実行に必要なリソースが足りなくなったら、ジョブ実行をするサーバだけ増やせば済みます。そして、ジョブを実行するサーバはOSを問いません。

構成

現在の構成は以下の通りです。 f:id:s-tokutake:20190106110930p:plain

RundeckサーバもジョブサーバもすべてEC2です。導入当時はデータセンターの物理マシンでしたが、構成自体は上の図とほとんど変わりません。 ジョブの実行ログはS3に保存し、RundeckのデータベースにはRDSを利用しています。AWSのサービスを最大限利用した構成にしました。 現時点では、RundeckサーバもジョブサーバもWindows Serverです。

導入にあたって、工夫した点、苦労した点を紹介します。

管理画面の認証

Rundeck自身がユーザー管理の機能を持っています。しかし、50人近くいる開発者全員のアカウントをRundeckに登録して適切に管理するのは大変です。外部の認証機構と連携する必要があるのは自明でした。 RundeckにはActive Directoryと連携する機能があります。また、oauth2_proxyに対応しているので外部のOAuth 2.0 サービスプロバイダーとも連携できます。 一休ではデータセンターにRundeckがあった時代は、AD連携機能を使って認証を行なっていました。クラウドに移行したときに、Rundeckサーバから社内のADが見えなくなってしまったので、oauth2_proxyとGitHubのOauth2の仕組みを使って、GitHubアカウントでログインできるようにしました。

oauth2_proxy は bitly社が開発しているOSSで、リバースプロキシとして動作し、oauthプロバイダとのやりとりを代理してくれる便利なツールです。Goで開発されているのでWindowsでも問題なく動作します。

※ このoauth2_proxy+GitHubでの認証の仕組みの構築には、minamijoyoさんの記事を参考にさせていただきました。ありがとうございます!

EC2プラグイン

RundeckにはEC2プラグインがあります。このプラグインを使うと特定のタグがついているEC2インスタンスを自動的にRundeckのジョブサーバにできます。

f:id:s-tokutake:20190106111304p:plain

これによって、なんらかのメンテナンスでジョブサーバの入れ替えや再構築が必要なときも簡単に対応できます。 また、動的にジョブサーバを追加することもできます。例えば、常時動作しているバッチサーバのスペックでは処理しきれないような大規模バッチ処理がある場合、高スペックなEC2インスタンスを起動して処理をさせ、完了したら、そのEC2インスタンスを停止する、という一連の流れを手動操作を介在させることなく実現できます。

sshサーバ

Linuxサーバなら悩む必要はないのですが、一休ではジョブを実行するサーバはWindowsサーバです。環境を構築した時点では、公式のWindows環境のOpenSSHの実装は、動作が不安定で使えませんでした。そこで、Windows環境で動作するSSHサーバを有償無償問わず、調査したところ、bitvise ssh server 最適と判断しました。

  • 有償ですが、安い。ライセンス買い切り。
  • 設定が簡単でシンプル。

当初は、無償のfreesshdで進めようと思っていたのですが、動作が安定せず、断念しました。

タスク移行

タスクスケジューラ上の100以上あるタスクを手動でRundeckのジョブとして移行していたら絶対にミスをします。また、当然、移行作業中も通常のサービス開発は行われています。新しいバッチ処理が追加されているかもしれません。移行作業と開発との間の齟齬が起きないようにする必要がありました。 そこでタスクスケジューラからxml形式でタスクをエクスポートし、Rundeckのジョブ定義xmlに変換するプログラムを書き、そのジョブ定義xmlをRundeckにインポートすることで、スムーズかつ齟齬がないように移行しました。

ジョブのエラー通知

Rundeckには、タスクの完了(成功、失敗)を通知する仕組みがあります。メール通知、webフックの呼び出しができます。また、プラグインを利用することでslackにも通知が飛ばせます。一休ではサービスのエラー通知はすべてslackに飛ばしています。なので、プラグインを使ってslackに通知しようと考えました。しかし、以下のふたつの理由でこのプラグインを使ってのslack通知はやめました。

  • ひとつひとつのジョブに設定しなければならないのが面倒。新しく追加したジョブに設定漏れが起きそう。
  • 通知内容が少ない。特にエラーになった場合は、実行したコマンドのステータスコードや標準出力の内容も通知したい。

そこで、以下のような方法にしました。

  • S3プラグインを使ってジョブの実行ログをS3に出力する。
  • S3へのログのPutをトリガにして動作するAWS Lamdbaを実装する。
  • このLamdbaはログの中身をみてエラーだったら、エラー内容(ステータスコードや標準出力)をSlackに通知する。成功の場合は通知しない。

このようにすることで、ジョブの通知設定に関わらず全てのエラーをslackに通知することができました。

ansibleを使って環境構築

oauth2_proxyのインストールやRundeckのインストール、各種構成ファイルの設定、監視の設定はすべてansibleで行うようにしました。こうすることでトライアンドエラーを繰り返しながら上述したような技術検証ができました。また、ansibleがWindows環境でも問題なく使えることがわかったのも収穫でした。

改善ポイント

  • 当初導入によって目論んでいた改善はほばすべて達成しました。
  • ブラウザから管理画面にアクセスできるようになったのでタスクスケジューラよりもはるかに簡単に管理できるようになりました。ジョブのフィルタもできます。また、タスクスケジューラ時代はさまざまな事情がありジョブの登録や変更は特権を持った特定のエンジニアしかできないようになっていました。このルールもRundeck移行によって見直すことができました。

  • ジョブフローも活用されています。導入当初は、使われていませんでしたが、数ヶ月経つと、特定のエンジニアが導入を推進する、ということをしなくても、自然と使われるようになっていきました。

  • また、当初見込んでいた改善ではないですが、タスクスケジューラを使ったバッチ処理よりもインフラの可用性は大きく向上しました。バッチの実行管理をするRundeckサーバと実行の定義のストアであるRDS、そして実際にバッチを実行するバッチサーバの3つを分離できました。この3つそれぞれ別々に障害対策を考えればいいので運用がしやすいです。フェールオーバの手順はタスクスケジューラ時代の障害時フェールオーバの手順よりもかなりシンプルになりました。

終わりに

今回紹介した内容は1年半くらい前に実施したことなので少し情報が古いかもしれません。しかし、LinuxのcronではなくWindowsのタスクスケジューラからRundeckに移行した例はあまりないのでは、と考え、紹介しました。RundeckはWindows環境でも十分に活用できます。 次回は、運用編として、この2年間で起こった運用トラブルとその対処について、紹介したいと思います。

この記事の筆者について

  • システム本部CTO室所属の 徳武 です。
  • サービスの技術基盤の開発運用、宿泊サービスの開発支援を行なっています。

Amazon Connect の導入と自社システムを連携した話

この記事は一休.comアドベントカレンダー2018の5日目です。

qiita.com


こんにちは。 CTO室の村石です。

一休ではAmazon Connect を導入し、カスタマーサービスの一部コールセンターを新しい体制へと変えました。

今回は導入した Amazon Connect に関して、概要から導入後の運用まで幅広く話をしようと思います。

Amazon Connect とは

AWSが提供するクラウド型のCTI*1システムのことで、コールセンターを簡単に作れることが魅力のサービスです。 また、Webサービスになっているため、ブラウザがあれば利用できます。

aws.amazon.com

コールセンターではよくある以下のようなことも、少しの設定で実現出来ることは大きな魅力だと思います。

  • 音声ガイダンスを流す
  • 案内で番号をプッシュさせる
  • 特定の担当部署に電話をつなげる

料金については、従量課金制となっており、通話が多いほど高くなります。 一方、オペレータ数などは料金の対象にならないため、柔軟に変更が可能です。

Amazon Connect は現在東京リージョンで提供されていませんが、近い将来提供されることが発表されていて今後が楽しみなサービスです。

(18/12/11 追記) 正式に東京リージョンでサービス開始されたようです。 ますます Amazon Connect の今後が楽しみなサービスですね。

aws.amazon.com

Amazon Connect の導入方法については割愛しますので、AWSの各種ドキュメントをご覧ください。

Amazon Connectの特徴

個人的に特に気になった特徴を紹介します。

短期間、初期費用不要で構築が可能

Amazon Connect インスタンスを作ってから、単純に電話できるようになるまでは、慣れれば数分で実現出来ます。 実際の運用環境を整えるには別途時間がかかりますが、時間のかかる電話線工事などがカットできるのは大きいです。

各種設定変更が楽

ここでいう各種設定とは以下のようなことです。(あくまで一部です。)

  • オペレータの追加
  • コールフローの編集
  • 営業時間の変更

Amazon Connect では、これらを管理サイトから変更することができます。 コールセンターの構築にベンダーを使うと、依頼が必要があったりと、オペレーションコストかかってしまいます。 時間がかかりがちの調整をせずとも、すぐに設定変更を行うことが出来るのは大きなポイントだと思います。

(現時点で)シドニーリージョン

前項でも述べたように、まだ日本で提供されていません。 今すぐ利用するためにはシドニーリージョンでの利用となります。 懸念として音声データの遅延が挙げられる思いますが、弊社が検証したところ、業務に差し支えるほどの遅延は確認できませんでした。

また、リージョンが海外のため、内部的には国際電話となります。 料金はそれほど気になりませんが、電話をかける際のダイヤルには気をつけないといけません。 しかし、東京リージョンでサービス開始されたとして、ダイヤルする際は国際電話でない保証はありません。

(18/12/11 追記) 「Amazon Connect とは」で追記した通り、東京リージョンにてサービス開始されましたので、削除させていただきました。

Amazon Connect の専用管理サイトが存在

AWS コンソール上の運用になるイメージを持つかもしれませんが、違います。 AWS コンソールでAmazon Connect のインスタンスを作成すると、専用の管理サイトが作成され、コールセンター業務は作成されたサイトで管理することになります。

電話を受けるオペレータのアカウントは、管理サイトから発行することになり、AWS アカウントとは別に存在します。

一通り構築が出来たらエンジニアは運用業務から離れることが出来る、というのも一つ特徴かと思います。

Amazon Connect のシステム

システム構成

電話のフローから見る構成図です。

システム構成-電話
システム構成-電話

オペレータはブラウザからWebサービスである Amazon Connect にログインして待機します。 Amazon Connect が着信を受け取り、実際にオペレータに繋がるまでに、いくつかの工程を通ります。 コールフロー / キュー / ルーティングプロファイル、この3点については、Amazon Connect を使う上で重要な項目のため少し詳しく説明します。

コールフロー

コールフローは、「着信した電話をどのように処理するか」を制御する重要な場所です。 電話がかかってきた時は、最初にコールフローに入ります。

コールフロー設定画面
コールフロー設定画面

上図のように、GUIを用いて設定することになっていて、シーケンスフローを組み立てる感覚で設定できます。

紹介しているのは、通話内容の録音設定を行い、後続のキューに転送するだけの単純な構成ですが、以下のように複雑な制御も設定可能です。

  • 営業時間内であるかチェックして、時間外なら音声ガイダンスを流して終了する
  • Lambda と連携し、任意の処理を走らせる
  • 発信者に番号プッシュの自動案内を行い、入力値によって応答するオペレータを変える

他にも、一般的なコールセンターで出来ることは一通り揃っていて、それらはすべてコールフローで設定することになります。

キュー

「着信した電話をため込む場所」です。 コールフローの終了後は基本的にキューに入り、オペレータと繋がるのを待つ状態になります。 待ちになった電話はFIFOのアルゴリズムに則り、順次オペレーターに繋がります。

ルーティングプロファイル

「キューとオペレータの橋渡し役」です。 キューに入った電話は、ルーティングプロファイルによって、電話可能のオペレータと結び付けられます。

ルーティングプロファイルとオペレータが「多対1」の関係であるのに対し、ルーティングプロファイルとキューは「多対多」の関係になっている、という点は混乱しやすいので注意が必要です。 一般的には、部署毎にルーティングプロファイルを作り、1対1の関係でキューを作るのが基本かと思いますので、気にならないかもしれません。

AWS の他サービスとの連携

Amazon Connect が取り巻く周辺のAWS事情です。 今後も更に連携できるものが増えていきそうです。

システム構成-AWS
システム構成-AWS

自社システムとの連携について

ここからは Amazon Connect と自社システムとの連携方法についてです。 連携の方法は大きく分けて2つの方法が考えられます。

  • コールフローの中で Lambda を使って連携
  • オペレータが電話を受けたタイミングで連携

ここでは、弊社で行った Lambda を使った連携を紹介します。 弊社が作成したのは、「Lambda を使って会員の情報を取得し、着信と同時にオペレータのブラウザに表示する」というものです。 簡単に処理フローを図示したものです。

Lambda連携-フロー図
Lambda連携-フロー図

これを実現するには、Lambda の他に amazon-connect-streams という JavaScript のライブラリも必要になります。 順を追って説明していきます。

Lambda 編

Lambda との連携はコールフローから行います。 まずはコールフローの中で Lambda と連携するための設定が必要です。 実際にコールフローを設定した内容です。

Lambda連携-コールフロー設定
Lambda連携-コールフロー設定

Amazon Connect と Lambda を繋げる

「AWS Lambda 関数を呼び出す」の設定項目には、呼び出したい Lambda のARNを設定します。

Lambda連携-関数を呼び出す
Lambda連携-関数を呼び出す

Lambda の返却値を Amazon Connect で設定する

「問い合わせ属性の設定」の設定項目には、Lambda 関数が返却した値を設定します。 この工程を行わないと、電話と共にデータが伝搬されません。

Lambda連携-問い合わせ属性の設定
Lambda連携-問い合わせ属性の設定

Lambda の処理

こちらは Lambda に記述する実際のソースコードになります。 python を用いています。 辞書型で渡される event 引数に発信者電話番号が入っています。 注意点としては、返却値のvalueは必ず文字列/数値/真偽値のいずれかである辞書型にする必要があります。

def lambda_handler(event, context):

    logger.info(event)
    
    end_point = event["Details"]["ContactData"]["CustomerEndpoint"]

    # ここで自社システムと連携して任意の処理を行う
    
    return {
        "response": json.dumps(end_point)
    }

引数 event 対するログ出力内容はこのようになっています。

{
    'Details': {
        'ContactData': {
            'Attributes': {},
            'Channel': 'VOICE',
            'ContactId': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
            'CustomerEndpoint': {
                'Address': '+81xxxxxxxxxx',
                'Type': 'TELEPHONE_NUMBER'
            },
            'InitialContactId': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
            'InitiationMethod': 'INBOUND',
            'InstanceARN': 'arn:aws:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
            'MediaStreams': {
                'Customer': {
                    'Audio': None
                }
            },
            'PreviousContactId': 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
            'Queue': {
                'ARN': 'arn:aws:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
                'Name': 'test-queue',
                'OutboundCallerId': {
                    'Address': '+81xxxxxxxxxx',
                    'Type': 'TELEPHONE_NUMBER'
                }
            },
            'SystemEndpoint': {
                'Address': '+81xxxxxxxxxx',
                'Type': 'TELEPHONE_NUMBER'
            }
        },
        'Parameters': {}
    },
    'Name': 'ContactFlowEvent'
}

amazon-connect-streams編

Lambda で連携したデータを電話を受けた時に表示するために必要になります。

amazon-connect-streams とは

Amazon Connect のオペレータ画面で使用する JavaScript ライブラリです。 実際に電話を受ける、かける、などの操作ができます。簡単に言うと電話機です。 これを使うことで、電話機を自作のWebサイトで利用することができます。

github.com

実際に amazon-connect-streams を使うには、AWS でのIPホワイトリストの設定と、Node.jsのビルドが必要です。 導入方法については、ここでは割愛しますので、上記ドキュメントをご覧ください。

CCP (Contact Control Panel)の表示

CCP とは、amazon-connect-streams の中で使われる機能の一部で、電話機のUIを指します。 以下のソースコードが示すように表示したい場所にdivタグを用意し、DOMを渡すことでその場所にiframeが展開されます。

let containerDiv = document.getElementById("containerDiv");
connect.core.initCCP(containerDiv, {
   ccpUrl: "https://[インスタンスエイリアス].awsapps.com" // 実際の管理サイトのURL
});

表示されるCCPです。

Amazon Connect CCP
CCP

着信時のデータ受け取り

// initCCPの後

connect.contact((contact) => {
    contact.onConnecting((conectingContact) => {
        let attributes = conectingContact.getAttributes();
        console.log(attributes);
    });
});

出力した結果は以下となり、lambda で連携した内容と一致していることが確認できます。

amazon connect streams データ取得
amazon connect streams データ取得

(おまけ) Amazon Connect Service API編

Amazon Connect では、Web API が用意されていて、データ取得/操作が行えます。 これらを利用すれば、オペレータに表示する画面から直接 Amazon Connect の機能を使えます。

docs.aws.amazon.com

API を利用するには、IAM のポリシー設定も必要になります。

キューに存在する待ち呼*2の数を取得

例として、キューに存在する待ち呼数の取得を紹介します。 当該情報を取得するには、get_current_metric_data というAPIを利用します。 python を用いて説明します。

def getCurrentQueue():

    import boto3

    # API クライアントを生成します。(IAMのポリシー情報を渡します。)
    client = boto3.client(
        "connect",
        region_name="ap-southeast-2",
        aws_access_key_id="xxxxxxxxxxxxxxxxxx",
        aws_secret_access_key="xxxxxxxxxxxxxxxxxx"
    )

    # キューの現在の情報を取得します。
    current_metoric = client.get_current_metric_data(
        InstanceId="[Amazon Connect インスタンス ID]",
        Filters={
            'Queues': [
                "[キューID]"
            ]
        },
        CurrentMetrics=[
            {
                'Name': 'CONTACTS_IN_QUEUE',
                'Unit': 'COUNT'
            }
        ]
    )

    logger.info(current_metoric["MetricResults"])

get_current_metric_data APIには、引数の CurrentMetrics 配列に別の情報を追加することで様々なデータが取得できます。 詳しくは、API ドキュメントをご覧ください。

docs.aws.amazon.com

以下は出力内容になります。

[
    {
        'Collections': [
            {
                'Metric': {
                    'Name': 'CONTACTS_IN_QUEUE',
                    'Unit': 'COUNT'
                },
                'Value': 0
            }
        ]
    }
]

Amazon Connect を導入してみて

Amazon Connect の導入を行い、技術面、運用面で思うところをあげました。

良かったこと

構築がとても楽

とにかく電話が出来るまでが早くて驚きました。 電話線工事などにかかる時間がなくなり、代わりに自社システム連携などに時間を割くことが出来ました。

拡張性が優秀

AWS のサービスであるため、Lambda など他サービスの連携が楽という利点があります。

また、amazon-connect-streams では電話機の機能だけを切り出してくれているため、それ以外すべてを使いやすくカスタマイズ出来ます。

もはや自社システムに 電話サービスを追加する感覚とも言えるでしょう。

コールフローの設定で柔軟に運用が可能

自社システムの連携を随時アップデートしていく環境では、どうしても本番環境で動作確認したい場合があります。

そんな時もコールフローで特定の電話番号だけ別の処理をさせることも出来るので、動作確認が容易になります。 メンテナンスによる急な営業時間外の設定など、緊急性のある運用もカバーできるところも良い点だと思います。

オペレーター事情に左右されにくい

Amazon Connect ではユーザに対する権限の付与や、人員の増減、権限の設定変更、などが簡単に出来ます。

ベンダーによっては、権限の変更に依頼が必要だったり、料金変更があることもあります。

人員変更が滅多にない組織なら気にならないかもしれませんが、スタートアップや柔軟に変更を行う組織の場合はありがたいでしょう。

課題に感じること

学習コストが高い(技術)

東京リージョンで提供されることが発表されているとは言え、まだ日本で導入している企業は少ないため、ドキュメントは少ないです。 弊社もトライ・アンド・エラーを繰り返して習得しました。

月の無料利用額があるため、まずはその額内でいろいろ試して習得するのが良いかと思います。

(18/12/11 追記) 「Amazon Connect とは」で追記した通り、東京リージョンにてサービス開始されましたので、削除させていただきました。

学習コストが高い(運用)

技術視点だけではなく、運用面でも学習コストが高いと感じました。

運用に入ると、コールセンターの管理者に Amazon Connect の管理を任せたいものです。 コールフロー、エージェント管理、メトリクスの作成など、習得しなければ使いこなせないものが多い印象です。

技術視点と同様に、ドキュメントが少ないため、こちらもトライ・アンド・エラーで習得しなければならないのが現状です。

一部メトリクス情報に難あり

一部の内容で満足いかない箇所がありました。 例えば、弊社で感じている箇所として以下があります。

  • リアルタイムのキュー内容表示において、自動更新が約15秒間隔(待ち呼に気付くのが遅れる)
  • 問い合わせ検索(発着信の内容を調べられる)では、通話に関するタイムスタンプに秒単位の表示が無い(APIでは取得しているのであくまで表示だけのようです。)

細かい話と捉えることも出来ますが、組織が定めるコールセンター業務のKPIに影響することも有りえます。 特に大規模な組織では気になるところではないでしょうか。

オペレータのステータス管理に不安あり

Amazon Connect ではオペレータに「Available」「offline」など、状態を管理出来ます。

「Available」という状態が電話を受け付けている状態を表しますが、この状態は明示的に変更しない限り、そのまま維持されます。 変更を怠ると、物理的に電話が取れない状況であろうと、ルーティングプロファイルによって電話が割り当てられてしまう危険があります。 これを運用以外の方法で防ぐには、Web APIを利用して自動的に状態を変更する、コールフローとシフトを連動させる、など一工夫必要になります。 導入するにあたり、方針は決めておく必要がありそうです。

また、ACW*3の状態に手動で変更出来ない、ということもあります。 Amazon Connect では、任意のカスタムステータスの作成が可能であり、似たステータスを作ることは可能です。 しかしメトリクスに影響するなど不安は残ります。

オペレータへ繋がる仕組みが今ひとつ

Amazon Connect では、ルーティングプロファイル内のオペレータに優先度設定や、特定のオペレータへ繋ぐ機能はありません。

組織のやり方によりますが、他のオペレータが全て電話で埋まった時に管理者も電話を受ける、という方針があった場合、実現する方法は難しいです。 埋まった時点で状態を変更する運用回避や、ルーティングプロファイルや Lambda を駆使する方法もありますが、難易度は高い印象です。

(18/12/08 追記) 上記取消線の内容は、管理者用のルーティングプロファイルを別途作成し、キューの優先度及び遅延時間を設定することで実現できました。

まとめ

AWS の1サービスとして提供される Amazon Connect ですが、まだ日本のコールセンター業務に適応するには、運用面で課題が残りそうな印象があります。 ここは、日本企業の導入が進むのと同時に、Amazon Connect も進化し、適応していくことを期待しています。

一方、技術面の視点から見ると、AWS との連携やカスタマイズの容易さなど、エンジニアがとっかかりやすい環境が揃っていると感じました。 今回弊社が行った自社システムの連携もほんの一部に過ぎず、コールセンターにおける業務効率化の可能性はとても大きいと思います。

以上、Amazon Connect の導入を検討している会社の参考になれば幸いです。

muraishis

*1:Computer Telephony Integration の略。電話とシステムの連携を行う技術のこと。

*2:オペレータに繋がるのを待っている着信のこと

*3:After Call Workの略。電話を切った後、対応内容の記録など、オペレータが作業をする時間のことをいう。

サードパーティJavaScriptの最適化

本記事は、一休.com Advent Calendar 2018の4日目の記事です。

qiita.com


宇都宮です。宿泊事業本部でWebフロントエンドの開発をしています。

今日は、パフォーマンス改善に取り組むフロントエンドエンジニアの多くが頭を悩ませているであろう、サードパーティスクリプト(3rd Party JavaScript)について書きます。

サードパーティスクリプトとは

サードパーティスクリプトとは、外部のドメインから読み込むJavaScriptのことです。典型的には、Google Analytics等のスクリプトが、サードパーティスクリプトに該当します。

一休.comでは、サードパーティスクリプトを、アクセス解析・広告のリターゲティング・A/Bテスト等、様々な用途に使用しています。これらのスクリプトは、一つ一つは小さなものであるため、画面表示のスピードに対するインパクトは意識しづらいものです。しかし、細かいコストが積み重なることで、サイトの読み込み速度に大きな悪影響を与えることもあります。

一休.comにおけるサードパーティスクリプト

一休.comでも、様々なサードパーティスクリプトを利用しています。たとえば、スマホのホテルページ( https://www.ikyu.com/sd/00001290/ )では、以下の外部ドメインからスクリプトを読み込んでいました。

  • bam.nr-data.net
  • js-agent.newrelic.com
  • b92.yahoo.co.jp
  • www.google-analytics.com
  • www.googleadservices.com
  • s.btstatic.com
  • yjtag.yahoo.co.jp
  • s.yjtag.jp
  • www.googletagmanager.com
  • googleads.g.doubleclick.net
  • static.criteo.net
  • s.yimg.jp

これらを合計した転送量は、ページ内で読み込んでいるJSの3分の1を占めます(300KB中、100KB)。

サードパーティスクリプトがページ読み込み速度に与える影響

↓は、スマホホテルページのパフォーマンス計測結果です。

https://www.webpagetest.org/result/181017_SD_14a6718d17894b5d25bea6ff2c01713d/

f:id:ryo-utsunomiya:20181203112751p:plain
サードパーティスクリプトあり

画面の描画完了まで(Speed Index)が3.142s、ユーザが操作可能になるまで(First Interactive)には8.3秒かかっています。

次に、WebpagetestのBlock機能を利用して、サードパーティスクリプトの読み込みを行わない状態で計測してみます。

https://www.webpagetest.org/result/181017_9Z_9051ce3990f33aadaae363806147fada/

f:id:ryo-utsunomiya:20181203122317p:plain
サードパーティスクリプトなし

画面の描画完了まで(Speed Index)が3.142s => 2.787s、ユーザが操作可能になるまで(First Interactive)は8.3秒 => 5.6秒に改善しました。

サードパーティスクリプトの多くはasyncで読み込むため、レンダリングに与える影響は軽微です。しかし、あるjsが別のjsを連れてくる、という構成になっていることが多く、jsファイルの読み込みがダラダラと続きがちです。このことは計測結果のWaterfallを見るとわかりやすいと思います。これによって、画面の表示が終わってもブラウザはまだローディング中で、画面を操作するともたつく、という状況が生まれます。

このように、サードパーティスクリプトを使用する際は、それがユーザ体験に与える悪影響も考慮する必要があります。

他のサイトは?

一休.comでは、サードパーティスクリプトによって一定のパフォーマンス劣化が見られることがわかりました。

では、他のサイトではどうでしょうか?

一例として、A/B Testing, Ads and Other Third Party Tagsというトークでは、あるWebサイトから1つスクリプトを取り除くことで、ページのロード時間が4秒改善し、サイトの売り上げが26%改善したことが紹介されています(このトークは、他にも面白い事例が満載なので、サードパーティスクリプトの改善に興味のある方は視聴をおすすめします)。

日本の事例としては、日本経済新聞社の宍戸さんが公開されている、『PWA導入の成果と課題』というスライドが、身につまされる内容で参考になります。

PWA導入の成果と課題 / nikkei-pwa-html5conf2018 - Speaker Deck

このスライドでは、インターネット全体で、サードパーティスクリプトのサイズが自前のスクリプトのサイズよりも多くなってきていること(1st party 100KBに対して3rd party 250KB)、日経新聞でも、サイズは明言されていないものの、jsリクエストの半分がサードパーティスクリプトであることなどが紹介されています。

最適化されたサイトの事例

次に、サードパーティスクリプトの配信が最適化されたサイトの事例も紹介しておきます。

宿泊予約サイトのExpediaは、一休.comと同様、様々なサードパーティスクリプトを使用しています。Expediaでは、パフォーマンスを最適化したSPA版を開発しており、スマートフォン向けホテル検索ページはSPAになっています。

Expediaのスマートフォン向けホテル検索ページ(※PCから閲覧する場合はUAをスマホのものにしてください)を開いて、Chrome DevToolsのNetworkタブ等で読み込んでいるjsのhostを確認すると、全て同一ドメイン(https://c.travel-assets.com おそらくExpediaのCDN)から取得していることに気づきます。

推測ですが、サードパーティスクリプトをセルフホストするか、トラッキングやA/Bテストのためのスクリプトを内製しているものと思われます。外部からは一切読み込まないという決断ができるのがすごいところ。

サードパーティスクリプトのパフォーマンス改善

サードパーティスクリプトの最適化について書かれた包括的なドキュメントとしては、Google Web FundamentalsのLoading Third-Party JavaScriptがおすすめです。

抜粋して紹介すると、

  • サードパーティスクリプトはasyncまたはdeferで読み込むこと
  • サードパーティスクリプトの配信サーバが遅い場合、セルフホストを検討すること
  • サイトに明確な価値をもたらさないスクリプトは削除すること
  • preconnect/dns-prefetch等のresource hintsを活用すること

などです。

一休.comでも、サードパーティスクリプトは基本asyncで読み込み、さらに、サードパーティスクリプトのドメインにはpreconnectを行っています。

一番強力な方法は「削除」なのですが、サードパーティスクリプトは多くがビジネスサイド主導で導入されており、開発側の判断だけでは削除まで踏み切れません(宍戸さんのスライドでも、技術の問題だけではないと言及があります)。

サードパーティスクリプトの最適化には、エンジニアリングチームだけでなく、サービスを運営する組織全体が、UXに高い意識をもつ必要があります。

"User First and Challenge" を社是とする一休としては、積極的に取り組んでいきたいところです。

今後の方針

一休.comで、今後行えそうなサードパーティ最適化の施策としては、以下を検討しています。

  • サードパーティスクリプトのアセットバジェットの導入
    • 読み込んでよいJSはトータルでXXKB以内、等
  • Google Tag Manager(gtm.js)の削除
    • 他のスクリプトを連れてくるだけのJSがVue.js 2個分(44KB)は大きすぎ
    • 簡単にスクリプトを追加できる = 簡単にサイトを遅くできる

まとめ

サードパーティスクリプトには、それぞれに独自のメリットがあります。たとえば、Google Analytics等のアクセス解析は、サイトを運営するうえで欠かせない情報を提供してくれます。

一方、サードパーティスクリプトにはコストがかかります。サードパーティスクリプトを読み込むと、サイトは確実に遅くなります。

用法・容量を守って、価値あるWebサービスを提供していきたいですね 💪

参考文献

vimeo.com

speakerdeck.com

developers.google.com

VueコンポーネントのState管理を考える

この記事は一休.comアドベントカレンダー2018の3日目の記事です。

qiita.com


宇都宮です。宿泊事業本部でWebフロントエンドの開発をしています。

一休.comにVue.jsを導入して、約1年が経ちました。スマートフォン版の予約入力画面から始まり、PCとスマートフォン版のホテルページほか、さまざまなUIコンポーネントがVue.jsで実装されるようになってきています。

また、予約入力画面のような複雑な状態管理を伴う画面の実装のため、Vuexを導入しています。

ここ1年ほどVue.js + Vuexというスタックで開発を行ってきて、アプリケーションの設計について色々と思うところがあったので、今回は現状でどういう構成が最適と考えているか、紹介します。

Vue.jsアプリケーションのState

Vueコンポーネントには、親から受け取るpropsと、自分自身で保持するstate(data)という2つの概念があります。また、子コンポーネントから親コンポーネントに何かしらの値を戻したい場合、eventの仕組みを利用することができます。

propsとdataについては説明を省きますが、eventについてはサンプルコードを載せておきます。

KeywordSearch.vueというコンポーネントがあって、このコンポーネントは検索キーワードの入力とバリデーションを受け持つとします。一方、検索処理の実行はAPI経由なのか画面遷移なのかが画面によって変わるため、親コンポーネントに委譲します。

このような場合、以下のようにeventの仕組みを利用することで、子から親へ値を受け渡すことができます。

// KeywordSearch.vue
<template>
  <div>
    <label>
      検索キーワード <input type="text" name="query" v-model="keyword" />
    </label>
    <button type="button" @click="search">検索</button>
  </div>
</template>
<script>
export default {
  name: "keyword-search",
  data() {
    return {
      keyword: "",
    };
  },
  methods: {
    search() {
      // search イベントを発火し、keywordを引数として渡す
      this.$emit("search", this.keyword);
    }
  }
};
</script>

// KeywordSearch.vueの親コンポーネント
<template>
  <div><keyword-search @search="handleSearch" /></div>
</template>
<script>
import KeywordSearch from "./KeywordSearch.vue";
export default {
  name: "App",
  components: {
    KeywordSearch
  },
  methods: {
    // KeywordSearchのsearchイベントのハンドラ
    handleSearch(keyword) {
      // 検索APIに問い合わせたり、画面遷移したり
    }
  }
};
</script>

まとめると、Vueコンポーネントにおいて、データの流れは以下のようになっています。

  • 自分自身で保持: data
  • 親 => 子: props
  • 子 => 親: event

このように、コンポーネント間のデータの流れがpropsとeventによって行われることをとらえて、「Props Down, Event Up」と呼ぶことがあります(もともとはReact.jsのコミュニティ発祥のフレーズだと思います)。

この辺の話はVue.jsのドキュメントでも詳しく説明されています。

jp.vuejs.org

グローバルな状態管理の必要性

ここまで説明してきたのは親子関係のあるコンポーネントの話です。しかし、実際のアプリケーションでは、親子関係のないコンポーネント間でデータを共有したい場合があります。これについても、Vue.jsおよびVuexのドキュメントに、Vuexを使うべき場面についての解説が載っています。

jp.vuejs.org

vuex.vuejs.org

一休.comの画面の例としては、「今すぐポイント割引後料金を表示」の切り替えボタンは、直接の親子関係のないコンポーネントがオン・オフの状態を共有するため、Vuexを使っています。

f:id:ryo-utsunomiya:20181202164300p:plain
「今すぐポイント割引後料金を表示」の切り替えボタン

Vuexのバッドプラクティス

Vuexは便利なのですが、何でもかんでもVuexを使うのは良いやり方とはいえません。Vuexを使っていると、以下のようなコンポーネントを書いてしまうことがあります。

<template>
  <div>{{ someState }}</div>
</template>
<script>
import { mapState } from "vuex";

export default {
  computed: {
    ...mapState(["someState"])
  }
};
</script>

このコンポーネントの作りがイマイチなのは、単に値を受け取って表示するだけのコンポーネントなのに、propsではなくStoreに依存している点です。この設計が良くないことを説明するために、モジュール結合度という概念を紹介します。

モジュール結合度

モジュール結合度とは、あるモジュールと別のモジュールの結合度を表す度合いです。低いほど疎結合、高いほど密結合となります。見た目を制御するコンポーネントの場合、様々な場所での使用が想定されるため、結合度は低い方が望ましいです。

モジュール結合度 説明
1 データ結合 引数で単純なデータを渡すパターン
2 スタンプ結合 引数で構造体などのオブジェクトを渡すパターン
3 制御結合 引数の種類によって、メソッドの内の処理が変わるパターン
4 外部結合 単一のグローバルデータを参照しているパターン
5 共通結合 複数のグローバルデータを参照しているパターン
6 内容結合 他のオブジェクトの内部を参照しているパターン

qiita.com

Vueコンポーネントでいうと、propsは「データ結合」ないし「スタンプ結合」なので、結合度は1〜2です。これに対して、storeは概念としてはグローバルデータの参照に当たり、複数のデータを参照することが多いため、「共通結合」の5、gettersやactionsに依存している場合は「内容結合」の6になります。

つまり、storeを参照するコンポーネントはstoreと密結合し、storeなしでは利用できなくなってしまうのです。

このような密結合が常に問題になるわけではありませんが、コンポーネントツリーの末端に近いようなコンポーネントがstoreを参照しているのは、コンポーネントの設計が歪になっていることのシグナルかもしれません。

Vue + Vuexアプリケーションの状態管理の指針

Vuexがその設計の参考としているFluxアーキテクチャでは、状態が一カ所に集約されていて、Single Source of Truthになると安心できる、という考え方があります。この考え方を適用すると、データは基本的にVuexのstoreから引いてくるのが正しいように思えます。

こうしたSingle Source of Truthの考え方と、疎結合なコンポーネント設計は、対立する概念ではありません。ここで参考になるのは、Presentational ComponentとContainer Componentという考え方です。

medium.com

ざっくりいうと、Presentational Componentは、propsを受け取って、表示をするだけのコンポーネント、Container ComponentはPresentational Componentを管理し、値を受け渡すコンポーネントです。

  • Container Componentはstoreを参照し、必要に応じてPresentational Componentにデータを渡す
  • Presentational Componentはstoreは参照しない

このようにコンポーネントを分類することで、storeと密結合する部分をContainer Componentに限定し、Presentational Componentは疎結合に保つことができます。

また、もう1つの設計指針として、「Vuexはグローバルな状態のストアである」という点を強調しておきたいと思います。modulesに区切ることで細かいstoreを定義することは可能ですが、実装上どこからでも参照できるVuex storeは、概念的にはグローバル変数と同じです。コンポーネントローカルな状態(要素の表示・非表示等)は、Vuex Storeで管理する状態ではありません。一方、ローディングの表示等、画面全体に影響するような状態はVuexで管理すると便利です。

まとめ

以下のような指針で設計を行うことで、Vueコンポーネント設計の基本を守りつつ、Vuexを適材適所で活用できます。

  • 親子関係のあるコンポーネント間のデータの受け渡しは「Event Up, Props down」で
  • 親子関係のないコンポーネント間のデータの共有はVuexで
  • コンポーネントの固有のデータはコンポーネントのローカルステート(data)で
  • グローバルなデータはVuexで

参考文献

jp.vuejs.org jp.vuejs.org vuex.vuejs.org qiita.com medium.com

SVGスプライトアイコンの作り方・使い方

この記事は一休.com アドベントカレンダー 2018の2日目の記事です。

qiita.com


宇都宮です。宿泊事業本部でフロントエンドの開発を行っています。

今回は、最近一休.comに導入した、SVGスプライトによるアイコンの作り方・使い方について紹介します。

f:id:ryo-utsunomiya:20181201135110p:plain
StorybookのSVGスプライトアイコン一覧

アイコンの一般的な使い方

アイコンは、一般的に、以下のような方式で使用されると思います。

  1. ビットマップ画像(gif, png等)
  2. アイコンフォント(Font Awosome等)
  3. SVG

このうち、ビットマップ画像によるアイコンは拡大・縮小に弱いため、様々な解像度の画面に対応する必要のある現代には不向きです。アイコンフォントはベクター画像なので拡大・縮小に強く、豊富なアイコンがライブラリとして提供されているのが魅力です。SVGもアイコンフォントと同様のベクター画像ですが、フォントにはない柔軟性を備えています。

一休.comは歴史のあるサービスのため、これらのアイコンが混在していますが、最近はSVGアイコンを使うことが多いです。

SVGの柔軟性

SVGは、HTMLに直接埋め込んで使用可能です。そのため、CSSによるスタイリングが可能です。アイコンフォントも色の設定やサイズの調整が可能ですが、パーツ毎に色を塗り分けたりするような柔軟なスタイリングは、SVGでしかできません。また、JavaScriptから操作しやすいという特徴もあります。

一休.comにおけるSVGアイコン使用の問題点

一休.comでのSVGアイコンの使用方法は、いくつかの変遷をたどっています。

はじめはimgタグでsvgファイルを読み込む使い方でしたが、これではSVGの柔軟性で挙げた特徴はほとんど活用できません。

<img src="/path/to/icon.svg" />

インラインSVGにすると、柔軟性は得られますが、記述が煩雑になります。

<svg ..(アイコンにもよるが、200バイトくらい).. />

そこで、Vueコンポーネント化が試みられました。以下のように、1つのSVGアイコンに対して、1つのVueコンポーネントを作る設計です。

<template>
  <svg .../>
</template>
<script>
  export default {
    name: 'some-icon',
  };
</script>

これによってSVGのスタイリングの柔軟性は増しましたが、この方式には2つ問題がありました。

1つはパフォーマンスで、アイコン1個あたり1KB(minify+gzip)、アイコン20個で約20KBものJSサイズ増加が発生したことです。本来SVGアイコンは1個200~300byte程度で、gzipするとさらに縮みます。Vueコンポーネント化することで、本来のサイズの10倍ほどに膨らんでしまっています(これはVueコンポーネント設計のまずさに起因しているため、個別にコンポーネントを作るのではなく、汎用的なSVGアイコンコンポーネントを導入するようにしていれば、パフォーマンスへの悪影響は緩和できたと思います)。

もう1つの問題は、VueコンポーネントはVueのコンテキストの中でしか使えないことです。一休.comはフルSPAではないので、サーバサイド(aspx/cshtml)で出力している部分もあります。サーバサイドで出力している部分では、Vueコンポーネントは使えないため、imgタグなどを使う必要があります。

これらの問題を解消し、

  1. SVGの機能をフル活用できる
  2. パフォーマンス上のオーバーヘッドが最小限である
  3. JSフレームワークに依存せず、どこでも使える

という条件を満たすソリューションを検討しました。

SVGスプライトとuse要素

SVGについて調べたところ、use要素というものがあることがわかりました。ページ内の別のSVGに定義されている要素を呼び出して使うことができます。

<!-- アイコン定義 -->
<svg>
  <symbol id="someIcon" ... />
</svg>

<!-- アイコン使用 -->
<svg>
  <use xlink:href="someIcon" />
<svg>

use要素を使う場合、必要なアイコンをSVGスプライトにまとめて、それをインラインSVGとしてHTML内に書き出す必要があります。インラインSVGはネットワークリクエストが発生しないため、パフォーマンス面ではアイコンを個別に読み込むよりも有利です。

この方式を採用すると、

  1. SVGの機能をフル活用できる
  2. パフォーマンス上のオーバーヘッドが最小限である
  3. JSフレームワークに依存せず、どこでも使える

という要件を全て満たせることがわかりました。

残る課題は現行の開発環境への組み込みです。

gulpによるSVGスプライト

SVGスプライト化にはgulpを使いました。webpackオンリーの環境ならwebpackでやっても良いと思います。webpackの役割をあまり増やしたくないのと、SVGスプライト関係のサンプルコードはgulpを使っているものが多かったこともあり、gulpを使用しました。

SVGスプライトのためのgulpタスクは以下のようになっています。

const gulp = require('gulp');
const path = require('path');
const svgmin = require('gulp-svgmin');
const svgstore = require('gulp-svgstore');
const cheerio = require('gulp-cheerio');

const commonDir = 'path/to/common';

gulp.task('svg-sprite',() => {
  gulp
    .src(commonDir + 'icon/*.svg')
    .pipe(
      svgmin(file => {
        const prefix = path.basename(
          file.relative,
          path.extname(file.relative),
        );
        return {
          plugins: [
            {
              cleanupIDs: {
                prefix: prefix + '-',
                minify: true,
              },
            },
          ],
        };
      }),
    )
    .pipe(svgstore({ inlineSvg: true }))
    .pipe(
      cheerio({
        run: function($) {
          $('svg').attr('style', 'display:none');
        },
        parserOptions: { xmlMode: true },
      }),
    )
    .pipe(gulp.dest(commonDir + 'icon-dist'));
});

このタスクは以下の流れで処理を行います。

  1. common/icon 配下にあるsvgファイルを取得
  2. gulp-svgminを使ってSVGを圧縮
  3. gulp-svgstoreを使ってSVGを結合
  4. gulp-cheerioを使って、結合したSVGファイルを非表示に
  5. common/icon-dist にファイル(icon.svg)を書き出し

このようにして、 https://www.ikyu.com/common/icon-dist/icon.svg (実際にサイトで使用しているSVGスプライト)は作成されています。また、このSVGスプライトは、サーバサイドでHTMLのbodyの開始直後に書き出されています。

f:id:ryo-utsunomiya:20181201133705p:plain

利用側では、以下のように、svg要素の中にuse要素を配置し、use要素のxlink:href属性にSVGのid(#ファイル名)を指定することで、アイコンを参照できます。スタイリングはCSSで行います。

<svg class="l-header-search-icon"><use xlink:href="#search"></use></svg>

まとめ

以上、SVGスプライトを使用したアイコンの作り方について紹介しました。

参考文献

GulpでSVGスプライトとアイコン一覧を一発生成 - Bit Journey's Tech Blog

Chrome Dev Summit 2018に参加しました!

この記事は一休.comアドベントカレンダー2018の1日目です。

こんにちは。レストラン事業本部の西村です。

11月12、13日にサンフランシスコで開催されたChrome Dev Summit 2018に参加しました。

f:id:nishimurae:20181130175843p:plain:w560

今年はChromeが10周年ということで、この10年で変わったこと、これからについての話で始まりました。 2日に渡って行われた22のセッションの中で、特に注目した点について深掘りしていきます。

1日目のセッション

1日目は現在提供している技術について、具体的な事例を交えながら紹介されました。

VisBug

VisBugは、hoveringとKeyboard shortcutsでブラウザ上でサイトの画像を差し替えたり、一部のコンテンツの内容やスタイルを変更できるChrome extensionです。

ブラウザ上でちょっとしたスタイル修正や画像の入れ替えをしてデザイン決め、といったことが簡単にできます!

f:id:nishimurae:20181129160030g:plain:w560

こちらはDay 1 Keynoteの最後に紹介されました。

Performance

例年以上にWebサイトのパフォーマンスに関する話が多く、ケーススタディも豊富でした。 ネイティブアプリがメインだったけれど、Webでも利用できるようにしたらアプリのダウンロード数も上がった!という話がSpotifyの事例で紹介されていました。

f:id:nishimurae:20181129172315p:plain:w500

こちらはGet Down to Business: Why the Web Mattersの中で紹介されています。

改善戦略の立て方

セッションの中で、プロジェクトの進め方に関する重要な教訓がありました。

  • 長期的なビジョンを持つ
  • 短期的な目標を計画する
  • 目標の照準を長期的なビジョンに合わせていく

パフォーマンスを改善してもビジネス的なKPIに直結するわけではなく、すぐに成果が出ないことに悩む時もあると思います。 長期的なビジョンを持ちながら短期的な目標を設定し着実にクリアしていくことを意識した方が達成感も持てると感じました。

Walmartの事例では、長期的な目標としてTime to Interactiveを70%削減、それに対して短期的な目標としてJavaScriptを500KB/CSSを40KB削減と設定しています。

f:id:nishimurae:20181129173452p:plain:w560

こちらはECの事例を用いて、Modern Websites for E-commerce in the Real Worldの中で語られています。

Performance Budgetの設定

Performance Budgetとは、Webサイトのパフォーマンスに影響する要素における数値的な限界値です。 計測ツールを使って様々な視点から分析し、適切なPerformance Budgetを設定することが重要です。

こちらはCarousellが設定しているPerformance Budgetです。

f:id:nishimurae:20181129172900p:plain:w560

Pinterestの事例では、JavaScriptのバンドルサイズ、そしてPinner Wait Time(PWT)という独自の指標を設定していました。 PWTはTime to Interactive + Image Loadingです。サービスにとって重要な画像を意識した指標ですね。

このように、それぞれの事業に沿ったPerformance Budgetを設定することはパフォーマンス改善の戦略を立てる上でとても重要です。

継続的な測定、改善

You can't improve what you don't measure. - Peter Drucker

計測しないものは改善できない、ということですね。セッションの中でも計測ツールが複数紹介されました。

Lighthouse

Lighthouseとは、Webサイトの品質向上に役立つ、オープンソースの自動化されたツールです。 Chrome Dev ToolsのAuditsタブに組み込まれているので、すでに利用している方も多いと思います。 今回は最新の変更点を紹介していました。

  • PWAのチェック項目が追加
  • Scoreの判定が厳しくなった
  • 回線の呼称を変更(Fast 3G => Slow 4G)

Scoreの判定が厳しくなった結果、緑と黄の比率が大きく変わっています。

f:id:nishimurae:20181129182943p:plain:w560

Lighthouseはlighthouse-ciのように、CIにも活用しやすくなってきています。 また、他のツールとの統合も積極的に進めていて、CalibretreoSpeedCurveSquareSpaceといったサードパーティ製のツールが紹介されました。

Chrome User Experience Report

Chrome User Experience Report(CrUX)は、ChromeユーザーによるWeb体験の実データを集計したレポートです。 BigQueryやPageSpeed Insightsで利用することができます。

最近の更新では、国ごとにデータセットが用意され地域別の分析ができるそうです。また、CrUX Dashboardではレポートをカスタマイズし、共有できます。

f:id:nishimurae:20181130110514p:plain:w560

PageSpeed Insights

PageSpeed Insightsとは、Webサイトのパフォーマンスを数値化して具体的な改善点を提案してくれる、統一されたツールです。 今回は、新しくリリースしたv5での変更点が紹介されていました。

  • 分析にLighthouseを使用
  • Lighthouseのパフォーマンスカテゴリのスコアを提供
  • フィールドデータにChrome User Experience Report(CrUX)を活用

これまでPageSpeed Insightsは独自の仕組みで測定をしていましたが、Lighthouseを利用することで以前とは違う検証結果になっているようです。

web.dev

web.devは、Lighthouseを使用した統合ツールの1つです。計測ツールとドキュメントが一体化されているため、測定後の次のステップが分かりやすくなっています。 現在beta版として提供されているので、少し紹介しようと思います。

f:id:nishimurae:20181129161228p:plain:w560

Lighthouseを使って結果をレポートしてくれます。その下にTodoがあり、優先度も表示されています。 ドキュメントがリンクされているのも特徴的です。

いくつか計測ツールを紹介しましたが、Googleはこれまでバラバラだった計測ツールをLighthouseに一本化していくことを進めていくようです。 Google製のツールだけでなく、サードパーティ製のツールも奨励していました。

計測するツールに関する基本的な部分は、State of the Union for Speed Toolingで語られています。

画像やフォント、JavaScriptに関するパフォーマンス改善の具体的なTipsについては、Speed Essentials: Key Techniques for Fast Websitesを見ると参考になります。

2日目のセッション

2日目は現在開発している新しい技術について、これからの展望が語られました。
すでにトライアルできるものから開発初期段階のものまで様々です。

virtual-scroller

virtual-scrollerは、バーチャルスクロール(画面内の必要なコンテンツのみレンダリングし、ユーザーのスクロールに応じて更新していく)を実現します。
Layered APIプロジェクトの1つとして進められていて、開発初期段階です。

Virtual Scrollとは

大量のコンテンツを表示するケースではレンダリングに時間がかかってしまいます。 例としてAddress BookやSNSのフィードなどが挙げられていました。

Virtual Scrollでは、画面外の不要なDOMを削除し必要な部分のみレンダリングするため、このようなケースのパフォーマンス改善に有効です。

f:id:nishimurae:20181128164519g:plain:w350

Virtual Scrollの技術自体は以前から存在し、特にネイティブアプリではお馴染みの技術です。 しかしWebに関してはまだ最善とは言えず、解決すべき問題が存在します。例えば、

  • 同じコンテンツ内でのリンクが動かない(全てのDOMが揃っていないため)
  • ページ内検索できない
  • 検索にインデックスさせられない

SEO観点での問題が大きいですね。画面外のDOMが存在しないため、実用面においてある程度犠牲を払わなければならないのが現実です。

どのように解決するのか

virtual-scrollerでは、リンクやページ内検索などの問題をInvisible DOMで解決しようとしています。 Invisible DOMとは、見えないけれども検索ができるDOMです。 検索などはできますが、レイアウトやスタイリング等のコストが不要なためパフォーマンスが上がります。

f:id:nishimurae:20181128164700g:plain:w350

通常のVirtual Scrollでは、画面外の不要な部分はDOMが存在しませんでした。Invisible DOMを利用したvirtual-scrollerでは、画面外の部分は見えませんがDOM自体はすべて存在します。

virtual-scollerではInvisible DOMをサポートする他にも、新たな問題を探しその解決にも取り組むそうです。 virtual-scroller: Let there be less (DOM)で詳細が語られています。

バーチャルレンダリングでは主にSEO観点での懸念があり、メリット/デメリットを理解した上で使用する必要があるというのが現状です。 今後Invisible DOMをサポートできるようになればより実用的になりそうです。

Web Packaging

Web Packagingは、端的に言うとWebサイトをパッケージ化する技術のことで、今回はSigned ExchangesBundled Exchangesが紹介されました。

1つ目のSigned Exchangesは、Exchange(HTTPリクエスト/レスポンスのペア)に署名して、任意のキャッシュサーバーから配信できるようにする仕組みです。

活用例として、AMPページのURLの最適化が紹介されていました。 Signed Exchangesにより署名されたAMPページを公開することで、Google検索は、AMPのキャッシュから配信されるAMPページではなく、Googleのキャッシュから配信される署名されたAMPページにリンクするようになります。

これがユーザーにとって何が嬉しいのか、もう少し具体的な話をしましょう。

f:id:nishimurae:20181126181634p:plain:w350

こちらは一休レストランのAMPページです。Googleの管理するAMPのキャッシュサーバーから配信されているので、URLを見るとドメインはwww.google.co.jpとなっています。 また、AMPページ用のヘッダーがアドレスバーの下に表示されています(上図赤枠)。

Signed Exchangesを利用することで、AMPページを通常のページと同様のドメインで、AMP用のヘッダーの表示なしで提供することができます。

2つ目のBundled Exchangesは、複数のExchange(HTTPリクエスト/レスポンスのペア)を1つにまとめる仕組みです。 現在プロトタイプの段階だそうですが、オフラインでのPWAのインストールなどに活用できるとのことでした。

Portals

Portalsは、SPAのようにサイト・ページ間のスムーズな遷移をブラウザで実現してくれる、現在開発中の技術です。 セッションではNavigationからTransitionへと説明されていましたが、異なるドメインであっても遷移間の摩擦を感じないページの移動が可能になります。

f:id:nishimurae:20181122173534p:plain

メリットとしては、

  • サイトを再構築することなく、
  • 異なるドメインであっても、

seamlessなページ遷移を可能にするという点です。

<portal>タグを埋め込むことでiframeのように利用することができます。iframeとの具体的な違いは以下の通りです。

f:id:nishimurae:20181128172647p:plain:w560

Portalが作動すると、documentがportalに置き換えられるため、常にトップレベルのブラウジングコンテキストとして作られます。 iframeは入れ子構造になるため、その点でも違いがあります。

まだ仕様策定の初期段階ではありますが、実用化が楽しみです。 デモでは「となりのヤングジャンプ」の事例が紹介されていましたが、ページ数の多い電子書籍にはかなり活用できそうですね。

Web PackagingとPortalsの話は、From Low Friction to Zero Friction with Web Packaging and Portalsで語られました。

フォーラム

朝から夕方まで休憩を挟みながらセッションが続きますが、その間隣の会場ではフォーラムが開催されています。 ここでは各ブースでデモを見たり、Googleのエンジニアと直接交流することができます。 セッションで語られたweb.dev、Lighthouse、VisBugなどのデモはもちろん、WebのパフォーマンスやUI/UXなど何でも相談できるReview Clinicというブースもあります。

今回はReview Clinicで一休.com レストランのスマホサイトのUI/UXについて聞いてみました。

最近のUI変更について聞いてみました!

10月にリリースした、プラン一覧のフィルターのUIについても聞いてみました。 プランを平日限定、飲み放題などの属性や時間帯で絞ったり、並べ替えを切り替えたりする機能です。

f:id:nishimurae:20181126193118j:plain:w350

上からこだわりフィルター(横スクロール)、時間帯タブ、並べ替えトグルの順番で並んでいます。 便利ですが多機能なため、どのように分かりやすく見せるかが難しい点です。

全部違うデザインなので少し分かりにくい。揃えたほうが良いと思う。
例えばフィルターの部分に関しては、スクロールできることが明らかに分かる方が良い。
スクロールバーを常に表示するとか、文字が分かりやすく途中で切れるようにするなど、何がベストか探してみてほしい。

やはり懸念していたように、複雑に見えたようです。

明らかなデザインをどのように実現していくかは、実際のユーザーの行動を数値的に見て判断する必要があります。 A/BテストをしたりしてどのようなUIが好まれるのか深掘りしてみると良いかもしれません。

学んだこと

Be Obvious: 明らかなデザインを意識すべき

会話の中で何度も "Be Obvious" と語られていました。 Googleでも様々なUIをユーザーの行動の結果を見て比較しているけれど、「明らかなデザイン」が良いという結果が出ているそうです。

機能としてはまず使ってもらえないと意味がなく、使ってもらうためには明らかに分かりやすいデザインでなければならないと感じました。

具体的に言うと以下のようなアプローチがあります。

  • カルーセルは画像がスクロールする方向に必ず半分くらいはみ出るようにして明らかに続きがあるように見せる
  • クリックできるボタンのスタイルを揃えてクリックできないものと区別する
  • アイコンにテキストで機能的な説明をつける(例: トレンドのアイコンに「トレンド」と説明をつける、など)

アクセシビリティを意識すべき

アクセシビリティとは、簡単に言うと、いかなるユーザーが、いかなるデバイスを使い、いかなる環境の下であっても利用できるようにする、ということです。 Webの制作者としては、具体的に以下の3つを意識すると良い、と話されていました。

  • タップターゲット
  • alt属性
  • 色のコントラスト比

ちなみにアクセシビリティはLighthouseで測定できます。 1日目のセッションで紹介したVisBugでも簡単にチェックすることができるので、そちらを利用してもいいかもしれません。

定量/定性的なユーザーフィードバックを元に意思決定すべき

1つ目の明らかなデザインの中でも触れていますが、UIに関する意思決定は定量/定性的なユーザーフィードバックを元に判断するべき、という話もされていました。

当然のことですが、一概に「このデザインが良い・悪い」ということはなく、ユーザーの動向を見ながら改善戦略を考えることの大切さを改めて感じました。

まとめ

初のChrome Dev Summit参加でしたが、総じて興味深い内容が多かったです。 特にセッション内でもケーススタディが多く、PWAの導入事例が国内外問わず増えたと感じました。 ケーススタディでは、実際に各社が設定したPerformance Budgetの話もされていて参考になりました。

技術的な観点で言うと、最も興味深かったのはやはりWeb PackagingPortalsです。 アプリケーションを再構築することなく利用できる、というのが嬉しいですね。

また、フォーラムやアフターパーティーのように交流できる場もあり、Googleのエンジニアやデザイナーとフランクに話ができるのも魅力でした。

おまけ:Women & Allies Receptionに参加しました!

実はChrome Dev Summit 2018の前日の夜にWomen & Allies Receptionというイベントにも参加しました。

Women TechMakersが主催していて、Chrome Dev Summit 2018参加者の女性全員が招待されていたようです。 実際参加していたのは50名くらいだったと覚えています。

イベント名の通り女性同盟なので参加者同士の交流がメインで、Googleの女性エンジニア、プロダクトマネジャー数人によるKeynote sessionもありました。 また、Googleからは、男性も含めChrome Dev Summitでセッションを担当している方など他に数名参加されていました。

Keynote sessionでは、ハラスメント問題や女性スピーカーが少ない問題などが話されていました。 つい最近起こったGoogle社でのストライキも、ハラスメント問題が関係していましたね。

女性スピーカーが少ない問題については、こちらの記事が取り上げられていました。

インポスター症候群やハラスメントに対する恐れなどが挙げられています。 Keynote session後のQ&Aでもこのあたりに関する議論が多かったように感じます。

明日は@ryo511さんによる「SVGスプライトアイコンの作り方・使い方」です。お楽しみに!

イベント開催のお知らせ ~12/12(水) Ikyu Frontend Meetup~

こんにちは。今日はイベント開催のご案内です。

12/12(水) に一休.com / 一休レストランの開発事例についてのミートアップイベントを開催いたします。

Ikyu Frontend Meetup

今回は「フロントエンド開発」をテーマとして

  • 一休レストラン スマートフォン検索ページのSPA化
  • 一休.com スマートフォンホテルページのパフォーマンス改善

を軸にNuxt.jsの導入、コンポーネント設計、CSS設計、画像最適化によるパフォーマンス改善などの事例をご紹介いたします。

セッションのほかにも、パネルディスカッションを予定していますので、参加者の皆さまと交流しながら、日々の学びを交換できればと思っています。

お申込みはこちらから。

ikyu.connpass.com

イベント実施に至ったきっかけ

user-first.ikyu.co.jp

この記事を公開したところ、「情報交換しましょう!」というお問合せを多数いただいたので、内容を膨らませてフロントエンド開発の取組みについてお話したら面白いのではないか、ということでイベントを開催することにしました。

お問合せをいただいた会社の方には、よいきっかけを与えてくださり、とても感謝しています。ありがとうございます。


まだ、募集枠には余裕がありますので、皆さまのご応募をお待ちしております!