Webのダークモードを実現するには

こんにちは、freeeのUXチームでデザインシステム “Vibes” を作っている id:ymrl です。

ダークモード流行ってますよね。私は最初はしっくりこないなと思っていたんですが、食わず嫌いは良くないと思って試しているうちに、いつの間にかダークモードのほうが落ち着くようになってしまいました。

そしてそうなってくると、だんだん「自分たちの作っているWebサービスもダークモードに対応するべきなのか?」という気持ちになってきてしまい、最近はずっとダークモードのことを考えています。ということで今回はダークモードをやるべきなのか、実現する方法はどうなっているのか、UIデザインで気をつけるべき点何かというのを考える記事を書いてみます。

※「ダークモード」はApple製品で使われている呼び方で、Androidでは「ダークテーマ」と呼ばれていて、Windowsでは「ダーク○○」のような呼び方をしていなさそうです。この記事では「ダークモード」で表記を統一して呼ぶことにします

Webにダークモードは必要なのか

現時点では、ダークモードはWebサイトの必須の機能というわけではなさそうです。有名なWebアプリケーションではたとえばYouTubeやGitHubはダークモードに対応していて、使用しているOSの設定に準じるようにしたり、好みの配色を選べるようになっているようです。

GitHubのスクリーンショット。Themesという項目名で Default to system / Default light / Default dark から選択することができる
GitHubの設定UI
設定方法は Managing your theme settingsで紹介されている

Web上でOSの設定に準じてスタイルを切り替えるのは、CSSのメディアクエリで prefers-color-scheme という特性を使うことで実現できるようです。つまりWebでは「ダークモードで使用しているかどうか」は「ユーザーの好み」として扱っているということなんですね。

developer.mozilla.org

YouTubeやGitHubのような毎日使うサービスでは、ユーザーの好みに寄り添うことができるよう、サービス側で配色を切り替えたり、ユーザーがどちらを使うか設定できるのは好ましそうです。会計freeeのようなビジネス向けSaaSでも同じことが言えるでしょう。

おそらく現在は、ダークモードを使用している多くのユーザーは、WebブラウザではダークでないWebページが表示されることに違和感を持っていません。そのためWebでのみ展開するアプリケーションであれば必ずしもダークモードへの対応を急ぐ必要はなさそうです。しかし、モバイルアプリもリリースしてそちらはダークモードに対応していたりすると、Webとアプリで表示の一貫性が崩れてしまったり、一部画面をwebviewで表示しているとその画面だけ明るい配色になってしまったりします。ネイティブアプリとの連続性を重視すると、ダークモードへの対応を考える必然性が生まれてきそうです。

Webでダークモードを実現する

上で述べたとおり、CSSのメディアクエリで prefers-color-scheme を使用することで、OSでの設定にあわせてダークモード/ライトモードを切り替えて表示することができます。Webアプリケーションで使用するには、各所の配色をCSSのカスタムプロパティ(変数)として定義しておき、メディアクエリによって切り替えることによって実現するのがシンプルそうです。

以下は雑に書いたダークモードを実現するコードの例で、OSの設定に従ってダークモードとライトモードを切り替えられるようになっています。

:root {
    --textColor: #333;
    --backgroundColor: #fff;
    --linkColor: #4575B4;
}
@media (prefers-color-scheme: dark) {
    :root {
        --textColor: #fff;
        --backgroundColor: #222;
        --linkColor: #6398DE;
    }
}
body {
    color: var(--textColor);
    background-color: var(--backgroundColor);
    margin: 1rem;
    padding: 0;
}
a {
    color: var(--linkColor);
}

上記のCSSをあてたページをダークモードとライトモードを切り替えながら見ているGIFアニメ

CSSのカスタムプロパティは残念ながらInternet Explorerでは使用できず、Internet Explorer向けにもスタイルを提供するためにはもっと記述量を増やす必要が出てきます(prefers-color-scheme も使用できないので、このメディアクエリ内だけはシンプルに保てるはずです)。最近は国内でも各社でInternet Explorerのサポートを終了する動きが加速しているため、Internet Explorerサポートを終了したサービスからダークモード対応のWebアプリケーションが増えてくのではと筆者は予想しています。先述のYouTubeやGitHubもInternet Explorerのサポートを終了しています。

