株式会社メドレーのブログ - TECH PLAY

TECH PLAY

株式会社メドレー

株式会社メドレー の技術ブログ

1412

皆さんこんにちは。開発本部の日下です。普段は オンライン診療アプリ「CLINICS」 および オンライン医療事典「MEDLEY」 の開発を担当しています。(昨年、新卒で昨年メドレーに入ったのでエンジニア歴は 1 年弱。ベテランが多いメドレーのエンジニアチームで奮闘しています) 先日開催された エンジニア特化型 Q&A サイト「 teratail 」 さんのイベント、 MANABIYA にメドレーがスポンサーとして協力させていただきました。 エンジニアの平木と参加しましたので、イベント当日の様子をレポートします。 MANABIYA とは teratail はご存知の方も多いかもしれませんが、MANABIYA というイベントをご存じない方もいるかもしれません。 MANABIYA は今回が初開催のイベントで、”疑問” を日本中から集め、カンファレンスを通じて解決策を見出し、”知恵” を生み出すことを目的とし、秋葉原から近い 3331 Arts Chiyoda にて 2 日間に渡って開催されました。 全体の雰囲気 全体的に初開催とは思えないほど人が多く、一部のセッションでは教室が満杯になり、入場制限がかかるほどでした。また、speaker として豪華なメンバー面々が数多く集まっており、最初から最後まで、参加したすべてのセッションで立ち見が出てるほど盛況だったのがとても印象的でした。 また、イベントの名前にもなっているように、学び舎というイメージがぴったりのコンセプトで統一されているのも特徴的でした。 会場自体も元々中学校だったものを利用したアートギャラリーを使用しており、教室や階段など、元を活かした作りになっていたのでイベントの雰囲気ととてもマッチしていました。 元々教室だったところでセッションが行われました セッション セッションは Web、インフラ、DB、プログラミングから、AI、IoT 等の最近話題になっている分野まで幅広く開かれていました。 我々が参加した 2 日目はプログラミング、Web、IoT のセッションが主に開催されていました。 メドレーのプロダクトはすべて Web サービスとして提供されていることもあり、私は、Web 関連のセッションを中心に、時間が空いたら他の分野のセッションもふらっと覗き見るような形で参加しました。 エンジニアとして成長する上で必要な戦略の話や、Service Worker や Web Payments など最近環境が整ってきた技術をプロダクトに組み込んでみた話など、幅広く見ることができました。 入場制限状態でやっと入れたものの立ち見の方の後ろから見ることに 運良く前の方の席が取れましたが、こちらも立ち見の方がたくさんいらっしゃいました 個人的に古川氏による「 Web Application 2018 From Performance Perspective 」は特に勉強になったセッションでした。 Web サイトのパフォーマンスに関してのエッセンスを詰めたようなセッションで、その歴史と共に、その時々のベストプラクティス、そしてその時代のバイブルをまとめ、今どういった背景でどういった対策をするべきか、その指針となるような話聞くことができました。 サイトパフォーマンスの歴史の概要を説明していただきました 特に、Web 側は SPA として動いている CLINICS を開発しているため、 Server rendered pages are not optional という言葉の意味が衝撃的で、帰る途中からずっとそのあたりのことを考えてしまうほどでした。 Speaker Deck にスライドが上がっていますので、気になる方はそちらをご参照ください。 Web アプリケーションのパフォーマンスに関することは個人的に気になっていたものの、どこから手を付けてよいのかわからず理解があまり進んでない分野だったため、必要な知識を 40 分という短い時間で把握することができたのは非常にありがたかったです。 まさにイベントの趣旨である”気になっていること”、「回答」を知りたいがなかなか ”知る機会がなかったこと” という ”疑問” を、カンファレンスを通じて解決策を見出し、”知恵” を生み出す体験ができたのではないかと思っています。 リアル版 teratail も登場 まとめ 大規模かつ幅広い分野を取り扱っており、自分の専門や興味のある分野以外も同時に開催されたため、気軽に参加することができるイベントでした。 初めてエンジニアリングに触れて 1 年弱が経ち、その間に業務などを通じて学んできた過程で言語化できていなかったことが思っていた以上にあったことを、このイベントを通じて改めて知ることができました。 こういった大規模なイベントは初参加だったのですが、多くのことが知れたのでとても良かったです。 次回開催される際は、また行ってみようと思っています。 イベントでメドレーのことを知りご興味持っていただいた方は、お気軽にご連絡ください! どんなエンジニア・デザイナーが働いているか、どんなことをやっているか等、ぜひ HP をご覧ください。 メドレー公式note|note 「医療ヘルスケアの未来をつくる」というミッションのもと、様々な医療課題を解決するためのデジタル活用を推進する【株式会社メドレー】の公式noteです。https://www.medley.jp/ www.medley.jp メドレー平木の「気になるあの人に聞いてみた」 メドレーのエンジニア平木が、社内の気になる人に仕事内容やこれまで等をゆるりとインタビューするコーナーです。 www.wantedly.com
こんにちは。開発本部で医療介護の求人サイト「 ジョブメドレー 」の開発を担当している田村です。 メドレー開発本部で行われている勉強会「TechLunch」で、ジョブメドレーについて「求人サイトでやって良かった会員登録施策」というタイトルでお話させていただきました。インターネットで検索するとこういう内容はたくさん出てきますが、そのうちの一つとして、参考にしていただければ幸いです。 背景 医療介護の求人サイト「 ジョブメドレー 」は、創業当初(2009 年)にリリースし会社と共に進化し続けてきたメドレーで最も歴史のあるサービスです。リリース開始から 9 年ほど経ちますが、個人・事業所にとって使いやすく愛されるサービスとなるよう、日々改善を続けています。その中でも、サービスの成長に重要な要素の 1 つである「ユーザの獲得」に向けた施策は、とても大切にしています。昨年に実施した中で「サイトの会員登録増加に効果が出た施策」について、社内の他サービスにとってもノウハウとなればと、少しだけ紹介させていただきしました。 AB テストによる改善 まずはじめに、既存のサイト内で改善できる点を洗い出して優先順位を付けて費用対効果が高そうなものから着手しました。実際に以下の 2 つを AB テストを行い改善しました。 LP の改善 デザイン変更 入力フォームの変更 会員登録バナーの変更 LP の改善 BEFORE / AFTER の変更点 ユーザの満足度や求人の特徴を強調 メリハリを付け、より直感的にわかりやすく 職種をイメージしやすいビジュアルに変更 BEFORE / AFTER の変更点 全ての入力項目のある長い 1 ステップ形式から入力項目を短く分割して 5 ステップ形式に変更 ユーザがゴールイメージができるように現在のステップを表示 入力しやすいように各項目を大きく表示 各ステップへの移動がしやすいようにスクロールしなくても「つぎへ」「もどる」ボタンが押せるようなボタン配置 サクサク入力できるように各ステップへの移動でページ遷移をさせない どのくらい効果があったのか ビジュアルや訴求内容のブラッシュアップ、そしてユーザビリティを改善したことで会員登録数が約 1.2 倍という結果になりました。1.2 倍で少ないと思うかもしれませんが、サイトの規模が大きくなるほど、 ちょっとした改善を積み上げていくことが重要 だと考えています。 会員登録バナーの変更 BEFORE / AFTER の変更点 ユーザがイメージしやすい訴求内容に 訴求内容を絞り、ユーザが内容をすぐ把握できるようにビジュアルを追加 サイトの配色に合ったバナーデザイン どのくらい効果があったのか バナーの訴求内容とデザインを変更したことで、CVR が約 2 倍という結果になりました。訴求内容を多く見せることも大事ですが、 ユーザがバナーを見て内容をすぐに理解できることを重視 しています。 ユーザの行動を分析して施策を立てる ジョブメドレーには、会員登録をしていないユーザが気になった求人を保存しておくことができる「キープ機能」があります。求人の保存期限は 2 週間でこの期間内に会員登録をすると保存期限の上限がなくなり、気になった求人をずっと保存しておくことができます。 施策のきっかけは、ある調査でユーザが積極的にキープ機能を活用していることがわかったことです。このキープ機能を利用しているユーザに保存期間に関する会員登録のメリットを提示すれば、会員登録してくれるのでは?という仮説を持ち、施策を実施することになりました。 BEFORE / AFTER の変更点 キープボタンをクリックした際、モーダルを表示 保存期間は 2 週間で会員登録すると期間を越えて利用できます!と表記 会員登録ボタンを設置 どのくらい効果があったのか 具体的な数値は公表できませんが、リリース当初の会員登録数と比較すると、最近ではおよそ 10 倍程度の結果となりました。ユーザにしてほしい行動・適切な導線改善などから見えてくる施策があるので、積極的に ユーザの行動を分析し施策を立てて実行することが重要 だと言えます。 まとめ いかがでしたでしょうか。今回ご紹介した内容の他にも、ジョブメドレーでは、様々な改善を日々続けています。こうした取り組みを通じて、AB テストでちょっとした改善を積み上げていくこと、ユーザの行動を分析し施策を立てて実行すること、そして地道な改善を積み上げていくことがサービスの成長には不可欠だと実感しています。こうした地道な取り組みに励むエンジニアの方は少なくないと思いますが、私たちが実施している施策事例が、皆様の参考となれば幸いです。 今後も「 ジョブメドレー 」を会社と共に成長し続けるサービスにしていきたいと思い、日々奮闘していきたいと思います。 お知らせ メドレーでは、医療介護の求人サイト「ジョブメドレー」の他にも、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 ちょっと興味があるという方も、ぜひお気軽にご連絡ください! メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
こんにちは。開発本部で医療介護の求人サイト「 ジョブメドレー 」の開発を担当している田村です。 メドレー開発本部で行われている勉強会「TechLunch」で、ジョブメドレーについて「求人サイトでやって良かった会員登録施策」というタイトルでお話させていただきました。インターネットで検索するとこういう内容はたくさん出てきますが、そのうちの一つとして、参考にしていただければ幸いです。 背景 医療介護の求人サイト「 ジョブメドレー 」は、創業当初(2009 年)にリリースし会社と共に進化し続けてきたメドレーで最も歴史のあるサービスです。リリース開始から 9 年ほど経ちますが、個人・事業所にとって使いやすく愛されるサービスとなるよう、日々改善を続けています。その中でも、サービスの成長に重要な要素の 1 つである「ユーザの獲得」に向けた施策は、とても大切にしています。昨年に実施した中で「サイトの会員登録増加に効果が出た施策」について、社内の他サービスにとってもノウハウとなればと、少しだけ紹介させていただきしました。 AB テストによる改善 まずはじめに、既存のサイト内で改善できる点を洗い出して優先順位を付けて費用対効果が高そうなものから着手しました。実際に以下の 2 つを AB テストを行い改善しました。 LP の改善 デザイン変更 入力フォームの変更 会員登録バナーの変更 LP の改善 BEFORE / AFTER の変更点 ユーザの満足度や求人の特徴を強調 メリハリを付け、より直感的にわかりやすく 職種をイメージしやすいビジュアルに変更 BEFORE / AFTER の変更点 全ての入力項目のある長い 1 ステップ形式から入力項目を短く分割して 5 ステップ形式に変更 ユーザがゴールイメージができるように現在のステップを表示 入力しやすいように各項目を大きく表示 各ステップへの移動がしやすいようにスクロールしなくても「つぎへ」「もどる」ボタンが押せるようなボタン配置 サクサク入力できるように各ステップへの移動でページ遷移をさせない どのくらい効果があったのか ビジュアルや訴求内容のブラッシュアップ、そしてユーザビリティを改善したことで会員登録数が約 1.2 倍という結果になりました。1.2 倍で少ないと思うかもしれませんが、サイトの規模が大きくなるほど、 ちょっとした改善を積み上げていくことが重要 だと考えています。 会員登録バナーの変更 BEFORE / AFTER の変更点 ユーザがイメージしやすい訴求内容に 訴求内容を絞り、ユーザが内容をすぐ把握できるようにビジュアルを追加 サイトの配色に合ったバナーデザイン どのくらい効果があったのか バナーの訴求内容とデザインを変更したことで、CVR が約 2 倍という結果になりました。訴求内容を多く見せることも大事ですが、 ユーザがバナーを見て内容をすぐに理解できることを重視 しています。 ユーザの行動を分析して施策を立てる ジョブメドレーには、会員登録をしていないユーザが気になった求人を保存しておくことができる「キープ機能」があります。求人の保存期限は 2 週間でこの期間内に会員登録をすると保存期限の上限がなくなり、気になった求人をずっと保存しておくことができます。 施策のきっかけは、ある調査でユーザが積極的にキープ機能を活用していることがわかったことです。このキープ機能を利用しているユーザに保存期間に関する会員登録のメリットを提示すれば、会員登録してくれるのでは?という仮説を持ち、施策を実施することになりました。 BEFORE / AFTER の変更点 キープボタンをクリックした際、モーダルを表示 保存期間は 2 週間で会員登録すると期間を越えて利用できます!と表記 会員登録ボタンを設置 どのくらい効果があったのか 具体的な数値は公表できませんが、リリース当初の会員登録数と比較すると、最近ではおよそ 10 倍程度の結果となりました。ユーザにしてほしい行動・適切な導線改善などから見えてくる施策があるので、積極的に ユーザの行動を分析し施策を立てて実行することが重要 だと言えます。 まとめ いかがでしたでしょうか。今回ご紹介した内容の他にも、ジョブメドレーでは、様々な改善を日々続けています。こうした取り組みを通じて、AB テストでちょっとした改善を積み上げていくこと、ユーザの行動を分析し施策を立てて実行すること、そして地道な改善を積み上げていくことがサービスの成長には不可欠だと実感しています。こうした地道な取り組みに励むエンジニアの方は少なくないと思いますが、私たちが実施している施策事例が、皆様の参考となれば幸いです。 今後も「 ジョブメドレー 」を会社と共に成長し続けるサービスにしていきたいと思い、日々奮闘していきたいと思います。 お知らせ メドレーでは、医療介護の求人サイト「ジョブメドレー」の他にも、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 ちょっと興味があるという方も、ぜひお気軽にご連絡ください! https://www.medley.jp/recruit/creative.html
こんにちは。開発本部で医療介護の求人サイト「 ジョブメドレー 」の開発を担当している田村です。 メドレー開発本部で行われている勉強会「TechLunch」で、ジョブメドレーについて「求人サイトでやって良かった会員登録施策」というタイトルでお話させていただきました。インターネットで検索するとこういう内容はたくさん出てきますが、そのうちの一つとして、参考にしていただければ幸いです。 背景 医療介護の求人サイト「 ジョブメドレー 」は、創業当初(2009 年)にリリースし会社と共に進化し続けてきたメドレーで最も歴史のあるサービスです。リリース開始から 9 年ほど経ちますが、個人・事業所にとって使いやすく愛されるサービスとなるよう、日々改善を続けています。その中でも、サービスの成長に重要な要素の 1 つである「ユーザの獲得」に向けた施策は、とても大切にしています。昨年に実施した中で「サイトの会員登録増加に効果が出た施策」について、社内の他サービスにとってもノウハウとなればと、少しだけ紹介させていただきしました。 AB テストによる改善 まずはじめに、既存のサイト内で改善できる点を洗い出して優先順位を付けて費用対効果が高そうなものから着手しました。実際に以下の 2 つを AB テストを行い改善しました。 LP の改善 デザイン変更 入力フォームの変更 会員登録バナーの変更 LP の改善 BEFORE / AFTER の変更点 ユーザの満足度や求人の特徴を強調 メリハリを付け、より直感的にわかりやすく 職種をイメージしやすいビジュアルに変更 BEFORE / AFTER の変更点 全ての入力項目のある長い 1 ステップ形式から入力項目を短く分割して 5 ステップ形式に変更 ユーザがゴールイメージができるように現在のステップを表示 入力しやすいように各項目を大きく表示 各ステップへの移動がしやすいようにスクロールしなくても「つぎへ」「もどる」ボタンが押せるようなボタン配置 サクサク入力できるように各ステップへの移動でページ遷移をさせない どのくらい効果があったのか ビジュアルや訴求内容のブラッシュアップ、そしてユーザビリティを改善したことで会員登録数が約 1.2 倍という結果になりました。1.2 倍で少ないと思うかもしれませんが、サイトの規模が大きくなるほど、 ちょっとした改善を積み上げていくことが重要 だと考えています。 会員登録バナーの変更 BEFORE / AFTER の変更点 ユーザがイメージしやすい訴求内容に 訴求内容を絞り、ユーザが内容をすぐ把握できるようにビジュアルを追加 サイトの配色に合ったバナーデザイン どのくらい効果があったのか バナーの訴求内容とデザインを変更したことで、CVR が約 2 倍という結果になりました。訴求内容を多く見せることも大事ですが、 ユーザがバナーを見て内容をすぐに理解できることを重視 しています。 ユーザの行動を分析して施策を立てる ジョブメドレーには、会員登録をしていないユーザが気になった求人を保存しておくことができる「キープ機能」があります。求人の保存期限は 2 週間でこの期間内に会員登録をすると保存期限の上限がなくなり、気になった求人をずっと保存しておくことができます。 施策のきっかけは、ある調査でユーザが積極的にキープ機能を活用していることがわかったことです。このキープ機能を利用しているユーザに保存期間に関する会員登録のメリットを提示すれば、会員登録してくれるのでは?という仮説を持ち、施策を実施することになりました。 BEFORE / AFTER の変更点 キープボタンをクリックした際、モーダルを表示 保存期間は 2 週間で会員登録すると期間を越えて利用できます!と表記 会員登録ボタンを設置 どのくらい効果があったのか 具体的な数値は公表できませんが、リリース当初の会員登録数と比較すると、最近ではおよそ 10 倍程度の結果となりました。ユーザにしてほしい行動・適切な導線改善などから見えてくる施策があるので、積極的に ユーザの行動を分析し施策を立てて実行することが重要 だと言えます。 まとめ いかがでしたでしょうか。今回ご紹介した内容の他にも、ジョブメドレーでは、様々な改善を日々続けています。こうした取り組みを通じて、AB テストでちょっとした改善を積み上げていくこと、ユーザの行動を分析し施策を立てて実行すること、そして地道な改善を積み上げていくことがサービスの成長には不可欠だと実感しています。こうした地道な取り組みに励むエンジニアの方は少なくないと思いますが、私たちが実施している施策事例が、皆様の参考となれば幸いです。 今後も「 ジョブメドレー 」を会社と共に成長し続けるサービスにしていきたいと思い、日々奮闘していきたいと思います。 お知らせ メドレーでは、医療介護の求人サイト「ジョブメドレー」の他にも、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 ちょっと興味があるという方も、ぜひお気軽にご連絡ください! メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
こんにちは。開発本部で医療介護の求人サイト「 ジョブメドレー 」の開発を担当している田村です。 メドレー開発本部で行われている勉強会「TechLunch」で、ジョブメドレーについて「求人サイトでやって良かった会員登録施策」というタイトルでお話させていただきました。インターネットで検索するとこういう内容はたくさん出てきますが、そのうちの一つとして、参考にしていただければ幸いです。 背景 医療介護の求人サイト「 ジョブメドレー 」は、創業当初(2009 年)にリリースし会社と共に進化し続けてきたメドレーで最も歴史のあるサービスです。リリース開始から 9 年ほど経ちますが、個人・事業所にとって使いやすく愛されるサービスとなるよう、日々改善を続けています。その中でも、サービスの成長に重要な要素の 1 つである「ユーザの獲得」に向けた施策は、とても大切にしています。昨年に実施した中で「サイトの会員登録増加に効果が出た施策」について、社内の他サービスにとってもノウハウとなればと、少しだけ紹介させていただきしました。 AB テストによる改善 まずはじめに、既存のサイト内で改善できる点を洗い出して優先順位を付けて費用対効果が高そうなものから着手しました。実際に以下の 2 つを AB テストを行い改善しました。 LP の改善 デザイン変更 入力フォームの変更 会員登録バナーの変更 LP の改善 BEFORE / AFTER の変更点 ユーザの満足度や求人の特徴を強調 メリハリを付け、より直感的にわかりやすく 職種をイメージしやすいビジュアルに変更 BEFORE / AFTER の変更点 全ての入力項目のある長い 1 ステップ形式から入力項目を短く分割して 5 ステップ形式に変更 ユーザがゴールイメージができるように現在のステップを表示 入力しやすいように各項目を大きく表示 各ステップへの移動がしやすいようにスクロールしなくても「つぎへ」「もどる」ボタンが押せるようなボタン配置 サクサク入力できるように各ステップへの移動でページ遷移をさせない どのくらい効果があったのか ビジュアルや訴求内容のブラッシュアップ、そしてユーザビリティを改善したことで会員登録数が約 1.2 倍という結果になりました。1.2 倍で少ないと思うかもしれませんが、サイトの規模が大きくなるほど、 ちょっとした改善を積み上げていくことが重要 だと考えています。 会員登録バナーの変更 BEFORE / AFTER の変更点 ユーザがイメージしやすい訴求内容に 訴求内容を絞り、ユーザが内容をすぐ把握できるようにビジュアルを追加 サイトの配色に合ったバナーデザイン どのくらい効果があったのか バナーの訴求内容とデザインを変更したことで、CVR が約 2 倍という結果になりました。訴求内容を多く見せることも大事ですが、 ユーザがバナーを見て内容をすぐに理解できることを重視 しています。 ユーザの行動を分析して施策を立てる ジョブメドレーには、会員登録をしていないユーザが気になった求人を保存しておくことができる「キープ機能」があります。求人の保存期限は 2 週間でこの期間内に会員登録をすると保存期限の上限がなくなり、気になった求人をずっと保存しておくことができます。 施策のきっかけは、ある調査でユーザが積極的にキープ機能を活用していることがわかったことです。このキープ機能を利用しているユーザに保存期間に関する会員登録のメリットを提示すれば、会員登録してくれるのでは?という仮説を持ち、施策を実施することになりました。 BEFORE / AFTER の変更点 キープボタンをクリックした際、モーダルを表示 保存期間は 2 週間で会員登録すると期間を越えて利用できます!と表記 会員登録ボタンを設置 どのくらい効果があったのか 具体的な数値は公表できませんが、リリース当初の会員登録数と比較すると、最近ではおよそ 10 倍程度の結果となりました。ユーザにしてほしい行動・適切な導線改善などから見えてくる施策があるので、積極的に ユーザの行動を分析し施策を立てて実行することが重要 だと言えます。 まとめ いかがでしたでしょうか。今回ご紹介した内容の他にも、ジョブメドレーでは、様々な改善を日々続けています。こうした取り組みを通じて、AB テストでちょっとした改善を積み上げていくこと、ユーザの行動を分析し施策を立てて実行すること、そして地道な改善を積み上げていくことがサービスの成長には不可欠だと実感しています。こうした地道な取り組みに励むエンジニアの方は少なくないと思いますが、私たちが実施している施策事例が、皆様の参考となれば幸いです。 今後も「 ジョブメドレー 」を会社と共に成長し続けるサービスにしていきたいと思い、日々奮闘していきたいと思います。 お知らせ メドレーでは、医療介護の求人サイト「ジョブメドレー」の他にも、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 ちょっと興味があるという方も、ぜひお気軽にご連絡ください! メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
こんにちは。開発本部で医療介護の求人サイト「 ジョブメドレー 」の開発を担当している田村です。 メドレー開発本部で行われている勉強会「TechLunch」で、ジョブメドレーについて「求人サイトでやって良かった会員登録施策」というタイトルでお話させていただきました。インターネットで検索するとこういう内容はたくさん出てきますが、そのうちの一つとして、参考にしていただければ幸いです。 背景 医療介護の求人サイト「 ジョブメドレー 」は、創業当初(2009 年)にリリースし会社と共に進化し続けてきたメドレーで最も歴史のあるサービスです。リリース開始から 9 年ほど経ちますが、個人・事業所にとって使いやすく愛されるサービスとなるよう、日々改善を続けています。その中でも、サービスの成長に重要な要素の 1 つである「ユーザの獲得」に向けた施策は、とても大切にしています。昨年に実施した中で「サイトの会員登録増加に効果が出た施策」について、社内の他サービスにとってもノウハウとなればと、少しだけ紹介させていただきしました。 AB テストによる改善 まずはじめに、既存のサイト内で改善できる点を洗い出して優先順位を付けて費用対効果が高そうなものから着手しました。実際に以下の 2 つを AB テストを行い改善しました。 LP の改善 デザイン変更 入力フォームの変更 会員登録バナーの変更 LP の改善 BEFORE / AFTER の変更点 ユーザの満足度や求人の特徴を強調 メリハリを付け、より直感的にわかりやすく 職種をイメージしやすいビジュアルに変更 BEFORE / AFTER の変更点 全ての入力項目のある長い 1 ステップ形式から入力項目を短く分割して 5 ステップ形式に変更 ユーザがゴールイメージができるように現在のステップを表示 入力しやすいように各項目を大きく表示 各ステップへの移動がしやすいようにスクロールしなくても「つぎへ」「もどる」ボタンが押せるようなボタン配置 サクサク入力できるように各ステップへの移動でページ遷移をさせない どのくらい効果があったのか ビジュアルや訴求内容のブラッシュアップ、そしてユーザビリティを改善したことで会員登録数が約 1.2 倍という結果になりました。1.2 倍で少ないと思うかもしれませんが、サイトの規模が大きくなるほど、 ちょっとした改善を積み上げていくことが重要 だと考えています。 会員登録バナーの変更 BEFORE / AFTER の変更点 ユーザがイメージしやすい訴求内容に 訴求内容を絞り、ユーザが内容をすぐ把握できるようにビジュアルを追加 サイトの配色に合ったバナーデザイン どのくらい効果があったのか バナーの訴求内容とデザインを変更したことで、CVR が約 2 倍という結果になりました。訴求内容を多く見せることも大事ですが、 ユーザがバナーを見て内容をすぐに理解できることを重視 しています。 ユーザの行動を分析して施策を立てる ジョブメドレーには、会員登録をしていないユーザが気になった求人を保存しておくことができる「キープ機能」があります。求人の保存期限は 2 週間でこの期間内に会員登録をすると保存期限の上限がなくなり、気になった求人をずっと保存しておくことができます。 施策のきっかけは、ある調査でユーザが積極的にキープ機能を活用していることがわかったことです。このキープ機能を利用しているユーザに保存期間に関する会員登録のメリットを提示すれば、会員登録してくれるのでは?という仮説を持ち、施策を実施することになりました。 BEFORE / AFTER の変更点 キープボタンをクリックした際、モーダルを表示 保存期間は 2 週間で会員登録すると期間を越えて利用できます!と表記 会員登録ボタンを設置 どのくらい効果があったのか 具体的な数値は公表できませんが、リリース当初の会員登録数と比較すると、最近ではおよそ 10 倍程度の結果となりました。ユーザにしてほしい行動・適切な導線改善などから見えてくる施策があるので、積極的に ユーザの行動を分析し施策を立てて実行することが重要 だと言えます。 まとめ いかがでしたでしょうか。今回ご紹介した内容の他にも、ジョブメドレーでは、様々な改善を日々続けています。こうした取り組みを通じて、AB テストでちょっとした改善を積み上げていくこと、ユーザの行動を分析し施策を立てて実行すること、そして地道な改善を積み上げていくことがサービスの成長には不可欠だと実感しています。こうした地道な取り組みに励むエンジニアの方は少なくないと思いますが、私たちが実施している施策事例が、皆様の参考となれば幸いです。 今後も「 ジョブメドレー 」を会社と共に成長し続けるサービスにしていきたいと思い、日々奮闘していきたいと思います。 お知らせ メドレーでは、医療介護の求人サイト「ジョブメドレー」の他にも、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 ちょっと興味があるという方も、ぜひお気軽にご連絡ください! メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
こんにちは。開発本部で医療介護の求人サイト「 ジョブメドレー 」の開発を担当している田村です。 メドレー開発本部で行われている勉強会「TechLunch」で、ジョブメドレーについて「求人サイトでやって良かった会員登録施策」というタイトルでお話させていただきました。インターネットで検索するとこういう内容はたくさん出てきますが、そのうちの一つとして、参考にしていただければ幸いです。 背景 医療介護の求人サイト「 ジョブメドレー 」は、創業当初(2009 年)にリリースし会社と共に進化し続けてきたメドレーで最も歴史のあるサービスです。リリース開始から 9 年ほど経ちますが、個人・事業所にとって使いやすく愛されるサービスとなるよう、日々改善を続けています。その中でも、サービスの成長に重要な要素の 1 つである「ユーザの獲得」に向けた施策は、とても大切にしています。昨年に実施した中で「サイトの会員登録増加に効果が出た施策」について、社内の他サービスにとってもノウハウとなればと、少しだけ紹介させていただきしました。 AB テストによる改善 まずはじめに、既存のサイト内で改善できる点を洗い出して優先順位を付けて費用対効果が高そうなものから着手しました。実際に以下の 2 つを AB テストを行い改善しました。 LP の改善 デザイン変更 入力フォームの変更 会員登録バナーの変更 LP の改善 BEFORE / AFTER の変更点 ユーザの満足度や求人の特徴を強調 メリハリを付け、より直感的にわかりやすく 職種をイメージしやすいビジュアルに変更 BEFORE / AFTER の変更点 全ての入力項目のある長い 1 ステップ形式から入力項目を短く分割して 5 ステップ形式に変更 ユーザがゴールイメージができるように現在のステップを表示 入力しやすいように各項目を大きく表示 各ステップへの移動がしやすいようにスクロールしなくても「つぎへ」「もどる」ボタンが押せるようなボタン配置 サクサク入力できるように各ステップへの移動でページ遷移をさせない どのくらい効果があったのか ビジュアルや訴求内容のブラッシュアップ、そしてユーザビリティを改善したことで会員登録数が約 1.2 倍という結果になりました。1.2 倍で少ないと思うかもしれませんが、サイトの規模が大きくなるほど、 ちょっとした改善を積み上げていくことが重要 だと考えています。 会員登録バナーの変更 BEFORE / AFTER の変更点 ユーザがイメージしやすい訴求内容に 訴求内容を絞り、ユーザが内容をすぐ把握できるようにビジュアルを追加 サイトの配色に合ったバナーデザイン どのくらい効果があったのか バナーの訴求内容とデザインを変更したことで、CVR が約 2 倍という結果になりました。訴求内容を多く見せることも大事ですが、 ユーザがバナーを見て内容をすぐに理解できることを重視 しています。 ユーザの行動を分析して施策を立てる ジョブメドレーには、会員登録をしていないユーザが気になった求人を保存しておくことができる「キープ機能」があります。求人の保存期限は 2 週間でこの期間内に会員登録をすると保存期限の上限がなくなり、気になった求人をずっと保存しておくことができます。 施策のきっかけは、ある調査でユーザが積極的にキープ機能を活用していることがわかったことです。このキープ機能を利用しているユーザに保存期間に関する会員登録のメリットを提示すれば、会員登録してくれるのでは?という仮説を持ち、施策を実施することになりました。 BEFORE / AFTER の変更点 キープボタンをクリックした際、モーダルを表示 保存期間は 2 週間で会員登録すると期間を越えて利用できます!と表記 会員登録ボタンを設置 どのくらい効果があったのか 具体的な数値は公表できませんが、リリース当初の会員登録数と比較すると、最近ではおよそ 10 倍程度の結果となりました。ユーザにしてほしい行動・適切な導線改善などから見えてくる施策があるので、積極的に ユーザの行動を分析し施策を立てて実行することが重要 だと言えます。 まとめ いかがでしたでしょうか。今回ご紹介した内容の他にも、ジョブメドレーでは、様々な改善を日々続けています。こうした取り組みを通じて、AB テストでちょっとした改善を積み上げていくこと、ユーザの行動を分析し施策を立てて実行すること、そして地道な改善を積み上げていくことがサービスの成長には不可欠だと実感しています。こうした地道な取り組みに励むエンジニアの方は少なくないと思いますが、私たちが実施している施策事例が、皆様の参考となれば幸いです。 今後も「 ジョブメドレー 」を会社と共に成長し続けるサービスにしていきたいと思い、日々奮闘していきたいと思います。 お知らせ メドレーでは、医療介護の求人サイト「ジョブメドレー」の他にも、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 ちょっと興味があるという方も、ぜひお気軽にご連絡ください! メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
こんにちは。開発本部で医療介護の求人サイト「 ジョブメドレー 」の開発を担当している田村です。 メドレー開発本部で行われている勉強会「TechLunch」で、ジョブメドレーについて「求人サイトでやって良かった会員登録施策」というタイトルでお話させていただきました。インターネットで検索するとこういう内容はたくさん出てきますが、そのうちの一つとして、参考にしていただければ幸いです。 背景 医療介護の求人サイト「 ジョブメドレー 」は、創業当初(2009 年)にリリースし会社と共に進化し続けてきたメドレーで最も歴史のあるサービスです。リリース開始から 9 年ほど経ちますが、個人・事業所にとって使いやすく愛されるサービスとなるよう、日々改善を続けています。その中でも、サービスの成長に重要な要素の 1 つである「ユーザの獲得」に向けた施策は、とても大切にしています。昨年に実施した中で「サイトの会員登録増加に効果が出た施策」について、社内の他サービスにとってもノウハウとなればと、少しだけ紹介させていただきしました。 AB テストによる改善 まずはじめに、既存のサイト内で改善できる点を洗い出して優先順位を付けて費用対効果が高そうなものから着手しました。実際に以下の 2 つを AB テストを行い改善しました。 LP の改善 デザイン変更 入力フォームの変更 会員登録バナーの変更 LP の改善 BEFORE / AFTER の変更点 ユーザの満足度や求人の特徴を強調 メリハリを付け、より直感的にわかりやすく 職種をイメージしやすいビジュアルに変更 BEFORE / AFTER の変更点 全ての入力項目のある長い 1 ステップ形式から入力項目を短く分割して 5 ステップ形式に変更 ユーザがゴールイメージができるように現在のステップを表示 入力しやすいように各項目を大きく表示 各ステップへの移動がしやすいようにスクロールしなくても「つぎへ」「もどる」ボタンが押せるようなボタン配置 サクサク入力できるように各ステップへの移動でページ遷移をさせない どのくらい効果があったのか ビジュアルや訴求内容のブラッシュアップ、そしてユーザビリティを改善したことで会員登録数が約 1.2 倍という結果になりました。1.2 倍で少ないと思うかもしれませんが、サイトの規模が大きくなるほど、 ちょっとした改善を積み上げていくことが重要 だと考えています。 会員登録バナーの変更 BEFORE / AFTER の変更点 ユーザがイメージしやすい訴求内容に 訴求内容を絞り、ユーザが内容をすぐ把握できるようにビジュアルを追加 サイトの配色に合ったバナーデザイン どのくらい効果があったのか バナーの訴求内容とデザインを変更したことで、CVR が約 2 倍という結果になりました。訴求内容を多く見せることも大事ですが、 ユーザがバナーを見て内容をすぐに理解できることを重視 しています。 ユーザの行動を分析して施策を立てる ジョブメドレーには、会員登録をしていないユーザが気になった求人を保存しておくことができる「キープ機能」があります。求人の保存期限は 2 週間でこの期間内に会員登録をすると保存期限の上限がなくなり、気になった求人をずっと保存しておくことができます。 施策のきっかけは、ある調査でユーザが積極的にキープ機能を活用していることがわかったことです。このキープ機能を利用しているユーザに保存期間に関する会員登録のメリットを提示すれば、会員登録してくれるのでは?という仮説を持ち、施策を実施することになりました。 BEFORE / AFTER の変更点 キープボタンをクリックした際、モーダルを表示 保存期間は 2 週間で会員登録すると期間を越えて利用できます!と表記 会員登録ボタンを設置 どのくらい効果があったのか 具体的な数値は公表できませんが、リリース当初の会員登録数と比較すると、最近ではおよそ 10 倍程度の結果となりました。ユーザにしてほしい行動・適切な導線改善などから見えてくる施策があるので、積極的に ユーザの行動を分析し施策を立てて実行することが重要 だと言えます。 まとめ いかがでしたでしょうか。今回ご紹介した内容の他にも、ジョブメドレーでは、様々な改善を日々続けています。こうした取り組みを通じて、AB テストでちょっとした改善を積み上げていくこと、ユーザの行動を分析し施策を立てて実行すること、そして地道な改善を積み上げていくことがサービスの成長には不可欠だと実感しています。こうした地道な取り組みに励むエンジニアの方は少なくないと思いますが、私たちが実施している施策事例が、皆様の参考となれば幸いです。 今後も「 ジョブメドレー 」を会社と共に成長し続けるサービスにしていきたいと思い、日々奮闘していきたいと思います。 お知らせ メドレーでは、医療介護の求人サイト「ジョブメドレー」の他にも、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 ちょっと興味があるという方も、ぜひお気軽にご連絡ください! メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
こんにちは。開発本部で医療介護の求人サイト「 ジョブメドレー 」の開発を担当している田村です。 メドレー開発本部で行われている勉強会「TechLunch」で、ジョブメドレーについて「求人サイトでやって良かった会員登録施策」というタイトルでお話させていただきました。インターネットで検索するとこういう内容はたくさん出てきますが、そのうちの一つとして、参考にしていただければ幸いです。 背景 医療介護の求人サイト「 ジョブメドレー 」は、創業当初(2009 年)にリリースし会社と共に進化し続けてきたメドレーで最も歴史のあるサービスです。リリース開始から 9 年ほど経ちますが、個人・事業所にとって使いやすく愛されるサービスとなるよう、日々改善を続けています。その中でも、サービスの成長に重要な要素の 1 つである「ユーザの獲得」に向けた施策は、とても大切にしています。昨年に実施した中で「サイトの会員登録増加に効果が出た施策」について、社内の他サービスにとってもノウハウとなればと、少しだけ紹介させていただきしました。 AB テストによる改善 まずはじめに、既存のサイト内で改善できる点を洗い出して優先順位を付けて費用対効果が高そうなものから着手しました。実際に以下の 2 つを AB テストを行い改善しました。 LP の改善 デザイン変更 入力フォームの変更 会員登録バナーの変更 LP の改善 BEFORE / AFTER の変更点 ユーザの満足度や求人の特徴を強調 メリハリを付け、より直感的にわかりやすく 職種をイメージしやすいビジュアルに変更 BEFORE / AFTER の変更点 全ての入力項目のある長い 1 ステップ形式から入力項目を短く分割して 5 ステップ形式に変更 ユーザがゴールイメージができるように現在のステップを表示 入力しやすいように各項目を大きく表示 各ステップへの移動がしやすいようにスクロールしなくても「つぎへ」「もどる」ボタンが押せるようなボタン配置 サクサク入力できるように各ステップへの移動でページ遷移をさせない どのくらい効果があったのか ビジュアルや訴求内容のブラッシュアップ、そしてユーザビリティを改善したことで会員登録数が約 1.2 倍という結果になりました。1.2 倍で少ないと思うかもしれませんが、サイトの規模が大きくなるほど、 ちょっとした改善を積み上げていくことが重要 だと考えています。 会員登録バナーの変更 BEFORE / AFTER の変更点 ユーザがイメージしやすい訴求内容に 訴求内容を絞り、ユーザが内容をすぐ把握できるようにビジュアルを追加 サイトの配色に合ったバナーデザイン どのくらい効果があったのか バナーの訴求内容とデザインを変更したことで、CVR が約 2 倍という結果になりました。訴求内容を多く見せることも大事ですが、 ユーザがバナーを見て内容をすぐに理解できることを重視 しています。 ユーザの行動を分析して施策を立てる ジョブメドレーには、会員登録をしていないユーザが気になった求人を保存しておくことができる「キープ機能」があります。求人の保存期限は 2 週間でこの期間内に会員登録をすると保存期限の上限がなくなり、気になった求人をずっと保存しておくことができます。 施策のきっかけは、ある調査でユーザが積極的にキープ機能を活用していることがわかったことです。このキープ機能を利用しているユーザに保存期間に関する会員登録のメリットを提示すれば、会員登録してくれるのでは?という仮説を持ち、施策を実施することになりました。 BEFORE / AFTER の変更点 キープボタンをクリックした際、モーダルを表示 保存期間は 2 週間で会員登録すると期間を越えて利用できます!と表記 会員登録ボタンを設置 どのくらい効果があったのか 具体的な数値は公表できませんが、リリース当初の会員登録数と比較すると、最近ではおよそ 10 倍程度の結果となりました。ユーザにしてほしい行動・適切な導線改善などから見えてくる施策があるので、積極的に ユーザの行動を分析し施策を立てて実行することが重要 だと言えます。 まとめ いかがでしたでしょうか。今回ご紹介した内容の他にも、ジョブメドレーでは、様々な改善を日々続けています。こうした取り組みを通じて、AB テストでちょっとした改善を積み上げていくこと、ユーザの行動を分析し施策を立てて実行すること、そして地道な改善を積み上げていくことがサービスの成長には不可欠だと実感しています。こうした地道な取り組みに励むエンジニアの方は少なくないと思いますが、私たちが実施している施策事例が、皆様の参考となれば幸いです。 今後も「 ジョブメドレー 」を会社と共に成長し続けるサービスにしていきたいと思い、日々奮闘していきたいと思います。 お知らせ メドレーでは、医療介護の求人サイト「ジョブメドレー」の他にも、医師たちがつくるオンライン医療事典「 MEDLEY 」、口コミで探せる介護施設の検索サイト「 介護のほんね 」、オンライン診療アプリ「 CLINICS 」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 ちょっと興味があるという方も、ぜひお気軽にご連絡ください! メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
こんにちは、開発本部の高井です。オンライン診療アプリ「 CLINICS 」のアプリ開発を主に担当しています。 CLINICS では Web に加えて、iOS 版と Android 版の各プラットフォームの仕様変更や機能追加などをほぼ同時に開発しているのですが、担当する人数が増えたりすることで、仕様に差が出たり、その結果手戻りが起きるということも増え始めていました。 そうした課題を解決するために実践した様々な施策の中から、特に有効だった 3 つの改善策について、今日はご紹介します。 背景 CLINICS の開発チームでは 5 人ほどのエンジニアがタスク単位で全てのプラットフォームを実装したり、大きいタスクの場合はプラットフォーム毎に別の開発者が担当する形で開発しています。 そのような形で機能追加や不具合対応の開発を進める中で、以下のような課題がありました。 プラットフォーム間で仕様やデザインが違う リリース直前に仕様の違いが見つかり、手戻りが発生する 各プラットフォームに対する習熟度にバラつきがあるため、開発者によって実装方法が違う 特にプラットフォーム毎に開発者がほぼ固定されてしまっていた時期には、コードレビューはしていても微妙な違いに気づかなかったり、同じ UI にするのに実装コストが高くてあきらめたり、ということが起こりがちでした。** プラットフォーム間で仕様やデザインが違うとユーザ体験の質がプラットフォームによってバラついてしまいますし、デザインや企画の作業も増えてしまいます** 。これらに加えて、エンジニアの人数が増えたり、デザイナーやカスタマーサポートなどエンジニア以外のメンバーとのコミュニケーションも増えたりしてきたこともあって、開発スピードも段々と遅くなってきていました。 そのような状況を改善するために、チーム内で継続的に実装方法や開発フローを見直し、改善策を実施してきました。 今回は以下の 3 つの改善策をご紹介します。具体的な実装については、主に iOS で使用しているコードを引用してご紹介します。(コードの一部を抜粋しているので、そのままでは使用することはできません。あくまでも参考コードとして読んでください。) DLS(デザイン言語システム)の導入 アプリエラーの共通化 コードレビューの手順改善 改善策 1 DLS(デザイン言語システム)の導入 まずは DLS(デザイン言語システム)の導入についてです。DLS とは以前、本ブログでもデザイナーの前田がご紹介させていただきましたが( デザイン言語システムを入れたらコミュニケーションコストがぐっと下がった話〜メドレー TechLunch〜 )、** UI に一貫性をもたせるため、配色やレイアウト、タイポグラフィやマージンなどのルール **を策定し、チーム全体で継続的に運用していくための仕組みです。策定したルールを組み込んだ各コンポーネントのデザインを元に、Web / iOS / Android の各プラットフォームで UI を実装して開発時に再利用できるようにしています。デザイン自体は下記のような形で Sketch ファイルで管理しています。 iOS については各コンポーネントをカスタムビュークラスとして実装し、再利用できるようにしました。DLS 導入以前はプラットフォーム毎に違った UI やルールで開発していたので、実装段階で担当する開発者毎の認識によって品質や仕様に差が出ている状態でした。DLS 導入によってそのような差が出にくくなり、一定の品質を保つことができるようになりました。 また、** UI の微調整などが減って、機能ロジックに重点を置いた開発に専念できるようになり、さらにデザイナーとの認識合わせが最小限になったことにより開発効率も上がった **と感じています。UI の基盤をつくったことで新しく画面を開発する場合でもコンポーネントを組み合わせ、エンジニアだけで実装が完了することも多くなり、その分デザイナーは次の施策やプロジェクトに専念できるようになりました。 実装についてですが、各コンポーネント毎に xib ファイルで UI パーツを作成し、それをクラスファイルで読み込んでカスタムビュークラスの見た目として使っています。カスタムビューは再利用しやすく、利用時にバラツキが出にくいように以下の点を満たすように実装しました。 Interface Builder/コードのどちらからでも初期化できる ビルドする前に Storyboard 上で UI パーツのデザインを確認できるように IBDesignable と IBInspectable を指定する カスタムビューの中で UI 要素のマージンや高さを指定する 例えば、セレクトフォームコンポーネントのカスタムビューは以下のような実装になっています。 xib ファイル クラスファイル import UIKit protocol ClinicsFormSelectDelegate : class { func didClickFormSelect ( sender : ClinicsFormSelect) } @IBDesignable class ClinicsFormSelect : UIView { @IBOutlet weak var selectView: SelectView! @IBInspectable var labelText: String = "Form-parts" { didSet { selectView. labelText = labelText } } weak var delegate: ClinicsFormSelectDelegate? // コードから初期化する場合に呼ばれる override init ( frame : CGRect) { super . init ( frame : frame) commonInit () } // Interface Builder から初期化する場合に呼ばれる required init? ( coder aDecoder : NSCoder) { super . init ( coder : aDecoder) commonInit () } private func commonInit () { // xib ファイルの読み込み let bundle = Bundle ( for : type ( of : self )) let view = UINib ( nibName : "ClinicsFormSelect" , bundle : bundle). instantiate ( withOwner : self , options : nil ). first as! UIView addSubview (view) backgroundColor = . clear view. backgroundColor = . clear // 読み込んだ View のサイズがカスタムクラス(ClinicsFormSelect)と同じサイズになるように Constraint を設定する view. translatesAutoresizingMaskIntoConstraints = false let bindings = [ "view" : view] addConstraints (NSLayoutConstraint. constraints ( withVisualFormat : "H:|[view]|" , options : NSLayoutFormatOptions ( rawValue : 0 ), metrics : nil , views : bindings)) addConstraints (NSLayoutConstraint. constraints ( withVisualFormat : "V:|[view]|" , options : NSLayoutFormatOptions ( rawValue : 0 ), metrics : nil , views : bindings)) } // xib ファイルの中に配置した UI 要素へのアクションのハンドリング @IBAction func didTap ( _ sender : UITapGestureRecognizer) { delegate?. didClickFormSelect ( sender : self ) } } CLINICS では主に Storyboard を使って UI を実装しているので、使用するときは Storyboard に UIView を置き、コンポーネントのクラス名を指定して使います。テキストなどのプロパティを設定し、Constraint を指定して配置すれば完了です。ユーザによるアクションのハンドリングや動的にプロパティを切り替える必要がある場合は、呼び出し側で処理を追加します。 最終的にビルドすると以下のように表示されます。(表示されている内容は開発中に作成した仮のデータで実際のものとは異なります。) 改善策 2 アプリエラーの共通化 以前は業務的に重要な処理のエラー以外はプラットフォーム毎で表示するエラーメッセージが異なっていたり、エラーハンドリング時に違った挙動をしていることがありました。その結果、ユーザ体験が一貫したものになっていないというだけでなく、お問い合わせがあってもカスタマーサポートが一次回答しにくかったり、伝えられた内容が曖昧なため開発者が調査するのに時間がかかったりすることがありました。 そこで、改めてフロント側で発生するエラーの定義を共通化し、エラーメッセージやエラーハンドリング時の処理も統一しました。** 問い合わせの効率化のために共通のエラーコードも決めて、エラー発生時に表示されるアラートに追加し、それらのエラー定義はドキュメントで一覧化して、カスタマーサポートにも共有 **するようにしました。 また、エラーハンドリング時にクラッシュレポートのログに記録する内容や送信するタイミングを統一して、開発者全員が理解しやすいようにしました。エラーコードの表示については、改善を検討していた時期にちょうど参加していた iOSDC Japan 2017 で、同じような課題に対する知見を 発表 されていたのを見て、早速取り入れました。最近ではユーザからの問い合わせにもエラーコードが使われることがあり、実際にコミュニケーションコストを低下させることができているように思います。 エラーのフィードバックは細かいところではありますが、ユーザのアクションを継続させるために重要な要素のひとつです。CLINICS はユーザ属性が老若男女問わず幅広いので特に気を配って改善を行ってきました。 実装についてですが、iOS では以下のように定義しています。 enum ApplicationError : Error { case commonRequestError ( String ) case createReservationCardError case createReservationScheduleIsFullError ~ var errorCode: String { switch self { case let . commonRequestError (viewId): return " \( viewId ) -0000" case . createReservationCardError : return "40-0001" case . createReservationScheduleIsFullError : return "40-0002" ~ var title: String { switch self { case . commonRequestError : return "接続エラー" case . createReservationCardError : return "決済失敗エラー" ~ var description: String { switch self { case . commonRequestError : return "データを正しく表示出来ない可能性があります。 \n 通信状況をお確かめいただくか、しばらく経ってから再度起動してください。" case . createReservationCardError : return "ご登録されているクレジットカードの決済中にエラーが発生しました。 \n おそれいりますが、もう一度最初から操作ください。" ~ Android でも同様に enum で定義しています。 enum class ApplicationError ( var code: String , val title: String , val description: String ) { CommonRequestError ( "0000" , "接続エラー" , "データを正しく表示出来ない可能性があります。 \n 通信状況をお確かめいただくか、しばらく経ってから再度起動してください。" ), CreateReservationCardError ( "40-0001" , "決済失敗エラー" , "ご登録されているクレジットカードの決済中にエラーが発生しました。 \n おそれいりますが、もう一度最初から操作ください。" ), CreateReservationScheduleIsFullError ( "40-0002" , "スケジュール空きなしエラー" , "選択された予約日時のスケジュールに空きがありませんでした。 \n おそれいりますが、別の予約日時をご選択のうえ、もう一度最初から操作ください。" ), ~ 改善策 3 コードレビューの手順改善 リリース当初から実装者以外のメンバーによるレビューは適宜行なっていましたが、レビューの段階でデグレや仕様の違いを見逃してしまうことがあったので、レビュー体制の強化とメンバーのソース理解の向上を図るために、以下のようにルールを設定しました。 セルフマージはしない PR に対して 2 人以上でレビューする ビューの変更があった場合には画面キャプチャを貼る それらを守りやすく、より効率的にするために Danger も導入しました。 導入手順は こちら にまとめられているほか、検索すればけっこう出てくるので省略します。弊社では iOS の CI は Bitrise を使用しているので Bitrise 上で実行して GitHub の PR に反映させています。 Danger では、以下の項目をチェックしています。上記のルールを反映しているのに加えて、PR の向き先と SwiftLint の実行結果もチェックしています。CLINICS の iOS アプリでは GitFlow を導入しているため、release ブランチと hot-fix ブランチ以外からの PR の向き先が develop ブランチになっていない場合には警告を出すようにしています。 レビュアーの人数が 2 人以上になっているか ビューの変更(xib、storyboard を触ったかどうかのみ確認)があった場合に画面キャプチャを貼っているかどうか PR が develop に向けて作成されているか SwiftLint のチェックを通っているか 弊社が iOS 開発で利用している Danger ファイルは以下の通りとなっています。導入する際のご参考にしてください。 # for only difference github. dismiss_out_of_range_messages # reviewers warn ( "レビュアーは 2 人以上指定してください" ) if github. github . pr_json [ "requested_reviewers" ]. length < 2 # view changes view_extensions = [ ".xib" , ".storyboard" ] has_view_changes = git. modified_files . any? { | file | view_extensions. any? { | ext | file. end_with? ext }} has_view_added = git. added_files . any? { | file | view_extensions. any? { | ext | file. end_with? ext }} pr_has_screenshot = github. pr_body =~ /https?: \/\/\S * \. (png|jpg|jpeg|gif){1}/ warn ( "見た目に変更がある場合は画面キャプチャを貼ってください" ) if (has_view_changes or has_view_added) and !pr_has_screenshot # base branch is_to_master = github. branch_for_base == 'master' is_to_develop = github. branch_for_base == 'develop' is_from_releases = !!github. branch_for_head . match ( /releases \/ [0-9]+ \. [0-9]+ \. [0-9]/ ) warn ( 'PR は develop に向けてください' ) if !is_to_develop and !(is_from_releases and is_to_master) # swiftLint swiftlint. lint_files inline_mode: true まとめ CLINICS におけるアプリ開発の品質と効率性を向上するための取り組みをご紹介しました。これらの取り組みによって プラットフォーム毎のデザインや機能のブレが少なくなり、認識ずれによる手戻りなどが少なくなったことで開発効率が上がった と感じます。プラットフォーム毎の違いを少なくして、より多くのメンバーがコードに手を入れやすい状態にすることで実装やコードレビューの質も向上しているように思います。 React Native などを利用して、コードそのものを共通化する方法もあるとは思いますが、プラットフォーム毎に別のコードで開発する場合でも、仕様や実装のルールを工夫することでより効率的に開発できるのではないでしょうか。 CLINICS チームでは他にも実装や開発プロセス、プロダクト運用について日々改善を行なっています。今後も、こうした取り組みを積極的に実践し、KPT 形式で振り返って、また次のアクションにつなげることで、多くの方に愛されるプロダクトを育てていきたいと思っています。 お知らせ メドレーでは、エンジニアやデザイナーを募集しています。ご興味のある方は、こちらからどうぞ! メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
こんにちは、開発本部の高井です。オンライン診療アプリ「 CLINICS 」のアプリ開発を主に担当しています。 CLINICS では Web に加えて、iOS 版と Android 版の各プラットフォームの仕様変更や機能追加などをほぼ同時に開発しているのですが、担当する人数が増えたりすることで、仕様に差が出たり、その結果手戻りが起きるということも増え始めていました。 そうした課題を解決するために実践した様々な施策の中から、特に有効だった 3 つの改善策について、今日はご紹介します。 背景 CLINICS の開発チームでは 5 人ほどのエンジニアがタスク単位で全てのプラットフォームを実装したり、大きいタスクの場合はプラットフォーム毎に別の開発者が担当する形で開発しています。 そのような形で機能追加や不具合対応の開発を進める中で、以下のような課題がありました。 プラットフォーム間で仕様やデザインが違う リリース直前に仕様の違いが見つかり、手戻りが発生する 各プラットフォームに対する習熟度にバラつきがあるため、開発者によって実装方法が違う 特にプラットフォーム毎に開発者がほぼ固定されてしまっていた時期には、コードレビューはしていても微妙な違いに気づかなかったり、同じ UI にするのに実装コストが高くてあきらめたり、ということが起こりがちでした。** プラットフォーム間で仕様やデザインが違うとユーザ体験の質がプラットフォームによってバラついてしまいますし、デザインや企画の作業も増えてしまいます** 。これらに加えて、エンジニアの人数が増えたり、デザイナーやカスタマーサポートなどエンジニア以外のメンバーとのコミュニケーションも増えたりしてきたこともあって、開発スピードも段々と遅くなってきていました。 そのような状況を改善するために、チーム内で継続的に実装方法や開発フローを見直し、改善策を実施してきました。 今回は以下の 3 つの改善策をご紹介します。具体的な実装については、主に iOS で使用しているコードを引用してご紹介します。(コードの一部を抜粋しているので、そのままでは使用することはできません。あくまでも参考コードとして読んでください。) DLS(デザイン言語システム)の導入 アプリエラーの共通化 コードレビューの手順改善 改善策 1 DLS(デザイン言語システム)の導入 まずは DLS(デザイン言語システム)の導入についてです。DLS とは以前、本ブログでもデザイナーの前田がご紹介させていただきましたが( デザイン言語システムを入れたらコミュニケーションコストがぐっと下がった話〜メドレー TechLunch〜 )、** UI に一貫性をもたせるため、配色やレイアウト、タイポグラフィやマージンなどのルール **を策定し、チーム全体で継続的に運用していくための仕組みです。策定したルールを組み込んだ各コンポーネントのデザインを元に、Web / iOS / Android の各プラットフォームで UI を実装して開発時に再利用できるようにしています。デザイン自体は下記のような形で Sketch ファイルで管理しています。 iOS については各コンポーネントをカスタムビュークラスとして実装し、再利用できるようにしました。DLS 導入以前はプラットフォーム毎に違った UI やルールで開発していたので、実装段階で担当する開発者毎の認識によって品質や仕様に差が出ている状態でした。DLS 導入によってそのような差が出にくくなり、一定の品質を保つことができるようになりました。 また、** UI の微調整などが減って、機能ロジックに重点を置いた開発に専念できるようになり、さらにデザイナーとの認識合わせが最小限になったことにより開発効率も上がった **と感じています。UI の基盤をつくったことで新しく画面を開発する場合でもコンポーネントを組み合わせ、エンジニアだけで実装が完了することも多くなり、その分デザイナーは次の施策やプロジェクトに専念できるようになりました。 実装についてですが、各コンポーネント毎に xib ファイルで UI パーツを作成し、それをクラスファイルで読み込んでカスタムビュークラスの見た目として使っています。カスタムビューは再利用しやすく、利用時にバラツキが出にくいように以下の点を満たすように実装しました。 Interface Builder/コードのどちらからでも初期化できる ビルドする前に Storyboard 上で UI パーツのデザインを確認できるように IBDesignable と IBInspectable を指定する カスタムビューの中で UI 要素のマージンや高さを指定する 例えば、セレクトフォームコンポーネントのカスタムビューは以下のような実装になっています。 xib ファイル クラスファイル import UIKit protocol ClinicsFormSelectDelegate : class { func didClickFormSelect ( sender : ClinicsFormSelect) } @IBDesignable class ClinicsFormSelect : UIView { @IBOutlet weak var selectView: SelectView! @IBInspectable var labelText: String = "Form-parts" { didSet { selectView. labelText = labelText } } weak var delegate: ClinicsFormSelectDelegate? // コードから初期化する場合に呼ばれる override init ( frame : CGRect) { super . init ( frame : frame) commonInit () } // Interface Builder から初期化する場合に呼ばれる required init? ( coder aDecoder : NSCoder) { super . init ( coder : aDecoder) commonInit () } private func commonInit () { // xib ファイルの読み込み let bundle = Bundle ( for : type ( of : self )) let view = UINib ( nibName : "ClinicsFormSelect" , bundle : bundle). instantiate ( withOwner : self , options : nil ). first as! UIView addSubview (view) backgroundColor = . clear view. backgroundColor = . clear // 読み込んだ View のサイズがカスタムクラス(ClinicsFormSelect)と同じサイズになるように Constraint を設定する view. translatesAutoresizingMaskIntoConstraints = false let bindings = [ "view" : view] addConstraints (NSLayoutConstraint. constraints ( withVisualFormat : "H:|[view]|" , options : NSLayoutFormatOptions ( rawValue : 0 ), metrics : nil , views : bindings)) addConstraints (NSLayoutConstraint. constraints ( withVisualFormat : "V:|[view]|" , options : NSLayoutFormatOptions ( rawValue : 0 ), metrics : nil , views : bindings)) } // xib ファイルの中に配置した UI 要素へのアクションのハンドリング @IBAction func didTap ( _ sender : UITapGestureRecognizer) { delegate?. didClickFormSelect ( sender : self ) } } CLINICS では主に Storyboard を使って UI を実装しているので、使用するときは Storyboard に UIView を置き、コンポーネントのクラス名を指定して使います。テキストなどのプロパティを設定し、Constraint を指定して配置すれば完了です。ユーザによるアクションのハンドリングや動的にプロパティを切り替える必要がある場合は、呼び出し側で処理を追加します。 最終的にビルドすると以下のように表示されます。(表示されている内容は開発中に作成した仮のデータで実際のものとは異なります。) 改善策 2 アプリエラーの共通化 以前は業務的に重要な処理のエラー以外はプラットフォーム毎で表示するエラーメッセージが異なっていたり、エラーハンドリング時に違った挙動をしていることがありました。その結果、ユーザ体験が一貫したものになっていないというだけでなく、お問い合わせがあってもカスタマーサポートが一次回答しにくかったり、伝えられた内容が曖昧なため開発者が調査するのに時間がかかったりすることがありました。 そこで、改めてフロント側で発生するエラーの定義を共通化し、エラーメッセージやエラーハンドリング時の処理も統一しました。** 問い合わせの効率化のために共通のエラーコードも決めて、エラー発生時に表示されるアラートに追加し、それらのエラー定義はドキュメントで一覧化して、カスタマーサポートにも共有 **するようにしました。 また、エラーハンドリング時にクラッシュレポートのログに記録する内容や送信するタイミングを統一して、開発者全員が理解しやすいようにしました。エラーコードの表示については、改善を検討していた時期にちょうど参加していた iOSDC Japan 2017 で、同じような課題に対する知見を 発表 されていたのを見て、早速取り入れました。最近ではユーザからの問い合わせにもエラーコードが使われることがあり、実際にコミュニケーションコストを低下させることができているように思います。 エラーのフィードバックは細かいところではありますが、ユーザのアクションを継続させるために重要な要素のひとつです。CLINICS はユーザ属性が老若男女問わず幅広いので特に気を配って改善を行ってきました。 実装についてですが、iOS では以下のように定義しています。 enum ApplicationError : Error { case commonRequestError ( String ) case createReservationCardError case createReservationScheduleIsFullError ~ var errorCode: String { switch self { case let . commonRequestError (viewId): return " \( viewId ) -0000" case . createReservationCardError : return "40-0001" case . createReservationScheduleIsFullError : return "40-0002" ~ var title: String { switch self { case . commonRequestError : return "接続エラー" case . createReservationCardError : return "決済失敗エラー" ~ var description: String { switch self { case . commonRequestError : return "データを正しく表示出来ない可能性があります。 \n 通信状況をお確かめいただくか、しばらく経ってから再度起動してください。" case . createReservationCardError : return "ご登録されているクレジットカードの決済中にエラーが発生しました。 \n おそれいりますが、もう一度最初から操作ください。" ~ Android でも同様に enum で定義しています。 enum class ApplicationError ( var code: String , val title: String , val description: String ) { CommonRequestError ( "0000" , "接続エラー" , "データを正しく表示出来ない可能性があります。 \n 通信状況をお確かめいただくか、しばらく経ってから再度起動してください。" ), CreateReservationCardError ( "40-0001" , "決済失敗エラー" , "ご登録されているクレジットカードの決済中にエラーが発生しました。 \n おそれいりますが、もう一度最初から操作ください。" ), CreateReservationScheduleIsFullError ( "40-0002" , "スケジュール空きなしエラー" , "選択された予約日時のスケジュールに空きがありませんでした。 \n おそれいりますが、別の予約日時をご選択のうえ、もう一度最初から操作ください。" ), ~ 改善策 3 コードレビューの手順改善 リリース当初から実装者以外のメンバーによるレビューは適宜行なっていましたが、レビューの段階でデグレや仕様の違いを見逃してしまうことがあったので、レビュー体制の強化とメンバーのソース理解の向上を図るために、以下のようにルールを設定しました。 セルフマージはしない PR に対して 2 人以上でレビューする ビューの変更があった場合には画面キャプチャを貼る それらを守りやすく、より効率的にするために Danger も導入しました。 導入手順は こちら にまとめられているほか、検索すればけっこう出てくるので省略します。弊社では iOS の CI は Bitrise を使用しているので Bitrise 上で実行して GitHub の PR に反映させています。 Danger では、以下の項目をチェックしています。上記のルールを反映しているのに加えて、PR の向き先と SwiftLint の実行結果もチェックしています。CLINICS の iOS アプリでは GitFlow を導入しているため、release ブランチと hot-fix ブランチ以外からの PR の向き先が develop ブランチになっていない場合には警告を出すようにしています。 レビュアーの人数が 2 人以上になっているか ビューの変更(xib、storyboard を触ったかどうかのみ確認)があった場合に画面キャプチャを貼っているかどうか PR が develop に向けて作成されているか SwiftLint のチェックを通っているか 弊社が iOS 開発で利用している Danger ファイルは以下の通りとなっています。導入する際のご参考にしてください。 # for only difference github. dismiss_out_of_range_messages # reviewers warn ( "レビュアーは 2 人以上指定してください" ) if github. github . pr_json [ "requested_reviewers" ]. length < 2 # view changes view_extensions = [ ".xib" , ".storyboard" ] has_view_changes = git. modified_files . any? { | file | view_extensions. any? { | ext | file. end_with? ext }} has_view_added = git. added_files . any? { | file | view_extensions. any? { | ext | file. end_with? ext }} pr_has_screenshot = github. pr_body =~ /https?: \/\/\S * \. (png|jpg|jpeg|gif){1}/ warn ( "見た目に変更がある場合は画面キャプチャを貼ってください" ) if (has_view_changes or has_view_added) and !pr_has_screenshot # base branch is_to_master = github. branch_for_base == 'master' is_to_develop = github. branch_for_base == 'develop' is_from_releases = !!github. branch_for_head . match ( /releases \/ [0-9]+ \. [0-9]+ \. [0-9]/ ) warn ( 'PR は develop に向けてください' ) if !is_to_develop and !(is_from_releases and is_to_master) # swiftLint swiftlint. lint_files inline_mode: true まとめ CLINICS におけるアプリ開発の品質と効率性を向上するための取り組みをご紹介しました。これらの取り組みによって プラットフォーム毎のデザインや機能のブレが少なくなり、認識ずれによる手戻りなどが少なくなったことで開発効率が上がった と感じます。プラットフォーム毎の違いを少なくして、より多くのメンバーがコードに手を入れやすい状態にすることで実装やコードレビューの質も向上しているように思います。 React Native などを利用して、コードそのものを共通化する方法もあるとは思いますが、プラットフォーム毎に別のコードで開発する場合でも、仕様や実装のルールを工夫することでより効率的に開発できるのではないでしょうか。 CLINICS チームでは他にも実装や開発プロセス、プロダクト運用について日々改善を行なっています。今後も、こうした取り組みを積極的に実践し、KPT 形式で振り返って、また次のアクションにつなげることで、多くの方に愛されるプロダクトを育てていきたいと思っています。 お知らせ メドレーでは、エンジニアやデザイナーを募集しています。ご興味のある方は、こちらからどうぞ! https://www.medley.jp/recruit/creative.html
こんにちは、開発本部の高井です。オンライン診療アプリ「 CLINICS 」のアプリ開発を主に担当しています。 CLINICS では Web に加えて、iOS 版と Android 版の各プラットフォームの仕様変更や機能追加などをほぼ同時に開発しているのですが、担当する人数が増えたりすることで、仕様に差が出たり、その結果手戻りが起きるということも増え始めていました。 そうした課題を解決するために実践した様々な施策の中から、特に有効だった 3 つの改善策について、今日はご紹介します。 背景 CLINICS の開発チームでは 5 人ほどのエンジニアがタスク単位で全てのプラットフォームを実装したり、大きいタスクの場合はプラットフォーム毎に別の開発者が担当する形で開発しています。 そのような形で機能追加や不具合対応の開発を進める中で、以下のような課題がありました。 プラットフォーム間で仕様やデザインが違う リリース直前に仕様の違いが見つかり、手戻りが発生する 各プラットフォームに対する習熟度にバラつきがあるため、開発者によって実装方法が違う 特にプラットフォーム毎に開発者がほぼ固定されてしまっていた時期には、コードレビューはしていても微妙な違いに気づかなかったり、同じ UI にするのに実装コストが高くてあきらめたり、ということが起こりがちでした。** プラットフォーム間で仕様やデザインが違うとユーザ体験の質がプラットフォームによってバラついてしまいますし、デザインや企画の作業も増えてしまいます** 。これらに加えて、エンジニアの人数が増えたり、デザイナーやカスタマーサポートなどエンジニア以外のメンバーとのコミュニケーションも増えたりしてきたこともあって、開発スピードも段々と遅くなってきていました。 そのような状況を改善するために、チーム内で継続的に実装方法や開発フローを見直し、改善策を実施してきました。 今回は以下の 3 つの改善策をご紹介します。具体的な実装については、主に iOS で使用しているコードを引用してご紹介します。(コードの一部を抜粋しているので、そのままでは使用することはできません。あくまでも参考コードとして読んでください。) DLS(デザイン言語システム)の導入 アプリエラーの共通化 コードレビューの手順改善 改善策 1 DLS(デザイン言語システム)の導入 まずは DLS(デザイン言語システム)の導入についてです。DLS とは以前、本ブログでもデザイナーの前田がご紹介させていただきましたが( デザイン言語システムを入れたらコミュニケーションコストがぐっと下がった話〜メドレー TechLunch〜 )、** UI に一貫性をもたせるため、配色やレイアウト、タイポグラフィやマージンなどのルール **を策定し、チーム全体で継続的に運用していくための仕組みです。策定したルールを組み込んだ各コンポーネントのデザインを元に、Web / iOS / Android の各プラットフォームで UI を実装して開発時に再利用できるようにしています。デザイン自体は下記のような形で Sketch ファイルで管理しています。 iOS については各コンポーネントをカスタムビュークラスとして実装し、再利用できるようにしました。DLS 導入以前はプラットフォーム毎に違った UI やルールで開発していたので、実装段階で担当する開発者毎の認識によって品質や仕様に差が出ている状態でした。DLS 導入によってそのような差が出にくくなり、一定の品質を保つことができるようになりました。 また、** UI の微調整などが減って、機能ロジックに重点を置いた開発に専念できるようになり、さらにデザイナーとの認識合わせが最小限になったことにより開発効率も上がった **と感じています。UI の基盤をつくったことで新しく画面を開発する場合でもコンポーネントを組み合わせ、エンジニアだけで実装が完了することも多くなり、その分デザイナーは次の施策やプロジェクトに専念できるようになりました。 実装についてですが、各コンポーネント毎に xib ファイルで UI パーツを作成し、それをクラスファイルで読み込んでカスタムビュークラスの見た目として使っています。カスタムビューは再利用しやすく、利用時にバラツキが出にくいように以下の点を満たすように実装しました。 Interface Builder/コードのどちらからでも初期化できる ビルドする前に Storyboard 上で UI パーツのデザインを確認できるように IBDesignable と IBInspectable を指定する カスタムビューの中で UI 要素のマージンや高さを指定する 例えば、セレクトフォームコンポーネントのカスタムビューは以下のような実装になっています。 xib ファイル クラスファイル import UIKit protocol ClinicsFormSelectDelegate : class { func didClickFormSelect ( sender : ClinicsFormSelect) } @IBDesignable class ClinicsFormSelect : UIView { @IBOutlet weak var selectView: SelectView! @IBInspectable var labelText: String = "Form-parts" { didSet { selectView. labelText = labelText } } weak var delegate: ClinicsFormSelectDelegate? // コードから初期化する場合に呼ばれる override init ( frame : CGRect) { super . init ( frame : frame) commonInit () } // Interface Builder から初期化する場合に呼ばれる required init? ( coder aDecoder : NSCoder) { super . init ( coder : aDecoder) commonInit () } private func commonInit () { // xib ファイルの読み込み let bundle = Bundle ( for : type ( of : self )) let view = UINib ( nibName : "ClinicsFormSelect" , bundle : bundle). instantiate ( withOwner : self , options : nil ). first as! UIView addSubview (view) backgroundColor = . clear view. backgroundColor = . clear // 読み込んだ View のサイズがカスタムクラス(ClinicsFormSelect)と同じサイズになるように Constraint を設定する view. translatesAutoresizingMaskIntoConstraints = false let bindings = [ "view" : view] addConstraints (NSLayoutConstraint. constraints ( withVisualFormat : "H:|[view]|" , options : NSLayoutFormatOptions ( rawValue : 0 ), metrics : nil , views : bindings)) addConstraints (NSLayoutConstraint. constraints ( withVisualFormat : "V:|[view]|" , options : NSLayoutFormatOptions ( rawValue : 0 ), metrics : nil , views : bindings)) } // xib ファイルの中に配置した UI 要素へのアクションのハンドリング @IBAction func didTap ( _ sender : UITapGestureRecognizer) { delegate?. didClickFormSelect ( sender : self ) } } CLINICS では主に Storyboard を使って UI を実装しているので、使用するときは Storyboard に UIView を置き、コンポーネントのクラス名を指定して使います。テキストなどのプロパティを設定し、Constraint を指定して配置すれば完了です。ユーザによるアクションのハンドリングや動的にプロパティを切り替える必要がある場合は、呼び出し側で処理を追加します。 最終的にビルドすると以下のように表示されます。(表示されている内容は開発中に作成した仮のデータで実際のものとは異なります。) 改善策 2 アプリエラーの共通化 以前は業務的に重要な処理のエラー以外はプラットフォーム毎で表示するエラーメッセージが異なっていたり、エラーハンドリング時に違った挙動をしていることがありました。その結果、ユーザ体験が一貫したものになっていないというだけでなく、お問い合わせがあってもカスタマーサポートが一次回答しにくかったり、伝えられた内容が曖昧なため開発者が調査するのに時間がかかったりすることがありました。 そこで、改めてフロント側で発生するエラーの定義を共通化し、エラーメッセージやエラーハンドリング時の処理も統一しました。** 問い合わせの効率化のために共通のエラーコードも決めて、エラー発生時に表示されるアラートに追加し、それらのエラー定義はドキュメントで一覧化して、カスタマーサポートにも共有 **するようにしました。 また、エラーハンドリング時にクラッシュレポートのログに記録する内容や送信するタイミングを統一して、開発者全員が理解しやすいようにしました。エラーコードの表示については、改善を検討していた時期にちょうど参加していた iOSDC Japan 2017 で、同じような課題に対する知見を 発表 されていたのを見て、早速取り入れました。最近ではユーザからの問い合わせにもエラーコードが使われることがあり、実際にコミュニケーションコストを低下させることができているように思います。 エラーのフィードバックは細かいところではありますが、ユーザのアクションを継続させるために重要な要素のひとつです。CLINICS はユーザ属性が老若男女問わず幅広いので特に気を配って改善を行ってきました。 実装についてですが、iOS では以下のように定義しています。 enum ApplicationError : Error { case commonRequestError ( String ) case createReservationCardError case createReservationScheduleIsFullError ~ var errorCode: String { switch self { case let . commonRequestError (viewId): return " \( viewId ) -0000" case . createReservationCardError : return "40-0001" case . createReservationScheduleIsFullError : return "40-0002" ~ var title: String { switch self { case . commonRequestError : return "接続エラー" case . createReservationCardError : return "決済失敗エラー" ~ var description: String { switch self { case . commonRequestError : return "データを正しく表示出来ない可能性があります。 \n 通信状況をお確かめいただくか、しばらく経ってから再度起動してください。" case . createReservationCardError : return "ご登録されているクレジットカードの決済中にエラーが発生しました。 \n おそれいりますが、もう一度最初から操作ください。" ~ Android でも同様に enum で定義しています。 enum class ApplicationError ( var code: String , val title: String , val description: String ) { CommonRequestError ( "0000" , "接続エラー" , "データを正しく表示出来ない可能性があります。 \n 通信状況をお確かめいただくか、しばらく経ってから再度起動してください。" ), CreateReservationCardError ( "40-0001" , "決済失敗エラー" , "ご登録されているクレジットカードの決済中にエラーが発生しました。 \n おそれいりますが、もう一度最初から操作ください。" ), CreateReservationScheduleIsFullError ( "40-0002" , "スケジュール空きなしエラー" , "選択された予約日時のスケジュールに空きがありませんでした。 \n おそれいりますが、別の予約日時をご選択のうえ、もう一度最初から操作ください。" ), ~ 改善策 3 コードレビューの手順改善 リリース当初から実装者以外のメンバーによるレビューは適宜行なっていましたが、レビューの段階でデグレや仕様の違いを見逃してしまうことがあったので、レビュー体制の強化とメンバーのソース理解の向上を図るために、以下のようにルールを設定しました。 セルフマージはしない PR に対して 2 人以上でレビューする ビューの変更があった場合には画面キャプチャを貼る それらを守りやすく、より効率的にするために Danger も導入しました。 導入手順は こちら にまとめられているほか、検索すればけっこう出てくるので省略します。弊社では iOS の CI は Bitrise を使用しているので Bitrise 上で実行して GitHub の PR に反映させています。 Danger では、以下の項目をチェックしています。上記のルールを反映しているのに加えて、PR の向き先と SwiftLint の実行結果もチェックしています。CLINICS の iOS アプリでは GitFlow を導入しているため、release ブランチと hot-fix ブランチ以外からの PR の向き先が develop ブランチになっていない場合には警告を出すようにしています。 レビュアーの人数が 2 人以上になっているか ビューの変更(xib、storyboard を触ったかどうかのみ確認)があった場合に画面キャプチャを貼っているかどうか PR が develop に向けて作成されているか SwiftLint のチェックを通っているか 弊社が iOS 開発で利用している Danger ファイルは以下の通りとなっています。導入する際のご参考にしてください。 # for only difference github. dismiss_out_of_range_messages # reviewers warn ( "レビュアーは 2 人以上指定してください" ) if github. github . pr_json [ "requested_reviewers" ]. length < 2 # view changes view_extensions = [ ".xib" , ".storyboard" ] has_view_changes = git. modified_files . any? { | file | view_extensions. any? { | ext | file. end_with? ext }} has_view_added = git. added_files . any? { | file | view_extensions. any? { | ext | file. end_with? ext }} pr_has_screenshot = github. pr_body =~ /https?: \/\/\S * \. (png|jpg|jpeg|gif){1}/ warn ( "見た目に変更がある場合は画面キャプチャを貼ってください" ) if (has_view_changes or has_view_added) and !pr_has_screenshot # base branch is_to_master = github. branch_for_base == 'master' is_to_develop = github. branch_for_base == 'develop' is_from_releases = !!github. branch_for_head . match ( /releases \/ [0-9]+ \. [0-9]+ \. [0-9]/ ) warn ( 'PR は develop に向けてください' ) if !is_to_develop and !(is_from_releases and is_to_master) # swiftLint swiftlint. lint_files inline_mode: true まとめ CLINICS におけるアプリ開発の品質と効率性を向上するための取り組みをご紹介しました。これらの取り組みによって プラットフォーム毎のデザインや機能のブレが少なくなり、認識ずれによる手戻りなどが少なくなったことで開発効率が上がった と感じます。プラットフォーム毎の違いを少なくして、より多くのメンバーがコードに手を入れやすい状態にすることで実装やコードレビューの質も向上しているように思います。 React Native などを利用して、コードそのものを共通化する方法もあるとは思いますが、プラットフォーム毎に別のコードで開発する場合でも、仕様や実装のルールを工夫することでより効率的に開発できるのではないでしょうか。 CLINICS チームでは他にも実装や開発プロセス、プロダクト運用について日々改善を行なっています。今後も、こうした取り組みを積極的に実践し、KPT 形式で振り返って、また次のアクションにつなげることで、多くの方に愛されるプロダクトを育てていきたいと思っています。 お知らせ メドレーでは、エンジニアやデザイナーを募集しています。ご興味のある方は、こちらからどうぞ! メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
こんにちは、開発本部の高井です。オンライン診療アプリ「 CLINICS 」のアプリ開発を主に担当しています。 CLINICS では Web に加えて、iOS 版と Android 版の各プラットフォームの仕様変更や機能追加などをほぼ同時に開発しているのですが、担当する人数が増えたりすることで、仕様に差が出たり、その結果手戻りが起きるということも増え始めていました。 そうした課題を解決するために実践した様々な施策の中から、特に有効だった 3 つの改善策について、今日はご紹介します。 背景 CLINICS の開発チームでは 5 人ほどのエンジニアがタスク単位で全てのプラットフォームを実装したり、大きいタスクの場合はプラットフォーム毎に別の開発者が担当する形で開発しています。 そのような形で機能追加や不具合対応の開発を進める中で、以下のような課題がありました。 プラットフォーム間で仕様やデザインが違う リリース直前に仕様の違いが見つかり、手戻りが発生する 各プラットフォームに対する習熟度にバラつきがあるため、開発者によって実装方法が違う 特にプラットフォーム毎に開発者がほぼ固定されてしまっていた時期には、コードレビューはしていても微妙な違いに気づかなかったり、同じ UI にするのに実装コストが高くてあきらめたり、ということが起こりがちでした。** プラットフォーム間で仕様やデザインが違うとユーザ体験の質がプラットフォームによってバラついてしまいますし、デザインや企画の作業も増えてしまいます** 。これらに加えて、エンジニアの人数が増えたり、デザイナーやカスタマーサポートなどエンジニア以外のメンバーとのコミュニケーションも増えたりしてきたこともあって、開発スピードも段々と遅くなってきていました。 そのような状況を改善するために、チーム内で継続的に実装方法や開発フローを見直し、改善策を実施してきました。 今回は以下の 3 つの改善策をご紹介します。具体的な実装については、主に iOS で使用しているコードを引用してご紹介します。(コードの一部を抜粋しているので、そのままでは使用することはできません。あくまでも参考コードとして読んでください。) DLS(デザイン言語システム)の導入 アプリエラーの共通化 コードレビューの手順改善 改善策 1 DLS(デザイン言語システム)の導入 まずは DLS(デザイン言語システム)の導入についてです。DLS とは以前、本ブログでもデザイナーの前田がご紹介させていただきましたが( デザイン言語システムを入れたらコミュニケーションコストがぐっと下がった話〜メドレー TechLunch〜 )、** UI に一貫性をもたせるため、配色やレイアウト、タイポグラフィやマージンなどのルール **を策定し、チーム全体で継続的に運用していくための仕組みです。策定したルールを組み込んだ各コンポーネントのデザインを元に、Web / iOS / Android の各プラットフォームで UI を実装して開発時に再利用できるようにしています。デザイン自体は下記のような形で Sketch ファイルで管理しています。 iOS については各コンポーネントをカスタムビュークラスとして実装し、再利用できるようにしました。DLS 導入以前はプラットフォーム毎に違った UI やルールで開発していたので、実装段階で担当する開発者毎の認識によって品質や仕様に差が出ている状態でした。DLS 導入によってそのような差が出にくくなり、一定の品質を保つことができるようになりました。 また、** UI の微調整などが減って、機能ロジックに重点を置いた開発に専念できるようになり、さらにデザイナーとの認識合わせが最小限になったことにより開発効率も上がった **と感じています。UI の基盤をつくったことで新しく画面を開発する場合でもコンポーネントを組み合わせ、エンジニアだけで実装が完了することも多くなり、その分デザイナーは次の施策やプロジェクトに専念できるようになりました。 実装についてですが、各コンポーネント毎に xib ファイルで UI パーツを作成し、それをクラスファイルで読み込んでカスタムビュークラスの見た目として使っています。カスタムビューは再利用しやすく、利用時にバラツキが出にくいように以下の点を満たすように実装しました。 Interface Builder/コードのどちらからでも初期化できる ビルドする前に Storyboard 上で UI パーツのデザインを確認できるように IBDesignable と IBInspectable を指定する カスタムビューの中で UI 要素のマージンや高さを指定する 例えば、セレクトフォームコンポーネントのカスタムビューは以下のような実装になっています。 xib ファイル クラスファイル import UIKit protocol ClinicsFormSelectDelegate : class { func didClickFormSelect ( sender : ClinicsFormSelect) } @IBDesignable class ClinicsFormSelect : UIView { @IBOutlet weak var selectView: SelectView! @IBInspectable var labelText: String = "Form-parts" { didSet { selectView. labelText = labelText } } weak var delegate: ClinicsFormSelectDelegate? // コードから初期化する場合に呼ばれる override init ( frame : CGRect) { super . init ( frame : frame) commonInit () } // Interface Builder から初期化する場合に呼ばれる required init? ( coder aDecoder : NSCoder) { super . init ( coder : aDecoder) commonInit () } private func commonInit () { // xib ファイルの読み込み let bundle = Bundle ( for : type ( of : self )) let view = UINib ( nibName : "ClinicsFormSelect" , bundle : bundle). instantiate ( withOwner : self , options : nil ). first as! UIView addSubview (view) backgroundColor = . clear view. backgroundColor = . clear // 読み込んだ View のサイズがカスタムクラス(ClinicsFormSelect)と同じサイズになるように Constraint を設定する view. translatesAutoresizingMaskIntoConstraints = false let bindings = [ "view" : view] addConstraints (NSLayoutConstraint. constraints ( withVisualFormat : "H:|[view]|" , options : NSLayoutFormatOptions ( rawValue : 0 ), metrics : nil , views : bindings)) addConstraints (NSLayoutConstraint. constraints ( withVisualFormat : "V:|[view]|" , options : NSLayoutFormatOptions ( rawValue : 0 ), metrics : nil , views : bindings)) } // xib ファイルの中に配置した UI 要素へのアクションのハンドリング @IBAction func didTap ( _ sender : UITapGestureRecognizer) { delegate?. didClickFormSelect ( sender : self ) } } CLINICS では主に Storyboard を使って UI を実装しているので、使用するときは Storyboard に UIView を置き、コンポーネントのクラス名を指定して使います。テキストなどのプロパティを設定し、Constraint を指定して配置すれば完了です。ユーザによるアクションのハンドリングや動的にプロパティを切り替える必要がある場合は、呼び出し側で処理を追加します。 最終的にビルドすると以下のように表示されます。(表示されている内容は開発中に作成した仮のデータで実際のものとは異なります。) 改善策 2 アプリエラーの共通化 以前は業務的に重要な処理のエラー以外はプラットフォーム毎で表示するエラーメッセージが異なっていたり、エラーハンドリング時に違った挙動をしていることがありました。その結果、ユーザ体験が一貫したものになっていないというだけでなく、お問い合わせがあってもカスタマーサポートが一次回答しにくかったり、伝えられた内容が曖昧なため開発者が調査するのに時間がかかったりすることがありました。 そこで、改めてフロント側で発生するエラーの定義を共通化し、エラーメッセージやエラーハンドリング時の処理も統一しました。** 問い合わせの効率化のために共通のエラーコードも決めて、エラー発生時に表示されるアラートに追加し、それらのエラー定義はドキュメントで一覧化して、カスタマーサポートにも共有 **するようにしました。 また、エラーハンドリング時にクラッシュレポートのログに記録する内容や送信するタイミングを統一して、開発者全員が理解しやすいようにしました。エラーコードの表示については、改善を検討していた時期にちょうど参加していた iOSDC Japan 2017 で、同じような課題に対する知見を 発表 されていたのを見て、早速取り入れました。最近ではユーザからの問い合わせにもエラーコードが使われることがあり、実際にコミュニケーションコストを低下させることができているように思います。 エラーのフィードバックは細かいところではありますが、ユーザのアクションを継続させるために重要な要素のひとつです。CLINICS はユーザ属性が老若男女問わず幅広いので特に気を配って改善を行ってきました。 実装についてですが、iOS では以下のように定義しています。 enum ApplicationError : Error { case commonRequestError ( String ) case createReservationCardError case createReservationScheduleIsFullError ~ var errorCode: String { switch self { case let . commonRequestError (viewId): return " \( viewId ) -0000" case . createReservationCardError : return "40-0001" case . createReservationScheduleIsFullError : return "40-0002" ~ var title: String { switch self { case . commonRequestError : return "接続エラー" case . createReservationCardError : return "決済失敗エラー" ~ var description: String { switch self { case . commonRequestError : return "データを正しく表示出来ない可能性があります。 \n 通信状況をお確かめいただくか、しばらく経ってから再度起動してください。" case . createReservationCardError : return "ご登録されているクレジットカードの決済中にエラーが発生しました。 \n おそれいりますが、もう一度最初から操作ください。" ~ Android でも同様に enum で定義しています。 enum class ApplicationError ( var code: String , val title: String , val description: String ) { CommonRequestError ( "0000" , "接続エラー" , "データを正しく表示出来ない可能性があります。 \n 通信状況をお確かめいただくか、しばらく経ってから再度起動してください。" ), CreateReservationCardError ( "40-0001" , "決済失敗エラー" , "ご登録されているクレジットカードの決済中にエラーが発生しました。 \n おそれいりますが、もう一度最初から操作ください。" ), CreateReservationScheduleIsFullError ( "40-0002" , "スケジュール空きなしエラー" , "選択された予約日時のスケジュールに空きがありませんでした。 \n おそれいりますが、別の予約日時をご選択のうえ、もう一度最初から操作ください。" ), ~ 改善策 3 コードレビューの手順改善 リリース当初から実装者以外のメンバーによるレビューは適宜行なっていましたが、レビューの段階でデグレや仕様の違いを見逃してしまうことがあったので、レビュー体制の強化とメンバーのソース理解の向上を図るために、以下のようにルールを設定しました。 セルフマージはしない PR に対して 2 人以上でレビューする ビューの変更があった場合には画面キャプチャを貼る それらを守りやすく、より効率的にするために Danger も導入しました。 導入手順は こちら にまとめられているほか、検索すればけっこう出てくるので省略します。弊社では iOS の CI は Bitrise を使用しているので Bitrise 上で実行して GitHub の PR に反映させています。 Danger では、以下の項目をチェックしています。上記のルールを反映しているのに加えて、PR の向き先と SwiftLint の実行結果もチェックしています。CLINICS の iOS アプリでは GitFlow を導入しているため、release ブランチと hot-fix ブランチ以外からの PR の向き先が develop ブランチになっていない場合には警告を出すようにしています。 レビュアーの人数が 2 人以上になっているか ビューの変更(xib、storyboard を触ったかどうかのみ確認)があった場合に画面キャプチャを貼っているかどうか PR が develop に向けて作成されているか SwiftLint のチェックを通っているか 弊社が iOS 開発で利用している Danger ファイルは以下の通りとなっています。導入する際のご参考にしてください。 # for only difference github. dismiss_out_of_range_messages # reviewers warn ( "レビュアーは 2 人以上指定してください" ) if github. github . pr_json [ "requested_reviewers" ]. length < 2 # view changes view_extensions = [ ".xib" , ".storyboard" ] has_view_changes = git. modified_files . any? { | file | view_extensions. any? { | ext | file. end_with? ext }} has_view_added = git. added_files . any? { | file | view_extensions. any? { | ext | file. end_with? ext }} pr_has_screenshot = github. pr_body =~ /https?: \/\/\S * \. (png|jpg|jpeg|gif){1}/ warn ( "見た目に変更がある場合は画面キャプチャを貼ってください" ) if (has_view_changes or has_view_added) and !pr_has_screenshot # base branch is_to_master = github. branch_for_base == 'master' is_to_develop = github. branch_for_base == 'develop' is_from_releases = !!github. branch_for_head . match ( /releases \/ [0-9]+ \. [0-9]+ \. [0-9]/ ) warn ( 'PR は develop に向けてください' ) if !is_to_develop and !(is_from_releases and is_to_master) # swiftLint swiftlint. lint_files inline_mode: true まとめ CLINICS におけるアプリ開発の品質と効率性を向上するための取り組みをご紹介しました。これらの取り組みによって プラットフォーム毎のデザインや機能のブレが少なくなり、認識ずれによる手戻りなどが少なくなったことで開発効率が上がった と感じます。プラットフォーム毎の違いを少なくして、より多くのメンバーがコードに手を入れやすい状態にすることで実装やコードレビューの質も向上しているように思います。 React Native などを利用して、コードそのものを共通化する方法もあるとは思いますが、プラットフォーム毎に別のコードで開発する場合でも、仕様や実装のルールを工夫することでより効率的に開発できるのではないでしょうか。 CLINICS チームでは他にも実装や開発プロセス、プロダクト運用について日々改善を行なっています。今後も、こうした取り組みを積極的に実践し、KPT 形式で振り返って、また次のアクションにつなげることで、多くの方に愛されるプロダクトを育てていきたいと思っています。 お知らせ メドレーでは、エンジニアやデザイナーを募集しています。ご興味のある方は、こちらからどうぞ! メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
こんにちは、開発本部の高井です。オンライン診療アプリ「 CLINICS 」のアプリ開発を主に担当しています。 CLINICS では Web に加えて、iOS 版と Android 版の各プラットフォームの仕様変更や機能追加などをほぼ同時に開発しているのですが、担当する人数が増えたりすることで、仕様に差が出たり、その結果手戻りが起きるということも増え始めていました。 そうした課題を解決するために実践した様々な施策の中から、特に有効だった 3 つの改善策について、今日はご紹介します。 背景 CLINICS の開発チームでは 5 人ほどのエンジニアがタスク単位で全てのプラットフォームを実装したり、大きいタスクの場合はプラットフォーム毎に別の開発者が担当する形で開発しています。 そのような形で機能追加や不具合対応の開発を進める中で、以下のような課題がありました。 プラットフォーム間で仕様やデザインが違う リリース直前に仕様の違いが見つかり、手戻りが発生する 各プラットフォームに対する習熟度にバラつきがあるため、開発者によって実装方法が違う 特にプラットフォーム毎に開発者がほぼ固定されてしまっていた時期には、コードレビューはしていても微妙な違いに気づかなかったり、同じ UI にするのに実装コストが高くてあきらめたり、ということが起こりがちでした。** プラットフォーム間で仕様やデザインが違うとユーザ体験の質がプラットフォームによってバラついてしまいますし、デザインや企画の作業も増えてしまいます** 。これらに加えて、エンジニアの人数が増えたり、デザイナーやカスタマーサポートなどエンジニア以外のメンバーとのコミュニケーションも増えたりしてきたこともあって、開発スピードも段々と遅くなってきていました。 そのような状況を改善するために、チーム内で継続的に実装方法や開発フローを見直し、改善策を実施してきました。 今回は以下の 3 つの改善策をご紹介します。具体的な実装については、主に iOS で使用しているコードを引用してご紹介します。(コードの一部を抜粋しているので、そのままでは使用することはできません。あくまでも参考コードとして読んでください。) DLS(デザイン言語システム)の導入 アプリエラーの共通化 コードレビューの手順改善 改善策 1 DLS(デザイン言語システム)の導入 まずは DLS(デザイン言語システム)の導入についてです。DLS とは以前、本ブログでもデザイナーの前田がご紹介させていただきましたが( デザイン言語システムを入れたらコミュニケーションコストがぐっと下がった話〜メドレー TechLunch〜 )、** UI に一貫性をもたせるため、配色やレイアウト、タイポグラフィやマージンなどのルール **を策定し、チーム全体で継続的に運用していくための仕組みです。策定したルールを組み込んだ各コンポーネントのデザインを元に、Web / iOS / Android の各プラットフォームで UI を実装して開発時に再利用できるようにしています。デザイン自体は下記のような形で Sketch ファイルで管理しています。 iOS については各コンポーネントをカスタムビュークラスとして実装し、再利用できるようにしました。DLS 導入以前はプラットフォーム毎に違った UI やルールで開発していたので、実装段階で担当する開発者毎の認識によって品質や仕様に差が出ている状態でした。DLS 導入によってそのような差が出にくくなり、一定の品質を保つことができるようになりました。 また、** UI の微調整などが減って、機能ロジックに重点を置いた開発に専念できるようになり、さらにデザイナーとの認識合わせが最小限になったことにより開発効率も上がった **と感じています。UI の基盤をつくったことで新しく画面を開発する場合でもコンポーネントを組み合わせ、エンジニアだけで実装が完了することも多くなり、その分デザイナーは次の施策やプロジェクトに専念できるようになりました。 実装についてですが、各コンポーネント毎に xib ファイルで UI パーツを作成し、それをクラスファイルで読み込んでカスタムビュークラスの見た目として使っています。カスタムビューは再利用しやすく、利用時にバラツキが出にくいように以下の点を満たすように実装しました。 Interface Builder/コードのどちらからでも初期化できる ビルドする前に Storyboard 上で UI パーツのデザインを確認できるように IBDesignable と IBInspectable を指定する カスタムビューの中で UI 要素のマージンや高さを指定する 例えば、セレクトフォームコンポーネントのカスタムビューは以下のような実装になっています。 xib ファイル クラスファイル import UIKit protocol ClinicsFormSelectDelegate : class { func didClickFormSelect ( sender : ClinicsFormSelect) } @IBDesignable class ClinicsFormSelect : UIView { @IBOutlet weak var selectView: SelectView! @IBInspectable var labelText: String = "Form-parts" { didSet { selectView. labelText = labelText } } weak var delegate: ClinicsFormSelectDelegate? // コードから初期化する場合に呼ばれる override init ( frame : CGRect) { super . init ( frame : frame) commonInit () } // Interface Builder から初期化する場合に呼ばれる required init? ( coder aDecoder : NSCoder) { super . init ( coder : aDecoder) commonInit () } private func commonInit () { // xib ファイルの読み込み let bundle = Bundle ( for : type ( of : self )) let view = UINib ( nibName : "ClinicsFormSelect" , bundle : bundle). instantiate ( withOwner : self , options : nil ). first as! UIView addSubview (view) backgroundColor = . clear view. backgroundColor = . clear // 読み込んだ View のサイズがカスタムクラス(ClinicsFormSelect)と同じサイズになるように Constraint を設定する view. translatesAutoresizingMaskIntoConstraints = false let bindings = [ "view" : view] addConstraints (NSLayoutConstraint. constraints ( withVisualFormat : "H:|[view]|" , options : NSLayoutFormatOptions ( rawValue : 0 ), metrics : nil , views : bindings)) addConstraints (NSLayoutConstraint. constraints ( withVisualFormat : "V:|[view]|" , options : NSLayoutFormatOptions ( rawValue : 0 ), metrics : nil , views : bindings)) } // xib ファイルの中に配置した UI 要素へのアクションのハンドリング @IBAction func didTap ( _ sender : UITapGestureRecognizer) { delegate?. didClickFormSelect ( sender : self ) } } CLINICS では主に Storyboard を使って UI を実装しているので、使用するときは Storyboard に UIView を置き、コンポーネントのクラス名を指定して使います。テキストなどのプロパティを設定し、Constraint を指定して配置すれば完了です。ユーザによるアクションのハンドリングや動的にプロパティを切り替える必要がある場合は、呼び出し側で処理を追加します。 最終的にビルドすると以下のように表示されます。(表示されている内容は開発中に作成した仮のデータで実際のものとは異なります。) 改善策 2 アプリエラーの共通化 以前は業務的に重要な処理のエラー以外はプラットフォーム毎で表示するエラーメッセージが異なっていたり、エラーハンドリング時に違った挙動をしていることがありました。その結果、ユーザ体験が一貫したものになっていないというだけでなく、お問い合わせがあってもカスタマーサポートが一次回答しにくかったり、伝えられた内容が曖昧なため開発者が調査するのに時間がかかったりすることがありました。 そこで、改めてフロント側で発生するエラーの定義を共通化し、エラーメッセージやエラーハンドリング時の処理も統一しました。** 問い合わせの効率化のために共通のエラーコードも決めて、エラー発生時に表示されるアラートに追加し、それらのエラー定義はドキュメントで一覧化して、カスタマーサポートにも共有 **するようにしました。 また、エラーハンドリング時にクラッシュレポートのログに記録する内容や送信するタイミングを統一して、開発者全員が理解しやすいようにしました。エラーコードの表示については、改善を検討していた時期にちょうど参加していた iOSDC Japan 2017 で、同じような課題に対する知見を 発表 されていたのを見て、早速取り入れました。最近ではユーザからの問い合わせにもエラーコードが使われることがあり、実際にコミュニケーションコストを低下させることができているように思います。 エラーのフィードバックは細かいところではありますが、ユーザのアクションを継続させるために重要な要素のひとつです。CLINICS はユーザ属性が老若男女問わず幅広いので特に気を配って改善を行ってきました。 実装についてですが、iOS では以下のように定義しています。 enum ApplicationError : Error { case commonRequestError ( String ) case createReservationCardError case createReservationScheduleIsFullError ~ var errorCode: String { switch self { case let . commonRequestError (viewId): return " \( viewId ) -0000" case . createReservationCardError : return "40-0001" case . createReservationScheduleIsFullError : return "40-0002" ~ var title: String { switch self { case . commonRequestError : return "接続エラー" case . createReservationCardError : return "決済失敗エラー" ~ var description: String { switch self { case . commonRequestError : return "データを正しく表示出来ない可能性があります。 \n 通信状況をお確かめいただくか、しばらく経ってから再度起動してください。" case . createReservationCardError : return "ご登録されているクレジットカードの決済中にエラーが発生しました。 \n おそれいりますが、もう一度最初から操作ください。" ~ Android でも同様に enum で定義しています。 enum class ApplicationError ( var code: String , val title: String , val description: String ) { CommonRequestError ( "0000" , "接続エラー" , "データを正しく表示出来ない可能性があります。 \n 通信状況をお確かめいただくか、しばらく経ってから再度起動してください。" ), CreateReservationCardError ( "40-0001" , "決済失敗エラー" , "ご登録されているクレジットカードの決済中にエラーが発生しました。 \n おそれいりますが、もう一度最初から操作ください。" ), CreateReservationScheduleIsFullError ( "40-0002" , "スケジュール空きなしエラー" , "選択された予約日時のスケジュールに空きがありませんでした。 \n おそれいりますが、別の予約日時をご選択のうえ、もう一度最初から操作ください。" ), ~ 改善策 3 コードレビューの手順改善 リリース当初から実装者以外のメンバーによるレビューは適宜行なっていましたが、レビューの段階でデグレや仕様の違いを見逃してしまうことがあったので、レビュー体制の強化とメンバーのソース理解の向上を図るために、以下のようにルールを設定しました。 セルフマージはしない PR に対して 2 人以上でレビューする ビューの変更があった場合には画面キャプチャを貼る それらを守りやすく、より効率的にするために Danger も導入しました。 導入手順は こちら にまとめられているほか、検索すればけっこう出てくるので省略します。弊社では iOS の CI は Bitrise を使用しているので Bitrise 上で実行して GitHub の PR に反映させています。 Danger では、以下の項目をチェックしています。上記のルールを反映しているのに加えて、PR の向き先と SwiftLint の実行結果もチェックしています。CLINICS の iOS アプリでは GitFlow を導入しているため、release ブランチと hot-fix ブランチ以外からの PR の向き先が develop ブランチになっていない場合には警告を出すようにしています。 レビュアーの人数が 2 人以上になっているか ビューの変更(xib、storyboard を触ったかどうかのみ確認)があった場合に画面キャプチャを貼っているかどうか PR が develop に向けて作成されているか SwiftLint のチェックを通っているか 弊社が iOS 開発で利用している Danger ファイルは以下の通りとなっています。導入する際のご参考にしてください。 # for only difference github. dismiss_out_of_range_messages # reviewers warn ( "レビュアーは 2 人以上指定してください" ) if github. github . pr_json [ "requested_reviewers" ]. length < 2 # view changes view_extensions = [ ".xib" , ".storyboard" ] has_view_changes = git. modified_files . any? { | file | view_extensions. any? { | ext | file. end_with? ext }} has_view_added = git. added_files . any? { | file | view_extensions. any? { | ext | file. end_with? ext }} pr_has_screenshot = github. pr_body =~ /https?: \/\/\S * \. (png|jpg|jpeg|gif){1}/ warn ( "見た目に変更がある場合は画面キャプチャを貼ってください" ) if (has_view_changes or has_view_added) and !pr_has_screenshot # base branch is_to_master = github. branch_for_base == 'master' is_to_develop = github. branch_for_base == 'develop' is_from_releases = !!github. branch_for_head . match ( /releases \/ [0-9]+ \. [0-9]+ \. [0-9]/ ) warn ( 'PR は develop に向けてください' ) if !is_to_develop and !(is_from_releases and is_to_master) # swiftLint swiftlint. lint_files inline_mode: true まとめ CLINICS におけるアプリ開発の品質と効率性を向上するための取り組みをご紹介しました。これらの取り組みによって プラットフォーム毎のデザインや機能のブレが少なくなり、認識ずれによる手戻りなどが少なくなったことで開発効率が上がった と感じます。プラットフォーム毎の違いを少なくして、より多くのメンバーがコードに手を入れやすい状態にすることで実装やコードレビューの質も向上しているように思います。 React Native などを利用して、コードそのものを共通化する方法もあるとは思いますが、プラットフォーム毎に別のコードで開発する場合でも、仕様や実装のルールを工夫することでより効率的に開発できるのではないでしょうか。 CLINICS チームでは他にも実装や開発プロセス、プロダクト運用について日々改善を行なっています。今後も、こうした取り組みを積極的に実践し、KPT 形式で振り返って、また次のアクションにつなげることで、多くの方に愛されるプロダクトを育てていきたいと思っています。 お知らせ メドレーでは、エンジニアやデザイナーを募集しています。ご興味のある方は、こちらからどうぞ! メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
こんにちは、開発本部の高井です。オンライン診療アプリ「 CLINICS 」のアプリ開発を主に担当しています。 CLINICS では Web に加えて、iOS 版と Android 版の各プラットフォームの仕様変更や機能追加などをほぼ同時に開発しているのですが、担当する人数が増えたりすることで、仕様に差が出たり、その結果手戻りが起きるということも増え始めていました。 そうした課題を解決するために実践した様々な施策の中から、特に有効だった 3 つの改善策について、今日はご紹介します。 背景 CLINICS の開発チームでは 5 人ほどのエンジニアがタスク単位で全てのプラットフォームを実装したり、大きいタスクの場合はプラットフォーム毎に別の開発者が担当する形で開発しています。 そのような形で機能追加や不具合対応の開発を進める中で、以下のような課題がありました。 プラットフォーム間で仕様やデザインが違う リリース直前に仕様の違いが見つかり、手戻りが発生する 各プラットフォームに対する習熟度にバラつきがあるため、開発者によって実装方法が違う 特にプラットフォーム毎に開発者がほぼ固定されてしまっていた時期には、コードレビューはしていても微妙な違いに気づかなかったり、同じ UI にするのに実装コストが高くてあきらめたり、ということが起こりがちでした。** プラットフォーム間で仕様やデザインが違うとユーザ体験の質がプラットフォームによってバラついてしまいますし、デザインや企画の作業も増えてしまいます** 。これらに加えて、エンジニアの人数が増えたり、デザイナーやカスタマーサポートなどエンジニア以外のメンバーとのコミュニケーションも増えたりしてきたこともあって、開発スピードも段々と遅くなってきていました。 そのような状況を改善するために、チーム内で継続的に実装方法や開発フローを見直し、改善策を実施してきました。 今回は以下の 3 つの改善策をご紹介します。具体的な実装については、主に iOS で使用しているコードを引用してご紹介します。(コードの一部を抜粋しているので、そのままでは使用することはできません。あくまでも参考コードとして読んでください。) DLS(デザイン言語システム)の導入 アプリエラーの共通化 コードレビューの手順改善 改善策 1 DLS(デザイン言語システム)の導入 まずは DLS(デザイン言語システム)の導入についてです。DLS とは以前、本ブログでもデザイナーの前田がご紹介させていただきましたが( デザイン言語システムを入れたらコミュニケーションコストがぐっと下がった話〜メドレー TechLunch〜 )、** UI に一貫性をもたせるため、配色やレイアウト、タイポグラフィやマージンなどのルール **を策定し、チーム全体で継続的に運用していくための仕組みです。策定したルールを組み込んだ各コンポーネントのデザインを元に、Web / iOS / Android の各プラットフォームで UI を実装して開発時に再利用できるようにしています。デザイン自体は下記のような形で Sketch ファイルで管理しています。 iOS については各コンポーネントをカスタムビュークラスとして実装し、再利用できるようにしました。DLS 導入以前はプラットフォーム毎に違った UI やルールで開発していたので、実装段階で担当する開発者毎の認識によって品質や仕様に差が出ている状態でした。DLS 導入によってそのような差が出にくくなり、一定の品質を保つことができるようになりました。 また、** UI の微調整などが減って、機能ロジックに重点を置いた開発に専念できるようになり、さらにデザイナーとの認識合わせが最小限になったことにより開発効率も上がった **と感じています。UI の基盤をつくったことで新しく画面を開発する場合でもコンポーネントを組み合わせ、エンジニアだけで実装が完了することも多くなり、その分デザイナーは次の施策やプロジェクトに専念できるようになりました。 実装についてですが、各コンポーネント毎に xib ファイルで UI パーツを作成し、それをクラスファイルで読み込んでカスタムビュークラスの見た目として使っています。カスタムビューは再利用しやすく、利用時にバラツキが出にくいように以下の点を満たすように実装しました。 Interface Builder/コードのどちらからでも初期化できる ビルドする前に Storyboard 上で UI パーツのデザインを確認できるように IBDesignable と IBInspectable を指定する カスタムビューの中で UI 要素のマージンや高さを指定する 例えば、セレクトフォームコンポーネントのカスタムビューは以下のような実装になっています。 xib ファイル クラスファイル import UIKit protocol ClinicsFormSelectDelegate : class { func didClickFormSelect ( sender : ClinicsFormSelect) } @IBDesignable class ClinicsFormSelect : UIView { @IBOutlet weak var selectView: SelectView! @IBInspectable var labelText: String = "Form-parts" { didSet { selectView. labelText = labelText } } weak var delegate: ClinicsFormSelectDelegate? // コードから初期化する場合に呼ばれる override init ( frame : CGRect) { super . init ( frame : frame) commonInit () } // Interface Builder から初期化する場合に呼ばれる required init? ( coder aDecoder : NSCoder) { super . init ( coder : aDecoder) commonInit () } private func commonInit () { // xib ファイルの読み込み let bundle = Bundle ( for : type ( of : self )) let view = UINib ( nibName : "ClinicsFormSelect" , bundle : bundle). instantiate ( withOwner : self , options : nil ). first as! UIView addSubview (view) backgroundColor = . clear view. backgroundColor = . clear // 読み込んだ View のサイズがカスタムクラス(ClinicsFormSelect)と同じサイズになるように Constraint を設定する view. translatesAutoresizingMaskIntoConstraints = false let bindings = [ "view" : view] addConstraints (NSLayoutConstraint. constraints ( withVisualFormat : "H:|[view]|" , options : NSLayoutFormatOptions ( rawValue : 0 ), metrics : nil , views : bindings)) addConstraints (NSLayoutConstraint. constraints ( withVisualFormat : "V:|[view]|" , options : NSLayoutFormatOptions ( rawValue : 0 ), metrics : nil , views : bindings)) } // xib ファイルの中に配置した UI 要素へのアクションのハンドリング @IBAction func didTap ( _ sender : UITapGestureRecognizer) { delegate?. didClickFormSelect ( sender : self ) } } CLINICS では主に Storyboard を使って UI を実装しているので、使用するときは Storyboard に UIView を置き、コンポーネントのクラス名を指定して使います。テキストなどのプロパティを設定し、Constraint を指定して配置すれば完了です。ユーザによるアクションのハンドリングや動的にプロパティを切り替える必要がある場合は、呼び出し側で処理を追加します。 最終的にビルドすると以下のように表示されます。(表示されている内容は開発中に作成した仮のデータで実際のものとは異なります。) 改善策 2 アプリエラーの共通化 以前は業務的に重要な処理のエラー以外はプラットフォーム毎で表示するエラーメッセージが異なっていたり、エラーハンドリング時に違った挙動をしていることがありました。その結果、ユーザ体験が一貫したものになっていないというだけでなく、お問い合わせがあってもカスタマーサポートが一次回答しにくかったり、伝えられた内容が曖昧なため開発者が調査するのに時間がかかったりすることがありました。 そこで、改めてフロント側で発生するエラーの定義を共通化し、エラーメッセージやエラーハンドリング時の処理も統一しました。** 問い合わせの効率化のために共通のエラーコードも決めて、エラー発生時に表示されるアラートに追加し、それらのエラー定義はドキュメントで一覧化して、カスタマーサポートにも共有 **するようにしました。 また、エラーハンドリング時にクラッシュレポートのログに記録する内容や送信するタイミングを統一して、開発者全員が理解しやすいようにしました。エラーコードの表示については、改善を検討していた時期にちょうど参加していた iOSDC Japan 2017 で、同じような課題に対する知見を 発表 されていたのを見て、早速取り入れました。最近ではユーザからの問い合わせにもエラーコードが使われることがあり、実際にコミュニケーションコストを低下させることができているように思います。 エラーのフィードバックは細かいところではありますが、ユーザのアクションを継続させるために重要な要素のひとつです。CLINICS はユーザ属性が老若男女問わず幅広いので特に気を配って改善を行ってきました。 実装についてですが、iOS では以下のように定義しています。 enum ApplicationError : Error { case commonRequestError ( String ) case createReservationCardError case createReservationScheduleIsFullError ~ var errorCode: String { switch self { case let . commonRequestError (viewId): return " \( viewId ) -0000" case . createReservationCardError : return "40-0001" case . createReservationScheduleIsFullError : return "40-0002" ~ var title: String { switch self { case . commonRequestError : return "接続エラー" case . createReservationCardError : return "決済失敗エラー" ~ var description: String { switch self { case . commonRequestError : return "データを正しく表示出来ない可能性があります。 \n 通信状況をお確かめいただくか、しばらく経ってから再度起動してください。" case . createReservationCardError : return "ご登録されているクレジットカードの決済中にエラーが発生しました。 \n おそれいりますが、もう一度最初から操作ください。" ~ Android でも同様に enum で定義しています。 enum class ApplicationError ( var code: String , val title: String , val description: String ) { CommonRequestError ( "0000" , "接続エラー" , "データを正しく表示出来ない可能性があります。 \n 通信状況をお確かめいただくか、しばらく経ってから再度起動してください。" ), CreateReservationCardError ( "40-0001" , "決済失敗エラー" , "ご登録されているクレジットカードの決済中にエラーが発生しました。 \n おそれいりますが、もう一度最初から操作ください。" ), CreateReservationScheduleIsFullError ( "40-0002" , "スケジュール空きなしエラー" , "選択された予約日時のスケジュールに空きがありませんでした。 \n おそれいりますが、別の予約日時をご選択のうえ、もう一度最初から操作ください。" ), ~ 改善策 3 コードレビューの手順改善 リリース当初から実装者以外のメンバーによるレビューは適宜行なっていましたが、レビューの段階でデグレや仕様の違いを見逃してしまうことがあったので、レビュー体制の強化とメンバーのソース理解の向上を図るために、以下のようにルールを設定しました。 セルフマージはしない PR に対して 2 人以上でレビューする ビューの変更があった場合には画面キャプチャを貼る それらを守りやすく、より効率的にするために Danger も導入しました。 導入手順は こちら にまとめられているほか、検索すればけっこう出てくるので省略します。弊社では iOS の CI は Bitrise を使用しているので Bitrise 上で実行して GitHub の PR に反映させています。 Danger では、以下の項目をチェックしています。上記のルールを反映しているのに加えて、PR の向き先と SwiftLint の実行結果もチェックしています。CLINICS の iOS アプリでは GitFlow を導入しているため、release ブランチと hot-fix ブランチ以外からの PR の向き先が develop ブランチになっていない場合には警告を出すようにしています。 レビュアーの人数が 2 人以上になっているか ビューの変更(xib、storyboard を触ったかどうかのみ確認)があった場合に画面キャプチャを貼っているかどうか PR が develop に向けて作成されているか SwiftLint のチェックを通っているか 弊社が iOS 開発で利用している Danger ファイルは以下の通りとなっています。導入する際のご参考にしてください。 # for only difference github. dismiss_out_of_range_messages # reviewers warn ( "レビュアーは 2 人以上指定してください" ) if github. github . pr_json [ "requested_reviewers" ]. length < 2 # view changes view_extensions = [ ".xib" , ".storyboard" ] has_view_changes = git. modified_files . any? { | file | view_extensions. any? { | ext | file. end_with? ext }} has_view_added = git. added_files . any? { | file | view_extensions. any? { | ext | file. end_with? ext }} pr_has_screenshot = github. pr_body =~ /https?: \/\/\S * \. (png|jpg|jpeg|gif){1}/ warn ( "見た目に変更がある場合は画面キャプチャを貼ってください" ) if (has_view_changes or has_view_added) and !pr_has_screenshot # base branch is_to_master = github. branch_for_base == 'master' is_to_develop = github. branch_for_base == 'develop' is_from_releases = !!github. branch_for_head . match ( /releases \/ [0-9]+ \. [0-9]+ \. [0-9]/ ) warn ( 'PR は develop に向けてください' ) if !is_to_develop and !(is_from_releases and is_to_master) # swiftLint swiftlint. lint_files inline_mode: true まとめ CLINICS におけるアプリ開発の品質と効率性を向上するための取り組みをご紹介しました。これらの取り組みによって プラットフォーム毎のデザインや機能のブレが少なくなり、認識ずれによる手戻りなどが少なくなったことで開発効率が上がった と感じます。プラットフォーム毎の違いを少なくして、より多くのメンバーがコードに手を入れやすい状態にすることで実装やコードレビューの質も向上しているように思います。 React Native などを利用して、コードそのものを共通化する方法もあるとは思いますが、プラットフォーム毎に別のコードで開発する場合でも、仕様や実装のルールを工夫することでより効率的に開発できるのではないでしょうか。 CLINICS チームでは他にも実装や開発プロセス、プロダクト運用について日々改善を行なっています。今後も、こうした取り組みを積極的に実践し、KPT 形式で振り返って、また次のアクションにつなげることで、多くの方に愛されるプロダクトを育てていきたいと思っています。 お知らせ メドレーでは、エンジニアやデザイナーを募集しています。ご興味のある方は、こちらからどうぞ! メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
こんにちは、開発本部の高井です。オンライン診療アプリ「 CLINICS 」のアプリ開発を主に担当しています。 CLINICS では Web に加えて、iOS 版と Android 版の各プラットフォームの仕様変更や機能追加などをほぼ同時に開発しているのですが、担当する人数が増えたりすることで、仕様に差が出たり、その結果手戻りが起きるということも増え始めていました。 そうした課題を解決するために実践した様々な施策の中から、特に有効だった 3 つの改善策について、今日はご紹介します。 背景 CLINICS の開発チームでは 5 人ほどのエンジニアがタスク単位で全てのプラットフォームを実装したり、大きいタスクの場合はプラットフォーム毎に別の開発者が担当する形で開発しています。 そのような形で機能追加や不具合対応の開発を進める中で、以下のような課題がありました。 プラットフォーム間で仕様やデザインが違う リリース直前に仕様の違いが見つかり、手戻りが発生する 各プラットフォームに対する習熟度にバラつきがあるため、開発者によって実装方法が違う 特にプラットフォーム毎に開発者がほぼ固定されてしまっていた時期には、コードレビューはしていても微妙な違いに気づかなかったり、同じ UI にするのに実装コストが高くてあきらめたり、ということが起こりがちでした。** プラットフォーム間で仕様やデザインが違うとユーザ体験の質がプラットフォームによってバラついてしまいますし、デザインや企画の作業も増えてしまいます** 。これらに加えて、エンジニアの人数が増えたり、デザイナーやカスタマーサポートなどエンジニア以外のメンバーとのコミュニケーションも増えたりしてきたこともあって、開発スピードも段々と遅くなってきていました。 そのような状況を改善するために、チーム内で継続的に実装方法や開発フローを見直し、改善策を実施してきました。 今回は以下の 3 つの改善策をご紹介します。具体的な実装については、主に iOS で使用しているコードを引用してご紹介します。(コードの一部を抜粋しているので、そのままでは使用することはできません。あくまでも参考コードとして読んでください。) DLS(デザイン言語システム)の導入 アプリエラーの共通化 コードレビューの手順改善 改善策 1 DLS(デザイン言語システム)の導入 まずは DLS(デザイン言語システム)の導入についてです。DLS とは以前、本ブログでもデザイナーの前田がご紹介させていただきましたが( デザイン言語システムを入れたらコミュニケーションコストがぐっと下がった話〜メドレー TechLunch〜 )、** UI に一貫性をもたせるため、配色やレイアウト、タイポグラフィやマージンなどのルール **を策定し、チーム全体で継続的に運用していくための仕組みです。策定したルールを組み込んだ各コンポーネントのデザインを元に、Web / iOS / Android の各プラットフォームで UI を実装して開発時に再利用できるようにしています。デザイン自体は下記のような形で Sketch ファイルで管理しています。 iOS については各コンポーネントをカスタムビュークラスとして実装し、再利用できるようにしました。DLS 導入以前はプラットフォーム毎に違った UI やルールで開発していたので、実装段階で担当する開発者毎の認識によって品質や仕様に差が出ている状態でした。DLS 導入によってそのような差が出にくくなり、一定の品質を保つことができるようになりました。 また、** UI の微調整などが減って、機能ロジックに重点を置いた開発に専念できるようになり、さらにデザイナーとの認識合わせが最小限になったことにより開発効率も上がった **と感じています。UI の基盤をつくったことで新しく画面を開発する場合でもコンポーネントを組み合わせ、エンジニアだけで実装が完了することも多くなり、その分デザイナーは次の施策やプロジェクトに専念できるようになりました。 実装についてですが、各コンポーネント毎に xib ファイルで UI パーツを作成し、それをクラスファイルで読み込んでカスタムビュークラスの見た目として使っています。カスタムビューは再利用しやすく、利用時にバラツキが出にくいように以下の点を満たすように実装しました。 Interface Builder/コードのどちらからでも初期化できる ビルドする前に Storyboard 上で UI パーツのデザインを確認できるように IBDesignable と IBInspectable を指定する カスタムビューの中で UI 要素のマージンや高さを指定する 例えば、セレクトフォームコンポーネントのカスタムビューは以下のような実装になっています。 xib ファイル クラスファイル import UIKit protocol ClinicsFormSelectDelegate : class { func didClickFormSelect ( sender : ClinicsFormSelect) } @IBDesignable class ClinicsFormSelect : UIView { @IBOutlet weak var selectView: SelectView! @IBInspectable var labelText: String = "Form-parts" { didSet { selectView. labelText = labelText } } weak var delegate: ClinicsFormSelectDelegate? // コードから初期化する場合に呼ばれる override init ( frame : CGRect) { super . init ( frame : frame) commonInit () } // Interface Builder から初期化する場合に呼ばれる required init? ( coder aDecoder : NSCoder) { super . init ( coder : aDecoder) commonInit () } private func commonInit () { // xib ファイルの読み込み let bundle = Bundle ( for : type ( of : self )) let view = UINib ( nibName : "ClinicsFormSelect" , bundle : bundle). instantiate ( withOwner : self , options : nil ). first as! UIView addSubview (view) backgroundColor = . clear view. backgroundColor = . clear // 読み込んだ View のサイズがカスタムクラス(ClinicsFormSelect)と同じサイズになるように Constraint を設定する view. translatesAutoresizingMaskIntoConstraints = false let bindings = [ "view" : view] addConstraints (NSLayoutConstraint. constraints ( withVisualFormat : "H:|[view]|" , options : NSLayoutFormatOptions ( rawValue : 0 ), metrics : nil , views : bindings)) addConstraints (NSLayoutConstraint. constraints ( withVisualFormat : "V:|[view]|" , options : NSLayoutFormatOptions ( rawValue : 0 ), metrics : nil , views : bindings)) } // xib ファイルの中に配置した UI 要素へのアクションのハンドリング @IBAction func didTap ( _ sender : UITapGestureRecognizer) { delegate?. didClickFormSelect ( sender : self ) } } CLINICS では主に Storyboard を使って UI を実装しているので、使用するときは Storyboard に UIView を置き、コンポーネントのクラス名を指定して使います。テキストなどのプロパティを設定し、Constraint を指定して配置すれば完了です。ユーザによるアクションのハンドリングや動的にプロパティを切り替える必要がある場合は、呼び出し側で処理を追加します。 最終的にビルドすると以下のように表示されます。(表示されている内容は開発中に作成した仮のデータで実際のものとは異なります。) 改善策 2 アプリエラーの共通化 以前は業務的に重要な処理のエラー以外はプラットフォーム毎で表示するエラーメッセージが異なっていたり、エラーハンドリング時に違った挙動をしていることがありました。その結果、ユーザ体験が一貫したものになっていないというだけでなく、お問い合わせがあってもカスタマーサポートが一次回答しにくかったり、伝えられた内容が曖昧なため開発者が調査するのに時間がかかったりすることがありました。 そこで、改めてフロント側で発生するエラーの定義を共通化し、エラーメッセージやエラーハンドリング時の処理も統一しました。** 問い合わせの効率化のために共通のエラーコードも決めて、エラー発生時に表示されるアラートに追加し、それらのエラー定義はドキュメントで一覧化して、カスタマーサポートにも共有 **するようにしました。 また、エラーハンドリング時にクラッシュレポートのログに記録する内容や送信するタイミングを統一して、開発者全員が理解しやすいようにしました。エラーコードの表示については、改善を検討していた時期にちょうど参加していた iOSDC Japan 2017 で、同じような課題に対する知見を 発表 されていたのを見て、早速取り入れました。最近ではユーザからの問い合わせにもエラーコードが使われることがあり、実際にコミュニケーションコストを低下させることができているように思います。 エラーのフィードバックは細かいところではありますが、ユーザのアクションを継続させるために重要な要素のひとつです。CLINICS はユーザ属性が老若男女問わず幅広いので特に気を配って改善を行ってきました。 実装についてですが、iOS では以下のように定義しています。 enum ApplicationError : Error { case commonRequestError ( String ) case createReservationCardError case createReservationScheduleIsFullError ~ var errorCode: String { switch self { case let . commonRequestError (viewId): return " \( viewId ) -0000" case . createReservationCardError : return "40-0001" case . createReservationScheduleIsFullError : return "40-0002" ~ var title: String { switch self { case . commonRequestError : return "接続エラー" case . createReservationCardError : return "決済失敗エラー" ~ var description: String { switch self { case . commonRequestError : return "データを正しく表示出来ない可能性があります。 \n 通信状況をお確かめいただくか、しばらく経ってから再度起動してください。" case . createReservationCardError : return "ご登録されているクレジットカードの決済中にエラーが発生しました。 \n おそれいりますが、もう一度最初から操作ください。" ~ Android でも同様に enum で定義しています。 enum class ApplicationError ( var code: String , val title: String , val description: String ) { CommonRequestError ( "0000" , "接続エラー" , "データを正しく表示出来ない可能性があります。 \n 通信状況をお確かめいただくか、しばらく経ってから再度起動してください。" ), CreateReservationCardError ( "40-0001" , "決済失敗エラー" , "ご登録されているクレジットカードの決済中にエラーが発生しました。 \n おそれいりますが、もう一度最初から操作ください。" ), CreateReservationScheduleIsFullError ( "40-0002" , "スケジュール空きなしエラー" , "選択された予約日時のスケジュールに空きがありませんでした。 \n おそれいりますが、別の予約日時をご選択のうえ、もう一度最初から操作ください。" ), ~ 改善策 3 コードレビューの手順改善 リリース当初から実装者以外のメンバーによるレビューは適宜行なっていましたが、レビューの段階でデグレや仕様の違いを見逃してしまうことがあったので、レビュー体制の強化とメンバーのソース理解の向上を図るために、以下のようにルールを設定しました。 セルフマージはしない PR に対して 2 人以上でレビューする ビューの変更があった場合には画面キャプチャを貼る それらを守りやすく、より効率的にするために Danger も導入しました。 導入手順は こちら にまとめられているほか、検索すればけっこう出てくるので省略します。弊社では iOS の CI は Bitrise を使用しているので Bitrise 上で実行して GitHub の PR に反映させています。 Danger では、以下の項目をチェックしています。上記のルールを反映しているのに加えて、PR の向き先と SwiftLint の実行結果もチェックしています。CLINICS の iOS アプリでは GitFlow を導入しているため、release ブランチと hot-fix ブランチ以外からの PR の向き先が develop ブランチになっていない場合には警告を出すようにしています。 レビュアーの人数が 2 人以上になっているか ビューの変更(xib、storyboard を触ったかどうかのみ確認)があった場合に画面キャプチャを貼っているかどうか PR が develop に向けて作成されているか SwiftLint のチェックを通っているか 弊社が iOS 開発で利用している Danger ファイルは以下の通りとなっています。導入する際のご参考にしてください。 # for only difference github. dismiss_out_of_range_messages # reviewers warn ( "レビュアーは 2 人以上指定してください" ) if github. github . pr_json [ "requested_reviewers" ]. length < 2 # view changes view_extensions = [ ".xib" , ".storyboard" ] has_view_changes = git. modified_files . any? { | file | view_extensions. any? { | ext | file. end_with? ext }} has_view_added = git. added_files . any? { | file | view_extensions. any? { | ext | file. end_with? ext }} pr_has_screenshot = github. pr_body =~ /https?: \/\/\S * \. (png|jpg|jpeg|gif){1}/ warn ( "見た目に変更がある場合は画面キャプチャを貼ってください" ) if (has_view_changes or has_view_added) and !pr_has_screenshot # base branch is_to_master = github. branch_for_base == 'master' is_to_develop = github. branch_for_base == 'develop' is_from_releases = !!github. branch_for_head . match ( /releases \/ [0-9]+ \. [0-9]+ \. [0-9]/ ) warn ( 'PR は develop に向けてください' ) if !is_to_develop and !(is_from_releases and is_to_master) # swiftLint swiftlint. lint_files inline_mode: true まとめ CLINICS におけるアプリ開発の品質と効率性を向上するための取り組みをご紹介しました。これらの取り組みによって プラットフォーム毎のデザインや機能のブレが少なくなり、認識ずれによる手戻りなどが少なくなったことで開発効率が上がった と感じます。プラットフォーム毎の違いを少なくして、より多くのメンバーがコードに手を入れやすい状態にすることで実装やコードレビューの質も向上しているように思います。 React Native などを利用して、コードそのものを共通化する方法もあるとは思いますが、プラットフォーム毎に別のコードで開発する場合でも、仕様や実装のルールを工夫することでより効率的に開発できるのではないでしょうか。 CLINICS チームでは他にも実装や開発プロセス、プロダクト運用について日々改善を行なっています。今後も、こうした取り組みを積極的に実践し、KPT 形式で振り返って、また次のアクションにつなげることで、多くの方に愛されるプロダクトを育てていきたいと思っています。 お知らせ メドレーでは、エンジニアやデザイナーを募集しています。ご興味のある方は、こちらからどうぞ! メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
こんにちは、開発本部の高井です。オンライン診療アプリ「 CLINICS 」のアプリ開発を主に担当しています。 CLINICS では Web に加えて、iOS 版と Android 版の各プラットフォームの仕様変更や機能追加などをほぼ同時に開発しているのですが、担当する人数が増えたりすることで、仕様に差が出たり、その結果手戻りが起きるということも増え始めていました。 そうした課題を解決するために実践した様々な施策の中から、特に有効だった 3 つの改善策について、今日はご紹介します。 背景 CLINICS の開発チームでは 5 人ほどのエンジニアがタスク単位で全てのプラットフォームを実装したり、大きいタスクの場合はプラットフォーム毎に別の開発者が担当する形で開発しています。 そのような形で機能追加や不具合対応の開発を進める中で、以下のような課題がありました。 プラットフォーム間で仕様やデザインが違う リリース直前に仕様の違いが見つかり、手戻りが発生する 各プラットフォームに対する習熟度にバラつきがあるため、開発者によって実装方法が違う 特にプラットフォーム毎に開発者がほぼ固定されてしまっていた時期には、コードレビューはしていても微妙な違いに気づかなかったり、同じ UI にするのに実装コストが高くてあきらめたり、ということが起こりがちでした。** プラットフォーム間で仕様やデザインが違うとユーザ体験の質がプラットフォームによってバラついてしまいますし、デザインや企画の作業も増えてしまいます** 。これらに加えて、エンジニアの人数が増えたり、デザイナーやカスタマーサポートなどエンジニア以外のメンバーとのコミュニケーションも増えたりしてきたこともあって、開発スピードも段々と遅くなってきていました。 そのような状況を改善するために、チーム内で継続的に実装方法や開発フローを見直し、改善策を実施してきました。 今回は以下の 3 つの改善策をご紹介します。具体的な実装については、主に iOS で使用しているコードを引用してご紹介します。(コードの一部を抜粋しているので、そのままでは使用することはできません。あくまでも参考コードとして読んでください。) DLS(デザイン言語システム)の導入 アプリエラーの共通化 コードレビューの手順改善 改善策 1 DLS(デザイン言語システム)の導入 まずは DLS(デザイン言語システム)の導入についてです。DLS とは以前、本ブログでもデザイナーの前田がご紹介させていただきましたが( デザイン言語システムを入れたらコミュニケーションコストがぐっと下がった話〜メドレー TechLunch〜 )、** UI に一貫性をもたせるため、配色やレイアウト、タイポグラフィやマージンなどのルール **を策定し、チーム全体で継続的に運用していくための仕組みです。策定したルールを組み込んだ各コンポーネントのデザインを元に、Web / iOS / Android の各プラットフォームで UI を実装して開発時に再利用できるようにしています。デザイン自体は下記のような形で Sketch ファイルで管理しています。 iOS については各コンポーネントをカスタムビュークラスとして実装し、再利用できるようにしました。DLS 導入以前はプラットフォーム毎に違った UI やルールで開発していたので、実装段階で担当する開発者毎の認識によって品質や仕様に差が出ている状態でした。DLS 導入によってそのような差が出にくくなり、一定の品質を保つことができるようになりました。 また、** UI の微調整などが減って、機能ロジックに重点を置いた開発に専念できるようになり、さらにデザイナーとの認識合わせが最小限になったことにより開発効率も上がった **と感じています。UI の基盤をつくったことで新しく画面を開発する場合でもコンポーネントを組み合わせ、エンジニアだけで実装が完了することも多くなり、その分デザイナーは次の施策やプロジェクトに専念できるようになりました。 実装についてですが、各コンポーネント毎に xib ファイルで UI パーツを作成し、それをクラスファイルで読み込んでカスタムビュークラスの見た目として使っています。カスタムビューは再利用しやすく、利用時にバラツキが出にくいように以下の点を満たすように実装しました。 Interface Builder/コードのどちらからでも初期化できる ビルドする前に Storyboard 上で UI パーツのデザインを確認できるように IBDesignable と IBInspectable を指定する カスタムビューの中で UI 要素のマージンや高さを指定する 例えば、セレクトフォームコンポーネントのカスタムビューは以下のような実装になっています。 xib ファイル クラスファイル import UIKit protocol ClinicsFormSelectDelegate : class { func didClickFormSelect ( sender : ClinicsFormSelect) } @IBDesignable class ClinicsFormSelect : UIView { @IBOutlet weak var selectView: SelectView! @IBInspectable var labelText: String = "Form-parts" { didSet { selectView. labelText = labelText } } weak var delegate: ClinicsFormSelectDelegate? // コードから初期化する場合に呼ばれる override init ( frame : CGRect) { super . init ( frame : frame) commonInit () } // Interface Builder から初期化する場合に呼ばれる required init? ( coder aDecoder : NSCoder) { super . init ( coder : aDecoder) commonInit () } private func commonInit () { // xib ファイルの読み込み let bundle = Bundle ( for : type ( of : self )) let view = UINib ( nibName : "ClinicsFormSelect" , bundle : bundle). instantiate ( withOwner : self , options : nil ). first as! UIView addSubview (view) backgroundColor = . clear view. backgroundColor = . clear // 読み込んだ View のサイズがカスタムクラス(ClinicsFormSelect)と同じサイズになるように Constraint を設定する view. translatesAutoresizingMaskIntoConstraints = false let bindings = [ "view" : view] addConstraints (NSLayoutConstraint. constraints ( withVisualFormat : "H:|[view]|" , options : NSLayoutFormatOptions ( rawValue : 0 ), metrics : nil , views : bindings)) addConstraints (NSLayoutConstraint. constraints ( withVisualFormat : "V:|[view]|" , options : NSLayoutFormatOptions ( rawValue : 0 ), metrics : nil , views : bindings)) } // xib ファイルの中に配置した UI 要素へのアクションのハンドリング @IBAction func didTap ( _ sender : UITapGestureRecognizer) { delegate?. didClickFormSelect ( sender : self ) } } CLINICS では主に Storyboard を使って UI を実装しているので、使用するときは Storyboard に UIView を置き、コンポーネントのクラス名を指定して使います。テキストなどのプロパティを設定し、Constraint を指定して配置すれば完了です。ユーザによるアクションのハンドリングや動的にプロパティを切り替える必要がある場合は、呼び出し側で処理を追加します。 最終的にビルドすると以下のように表示されます。(表示されている内容は開発中に作成した仮のデータで実際のものとは異なります。) 改善策 2 アプリエラーの共通化 以前は業務的に重要な処理のエラー以外はプラットフォーム毎で表示するエラーメッセージが異なっていたり、エラーハンドリング時に違った挙動をしていることがありました。その結果、ユーザ体験が一貫したものになっていないというだけでなく、お問い合わせがあってもカスタマーサポートが一次回答しにくかったり、伝えられた内容が曖昧なため開発者が調査するのに時間がかかったりすることがありました。 そこで、改めてフロント側で発生するエラーの定義を共通化し、エラーメッセージやエラーハンドリング時の処理も統一しました。** 問い合わせの効率化のために共通のエラーコードも決めて、エラー発生時に表示されるアラートに追加し、それらのエラー定義はドキュメントで一覧化して、カスタマーサポートにも共有 **するようにしました。 また、エラーハンドリング時にクラッシュレポートのログに記録する内容や送信するタイミングを統一して、開発者全員が理解しやすいようにしました。エラーコードの表示については、改善を検討していた時期にちょうど参加していた iOSDC Japan 2017 で、同じような課題に対する知見を 発表 されていたのを見て、早速取り入れました。最近ではユーザからの問い合わせにもエラーコードが使われることがあり、実際にコミュニケーションコストを低下させることができているように思います。 エラーのフィードバックは細かいところではありますが、ユーザのアクションを継続させるために重要な要素のひとつです。CLINICS はユーザ属性が老若男女問わず幅広いので特に気を配って改善を行ってきました。 実装についてですが、iOS では以下のように定義しています。 enum ApplicationError : Error { case commonRequestError ( String ) case createReservationCardError case createReservationScheduleIsFullError ~ var errorCode: String { switch self { case let . commonRequestError (viewId): return " \( viewId ) -0000" case . createReservationCardError : return "40-0001" case . createReservationScheduleIsFullError : return "40-0002" ~ var title: String { switch self { case . commonRequestError : return "接続エラー" case . createReservationCardError : return "決済失敗エラー" ~ var description: String { switch self { case . commonRequestError : return "データを正しく表示出来ない可能性があります。 \n 通信状況をお確かめいただくか、しばらく経ってから再度起動してください。" case . createReservationCardError : return "ご登録されているクレジットカードの決済中にエラーが発生しました。 \n おそれいりますが、もう一度最初から操作ください。" ~ Android でも同様に enum で定義しています。 enum class ApplicationError ( var code: String , val title: String , val description: String ) { CommonRequestError ( "0000" , "接続エラー" , "データを正しく表示出来ない可能性があります。 \n 通信状況をお確かめいただくか、しばらく経ってから再度起動してください。" ), CreateReservationCardError ( "40-0001" , "決済失敗エラー" , "ご登録されているクレジットカードの決済中にエラーが発生しました。 \n おそれいりますが、もう一度最初から操作ください。" ), CreateReservationScheduleIsFullError ( "40-0002" , "スケジュール空きなしエラー" , "選択された予約日時のスケジュールに空きがありませんでした。 \n おそれいりますが、別の予約日時をご選択のうえ、もう一度最初から操作ください。" ), ~ 改善策 3 コードレビューの手順改善 リリース当初から実装者以外のメンバーによるレビューは適宜行なっていましたが、レビューの段階でデグレや仕様の違いを見逃してしまうことがあったので、レビュー体制の強化とメンバーのソース理解の向上を図るために、以下のようにルールを設定しました。 セルフマージはしない PR に対して 2 人以上でレビューする ビューの変更があった場合には画面キャプチャを貼る それらを守りやすく、より効率的にするために Danger も導入しました。 導入手順は こちら にまとめられているほか、検索すればけっこう出てくるので省略します。弊社では iOS の CI は Bitrise を使用しているので Bitrise 上で実行して GitHub の PR に反映させています。 Danger では、以下の項目をチェックしています。上記のルールを反映しているのに加えて、PR の向き先と SwiftLint の実行結果もチェックしています。CLINICS の iOS アプリでは GitFlow を導入しているため、release ブランチと hot-fix ブランチ以外からの PR の向き先が develop ブランチになっていない場合には警告を出すようにしています。 レビュアーの人数が 2 人以上になっているか ビューの変更(xib、storyboard を触ったかどうかのみ確認)があった場合に画面キャプチャを貼っているかどうか PR が develop に向けて作成されているか SwiftLint のチェックを通っているか 弊社が iOS 開発で利用している Danger ファイルは以下の通りとなっています。導入する際のご参考にしてください。 # for only difference github. dismiss_out_of_range_messages # reviewers warn ( "レビュアーは 2 人以上指定してください" ) if github. github . pr_json [ "requested_reviewers" ]. length < 2 # view changes view_extensions = [ ".xib" , ".storyboard" ] has_view_changes = git. modified_files . any? { | file | view_extensions. any? { | ext | file. end_with? ext }} has_view_added = git. added_files . any? { | file | view_extensions. any? { | ext | file. end_with? ext }} pr_has_screenshot = github. pr_body =~ /https?: \/\/\S * \. (png|jpg|jpeg|gif){1}/ warn ( "見た目に変更がある場合は画面キャプチャを貼ってください" ) if (has_view_changes or has_view_added) and !pr_has_screenshot # base branch is_to_master = github. branch_for_base == 'master' is_to_develop = github. branch_for_base == 'develop' is_from_releases = !!github. branch_for_head . match ( /releases \/ [0-9]+ \. [0-9]+ \. [0-9]/ ) warn ( 'PR は develop に向けてください' ) if !is_to_develop and !(is_from_releases and is_to_master) # swiftLint swiftlint. lint_files inline_mode: true まとめ CLINICS におけるアプリ開発の品質と効率性を向上するための取り組みをご紹介しました。これらの取り組みによって プラットフォーム毎のデザインや機能のブレが少なくなり、認識ずれによる手戻りなどが少なくなったことで開発効率が上がった と感じます。プラットフォーム毎の違いを少なくして、より多くのメンバーがコードに手を入れやすい状態にすることで実装やコードレビューの質も向上しているように思います。 React Native などを利用して、コードそのものを共通化する方法もあるとは思いますが、プラットフォーム毎に別のコードで開発する場合でも、仕様や実装のルールを工夫することでより効率的に開発できるのではないでしょうか。 CLINICS チームでは他にも実装や開発プロセス、プロダクト運用について日々改善を行なっています。今後も、こうした取り組みを積極的に実践し、KPT 形式で振り返って、また次のアクションにつなげることで、多くの方に愛されるプロダクトを育てていきたいと思っています。 お知らせ メドレーでは、エンジニアやデザイナーを募集しています。ご興味のある方は、こちらからどうぞ! メンバーのストーリー | 株式会社メドレー メンバーのストーリー 家族や友人が病気になった時に救いの手を差しのべる医療の力。... www.medley.jp
こんにちは。開発本部の医療メディアチームでデザインをしている波切です。 メドレー開発本部で行われている勉強会「TechLunch」で、デザイナー以外の方も知っておいて損はない「ブランドとは?」というお話をさせていただきました。多くの方が何となく知っていることも多いかもしれませんが、再入門的に参考にしていただけると嬉しいです。 背景 メドレーでは時期を問わずプロダクトの在り方について常日頃から様々な場面で議論がなされています。 こういった議論の中でブランドとしてどのように見せられるのが良いだろうか、といった検討をすることも多々あり、改めてブランドについて学び直したいと思ったのが今回のきっかけになります。 TechLunch ではエンジニア・デザイナー・ディレクター・医師(!)と様々な職種の人が参加しています。 この時代では当たり前かもしれないブランドの基礎を改めて学び直し、デザイナー以外の職種の方にも共有しましたので、ブログでもご紹介させていただければと思います。 ブランドってなんでしょう ブランドとブランディングの違いって? まずは混合しやすいブランドとブランディングの定義から。 ある特定の商品やサービスが消費者・顧客によって識別されているとき、 その商品やサービスを「ブランド」と呼ぶ ※製品名、パッケージング、広告、価格、使用経験などにより、その製品につけられた製品特性と価値(機能的および非機能的)とのユニークなコンビネーション。消費者・顧客の目から見た場合、その製品を競合から差別化するもの。 (via ブランド・マネージャー認定協会 用語集 ) ブランディングとは、ブランドに対する共感や信頼などを通じて顧客にとっての価値を高めていく、企業と組織のマーケティング戦略の 1 つ。ブランドとして認知されていないものをブランドに育て上げる、あるいはブランド構成要素を強化し、活性・維持管理していくこと。また、その手法。ここでいうブランドとは高級消費財に限らず、その対象としては、商品やサービス、それらを供給する企業や団体のほか、人物・建築物・史跡・地域 ・祭事など、あらゆるものが該当する。 (via wikipedia:ブランディング ) ブランド とは「企業・製品に対して消費者が持っているイメージ(記号)であり、競合との差別化を生み出す価値の総体」を指し、 ブランディング は「ブランド価値を与えるための手段」と捉えることができると思います。 この定義になぞらえてコカ・コーラを例にブランドとして認知される具体的なステップとして紹介すると、以下のようになります。 ロゴなどの識別記号が記憶される コカ・コーラのロゴが記憶される (生活者の頭の中に、ロゴなどの識別記号が記憶される) 記号から体験が思い浮かぶ コカ・コーラのロゴを見れば炭酸飲料であることや、爽やかな気分になれることが思い浮ぶ (識別記号を見れば、知覚体験を想起できる) 体験から記号を思い出す 爽やかな気分になりたいと思ったら、コカ・コーラを思い出す。ロゴが思い浮かぶ (知覚価値が頭に浮かんだら、識別記号が想起される)  「ブランド連想」「ブランド資産」といった言葉もあり、ブランド(識別記号と知覚体験)に対してポジティブな印象を築き蓄積させることがブランディングのカギになってきます。 ブランド構築 前述の記号をブランドの土台とするとコーポレートアイデンティティ(CI)やヴィジュアルアイデンティティ(VI)といったクリエイティブが大きな役割を果たしますが、現在ではユーザーはブランドを知覚する機会が多く、差別化のためにもブランドは顧客体験をベースに作っていくことも重要になります。 「良い顧客体験を提供しブランドの競争力を高める」 という考え方に基づいて、ブランド戦略を考える順番は理想的な体験を描いてから必要なモノや技術を考えます。これはブランドに限らず様々な場面で意識したいことです。 ブランドに大事な一貫性 魅力的なブランドは顧客体験が蓄積して形成されていきます。蓄積されるブランド体験の要素は「体験の魅力度」「体験の量と時間」「体験の一貫性」と 3 つあり、ブランドの価値はこの 3 つの要素のかけ算にあります。 体験が魅力的であり、その体験の回数が多く長い時間にわたって経験し、体験自体に一貫性があるブランドがユーザーとって良いものとされます。 3 つのうち特に重要なものは最後の 「体験の一貫性」 にあり、この一貫性は 2 つに分けることができます。 時系列で一貫性 :時代で左右されない顧客体験がブランドから提供される 接点の一貫性 :ブランドを買ったり利用する前から、購入プロセス、購入後の利用シーンにおいて、一貫した顧客体験ができる 「モノとコト」にも例えやすいところですが、製品としての一貫性に加えて体験する前後のグランドデザインにも一貫性を持たすことが重要になります。 例としてスターバックスは広告費をほとんどかけずに今のブランド認知度を築いたことは有名ですが、そこにはブランドの価値を築くためのブランディングに一貫性があり、かつそれらが時代性とマッチしたのが要因ではないかと思います。 ブランディングのメリット 選択意思決定の単純化・固定化 顧客の知識が整理されることで競合と差別化され再び同じ物を選ぶようになる ユーザーのロイヤル化 親しみや信頼が増大されることでブランドロイヤリティが形成される なぜブランドにこだわるのか、という点でもこれらメリットを実現していくことが重要です。 デザイナーとして気遣い溢れる UI や、サービスの思想を記号に落とし込んだ VI などモノづくり視点でのこだわりや重要さを踏まえた上で、他職種の方にもこれらのメリットや競争としての必要であることを理解してもらえるよう働きかけることを意識していきたいところです。 ブランディングの悩みどころ ここからは基礎を踏まえて、実践的に行われているブランディングで悩みやすいところを事例で紹介しながら簡単なディスカッションをしていきました。一部だけ抜粋してご紹介します。 製品ブランドの管理 会社のブランド管理の思想を定義できても、変化の早い業界であればイメージ通りになかなか通らないことも多々有りえます。 少ないブランド資産を活用する意味でもスタートアップは横串型に整理されることが多くありますが、ある程度の規模感になって基礎体力がある企業であると個別適応型でもブランドとして信頼性を保てますし、横串型に比べて動きやすさがあると思います。 一方で、プラットフォーマーとして存在したいなら横串のブランド価値からファンを囲い込むべきかもしれません。Techlunch の中でもメドレーであればどうあると良いかについて議論ができました。 ブランディングのタイミング 顧客体験の蓄積が重要なブランドでありますが、どの段階でブランディングに取り組むかは状況によりますが意見が出やすいところだと思います。 ICC FUKUOKA2017 にてブランディングについてのセッションがあり、取り組むタイミングについての議論がうまくまとめられていたため Techlunch で事例として共有しました。プロダクトとしての差別化が基本であることに加えて、ブランドの在り方を組織にインストールさせるためにブランディングに取り組むケースも紹介されています。 僕はブランドが常に必要かと言うと“No”だと思います。 コモディティ化し始めたり、競争が始まって差別化しなくてはならない時に、プロダクトの機能などで差別化ができない、または必ずしもパフォーマンスで差別化ができない時に唯一残された選択が、ブランドを作るということであると思います。 [株式会社 Bloom&Co. 彌野泰弘] ユーザーを獲りにいくというフェーズですよね。 メルカリの場合、やはり最初の 100 万ダウンロードくらいまでは、結構チューニングをしながらオンラインのマーケティングで(ユーザーを)獲得してきてきました。 中略 やはり 100 万ダウンロードくらいあって、リテンションレートが高くユーザーが積み上がる状態になっていれば、大きくマスマーケティング(TVCM)をやっても獲得したユーザーは残りますからね。 [株式会社メルカリ 小泉文明] 僕は、ユーザーを獲得する手前でブランドが必要だと思っているんですよね。 ブランドというのは必ずしも外に対してだけではなくて、(組織の)中の人に対して必要であることもすごく多いのです。 中略 資生堂は当時 130 年くらい経っている会社だったので、その 130 年もこの後の 130 年も、世の中を美しくするとか、人を美しくするとか、それは女性に限らず、お化粧に限らず美しくするということが必要だよね、軸だよねという話になって、そのスローガンと共に前田新社長体制で進んでいくことになりました。 [株式会社 dof 齋藤太郎] (via スタートアップのブランディングはいつから必要か?【F17-7C #3】 ) 共有した後には、リリース当初からブランドやクリエイティブが作り込まれたプロダクトが最近話題になることが多いということも話に上がりました。 もちろんブランディングのタイミングは状況により千差万別ですが、プロダクトをゼロから作る際には、プロダクトの在り方と合わせてどんなブランドを作って行きたいのかも早めに考えられることが必要だ、など具体的なディスカッションも出来ました。 新たなブランドが受け入れられないことも 基本的にブランドを新しくすることは見慣れたものが変わってしまう恐怖から反発を生むケースが多いですが、その中でも GAP はロゴの 2010 年リニューアル公表後ネット上からの反発が強くわずか 6 日間という短期間で新しいロゴの使用を止め、元のロゴに戻してしまうという一件がありました。(この件は 株価 にも大きな影響を与えました) 一方、同じような境遇で Airbnb も 2014 年のリニューアル当初ロゴは不評でしたが今ではリニューアルの成功例として扱われる存在になっています。 Techlunch でも歴史の有無が差になったのか、など様々な意見が出てきました。この件はロゴとしての王道を極めようとした以上の背景を提示出来なかった Gap に対して、 Airbnb はサービスのストーリーをロゴに内包 し、地道にロゴを介したコミュニケーションに徹したことが明暗を分けたように思います。 この事例はロゴのアイデンティティをどこまで確立させられたかの違いにあることに加えて、デザインの意思決定を一時的な多数意見に委ねた事例としても学ぶことが多いです。 まとめ 私個人が元々グラフィックデザインをしていた経験もあり、今まではブランディングの中でも興味が CI や VI に傾倒していましたが、体験全体がブランドに大きな影響を与えるこの時代、組織としてブランド構築をしていく意識が重要であることが今回の大きな学びでした。 また基礎を学ぶ上で書籍を読んでいましたが、最近の事例などを学ぶ際にはブログなどでの情報収集がとても有効で、学び方も変わってきているなと思いました。今回紹介した内容はあくまで入門編なので、興味があれば今回参考にさせていただいた本とブログ・記事からより深堀りが出来るのでオススメします。 プラットフォームブランディング コーポレート・アイデンティティ戦略―デザインが企業経営を変える ブランド・エクイティ研究の展望 ~価値をめぐる議論の系譜を中心に~ UX とブランド ブランドアイデンティティとは|ブランド構築を成果に導く BI の創り方|成功事例有 スタートアップのブランディングはいつから必要か? ロゴのリデザインーなぜ Gap が失敗し Airbnb が受け入れられたのか 武器になる「ロゴ」を生み出す、CI デザインとは何か? Techlunch ではデザイナー以外の方からも事例に対して意見が出たり、疑問に対して参加者でディスカッションが出来たことがとても有意義でした。今後はこれらを意識しながらブランドの土台となる価値や在り方をデザイン出来るようにしていきたいと思います。 お知らせ  メドレーでは、医療介護の求人サイト「ジョブメドレー」、医師たちがつくるオンライン医療事典「MEDLEY」、口コミで探せる介護施設の検索サイト「介護のほんね」、オンライン診療アプリ「CLINICS」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 興味のある方、ぜひメドレーへ遊びにいらしてください。 www.medley.jp
こんにちは。開発本部の医療メディアチームでデザインをしている波切です。 メドレー開発本部で行われている勉強会「TechLunch」で、デザイナー以外の方も知っておいて損はない「ブランドとは?」というお話をさせていただきました。多くの方が何となく知っていることも多いかもしれませんが、再入門的に参考にしていただけると嬉しいです。 背景 メドレーでは時期を問わずプロダクトの在り方について常日頃から様々な場面で議論がなされています。 こういった議論の中でブランドとしてどのように見せられるのが良いだろうか、といった検討をすることも多々あり、改めてブランドについて学び直したいと思ったのが今回のきっかけになります。 TechLunch ではエンジニア・デザイナー・ディレクター・医師(!)と様々な職種の人が参加しています。 この時代では当たり前かもしれないブランドの基礎を改めて学び直し、デザイナー以外の職種の方にも共有しましたので、ブログでもご紹介させていただければと思います。 ブランドってなんでしょう ブランドとブランディングの違いって? まずは混合しやすいブランドとブランディングの定義から。 ある特定の商品やサービスが消費者・顧客によって識別されているとき、 その商品やサービスを「ブランド」と呼ぶ ※製品名、パッケージング、広告、価格、使用経験などにより、その製品につけられた製品特性と価値(機能的および非機能的)とのユニークなコンビネーション。消費者・顧客の目から見た場合、その製品を競合から差別化するもの。 (via ブランド・マネージャー認定協会 用語集 ) ブランディングとは、ブランドに対する共感や信頼などを通じて顧客にとっての価値を高めていく、企業と組織のマーケティング戦略の 1 つ。ブランドとして認知されていないものをブランドに育て上げる、あるいはブランド構成要素を強化し、活性・維持管理していくこと。また、その手法。ここでいうブランドとは高級消費財に限らず、その対象としては、商品やサービス、それらを供給する企業や団体のほか、人物・建築物・史跡・地域 ・祭事など、あらゆるものが該当する。 (via wikipedia:ブランディング ) ブランド とは「企業・製品に対して消費者が持っているイメージ(記号)であり、競合との差別化を生み出す価値の総体」を指し、 ブランディング は「ブランド価値を与えるための手段」と捉えることができると思います。 この定義になぞらえてコカ・コーラを例にブランドとして認知される具体的なステップとして紹介すると、以下のようになります。 ロゴなどの識別記号が記憶される コカ・コーラのロゴが記憶される (生活者の頭の中に、ロゴなどの識別記号が記憶される) 記号から体験が思い浮かぶ コカ・コーラのロゴを見れば炭酸飲料であることや、爽やかな気分になれることが思い浮ぶ (識別記号を見れば、知覚体験を想起できる) 体験から記号を思い出す 爽やかな気分になりたいと思ったら、コカ・コーラを思い出す。ロゴが思い浮かぶ (知覚価値が頭に浮かんだら、識別記号が想起される)  「ブランド連想」「ブランド資産」といった言葉もあり、ブランド(識別記号と知覚体験)に対してポジティブな印象を築き蓄積させることがブランディングのカギになってきます。 ブランド構築 前述の記号をブランドの土台とするとコーポレートアイデンティティ(CI)やヴィジュアルアイデンティティ(VI)といったクリエイティブが大きな役割を果たしますが、現在ではユーザーはブランドを知覚する機会が多く、差別化のためにもブランドは顧客体験をベースに作っていくことも重要になります。 「良い顧客体験を提供しブランドの競争力を高める」 という考え方に基づいて、ブランド戦略を考える順番は理想的な体験を描いてから必要なモノや技術を考えます。これはブランドに限らず様々な場面で意識したいことです。 ブランドに大事な一貫性 魅力的なブランドは顧客体験が蓄積して形成されていきます。蓄積されるブランド体験の要素は「体験の魅力度」「体験の量と時間」「体験の一貫性」と 3 つあり、ブランドの価値はこの 3 つの要素のかけ算にあります。 体験が魅力的であり、その体験の回数が多く長い時間にわたって経験し、体験自体に一貫性があるブランドがユーザーとって良いものとされます。 3 つのうち特に重要なものは最後の 「体験の一貫性」 にあり、この一貫性は 2 つに分けることができます。 時系列で一貫性 :時代で左右されない顧客体験がブランドから提供される 接点の一貫性 :ブランドを買ったり利用する前から、購入プロセス、購入後の利用シーンにおいて、一貫した顧客体験ができる 「モノとコト」にも例えやすいところですが、製品としての一貫性に加えて体験する前後のグランドデザインにも一貫性を持たすことが重要になります。 例としてスターバックスは広告費をほとんどかけずに今のブランド認知度を築いたことは有名ですが、そこにはブランドの価値を築くためのブランディングに一貫性があり、かつそれらが時代性とマッチしたのが要因ではないかと思います。 ブランディングのメリット 選択意思決定の単純化・固定化 顧客の知識が整理されることで競合と差別化され再び同じ物を選ぶようになる ユーザーのロイヤル化 親しみや信頼が増大されることでブランドロイヤリティが形成される なぜブランドにこだわるのか、という点でもこれらメリットを実現していくことが重要です。 デザイナーとして気遣い溢れる UI や、サービスの思想を記号に落とし込んだ VI などモノづくり視点でのこだわりや重要さを踏まえた上で、他職種の方にもこれらのメリットや競争としての必要であることを理解してもらえるよう働きかけることを意識していきたいところです。 ブランディングの悩みどころ ここからは基礎を踏まえて、実践的に行われているブランディングで悩みやすいところを事例で紹介しながら簡単なディスカッションをしていきました。一部だけ抜粋してご紹介します。 製品ブランドの管理 会社のブランド管理の思想を定義できても、変化の早い業界であればイメージ通りになかなか通らないことも多々有りえます。 少ないブランド資産を活用する意味でもスタートアップは横串型に整理されることが多くありますが、ある程度の規模感になって基礎体力がある企業であると個別適応型でもブランドとして信頼性を保てますし、横串型に比べて動きやすさがあると思います。 一方で、プラットフォーマーとして存在したいなら横串のブランド価値からファンを囲い込むべきかもしれません。Techlunch の中でもメドレーであればどうあると良いかについて議論ができました。 ブランディングのタイミング 顧客体験の蓄積が重要なブランドでありますが、どの段階でブランディングに取り組むかは状況によりますが意見が出やすいところだと思います。 ICC FUKUOKA2017 にてブランディングについてのセッションがあり、取り組むタイミングについての議論がうまくまとめられていたため Techlunch で事例として共有しました。プロダクトとしての差別化が基本であることに加えて、ブランドの在り方を組織にインストールさせるためにブランディングに取り組むケースも紹介されています。 僕はブランドが常に必要かと言うと“No”だと思います。 コモディティ化し始めたり、競争が始まって差別化しなくてはならない時に、プロダクトの機能などで差別化ができない、または必ずしもパフォーマンスで差別化ができない時に唯一残された選択が、ブランドを作るということであると思います。 [株式会社 Bloom&Co. 彌野泰弘] ユーザーを獲りにいくというフェーズですよね。 メルカリの場合、やはり最初の 100 万ダウンロードくらいまでは、結構チューニングをしながらオンラインのマーケティングで(ユーザーを)獲得してきてきました。 中略 やはり 100 万ダウンロードくらいあって、リテンションレートが高くユーザーが積み上がる状態になっていれば、大きくマスマーケティング(TVCM)をやっても獲得したユーザーは残りますからね。 [株式会社メルカリ 小泉文明] 僕は、ユーザーを獲得する手前でブランドが必要だと思っているんですよね。 ブランドというのは必ずしも外に対してだけではなくて、(組織の)中の人に対して必要であることもすごく多いのです。 中略 資生堂は当時 130 年くらい経っている会社だったので、その 130 年もこの後の 130 年も、世の中を美しくするとか、人を美しくするとか、それは女性に限らず、お化粧に限らず美しくするということが必要だよね、軸だよねという話になって、そのスローガンと共に前田新社長体制で進んでいくことになりました。 [株式会社 dof 齋藤太郎] (via スタートアップのブランディングはいつから必要か?【F17-7C #3】 ) 共有した後には、リリース当初からブランドやクリエイティブが作り込まれたプロダクトが最近話題になることが多いということも話に上がりました。 もちろんブランディングのタイミングは状況により千差万別ですが、プロダクトをゼロから作る際には、プロダクトの在り方と合わせてどんなブランドを作って行きたいのかも早めに考えられることが必要だ、など具体的なディスカッションも出来ました。 新たなブランドが受け入れられないことも 基本的にブランドを新しくすることは見慣れたものが変わってしまう恐怖から反発を生むケースが多いですが、その中でも GAP はロゴの 2010 年リニューアル公表後ネット上からの反発が強くわずか 6 日間という短期間で新しいロゴの使用を止め、元のロゴに戻してしまうという一件がありました。(この件は 株価 にも大きな影響を与えました) 一方、同じような境遇で Airbnb も 2014 年のリニューアル当初ロゴは不評でしたが今ではリニューアルの成功例として扱われる存在になっています。 Techlunch でも歴史の有無が差になったのか、など様々な意見が出てきました。この件はロゴとしての王道を極めようとした以上の背景を提示出来なかった Gap に対して、 Airbnb はサービスのストーリーをロゴに内包 し、地道にロゴを介したコミュニケーションに徹したことが明暗を分けたように思います。 この事例はロゴのアイデンティティをどこまで確立させられたかの違いにあることに加えて、デザインの意思決定を一時的な多数意見に委ねた事例としても学ぶことが多いです。 まとめ 私個人が元々グラフィックデザインをしていた経験もあり、今まではブランディングの中でも興味が CI や VI に傾倒していましたが、体験全体がブランドに大きな影響を与えるこの時代、組織としてブランド構築をしていく意識が重要であることが今回の大きな学びでした。 また基礎を学ぶ上で書籍を読んでいましたが、最近の事例などを学ぶ際にはブログなどでの情報収集がとても有効で、学び方も変わってきているなと思いました。今回紹介した内容はあくまで入門編なので、興味があれば今回参考にさせていただいた本とブログ・記事からより深堀りが出来るのでオススメします。 プラットフォームブランディング コーポレート・アイデンティティ戦略―デザインが企業経営を変える ブランド・エクイティ研究の展望 ~価値をめぐる議論の系譜を中心に~ UX とブランド ブランドアイデンティティとは|ブランド構築を成果に導く BI の創り方|成功事例有 スタートアップのブランディングはいつから必要か? ロゴのリデザインーなぜ Gap が失敗し Airbnb が受け入れられたのか 武器になる「ロゴ」を生み出す、CI デザインとは何か? Techlunch ではデザイナー以外の方からも事例に対して意見が出たり、疑問に対して参加者でディスカッションが出来たことがとても有意義でした。今後はこれらを意識しながらブランドの土台となる価値や在り方をデザイン出来るようにしていきたいと思います。 お知らせ  メドレーでは、医療介護の求人サイト「ジョブメドレー」、医師たちがつくるオンライン医療事典「MEDLEY」、口コミで探せる介護施設の検索サイト「介護のほんね」、オンライン診療アプリ「CLINICS」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 興味のある方、ぜひメドレーへ遊びにいらしてください。 www.medley.jp
こんにちは。開発本部の医療メディアチームでデザインをしている波切です。 メドレー開発本部で行われている勉強会「TechLunch」で、デザイナー以外の方も知っておいて損はない「ブランドとは?」というお話をさせていただきました。多くの方が何となく知っていることも多いかもしれませんが、再入門的に参考にしていただけると嬉しいです。 背景 メドレーでは時期を問わずプロダクトの在り方について常日頃から様々な場面で議論がなされています。 こういった議論の中でブランドとしてどのように見せられるのが良いだろうか、といった検討をすることも多々あり、改めてブランドについて学び直したいと思ったのが今回のきっかけになります。 TechLunch ではエンジニア・デザイナー・ディレクター・医師(!)と様々な職種の人が参加しています。 この時代では当たり前かもしれないブランドの基礎を改めて学び直し、デザイナー以外の職種の方にも共有しましたので、ブログでもご紹介させていただければと思います。 ブランドってなんでしょう ブランドとブランディングの違いって? まずは混合しやすいブランドとブランディングの定義から。 ある特定の商品やサービスが消費者・顧客によって識別されているとき、 その商品やサービスを「ブランド」と呼ぶ ※製品名、パッケージング、広告、価格、使用経験などにより、その製品につけられた製品特性と価値(機能的および非機能的)とのユニークなコンビネーション。消費者・顧客の目から見た場合、その製品を競合から差別化するもの。 (via ブランド・マネージャー認定協会 用語集 ) ブランディングとは、ブランドに対する共感や信頼などを通じて顧客にとっての価値を高めていく、企業と組織のマーケティング戦略の 1 つ。ブランドとして認知されていないものをブランドに育て上げる、あるいはブランド構成要素を強化し、活性・維持管理していくこと。また、その手法。ここでいうブランドとは高級消費財に限らず、その対象としては、商品やサービス、それらを供給する企業や団体のほか、人物・建築物・史跡・地域 ・祭事など、あらゆるものが該当する。 (via wikipedia:ブランディング ) ブランド とは「企業・製品に対して消費者が持っているイメージ(記号)であり、競合との差別化を生み出す価値の総体」を指し、 ブランディング は「ブランド価値を与えるための手段」と捉えることができると思います。 この定義になぞらえてコカ・コーラを例にブランドとして認知される具体的なステップとして紹介すると、以下のようになります。 ロゴなどの識別記号が記憶される コカ・コーラのロゴが記憶される (生活者の頭の中に、ロゴなどの識別記号が記憶される) 記号から体験が思い浮かぶ コカ・コーラのロゴを見れば炭酸飲料であることや、爽やかな気分になれることが思い浮ぶ (識別記号を見れば、知覚体験を想起できる) 体験から記号を思い出す 爽やかな気分になりたいと思ったら、コカ・コーラを思い出す。ロゴが思い浮かぶ (知覚価値が頭に浮かんだら、識別記号が想起される)  「ブランド連想」「ブランド資産」といった言葉もあり、ブランド(識別記号と知覚体験)に対してポジティブな印象を築き蓄積させることがブランディングのカギになってきます。 ブランド構築 前述の記号をブランドの土台とするとコーポレートアイデンティティ(CI)やヴィジュアルアイデンティティ(VI)といったクリエイティブが大きな役割を果たしますが、現在ではユーザーはブランドを知覚する機会が多く、差別化のためにもブランドは顧客体験をベースに作っていくことも重要になります。 「良い顧客体験を提供しブランドの競争力を高める」 という考え方に基づいて、ブランド戦略を考える順番は理想的な体験を描いてから必要なモノや技術を考えます。これはブランドに限らず様々な場面で意識したいことです。 ブランドに大事な一貫性 魅力的なブランドは顧客体験が蓄積して形成されていきます。蓄積されるブランド体験の要素は「体験の魅力度」「体験の量と時間」「体験の一貫性」と 3 つあり、ブランドの価値はこの 3 つの要素のかけ算にあります。 体験が魅力的であり、その体験の回数が多く長い時間にわたって経験し、体験自体に一貫性があるブランドがユーザーとって良いものとされます。 3 つのうち特に重要なものは最後の 「体験の一貫性」 にあり、この一貫性は 2 つに分けることができます。 時系列で一貫性 :時代で左右されない顧客体験がブランドから提供される 接点の一貫性 :ブランドを買ったり利用する前から、購入プロセス、購入後の利用シーンにおいて、一貫した顧客体験ができる 「モノとコト」にも例えやすいところですが、製品としての一貫性に加えて体験する前後のグランドデザインにも一貫性を持たすことが重要になります。 例としてスターバックスは広告費をほとんどかけずに今のブランド認知度を築いたことは有名ですが、そこにはブランドの価値を築くためのブランディングに一貫性があり、かつそれらが時代性とマッチしたのが要因ではないかと思います。 ブランディングのメリット 選択意思決定の単純化・固定化 顧客の知識が整理されることで競合と差別化され再び同じ物を選ぶようになる ユーザーのロイヤル化 親しみや信頼が増大されることでブランドロイヤリティが形成される なぜブランドにこだわるのか、という点でもこれらメリットを実現していくことが重要です。 デザイナーとして気遣い溢れる UI や、サービスの思想を記号に落とし込んだ VI などモノづくり視点でのこだわりや重要さを踏まえた上で、他職種の方にもこれらのメリットや競争としての必要であることを理解してもらえるよう働きかけることを意識していきたいところです。 ブランディングの悩みどころ ここからは基礎を踏まえて、実践的に行われているブランディングで悩みやすいところを事例で紹介しながら簡単なディスカッションをしていきました。一部だけ抜粋してご紹介します。 製品ブランドの管理 会社のブランド管理の思想を定義できても、変化の早い業界であればイメージ通りになかなか通らないことも多々有りえます。 少ないブランド資産を活用する意味でもスタートアップは横串型に整理されることが多くありますが、ある程度の規模感になって基礎体力がある企業であると個別適応型でもブランドとして信頼性を保てますし、横串型に比べて動きやすさがあると思います。 一方で、プラットフォーマーとして存在したいなら横串のブランド価値からファンを囲い込むべきかもしれません。Techlunch の中でもメドレーであればどうあると良いかについて議論ができました。 ブランディングのタイミング 顧客体験の蓄積が重要なブランドでありますが、どの段階でブランディングに取り組むかは状況によりますが意見が出やすいところだと思います。 ICC FUKUOKA2017 にてブランディングについてのセッションがあり、取り組むタイミングについての議論がうまくまとめられていたため Techlunch で事例として共有しました。プロダクトとしての差別化が基本であることに加えて、ブランドの在り方を組織にインストールさせるためにブランディングに取り組むケースも紹介されています。 僕はブランドが常に必要かと言うと“No”だと思います。 コモディティ化し始めたり、競争が始まって差別化しなくてはならない時に、プロダクトの機能などで差別化ができない、または必ずしもパフォーマンスで差別化ができない時に唯一残された選択が、ブランドを作るということであると思います。 [株式会社 Bloom&Co. 彌野泰弘] ユーザーを獲りにいくというフェーズですよね。 メルカリの場合、やはり最初の 100 万ダウンロードくらいまでは、結構チューニングをしながらオンラインのマーケティングで(ユーザーを)獲得してきてきました。 中略 やはり 100 万ダウンロードくらいあって、リテンションレートが高くユーザーが積み上がる状態になっていれば、大きくマスマーケティング(TVCM)をやっても獲得したユーザーは残りますからね。 [株式会社メルカリ 小泉文明] 僕は、ユーザーを獲得する手前でブランドが必要だと思っているんですよね。 ブランドというのは必ずしも外に対してだけではなくて、(組織の)中の人に対して必要であることもすごく多いのです。 中略 資生堂は当時 130 年くらい経っている会社だったので、その 130 年もこの後の 130 年も、世の中を美しくするとか、人を美しくするとか、それは女性に限らず、お化粧に限らず美しくするということが必要だよね、軸だよねという話になって、そのスローガンと共に前田新社長体制で進んでいくことになりました。 [株式会社 dof 齋藤太郎] (via スタートアップのブランディングはいつから必要か?【F17-7C #3】 ) 共有した後には、リリース当初からブランドやクリエイティブが作り込まれたプロダクトが最近話題になることが多いということも話に上がりました。 もちろんブランディングのタイミングは状況により千差万別ですが、プロダクトをゼロから作る際には、プロダクトの在り方と合わせてどんなブランドを作って行きたいのかも早めに考えられることが必要だ、など具体的なディスカッションも出来ました。 新たなブランドが受け入れられないことも 基本的にブランドを新しくすることは見慣れたものが変わってしまう恐怖から反発を生むケースが多いですが、その中でも GAP はロゴの 2010 年リニューアル公表後ネット上からの反発が強くわずか 6 日間という短期間で新しいロゴの使用を止め、元のロゴに戻してしまうという一件がありました。(この件は 株価 にも大きな影響を与えました) 一方、同じような境遇で Airbnb も 2014 年のリニューアル当初ロゴは不評でしたが今ではリニューアルの成功例として扱われる存在になっています。 Techlunch でも歴史の有無が差になったのか、など様々な意見が出てきました。この件はロゴとしての王道を極めようとした以上の背景を提示出来なかった Gap に対して、 Airbnb はサービスのストーリーをロゴに内包 し、地道にロゴを介したコミュニケーションに徹したことが明暗を分けたように思います。 この事例はロゴのアイデンティティをどこまで確立させられたかの違いにあることに加えて、デザインの意思決定を一時的な多数意見に委ねた事例としても学ぶことが多いです。 まとめ 私個人が元々グラフィックデザインをしていた経験もあり、今まではブランディングの中でも興味が CI や VI に傾倒していましたが、体験全体がブランドに大きな影響を与えるこの時代、組織としてブランド構築をしていく意識が重要であることが今回の大きな学びでした。 また基礎を学ぶ上で書籍を読んでいましたが、最近の事例などを学ぶ際にはブログなどでの情報収集がとても有効で、学び方も変わってきているなと思いました。今回紹介した内容はあくまで入門編なので、興味があれば今回参考にさせていただいた本とブログ・記事からより深堀りが出来るのでオススメします。 プラットフォームブランディング コーポレート・アイデンティティ戦略―デザインが企業経営を変える ブランド・エクイティ研究の展望 ~価値をめぐる議論の系譜を中心に~ UX とブランド ブランドアイデンティティとは|ブランド構築を成果に導く BI の創り方|成功事例有 スタートアップのブランディングはいつから必要か? ロゴのリデザインーなぜ Gap が失敗し Airbnb が受け入れられたのか 武器になる「ロゴ」を生み出す、CI デザインとは何か? Techlunch ではデザイナー以外の方からも事例に対して意見が出たり、疑問に対して参加者でディスカッションが出来たことがとても有意義でした。今後はこれらを意識しながらブランドの土台となる価値や在り方をデザイン出来るようにしていきたいと思います。 お知らせ  メドレーでは、医療介護の求人サイト「ジョブメドレー」、医師たちがつくるオンライン医療事典「MEDLEY」、口コミで探せる介護施設の検索サイト「介護のほんね」、オンライン診療アプリ「CLINICS」などのプロダクトを提供しています。これらのサービスの拡大を受けて、その成長を支えるエンジニア・デザイナーを募集しています。 興味のある方、ぜひメドレーへ遊びにいらしてください。 www.medley.jp