こんにちは。Backlog開発チームの藤田です。去る2020年12月5日にヌーラボが行ったオンラインイベント「NuCon2020」では、最初のセッションとして「Backlogカンバンボードの技術」を発表しました。
この日のために購入した新しいヘッドセットで発表中、急にマイクが不通になるトラブルもありましたが、スタッフや視聴者の皆さんの温かい後押しもありどうにか復旧して無事にほぼオンタイムでセッションを終えることができました。ありがとうございます。(結局マイクはiPhone付属のEarPodsに差し替えたのでなんのために購入…😓ってなりました)
今日は発表内容をブログという形でも公開したいと思います。
本記事はJBUGさん主催のBacklogアドベントカレンダー2020に参加しています。
目次
発表資料
概要
2020年1月に新機能「カンバンボード」をリリースしました。この機能を開発した「kanbanプロジェクト」で選択した技術や挑戦、乗り越えた問題について、一部だけですがご紹介します。
なお、ブログやリリース記事などでは「カンバンボード」と呼んでいますが、これは外向きに検索性を高めるための造語で、アプリケーション上やヘルプでは単に「ボード」と表記しています。
Backlogの技術スタック
BacklogのGitやファイル共有などのサブモジュールを除いたWebアプリケーション部分は単一レポジトリ、単一実行イメージのいわゆるモノリシックな構成になっていて、Amazon EC2インスタンス上で稼働しています。
モノリスが一概に悪いものとは思いません。
しかし、Backlogという多機能なアプリケーションをこうしてたくさんの方に使っていただき、チームも会社もだんだん大きくなってきたという状況で、今後もスピード感をもって開発していくためにはどこかでモノリスを卒業する必要があるだろうと考えています。
kanbanプロジェクトでの挑戦
kanbanプロジェクトでは、フロントエンド開発がとても重要な位置を占めます。具体的にはSPA的なインタラクション、WebSocketによるプッシュ通信が必須です。
開発にあたり、下図の「普通」と「挑戦」、あるいはその間をとるのか、どう作るのかはとても迷いました。
迷った末、「挑戦」コースで進めることにしました。メリットを採った形です。
kanbanの技術スタックはこんな感じになっています。
特に大きな役割を果たしている2つの技術をご紹介します。
GraphQL
フロントエンドとバックエンドの通信にREST APIではなくGraphQLを使っています。通信自体はHTTP POSTメソッドで、そのPOSTボディにクエリ言語を載せ、レスポンスにJSONが返る方式です。
GraphQLではフロントエンド開発者がクエリを少し変化させると、バックエンド開発者に何も言わなくてもレスポンスの型が変化します。
その点でSQLと少し似ていますがSQLほど完全な自由度を許すのではなく、個人的にはいい塩梅だと思ってます。
上記例の左側でクエリに「friends」を要求していない時、バックエンド側ではDBの「friends」テーブルには一切アクセスしていません。GraphQLのScala実装であるSangriaを使ったバックエンドが、ちゃんと必要に応じて最小限のDBアクセスを行っています。
フロントエンドの仕様とバックエンドの仕様の間にある程度の「遊び」を持たせられるのが開発効率の上で非常に有効だと感じています。
Kubernetes
Backlog本体と分離して別サービスにするということで、実行環境はDockerコンテナ、それも素のECSではなく将来の布石のためにKubernetesのAWS実装であるEKSを選択しました。
当初EKSに載せようと考えていたのはkanbanのバックエンドとWebSocket通知サービスの2つだけでした。しかし同時に走っていたGit LFSプロジェクトもEKSに相乗りしようということになり、kanbanリリースより先にこのEKSクラスタを使って公開されています。
構築がしっかりできさえすれば、Kubernetesがもたらす高可用性、デプロイ安定性、設定ファイル群が一貫していて他の仕組みを必要としないことによるメンテナンス性など、運用クオリティ向上のメリットは数知れません。
EKSクラスタとそれにまつわるログやモニタリング等々の構築にはかなりのコストが必要で、上図のつよつよエンジニアの吉岩さんが何ヶ月もかかりっきりになりました。
しかしこのチャレンジで得られた
- 実際に安定稼働しているEKSクラスタ
- 組織に蓄積された経験
はBacklogの今後にとって非常に大きなリターンだったという手応えを感じています。
困難を乗り越えた話
初めてづくしのプロジェクトだったので、無数の困難や問題を一つ一つ乗り越えていきました。少しだけ紹介します。
負荷試験
kanbanのバックエンドサービスはScalaで実装したJVMアプリケーションです。そのため
- 起動してHotspotの「暖気運転」するのに数十秒かかる
- メモリ量をきちんと規定する必要がある
といった特徴があります。これをKubernetes上で稼働させるのですが、どういう設定をすれば必要なリクエストを全て捌けるかのベストプラクティスが無さそうなので、実験して確かめる他ありませんでした。
使ったのはGatlingというツールで、レポートのHTMLがきれいで見やすく、何十回も試行錯誤する上で非常に助けになりました。
ストーリーが最後まで通ったというTypetalkのポストを見た時は「うわーやった!」と声が出ました。
もともと目標負荷を過剰気味に設定していたので、リリース時はかなり富豪なリソース設定でのスタートでしたが、その後実運用でメトリクスを観測しながら徐々にスペックを落としコストを減らしています。
プッシュ通知が届かない問題
当初プッシュ通知のためのサービスをGoで開発しており、社内向けの環境でも問題なく稼働して自分たちで便利に使っていたのですが、リリース直前に問題が発覚しました。本番8環境にリリースしてみたら1環境だけプッシュ通知が動作しないのです。
原因はその環境だけAWSのApplication Load BalancerでなくClassic Load Balancerを使用していたことでした。
私は1環境だけClassic Load Balancerになっていることも、Classic Load BalancerがWebSocketを通さないということも知らなかったので、いろいろ準備が足りてなかったのは間違いありません。それはともかく、どうにかしないといけません。
そうしたら何やらチーム外から救世主ワタ=ナベが現れてさっと救ってくれ、事なきを得ました。
今考えたらこれ、技術で乗り越えた話というよりは、うちの会社すごいでしょという自慢ですね。
すごいでしょ。
UIのちょっとした工夫
最後にちょっとしたことですが結構大事だと思っているUIの工夫です。
Backlogの共通部分であるナビゲーションメニューやサイドメニューは意外にたくさん機能が入っています。別リポジトリで開発するからといって、この共通部分を全てReactで実装し直すのは避けたいところでした。そこで、これらのメニュー部分は本体の延長線上として作り、中身のコンテンツ部分だけReactで描画することにしました。
しかし、HTMLロード後、kanbanフロントエンドがロードされて画面描画が終わるまでの間、ほんの1〜2秒ですが、メニューは描画されているが中身が空っぽという画面が表示されます。
これは短い時間でもユーザーにとってストレスになるので、最初にロードするHTMLにちょっとした仕掛けを入れています。
Reactで要素を描画する予定の場所に中身のないダミー要素を表示しておき、Reactが描画するときに消去しています。たったこれだけで、1〜2秒がストレスなく待てるようになります。短い時間であれば、プログレスバーや「ぐるぐるアイコン」よりもこのほうがストレスが少ないです。(ちなみに私はタイトルやリストボックスの場所を枠でなくグレーで塗りつぶしてるの上手いと思いました。)
できるだけストレスの少ない画面にすることで、「ボードを開くの面倒だな…」と思わず気軽にどんどん使ってもらえるように心がけました。進行中のプロジェクトのボード画面をブックマークして、「Backlogを開く=ボードを開く」という感じの使い方もおすすめです。
さいごに
kanbanプロジェクトで行った技術的チャレンジについて、いくつかかいつまんでご紹介しました。
機能リリースまでにはこれ以外にも、上から下まで数え切れないほどの課題問題があり、社内外のたくさんの方に助けてもらいながら楽しく開発でき、とても大きな経験になりました。
技術以外でも、マーケティングイベントで発表したり、カンバンボードに関係するほとんど全てのことに関わらせてもらえたのもヌーラボならではだと思います。
ヌーラボでは一緒に働く仲間を募集しているので、よかったら覗いてみてください。
こちらもオススメ:
プロジェクト管理とは?目的や項目、管理手法について徹底解説! | Backlogブログ
プロジェクト管理の基本や主な項目を紹介。CCPMやWBSなどのプロジェクト管理の代表的な手法やプロジェクト管理全体の流れを解説。これからプロ…
backlog.com