ダークモードでのUIデザイン

技術的にWebのダークモードがどう実現されるのかはわかってきました。ではダークモードのUIデザインではどんなことに気をつける必要があるのでしょうか。

なかなか想像が難しい気がしていたので、freee社内で開発しているデザインシステム “Vibes” のStorybookから適当なサンプルを見繕って、ブラウザの開発者ツールでスタイルを書き換えてダークモードの配色にしながら考えてみました。

入力フォームと送信ボタンのあるサンプルUIと、それをダークモードにしたものを並べてある
ダークモードの配色を試した画面

領域の表現

今回は背景色としてほとんど黒に近い濃いグレーから明度をすこしずつ上げた色を、かなり適当に3色用意しました。完全な黒にしないのは最近のスマートフォンのようにOLEDを使用しているディスプレイでは、完全な黒から他の色への描画が遅延することがあるからだとか。

元々の配色 #FFFFF, #F9F7F4, #EFEDE8 と、ダークモード用の #121212, #222222, #272727 を並べている

一般的に、ライトモードのときはほかのUIにオーバーレイするUIに影をつける表現をするのに対し、ダークモードではUIの応じて背景色を明るくすることで「浮いている」ことを表現します。Vibesでは画面内の区切られた領域を表現するために背景色を変えている部分があり、「浮いている」部分だけでなく、そういった部分の背景色も用意しなければならなくなりそうです。

今回はそういった要素が無い場所で試していましたが、実際のfreeeのUIではモーダルウインドウやポップアップメニューが多用されています。シャドウ・ボーダー・背景色の組み合わせをライトモードのときとは別に考えていく必要があり、単純な色の置き換えのように一筋縄ではいかなそうなことが見えてきました。

色の調整

Vibesでは、テキストの配色のコントラスト比を 4.5:1 になるように設計しています。これは freeeアクセシビリティー・ガイドラインでの定義 やその元となった WCAG (Web Content Accessibility Guidelines) での定義に従ったものです。

ダークモードの配色を作ってみると、文字やボーダーの色選びがライトモードのときよりもしやすいと感じました。コントラスト比は「相対輝度」によって計算するのですが、相対輝度の高い白や薄いベージュに対してコントラスト比を高めるには相対輝度を低く、暗い色にしていく必要があり、しかしそうすると色どうしの識別が難しくなっていくのです。ダークモードでは比較対象が暗い色なので相対輝度の高い明い色がたくさん使えるようになり、使える色の種類が多くなったように感じられたのだと思います。

コンピューターで表現される色はR, G, Bの三原色の組み合わせで表現されるわけですが、人間の目はこれらのうちGを強く感じ、Bを最も弱く感じるため、相対輝度の計算時にはそれを調整する係数がかかるようになっています。つまりfreeeのコーポーレートカラーである青は他の色より暗めに見えるのを調整する必要があるわけですが、freeeの印象を残しつつも視認性の高い色を選べるよう、特に慎重に進める必要がありそうです。

ライトモード用の配色の #C33939, #4575B4, #6F6B62 と、ダークモード用に調節した #E46F6F, #6398DE, #9D9A92

まとめ

今回はダークモードの実装やUIデザインを試作したことで、技術的な課題やUIデザインで注意の必要そうなところが見えてきました。ただ色を置き換えるだけというわけでなく、情報の表現の仕方やユーザーの受ける印象も調整しようとすると、それなりに手間がかかりそうということも見えてきています。そのあたりも踏まえつつ、ユーザーの期待に応えられるUIデザインをしていければな、と思っています。

エンジニア未経験のプロダクトマネージャーが、エンジニア留学のために勉強したこと

こんにちは。プロダクトマネージャーのmikiです。今回はじめての投稿ですので、簡単に自己紹介をさせていただきます。

私は4年ほど前にfreeeに入社しました。最初の2年はカスタマーサクセスとして、会計事務所さん・IPOユーザーさん・API連携希望ユーザーさんなどの様々な導入支援を担当し、その後、アライアンス事業部にて、パートナープログラムの策定・パートナー企業内でのカスタマーサクセスチームの立ち上げのご支援をしてきました。そして最近プロダクトマネージャーに異動になり、公式アプリを担当しております。

