はじめまして、Yahoo! JAPANアプリの通知系バックエンドシステムを担当している福盛です。 今回はYahoo! JAPANアプリの「お知らせ」画面のバックエンドシステムの刷新をテーマに、「刷新にあたっての設計」と「その開発過程」についてお話ししたいと思います。
Yahoo! JAPANアプリの「お知らせ」画面は、現在アプリを通じて送信されたプッシュ通知の内容を一覧できる機能を提供しています。 表示される内容は例えば
- 最近の注目ニュース
- 災害情報
- 荷物の配送状況のお知らせ
- ヤフーの各種サービスからのお知らせ
などです。
また上記の内容に加え、今後コンテンツの拡充を積極的に進めていくよう開発しています。
システムの刷新〜PHPからScalaへ、仮想マシンからPaaSへ
従来の「お知らせ」画面のバックエンドは、仮想マシンのクラスタに構築されたPHPで動作するプログラムでした。
この構成は立派に動作しているものの、以下のような問題を抱えていました。
- データソース(MySQL, Cassandra)の追加にともないコードの継ぎ足しが行われるため、改修が徐々につらくなっていく
- 仮想マシンの管理、特にOSのセキュリティアップデートなどの対応に工数が取られる
現在ヤフーでは全社をあげてシステムの刷新を行っています。大きな変化としては
- 従来仮想マシンを使用していた部分をPaaSあるいはコンテナベースでの運用に切り替える
- 使用プログラミング言語の見直し
があります。今回その流れに合わせ、「お知らせ」画面のバックエンドシステムを刷新することにしました。
PaaS(Platform as a Service)の利用
従来システムでは仮想マシンクラスタの上でアプリケーションパッケージを構築、デプロイする作業を行っていましたが、 今回はPaaS(Platform as a Service)を活用するようにしました。
Scalaの採用
使用する言語はScalaを使うことにしました。僕の所属するチームでは1年ほど前からPaaS環境への移行に合わせScalaの採用を始めており、その記述の簡潔性と型安全性による品質向上効果を実感していました。またPaaS上でのScalaによるシステムの運用についても十分なノウハウが蓄積されていたため、今回もこの流れに沿ってPHPからの移行を行うことを開発の初期に決断していました。
その一方、今回の刷新プロジェクトのメンバーは半分以上がScala未経験という状況でした。
設計〜変化に強い構造を意識する
本格的な開発が始まる前に、全体の設計方針を決めました。
まず従来システムでは
- 複数のデータソース(MySQL, Cassandra)へのアクセス
- APIレスポンスの生成
を単体のPHPプログラムが行っていました。今回の刷新に合わせ、変化に強い構造として
- クライアントからのAPIリクエストを受け、レスポンスを返すコンポーネント(APIコンポーネント)
- レガシーなデータソースに接続し、その内容を取得するコンポーネント(データソースコンポーネントA)
- ここ1年ほどで作られた新しいデータソースに接続し、その内容を取得するコンポーネント(データソースコンポーネントB)
の3コンポーネントからなるシステム構成を考えました。
APIコンポーネントは2つのデータソースコンポーネントからHTTPでデータを受け、これらを整形した上でクライアントへレスポンスを返します。
これにより、
- 各コンポーネントの開発は独立して行うことができる
- クライアント−サーバー間のAPI仕様が更新された際に、APIコンポーネントの改修だけ行えば良い
- 今後データソースが追加、廃止された際の改修が容易
というメリットが得られます。
システムを構成する3コンポーネントはいずれもWebアプリケーションです。これらのために3つのリポジトリを作成し、アプリケーションとしての最低限("Hello, World"レベル)のひな形がある状態まで進んだところで、本格的な開発に進みます。
刷新のための開発プロセス
開発が本格化する時点で開発プロセスも整備しておく必要があります。所属する部署では以前よりアジャイル系のプロセスを導入していましたが、今回はJIRAを活用してこれをさらにスムーズに回すことを試みました。
JIRAを使う〜ホワイトボードは狭すぎる
以前よりホワイトボート+付せん紙ベースでのカンバン、チケット管理は行っていましたが、チケットの数が多くなると管理が困難だったり、バーンダウンチャートを作るための作業のオーバヘッドが大きくなる(結果バーンダウンチャートの更新が遅れたり、作られなくなったりする)という問題がありました。
- 多数のチケットがあっても困らない
- 自動化により見積りの集計が容易になる
- エピックバーンダウンチャートで進み/遅れが把握できるようになる
ための手段として、今回JIRAの「エピック機能」を活用してみることにしました。
初期チケットを切る
まずエピック「お知らせ画面刷新開発」を新たに作成し、先に書いた設計方針から、実際に動くものを作るにはなにが必要かを考えながら、バックログにチケットを切っていきます。
チケットは軽く、でもやることが分かるように
それぞれのチケットには紙ベースでやっていたときと同様、(付せん紙におさまるくらいの長さの)簡単なタイトルをつけて行きます。JIRAのチケットにはさまざまな情報を書く機能がありますが、それらは使いません。
今回特に意識したのはチケットを「〇〇コンポーネントは△△できる」といった、「主語-述語」で書けるストーリーとして記述することです。 例えば
- APIコンポーネントはJSON形式のスタブレスポンスを返却できる
- データソースコンポーネントAは起動時にMySQLへ接続できる
- ...
といった具合です。コンポーネントを主語にすることで、そのコンポーネントの実現すべきことを明確に、また完了条件を明確にするという効果を狙っています。
このようにして30個ほどの初期チケットを作成しました。
見積りはTシャツサイズ法で
初期チケットをそろえたところで各チケットの工数見積もりを行います。 工数はいわゆるTシャツサイズ法、つまり工数が比較的小さいと思われるものはS, 中くらいの工数ならばM, 工数が大きそうなものはLとするというアプローチに基づいて行いましたが、S/M/Lでの表現になじみがないメンバーも多いこと、また全体の工数を算出する際に数値である方が都合が良いという点から、S=2, M=4, L=8の数字を割り振るようにしました。 さらに、
- 迷ったときは一つ上のサイズを選ぶこと
- L(=8)を超えるようなチケットがある場合には必ず分割する
を意識して見積もりとチケットの分割を行っていきます。
チケットはいつでも並べ替えられるように
工数まで入ったチケットがそろったところで、どこからどの順番で進めるかを考えます。JIRAのバックログはドラッグアンドドロップにより、チケットの順序を自由に並べ替えられるのでこれを活用しました。 最初に到達したい/できるラインをざっくりと見極めて、開発を始めます。
開発本番
新規参加メンバーが半分以上のため、Scalaや使用するWebフレームワークの習熟を開発と並行して行わなければなりません。 今回はこれらの問題に対し、以下の手を試してみました。
ペアプログラミングとPull Requestの活用
まず開発の立ち上げ時に用意したWebアプリケーションのひな形を原型として、各コンポーネントの基本形を用意する、そこからスタブのJSONを返すよう改修していく、という作業を、経験者と新規参加メンバーのペアプログラミングというかたちで始めました。
ある程度感覚がつかめてきたところで、新規参加メンバー同士でのペアプログラミングも行います。これにより一人ではハマる状況を回避しながら、メンバー間でコンポーネントの理解を進める効果を得ています。
Pull Requestによるレビューも重要です。Scalaとして、あるいはWebフレームワークとしてより良い書き方がある場合にはコメントなどで改善をしたり、場合によってはそのPull Requestが発行されたブランチから孫ブランチを切った上で、レビュー対象のPull Requestへの改善用Pull Requestを発行したりといった工夫を行いました。
コンポーネントに担当者が張り付かないようにする
かつてのプロジェクトで、各コンポーネントにそれぞれ専任の担当者がついて開発を進めるという方式で進めたことがありました。しかし「あるコンポーネントの進行でハマると他の人が助けられない」「コンポーネント間でのつなぎこみでインターフェースの齟齬が生じやすい」という問題が開発後半に現れ、苦労しました。
今回は3つのコンポーネントからなるシステムですが、このような問題を回避するために「コンポーネントに担当者を割り当てない」よう注意しました。先に述べたペアプログラミングもこの方針を進める上で効果があったと思います。
実際、開発の中盤で(別件などが立て込んで)僕の開発の手が止まってしまったとき(恥ずかしいことですが)、他の開発メンバーが僕の持っているチケットを肩代わりして進めてくれたことがあり、非常に助かりました。
進行は「エピックバーンダウンチャート」を活用する
従来の開発では進行状況をカンバン上の付せん紙の移動の様子でなんとなく把握しようとしていましたが、全ての開発チケットがカンバンの上に載らないままスプリントが進んでいくため、終わりがよく見えない状態が発生することもありました。 また付せん紙で見積もりの数字を書きつつ、バーンダウンチャートを書いていく方式も集計やグラフ作成の手間が大きく、いま一つ決め手に欠ける状況が続いていました。
今回はJIRAの「エピックバーンダウンチャート」を活用して、開発全体の進行度合いを可視化させることを試みました。
JIRAの「エピックバーンダウンチャート」は「エピック」という単位でまとめられたチケットの総工数とその消化度合いをもとに、現在の進行度と完了見込みを可視化する「バーンダウンチャート」を自動的に計算、表示させる機能です。 JIRAの「エピックバーンダウンチャート」は少なくとも3スプリント(本プロジェクトでは3週分)のチケット消化記録がないと表示されないなど、小回りが効かず不満の残る部分もありますが、集計とグラフ化をすべて任せることができる点は大変重宝しました。
開発終盤〜増えるチケットと着地点の折り合い
開発が進行していくとチケットが消化され、バーンダウンチャートも週ごとに低くなっていきます...が、同時に設計と開発初期には分からなかった課題が新たなチケットとして登場します。そして開発終了予定の時期が近づくとどうしても全部をクリアすることができない状況も当然発生します。
その際、バックログに置かれたチケットを「やるべき順」に並べ直し、下の方にあるチケットをやらないと判断する過程が必要です。 これを実現する場合には、先に述べたようにチケットは「〇〇コンポーネントが△△できる」という書き方で統一し、かつそれぞれのチケットは独立していることが重要です。
今回の開発でもリリース後の改修で対応するものを切り出して別のエピックに移動させるなどの措置をとりましたが、最終的なチケット数は初期に立てたチケットの約2倍弱となっています。
それでもメンバーの頑張りと関係部署との調整により、予定された開発完了期日を大きく外すことなく開発を完了することができました。
今後について〜「捨てやすい」設計
設計時に特に意識していたのは、「将来レガシーなデータソースを切り離せるように作る」という点でした。システムの改修ではコードや機能の追加ばかりがクローズアップされますが、古くなったものを削除したり廃止したりすることも今後重要となると考えたためです。データソースとAPIをHTTPサーバーで結ぶ構成は純粋なパフォーマンスの観点からは不利ではありますが、データソースの廃止やコードの削除を最小限の手間で行えるという利点があります。効果については今後そのような状況が発生した際に、改めて検証してみたいところです。
まとめ〜開発は学習過程、プロダクトはソフトウェアとチーム
今回はチームの半数以上がScala未経験という状態から始めたプロジェクトでしたが、なんとか無事に完了させることができました。参加メンバーには大変感謝しています。
従来のPHPベースのシステムと比較して、改修版のシステムはScalaを採用したことによるバグ低減効果、コンポーネントを分けることによる不具合の発見と修正の効率化、PaaSを採用したことによる共通インフラ(アプリケーションログ検索、パフォーマンス解析システムなど)の活用といったメリットを大いに実感できるものとなりました。これらの詳細についてはぜひ別の機会に紹介したいと思っています。
このプロジェクトが一段落して改めて思ったのは、開発とは技術や要件を理解していく、いわば「学習過程」とでも呼ぶべき活動である、ということです。今回学習した事柄だけでも、「Scalaによる開発」「フレームワークによるRest型Webサービスの構築」「Yahoo! JAPAN公式アプリとのAPI仕様」「PaaS環境でのリリース・運用」など多岐にわたります。
つまりこのプロジェクトの成果物(プロダクト)は、
- 完成したソフトウエア、システム
だけでなく、
- Scalaにより構築された、Yahoo! JAPAN公式アプリのバックエンドを開発、運用、改修ができるチーム
であるとも言えます。「システム」と「チーム」、この2つの資産を増やして、よりよい仕事をしていくことが今後私たちに求められていることではないかと思うのです。
参考資料
今回の開発プロセスは基本的に以下の本を参考にしています。
アジャイル系開発プロセスの要点をまとめた本として、とても分かりやすい一冊です。発売から8年たちますが、原点に戻るためにたびたび読み返しています。
こちらの記事のご感想を聞かせください。
- 学びがある
- わかりやすい
- 新しい視点
ご感想ありがとうございました