事業の「できるだけ全体」を意識して、ソフトウェアを育てる

医療、介護、ヘルスケア、シニアライフの領域で高齢社会に適した情報インフラを構築している株式会社エス・エム・エスでエンジニアをしている @moro です。 主に介護領域におけるキャリア分野のサービス、平たく言えば介護の担い手である従事者の方の就職・転職を良いものにするための事業に携わっており、特に カイゴジョブという求人サービスの開発・運用をしています。

カイゴジョブについて

カイゴジョブは 2004 年にオープンした、介護職向け求人情報サービスです。 2019年9月にフルリニューアルし、現在は Ruby on Rails で動いています。筆者は2018年にエス・エム・エスに転職してこのリニューアルに関わり、以来ずっとカイゴジョブの開発・改善を続けています。

現代のソフトウェアサービスでは、リリースしたら完了でそのあとは変更しない、というものは少なく、多くは継続的に変化し続けます。これは、サービスによって解決したい社会課題、つまり事業のありようが変化していくためです。

カイゴジョブも例にもれず、サービス開始当初からリニューアルに至るまでも、またリニューアルリリースから今日に至るまでも、たくさんの人々が・各々の思惑で・日々いろいろな施策を実施してきました。

※ 本稿では、以下のように用語を使い分けます

  • 事業
    • エス・エム・エスにおける介護領域のキャリア事業。あるいはその一部としての求人広告事業。
  • サービス
    • www.kaigojob.com で運営しているカイゴジョブサービスといった、上記事業を遂行するために存在するサイトなど。
  • ソフトウェアプロダクト
    • リポジトリ内のコードや、AWSインフラで動いているプロセス群といった、上記サービスをソフトウェアとして実現するための各種コードやデータ。

つまるところ、事業が変化すればサービスも変化する必要があり、そしてその実装であるソフトウェアにも変更が発生します。

本稿は、このカイゴジョブのリニューアルとその後の継続的なサービス開発を通じ、ソフトウェアを変化し続けられるようにするためにやっていることを紹介します。

「できるだけ全体」を知ろうとする

長く続いたサービスのリニューアルでは、初期担当者の異動や退職、サービス責任者の交代などの理由で、そのサービスの全体を知っている人がいないという事態がたびたび発生します。例にもれず、カイゴジョブのリニューアルにおいても、開発チーム内にすべてを知っている人はいませんでした。

一方、「すべて」を知っている人はいなくとも、日々それぞれの業務をしている人々はもちろん存在します。そこで、その人々と会話し、日頃の業務を知ることで、カイゴジョブというサービスの全体はどういったものであるかを描き出そうとしたわけです。

リニューアルのために関係者と会話をしていった結果、カイゴジョブに大きく3種類のアクターが存在し、それぞれ下記のようなユースケースがあることがわかってきました。

  • A: 介護従事者を採用したい法人として
    • A-1. カイゴジョブに求人広告を出稿したい
    • A-2. 応募してくれた求職者に連絡を取りたい
  • B: 転職を考えている求職者として
    • B-1. カイゴジョブに登録したい
    • B-2. 求人情報を閲覧・検索したい
    • B-3. 気に入ったものに応募し、転職プロセスを始めたい
  • C: エス・エム・エス業務担当者として、上記の一連のフローを支援したい
    • C-1. 法人対応の担当者として、顧客がカイゴジョブを利用できるようにしたい
    • C-2. 広告担当者として、求人広告内容を確認し掲載したい。不備があれば顧客に修正依頼したい
    • C-3. 請求担当者として、カイゴジョブの利用状況に応じて費用請求したい

サービスを開発する場合、どうしてもインターネットから見える主要画面に力を入れたくなります。カイゴジョブの例であれば、Bがその「インターネットから見える」部分にあたるでしょう。ここの改善に注力したい感覚は、まったくもって妥当です。