そして実は、現在はプロダクトマネージャー業務はお休みしていて、エンジニア留学の1期生として1月からAPIチームに参画し、エンジニアとして働いております。

エンジニア留学とは

freee社内の留学制度でエンジニアではない人が、3ヶ月間、エンジニアチームに一時的に参画し、エンジニアとして業務を遂行し、学習を深める制度です。

エンジニア留学へのマネージャーからの期待値(ミッション)

  • プロダクトマネージャーは開発チームと技術的なコミュニケーションができる必要がある。特に公式アプリはデベロッパーと直接の技術コミュニケーションが多いので業務知識に加え、より深い技術理解が必要である。 そのために必要な技術や開発プロセスおよび開発の勘所(仕様を一つ追加することの開発的なリスク、リファクタの必要性、どこまで詳細に仕様つめる必要があるか、開発にかかる工数など)を座学に加え、実務経験を通して学習してくること。

1週間の過ごしかた

マネージャーからの受け取ったミッションを達成するべく、現在の1週間のスケジュールはこんな感じで、なるべく起きている時間のほとんどはプログラミングの勉強に当てるようにしています。

1週間のスケジュール。朝6時から9時までは勉強、土日はほとんど勉強。

社内のイベント登壇用に作成したもので、少し時間のメモリが粗いことは多めにみてやってください。

エンジニア留学に向けた準備

エンジニア留学の1期生として年明けからエンジニアになるよ!とマネージャーから話をもらったのは12月の上旬のことでした。それから留学をするにあたって、少しずつ準備をはじめました。

PCをWindowsからMacに変える

エンジニアのほとんどの人がMacを使っていて、技術の解説はMacであることが多いとのことで、環境は合わせた方がいいと思い、変更しました。

仲間を作る

留学にあたって、基礎力となるプログラミング言語は独学での習得が不可欠でした。私は、なにかを学習するときは決まって、仲間を作るとうまくいくタイプだったので、オンラインのもくもく会に参加したり、もくもく会を開催したり、2月末を目標にHTML/CSS/JavaScript/Reactまで一緒に勉強したい人を募集して学習グループを結成してみたりと、積極的に駆け出しエンジニアの仲間を作る活動を行いました。

自己育成計画書を作成し学習を進める

これは新しい部署に異動するときには必ずやっていることです。自分がなにか新しいことを吸収してる期間は目に見えるアウトプットを出しづらいため、自分は世の中の役に立ってるんだろうかという気持ちが蔓延し、必要以上に自己肯定感が下がりやすい傾向にあると自己理解しています。トップスピードのまま3ヶ月間を駆け抜けられるように、自分がどれくらい昨日より今日、進歩したのかわかるようにスプレッドシートにて計画とその進捗管理を行い、モチベーションが下がらない工夫をしました。

今回は、上記3つの中でも、自己育成計画をピックアップし、 計画を立てる上で、非常に参考になりましたフロントエンドのロードマップ に沿ってどのように学習したかをご紹介させていただきます。

フロントエンドのロードマップ

roadmap.sh

これは@kamranahmedse さんが作成されたフロントエンド開発・運用に必要なスキルや知識・ツールなどをひとまとめにしてくれているロードマップ です。 上記のサイトに定期的にバージョンアップされながら公開されているようです。

ありがたいことに@TetsuKinomuraさんによる日本語版もあるので、こちらも貼っておきます。

さらに、親切なことにYouTuberのトラハックさんがこのロードマップについて解説もしてくれていました。これにより何を勉強しなければならないかという全体像をとてもよく理解できました。

youtu.be

エンジニア留学が決まったとき、何から手をつければいいのかわからず、勉強しておくといいと言われたものを手あたり次第に学び始めていました。あとからこのロードマップや解説動画に出会い、自分のやってきていたことがそんなにずれていなさそうで、ほっとしたのを覚えています。

また初学者にとって、自分の歩み方がずれていないか?という不安は日々ついてまわるので、学習のスタート時点でこういったロードマップがあると、とても安心だなと思いました。いつかfree初学者向けに、会計freeeの使い方やfreeeのAPIを叩くために必要な最低限の知識等をロードマップ にして公開してみたいです。

ロードマップ を眺めて立てた自己育成計画

下記はロードマップ とにらめっこし、1月〜12月にかけて立てた計画の一部抜粋です。

自己育成計画の一部抜粋。スプレッドシートに基礎的な内容から並べている

以降は、フロントエンドのロードマップにそって、どのように学習したかをご紹介します。

Internetについての学習

APIチームのマネージャーから年末に冬休みの宿題として、『Real Word HTTP』を紹介され、PdMのマネージャーからは『Webを支える技術』を紹介してもらいました。 しかし、いずれも読むための知識が圧倒的に足りなくて、音読はできるが理解ができない状態に陥ってしまいました。 そのため、もう一段レベルを下げて、『Web技術の基本』という文系の人向けにわかりやすくしてくれていそうな本を見つけたので、この本からまず入って学習を進めました。

HTML,CSS,JavaScriptの学習

この領域は、ドットインストールとYouTuberのしまぶーさんの動画で学習を進めました。 各領域はドットインストールは抜け漏れなく学習できるので、ざっと1回勉強をして、実践でじゃんけんアプリなどを作って、わからないことが出た場合は2回目を2倍速で見るという感じで活用していました。 ドットインストールは受講を終えていくとどんどん緑の棒が長くなっていき進捗がわかるので楽しかったです。

ドットインストールのキャプチャ

一方でドットインストールだけでは全体像や技術の背景・現在の開発現場でどこまで使われているのかなどはわからなかったので、そのあたりはしまぶーさんによる解説動画を見て理解していきました。もはやモダンな開発ではCSSや素のJavaScirptは書かないという事実は動画を見るまで知らなかったので、出会ってなかったらひたすらCSSを特訓していたかもしれません。3ヶ月の学習時間の配分を見誤らないかったのはしまぶーさんのおかけでした。

youtu.be

バージョン管理システム(GitHub,Git)

この領域については、Udemyの「Git:はじめてのGitとGitHub」で学習しました。

freeeで使われている方法についてはAPIチームのエンジニアのまっつーさんからレクチャーを受け、会計freeeのコード修正・プルリクエスト作成の実践学習を通して理解を深めました。

www.udemy.com

パッケージマネージャーとビルドルール

この領域については、YouTuberのしまぶーさんの動画で学習を進め、パッケージマネージャー・webpackの誕生の背景をざっと理解しました。

youtu.be

フレームワーク(React,Angular,Vue)

freee公式アプリはReactを採用しているので、まずはReactに限定し、学習を進めました。 この領域はじゃけぇさんのUdemyの「モダンJavaScriptの基礎から始める挫折しないためのReact入門」を用いて、JavaScriptの基礎を復習しつつ、Todoアプリを作成しながら学習しました。

www.udemy.com

axiosについては、YouTuberあべちゃんのReact入門をもとに、JSONPlaceholderやpixabayを用いてAPI通信の学びを深めました。

youtu.be

以上、自己育成計画をベースに学習した内容のご紹介でした。

FirebaseでReactを用いてアプリを作る基礎力は徐々についてきたので、引き続きTypeScriptを学び、いつか個人としてfreeeアプリストアでアプリをリリースすることを夢見て技術力をさらに上げていきたいと思っています。

来週は自分が対応した公式アプリの不具合の修正や機能拡張が続々とリリースされるのでとても楽しみです。

エンジニア留学はあと残り2週間!最後まで駆け抜けます!

Docker image を導入して protobuf を使う

こんにちは、会計freeeの開発をしている清水です。2020年4月に新卒としてfreeeに入りもうすぐ一年が経とうとしています。

この記事では私の所属チームのプロジェクトで試している、protobuf のための開発環境について書きます。

背景

現在私たちのチームでは、会計freeeのバックエンドのアーキテクチャ移行を進めています。会計freeeは長年にわたって開発が続けられているRailsアプリケーションです。現在でも社内の多くのチームのエンジニアが開発に関わっています。そんな中で実装は複雑化し、機能ごとの依存関係が分かりづらい状態になっていました。新しいアーキテクチャの目的は、そんなアプリケーションの実装の依存関係を明確にし、より安心して開発を継続できるようにすることです。