しかしその体験を良くするにはBだけを作り込めばよいわけではなく、A-1ができる必要もありますし、そのためにはC-1や2の業務ができる必要があります。 さらに、サービス上でできることはB-3の応募が大きなポイントとなりますが、求職者にとっても事業者にとっても、本当に大事なのはそこからの転職プロセスであり、さらに入職後です。それをスムーズに実現するためにはA-2が滞りなく進むことが必要です。

そのためリニューアルの際は、Bの箇所だけでなく、法人がサービスの利用契約をしてから実際に求人広告を掲載するまでのオペレーションや月々の利用状況に応じた請求のオペレーションをどこまでこのシステム内に作り込むべきかを早期に議論しました。議論の結果、契約や請求にまつわる主要部分は外部のシステムに役割を完全に移行し、リニューアルしているソフトウェアからは自動/手動でデータ連携するのみに留めることとなり、リニューアルのスコープを小さくできています。そのように整理できたのも、早い段階でそこに境界を設定できることを可視化できたためであると思います。

この「まず粗く全体を作る手法」はリニューアルを終えた現在でも続けています。

もちろん、なにかのフィーチャに取り組む際に毎度が毎度「顧客契約〜請求」までの全フローを考えているわけではありません(逆にそれが必須となるのが、既存事業のリニューアルの大変さですね)。

それでも、2-4週間ほど掛かりそうな大きめのフィーチャについてはいまも「フィーチャ全体を粗くつなげる」「各要素を育てていく」サイクルを繰り返しています。 どんなフィーチャも利用者がそれを利用するためのコンテキストがあり、またフィーチャによって得られる便益があります。

ここでもやはり、フィーチャの目玉となる部分を作り込む前に「できるだけ全体」を俯瞰して理解できることは、結果としてフィーチャの磨き込みにおいても役立ちます。

「全体」をベースに重点箇所を育てる

いったん「最初の全体」を描き出した次は、これらの業務を一通り辿れるようにすることを最初のマイルストーンとしました。

  • C-1. 法人対応の担当者として、顧客がカイゴジョブを利用できるようにしたい
  • A-1. 介護従事者を採用したい法人として、カイゴジョブに求人広告を出稿したい
  • C-2. 広告担当者として、求人広告内容を確認し掲載したい。不備があれば顧客に修正依頼したい
  • B-1. 転職を考えている求職者として、カイゴジョブに登録したい
  • B-2. 転職を考えている求職者として、求人情報を閲覧・検索したい
  • B-3.転職を考えている求職者として、 気に入ったものに応募し、転職プロセスを始めたい
  • A-2. 介護従事者を採用したい法人として、応募してくれた求職者に連絡を取りたい
  • C-3. 請求担当者として、カイゴジョブの利用状況に応じて費用請求したい

この段階では、Rails + 古典的なHTMLリンクやフォームでの遷移が中心で、デザインも仮組みです。

他システムとの連携においても「ここでJSONを取りに行く」「CSVをエクスポートする」くらいの精度で実装していき、内部のファイルレイアウトなどは「あとで決める」箱に入れておきました。実装としては、データの入出力部分を抽象化したアダプターを作成しておき、本実装した後に切り替えるという手法で仕上げています。

このような粗い実装であっても、一通りのフローをつなげて動かせるようになることで、リニューアル中のカイゴジョブは「皆それぞれリニューアルに期待している無限の可能性」から「粗くとも、それぞれのアクターが自身のユースケースを体験できるソフトウェアプロダクト」に変化しました。これには大きなメリットが2つあります。

1つめは、以降の開発プロセスに、現代的な継続的改善のプラクティスを導入できるようになることです。 たとえば、新フィーチャを開発するためにPull Requestをつくると自動テストが走り、レビューを経てマージすれば即座にステージング環境にデプロイされ、事業メンバーを含む関係者全員がその機能を触れる。そういった仕組みが有効であることはよく知られています。

2つめのメリットは、その触ってみる際に重点箇所の前後のフローも動作させることで、実際の利用者のコンテキストを体験しやすくもなることです。 たとえば「求職者が求人広告を閲覧し、応募する」体験を磨き込みたい場合、サイトに来てもらって会員登録するところから一連を動かせる場合と、開発者に依頼して払い出されたダミーアカウントで応募する場合では、得られる体験がまったく違ってきます。