このあたりのより詳しい話は以前id:mihyaeru21が発表した以下の資料にまとまっています。

speakerdeck.com

現在移行を行っている範囲では、アーキテクチャ移行の第一段階として API Model と呼ばれる新たなインターフェースを導入しました。これは ActiveRecord に依存しないデータ構造で、バックエンドの実装内部において、モジュール同士は基本的にこのAPI Modelを介してのみやり取りを行うような設計になります。

現在のところ API Model の実装には、protobuf を採用しています。型が定義できること、また将来的に機能をマイクロサービスとして切り出す際もインターフェースとしてgRPCでそのまま流用できることがメリットです。

自動生成のためのコンテナ

API Model には protobuf を利用するため、Rails アプリケーションで実行される Ruby コードは、proto ファイルの定義から自動生成します。また読みやすい HTML 形式のドキュメントも、protoc のプラグインである protoc-gen-doc を使って、コードと一緒に定義から自動生成します。これにより常に実際に動くコードに連動してドキュメントが更新されるようになります。

例えば入力となる proto ファイルの定義と、自動生成される Ruby のコードと HTML のドキュメントは以下のような対応関係になります。

syntax = "proto3";

// コメント1
message Hoge {
  int64  number = 1; // コメント2
  string code   = 2; // コメント3
}
...
Google::Protobuf::DescriptorPool.generated_pool.build do
  add_file("sample.proto", :syntax => :proto3) do
    add_message "Hoge" do
      optional :number, :int64, 1
      optional :code, :string, 2
    end
  end
end

Hoge = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("Hoge").msgclass

protoファイルから生成されるドキュメント
生成されるドキュメント(protoファイルのコメントも反映される)

開発にあたっては、エンジニアごとのローカル環境に依存して生成物に差が生まれないようにする仕組みを用意する必要がありました。そこで自動生成のためのツールのバージョンや、実行環境を固定するためにDocker imageを利用し、Amazon Elastic Container Registry (ECR) を介してそれを開発者間で共有するようにしています。

Dockerfile はだいたい以下のような感じになり、build 時に使用する protocと proto-gen-doc のバージョンを指定します。

FROM debian:buster-slim

ARG PROTOC_VERSION
ARG PROTOC_GEN_DOC_VERSION

ADD https://github.com/google/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip ./
ADD https://github.com/pseudomuto/protoc-gen-doc/releases/download/v${PROTOC_GEN_DOC_VERSION}/protoc-gen-doc-${PROTOC_GEN_DOC_VERSION}.linux-amd64.go1.15.2.tar.gz ./
RUN apt-get -q -y update && \
  apt-get -q -y install unzip && \
  unzip protoc-${PROTOC_VERSION}-linux-x86_64.zip -d ./usr/local && \
  tar xvzf protoc-gen-doc-${PROTOC_GEN_DOC_VERSION}.linux-amd64.go1.15.2.tar.gz && \
  cp protoc-gen-doc-${PROTOC_GEN_DOC_VERSION}.linux-amd64.go1.15.2/protoc-gen-doc ./usr/local/bin && \
  ...

# 生成物を手元に得るためのマウントポイント
VOLUME ["/ruby", "/docs", "/proto"]

ENTRYPOINT [ "protoc" ]

手元に落としてきた Docker イメージからコンテナを起動し、ローカルの proto ファイルから、コンテナ側でコードとドキュメントを生成します。最後にこの流れ実行できる Rake タスクを用意すれば開発環境の準備は完了です。

以上で開発者の環境による差分を気にすることなく、インターフェースの定義にだけに集中して開発が進められるようになりました。

低カロリーにスクラムマスターを始める方法

こんにちは、freeeで人事労務freeeを開発している id:gn-spawn です。 『シン・エヴァンゲリオン劇場版𝄇』面白かったですね。 パンフレットには制作スタッフのインタビューが記載されていて、感動した作品を作っている側の仕事術が読めるのはとても貴重で奮い立たせられました。

それはそうと最近スクラムマスターになったので、プロセスの改善を行った話を書いていきます。

スクラムマスターを引き継ぎという形で始めた