こうして、実際のソフトウェアプロダクト(まだ粗いけど)を触ってみることで、ソフトウェアやフィーチャへの期待が具体化していきます。具体化した期待を実装してプロダクトが変わっていく様子を「ソフトウェアを育てる」と呼んでいます。

(例) 継続的に育てるためのブランチ戦略

リリース前はともかく、すでにリリースしたソフトウェアに対して未完成なフィーチャをコードベースに入れていくかは、ちょっと悩ましいところです。例えば開発ブランチを用意して、長期間そこで開発する場合、最後にマージするタイミングで苦労することがよく知られています。

この問題の汎用的かつ唯一の正しい手段はないでしょうが、カイゴジョブではフィーチャトグル (Wikipedia)の仕組みを実装し、使っています(内部ではフィーチャフラグと呼んでいます)。

といっても、複雑な作り込みはせず、任意の箇所で条件分岐のための真偽値を返すだけの実装になっています。単純ですが十分に役立っています。

# Haml による Rails ビューでフィーチャフラグを利用する例
- if feature_flag.enabled?(:sugoi_feature)
  #sugoi-feature
    %h2 すごいフィーチャのdivです

このような牧歌的な仕組みだと、フィーチャフラグが野放図に増加したり、あるいは『フィーチャAとBが同時に有効なときのみXする』といった複雑な依存が発生して手に負えなくなったりといった懸念もあるでしょう。 しかし、今のところはチームできちんと棚卸しをすることにより問題は出ていませんし、仮に出始めても単純な if 文なので、コードレビュープロセスなどで改善できると思っています。

「全体」と思っていたものは変わる

ここまで述べてきたように、はじめに「できるだけ全体」を描こうとすることには大きなメリットがあります。 中でも最大のものは、-- 逆説的ではありますが --「できるだけ全体」が真の全体ではないことがはっきりすることです。

私たち開発者も、ソフトウェアを使って事業を遂行する人々も、ソフトウェアがどのように動作するかを理解するには、動作させてみるのが一番です。「できるだけ全体」を動作させてみることで、見落としていたものや、もっと改善できる箇所に気づけます。

動作するソフトウェアにより得られたフィードバックの他に、開発期間中の事業環境の変化が、求められるソフトウェアと最初に描いた「できるだけ全体」との間に差異を生むこともあります。

また、ある時点での「できるだけ全体」を実装しリリースしたフィーチャが好評であれば、その部分を伸ばしていく事業判断がなされるかもしれません。 逆に残念ながらそのフィーチャを終了することもあるでしょう。

このように、「全体」と思っていたものは絶えず変化します。そしてその変化、ソフトウェアへの変更要求として現れてきます。

知った事実をシステムに取り込み「できるだけ全体」を拡張する

我々開発者は変更を喜ぶべきだ、そのために我々は雇われている。「要件変更」は我々のゲームの名前なのだ。我々のキャリアや給料はこうした変更によって支えられている。我々の仕事は、変更を受け入れてエンジニアリングする能力と、そうした変更を比較的安価にできるかどうかにかかっている。

(『Clean Agile』 「第2章 アジャイルにする理由 まっとうな期待」より)

ソフトウェアを取り巻く環境は大なり小なり日々変わっていくので、ソフトウェアへの期待も大なり小なり日々変わっていきます。そこで私たち開発者も、変わっていく「できるだけ全体」に対して近づくように変更していきます。そうして近づいていくとまた事業が変わり、また望まれる全体が変わり……現代的なサービス開発はこの無限の繰り返しです。

私が大事だと思い日々心がけているのは、その無限に続くプロセスを悲観的に捉えず、楽しみながらソフトウェアを変更していくことです。 計画の最初期に全体を描ききれなかったのは失敗などでは決してなく、ラフスケッチを描いたことによって全員の理解が深まり、それにより新しい変更要求を発見できた証なのです。