freeeでは多くのチームがアジャイル開発のプロセスを使ってプロダクトの開発を行っています。 私の所属するチームも1週間でスプリントを区切ったアジャイル開発を採用しています。 他の会社や組織では専任のスクラムマスターがいる場合もありますが、弊チームではスクラムマスターはエンジニアと兼任で行っています。

私のチームでは以下のような流れで開発を進めています。

小さいリリースと検証・改善を繰り返す
小さいリリースと検証・改善を繰り返す

スクラムを実施するにあたってチームでやっていることは以下のとおりです。

  • 毎朝のデイリーミーティング
  • スプリントレビュー
  • レトロスペクティブ
  • プランニング

なぜスクラムマスターになったのか

マネージャーとの1on1の中で

  • スクラムマスターのマネージャーが非常に忙しそうなので、自分が一部でも引き継げる部分はないか
  • プロセスの改善が好きなのでそういった領域で引き継ぎたい

という話をしていると、「スクラムマスターをやってみないか」と提案されました。 今までもスクラムでの開発経験はあるものの、自分でオーナーシップを持って運用したことはありませんでした。 色々な人とコミュニケーションを取るのが好き、少しでもマネージャーから委譲できればというモチベーションで挑戦してみました。

引き継ぐにあたってやったこと

まずはデイリーミーティングのファシリテーションから引き継ぎました。 前述のモチベーションから徐々に引き継いでいく方法を取りました。私がスクラムのオーナーに慣れていないというのも理由の一つです。

やり方を知らなかった私は、前スクラムマスターのやり方をそのまま行いました。

実際に感じた問題

全ての引き継ぎを行ったところ、思ったよりも時間が取られることが分かりました。 エンジニアとスクラムマスターが兼任なので、準備に時間が取られて思うように実装の時間が取られたりしてしまいました。

これは単に私が不慣れな部分があるのですが、実装の時間が取れないのはチームメンバーへの負担も増えますし、リリースしたい機能の開発も遅れてしまいます。

特に時間がかかっているのは

  • バックログの整理
  • バーンダウンの更新

の2点です。「スクラムマスター」のロールをやる以上はチームメンバーが迷わないように完璧な準備が必要だと思いこんでいました。

他チームを見て改善していく

まず問題の改善を行う場合に、スパッと「ここが今のやり方だとマズいよね」と分かれば一番なのですが知識や経験が無いとなかなか難しい部分です。 そこで先ずは他のチームのスクラムイベントを見学してみることにしました。

今は感染症対策もあり、ほとんどのエンジニアチームがオンラインでミーティングをしているので気軽に見に行けるのは助かりました。 その中から自分たちのチームにフィットするやり方を見つけて、取り入れていくことで改善しています。

実施したアクション

他チームのスクラムイベントを見学して、以下のことを実施しました。

  • バックログを整理しない
    • プランニングで整理もメンバーと一緒に行う
  • 準備の委譲
    • メンバーのスプリントごとに出した成果を自分で書いてもらう
    • バーンダウンもとりあえず準備してツッコミがあればその場で直す

スクラムマスターとしてちゃんと準備をしなくては。と思っていたせいで準備に時間がかかっていました。 しかし、メンバーを信頼して完璧に準備をすることをやめてみました。 その結果、精神的負担が減って漫然とした多忙さを感じることがなくなり、プロセスの改善にフォーカスできるようになりました。

得られた結果

スクラムイベントの最後に、感想や改善案を書けるアンケートを置いています。レトロスペクティブでそういうのはやれば良いのでは?とも思いましたが、 レトロスペクティブでは開発に関することにフォーカスを当てています。 私へのアンケートとして匿名も可能な形で書いてもらうことで、フィードバックを受けやすい形にしています。

プロセスの改善にフォーカスできるようになったおかげで、チームとしてより良いやり方を試行錯誤ながら追求しています。

まとめ

スクラムマスターに挑戦して一番のメリットは、プロジェクトの全体像を意識してオーナーシップを持てるようになったことです。 ユーザーに素早く価値を届けるにはどうしたら良いか?というのは、「頑張ってコードを書く」という単純なものではないと思っています。 職種に関わらず、プロダクトに関わる人全員を巻き込んで進めていくのはエンジニアだけで進めたときに見えないものが見えるので非常に面白いです。