この発見は、事業的な発見に限りません。コードベースと向き合っていくうちにドメインの理解が進み、結果としてコードをリファクタリングしたくなることもあるでしょう。 実際にカイゴジョブで起こった変更を紹介します。

(例)応募モデルのアーキテクチャをするっと変えた話

求人サービスたるカイゴジョブでは『求職者の方が求人広告を閲覧して応募する』という出来事がとても重要です。必然、その応募データが作成されたときは、応募者本人への確認メールや、広告を出している事業者への通知メールの送信など、様々な処理が発生します。

Railsというフレームワークにおいて「データAが作成されたらそこから操作Xと操作Yが起こる」ことを実装したい場合どうするか。 そうですね、ActiveRecord コールバック……は私のキャリアにおいてツラいことが多かったので避けました。 代わりに、Plain Old Ruby なフォームオブジェクトを用意し、応募可否のバリデーションや通知の送出をカプセル化するファサードとしました。 2018年時点では、このような単純な作りでリニューアル完了、リリースしています。

その後、無事にリリースされた新カイゴジョブで事業を進めていくと、やはり「応募」に係る処理は増えていきます。応募後にできることが増えていったり、通知手段や通知ルールを柔軟に設定できるようにしたり、応募可否制御のパターンが増えたりと様々なパターン分岐が必要となり、フォームオブジェクトが肥大化してきました。

その変化に対応して、コードベースの平穏を取り戻すべく、私たちは Rails Event Store を導入することにしました。 これによって、アプリケーション内で Pub-Sub 構造をつくるためのカタが確立し、各々の応募後処理の間の独立性を高めることができるようになりました。 これからなにか新しい応募後の処理を追加する場合も、既存の処理への論理的な影響は発生しないため、安心して拡張できます。

こうして、コードに現れる変化の要求を取り込み、我々のコードベースの「全体」は、応募後の追加処理を柔軟かつ安心して追加できるようになりました。 それを活かして、その後の新しい事業施策もスムーズにリリースできています。

一方で、RailsEventStore の採用にしても、完全にそれ中心で行くような判断をして作り込んだというわけではありません。 現時点で、Event Sourcingの概念を取り入れるメリットは少ないと判断して従来のデータモデルを使い続けていますし、イベント駆動で発火される処理も同期的に動作します。 あくまでコアなイベントと付随する処理の間にコード上の境界を導入し、依存関係をシンプルにするための利用にとどめています。 今後、Event Sourcingを採用するかステイすべきか、それとは別に処理を非同期にしたりさらにファンアウトの仕組みも導入すべきかなど、今後出てくる要求を見守りたいと思います。

このようにして、変わり行く事業と変わり行くコードベースの様子に注意をはらいながら、ソフトウェアを良い感じに保てるようにメンテナンスしていきます。

むすび

エス・エム・エスでカイゴジョブの開発に携わりながら、私が日頃から心がけていることを事例を交えて紹介しました。

事業として今後やりたいことは多く、それに伴いソフトウェアも変化していきます。 そのような中で私も、開発者として腕を振るう余地もたくさんあり、変化対応を楽しみながらカイゴジョブを育てています。

今回紹介したカイゴジョブのコードベースも、開発開始から3年弱、事業の要求に随時答えてきた実用コードとしては、なかなか興味深いコードベースになっていると思いますので、興味のある方はお声がけください。また、ある程度のキャリアが長い方を中心に「リニューアルといえばデータ移行! どうやったの?」と思った方もいるかも知れません。そこは本稿の趣旨がブレるため省きましたが……大変でした。そのあたりカジュアルに話したい方もぜひ下記リンクからご連絡ください。

本ブログの別の記事『「継続性アーキテクト」という生き方』にて技術責任者の田辺も言っているように、エス・エム・エスには色々なステージの多くの事業があります。 本稿のような働き方のチームもあれば、また違った文化のチームもあります。

カイゴジョブチームを面白いと思った方も、他の話を聞きたいなと思った方も、ちょっとでも興味がありましたら下記リンクからご連絡ください。