ユーザーへの価値提供機会を増やすためにリプレースを決意した話

こんにちは、介護事業者向け経営支援サービス「カイポケ」のエンジニアの加藤です。

カイポケが提供するサービスの一つ、障害者支援を行う事業所向けサービスの開発をしています。

現在、私たちのチームは一部機能のリプレースを行っています。本稿ではリプレースに至った経緯についてお話ししたいと思います。

※「しょうがい」には「障害」「障がい」「障碍」といった複数の表記があります。それぞれに意味があり、何が適切かは様々な見解がありますが、本記事では法令表記もある「障害」で統一しています。

※ 本稿では、伝わり易くすることを優先した表現を使っています。本稿の表現に正確性が欠けるものがある点を、あらかじめご了承ください。

我々のミッション

私たちチームのミッションは一言で表すと、ユーザーの業務効率化と経営状態健全化に貢献することです(カイポケのミッションの詳細はこちらをご参照ください)。このミッションの実現のために、私たちが考えていること・行っていることをお話しします。

私たちチームの担当プロダクトのユーザーは、障害者支援(障害児含む)を行っている障害者支援事業所の経営者・職員の方々です。 ユーザーは日々、障害を持つ方々の介護・自立支援を主体業務としつつも、事業所経営に必要な多くの付帯業務をこなしています。そこでカイポケを利用することで、付帯業務の効率を上げて、主体業務に集中しやすい状況を作っていただきたいと考えています。

複雑なドメインを持つユーザーの付帯業務

付帯業務と一言で表してはいても実際は複数の業務があります。その中でも、効率アップを実現したい業務の一つに請求業務が挙げられます。なぜなら障害者支援事業者が行う請求は、一般的なサービスの請求より複雑なためです。

一般的なサービスでは「サービス提供者が、サービス内容と料金を考え、サービス利用者にサービスを提供して、料金をサービス利用者へ請求する」という流れが多いと思います。

これが障害者支援では、「国や自治体がサービス内容と料金を法令に基づいて制度化する。その制度に沿ってサービス提供者(事業者)がサービス利用者(障害者)にサービスを提供して、料金の一部をサービス利用者に請求し、残りは自治体に請求する」といった流れです。(この流れは医療の保険制度と似ています。)

一見すると、本来サービス提供者が考えるべきサービス内容と料金が制度化されているなら、その分楽に見えるかもしれません。しかし、もちろんそう簡単な話ではありません。

国や自治体が制度化した内容は、理解しやすい内容ではなく、とても複雑です。複雑である理由はいくつかありますが、ここでは3つに絞って説明します。

  • 1つ目は、サービス内容のパターンが多く料金設定も細かいこと。
  • 2つ目は、請求業務に登場するアクターが多いこと。
  • 3つ目は、制度自体が改定され続けていること。

まず1つ目、サービス内容のパターンが多く料金設定も細かいこと。 一言で障害者といっても、どこに障害をお持ちなのか、どの程度のものなのかが人によって異なります。そのため、障害者に必要なサポートの形も様々で、それに即した多様なサービス内容が必要です。 多様なサービスがあるのだから当然料金設定も細かくなりますし、同じサービス内容でも時間単位の段階性料金が設定されていたりと、とても細かい料金パターンとなっています。

次に2つ目、請求業務に登場するアクターが多いこと。 一般的なサービスの請求業務のアクターは、サービス提供者とサービス利用者の2アクターだと思います。一方、障害者支援はここに国・自治体というアクターが追加されます。ここでは詳しく話しませんが、さらに他事業所というアクターが追加される場合もあります。 業務におけるアクターが増えれば増えるほどフローも複雑になるので、それを制度化したものも伴って複雑化します。

最後に3つ目、制度自体が改定され続けていること。 この制度は不変ではなく改定され続けています。大小様々な改定が数ヶ月から数年毎に入ります。人々の生活は社会情勢や技術の進歩によって日々変化しています。その変化に対応するため、障害者支援の制度も変えていく必要があるということです。 制度に沿って請求する以上、改定される制度の情報をキャッチアップし続ける必要があります。

ドメインの複雑度をカイポケが引き受けたい

これらの理由で複雑化した制度を理解した上で請求をすることは大変そう、ということはご想像いただけるかと思います。障害者支援を行う方々は、複雑な制度の上に成り立つ請求業務を介護・自立支援といった主体業務と並行して行う必要があるのです。

そこで私たちは、複雑な制度を読み解き、制度の変更に追随しながら、使いやすいプロダクト(カイポケ)にしてユーザーへ提供する。つまり付帯業務の持つ複雑度をカイポケが引き受けて吸収する。そうそうすることで障害者支援事業所の業務効率アップに貢献できると考えています。

ここまでミッションと実現したいことについてお話ししてきました。これらのために日々頑張ってはいるのですが、もちろん全てがうまくいっているわけではありません。課題も多くあります。

複雑な制度 × 期限必達 = 複雑化した仕様と肥大化したコードベース

カイポケの障害者支援領域は複数プロダクトがありますが、最も長いプロダクトはサービスインから8年経過しています。その間、サービスを運用していく中で、大きな制度改定への対応も数回乗り越えてきました。

改定後の新しい制度に関する情報は厚生労働省から公開されるものをソースとしています。新しい制度の情報は少しずつドラフトの状態で公開されるのですが、確定情報が出てから制度施行日まで余裕がないこともあります。過去に私が経験した制度改定への対応では、制度施行日の数日前まで確定情報が公開されないということもありました。

そういった背景もあり、ときには開発に十分な時間が確保できず、急いでリリースまで行う必要があることがあります。「新しい制度への対応版のリリースが遅れる=ユーザーの業務が止まってしまう」ということを意味するからです。

理想を言えば、「適切な時間を使って、要件を検討し、既存の要件と新しい要件を最適化しながら仕様に落とし込み、その仕様に沿って実装し、リファクタリングを行い、必要なテストをクリアしてから、リリースする」というプロセスを踏みたいところです。しかし、デットラインまであと数日という状況ではそうも言ってられません。

ではどこを削るか?ですが、過去の私たちは、”既存の要件と新しい要件を最適化しながら仕様に落とし込む” と ”リファクタリングを行う” に対し、”適切な時間を掛けること” を削るという選択をしました。全ての変更において一貫してこの選択をしたわけではないですが、いくつかの変更において選択してきたことは事実です。

新しい要件は、既存の仕様に簡単に上乗せできるものばかりではありません。ときには既存の仕様を見直した上で新しい仕様を取り込むべきものもあります。 しかしながら、新しい制度の施行日という期限がある以上、変更箇所を少なくするために既存に手を入れずに新しい要件を加えるということもありました。そういった対応は少なからず歪さや冗長な面を残すことになります。

このような歪さや冗長な面は、その瞬間においては許容できるレベルであったとしても、年月を経るごとに当時の記憶も薄まり、忘れたころに複雑で理解し難い仕様として開発者を苦しめることになります。

ミッションの説明でお伝えしたように、障害者支援における請求のドメインはとても複雑です。ドメインが複雑な上に輪を掛けて仕様も複雑になってしまっています。つまり結果だけ見れば、過去の私たちの選択は「仕様の複雑度 > ドメインの複雑度」という状態を招いてしまいました。

また、仕様の複雑度が高いということは、コードベースの複雑度も増します。複雑度が増せば自然とコード量も増え肥大化していきます。複雑度が高く肥大化したコードベースのメンテナンス性は言わずもがな悪いものです。

これまでも私たちは、コードベースに一定の秩序を取り戻そうと、制度改定の合間などの時間的制約が少ないときにリファクタリングを行ってきました。ただリファクタリングも肥大化したコードベース相手では膨大な時間を要するため、まだまだ道半ばです。 仮にこの先、多くのリソースを投入してリファクタリングを完遂したとしても、複雑な仕様は残ります。それでは一時的な効果はありますが、根本的な解決とはなりません。

時を経るごとに複雑になっていく仕様、複雑度を増す仕様に引きずられて肥大化していくコードベース、そんな状況を改善しようと行うリファクタリング。自分たちで穴を掘って、後で穴を埋める、そしてまた穴を掘る、という消耗戦を続けてきました。 この消耗戦を終わらせなければ、いつか私たちの手に負えない状況になってしまうでしょう。そうなる前に「複雑化した仕様」と「肥大化したコードベース」をなんとかしなければなりません。

ユーザーへの価値提供を増やしたい

話は変わりますが、数年前からカイポケは内製化を進めてきました。(内製化の話は「【前編】開発内製化の5年の軌跡。「消耗戦の悪魔のループ」をどう乗り越えたのか」をご参照ください)

私を含めカイポケのエンジニアの多くは、内製化へ舵切りしてからJOINしています。それから、制度改定や機能追加、リファクタリング、不具合への対応などを通して、ドメインとプロダクトに関する知識を蓄積してきました。

そうなると見えてくるものがあります。「ココがこうだったら便利そう」とか「ユーザー業務を考えると今と違うアプローチの方が使い易くなるだろう」といった、ユーザーに今より多くの価値を提供できそう!というアイデアです。

ではそのアイデアを実装してみよう!となるのですが、アイデアはあくまで仮説です。事前にいくら検証したところで効果が100%保証されるものではありません。そのため、仮説→検証→実装→リリース→効果測定→仮説→(以下略)というループを高速に回していきたいのですが、そこで壁となるのが複雑化した仕様と肥大化したコードベースです。

複雑化した仕様と肥大化したコードベースに変更を入れることは容易ではなく、設計・実装・テストに多くの時間を要します。アイデアを実現しようとするたびに、たくさんの時間が掛かってしまうのであれば、実現するアイデアはより効果が期待できるものに限定する必要があります。ユーザーに提供できる価値のありそうなアイデアはたくさんあるのに、それらを実現するための時間が足りなくて、仮説のまま終わってしまうアイデアが多い。これはとても勿体ない話です。

リプレースへ

ここまで私たちが抱える課題についてお話ししてきましたが、ここからは課題解決に向けて私たちが決断したリプレースについてお話しします。

上述の課題は以前より認識はしていました。ただ、制度改定であったり、リソースが足りなかったりと、なかなか根本的な解決に踏み切ることができない状況でした。そんな状況がしばらく続きましたが、ついに根本的な対応ができそうなタイミングが巡ってきました。それが今です。 次回の大きな制度改定まで期間があり(次回予定は2024年4月)、内製化以降エンジニアも増えてドメインやプロダクトに関する知識も蓄積できてきた、という2つの要因が揃った今だと判断して、根本的な解決としてリプレースを行うことにしました。

まず、リプレースのスコープは、広げ過ぎると時間も掛かりリスクも大きいため、現実的かつ効果的なスコープとして、一つの領域における請求機能(※)に絞りました。

※私たちチームが担当している領域は障害者と障害児の2種類あり、今回は障害児の請求機能がスコープ。

次に、どのように進めるかですが、リプレースで行うことは大きく3つです。

  • 既存の仕様を参考にしつつも、複雑さを排除した新たなドメインモデルを設計・構築する。
  • 言語の表現力も借りて、基本に沿って秩序あるコードベースを再構築する。
  • ドメインモデルとコードベースに対し、変更容易性を維持する仕組み作りや取り組みをする。

1つ目は複雑化した仕様に対する対処で「仕様の複雑度 ≦ ドメインの複雑度」を実現すべく新しいドメインモデルを再構築します。

2つ目は肥大化したコードベースへの対処で、モダンな言語仕様の力も借りて、適切なコード量でメンテナブルなコードベースを手に入れるために、基本を守って実装します。

1つ目と2つ目を達成できれば、開発スピードが上がることが期待できますが、ここで終わってしまっては一時凌ぎにしかなりません。そこで大事なのが3つ目です。

3つ目は、今後も続く制度改定や新しい価値を提供するための機能追加を行うときに、過去の私たちと同じ選択(既存変更を抑えて単に上乗せする選択)をしなくて済むように短時間で開発できる状態を維持するための仕組み作りや取り組みです。

しかしながら画期的なソリューションを発見したわけではありません。変更容易性を維持するために、やるべきことをしっかりやる、というだけです。

具体例を挙げると、

  • ドメインモデルは、制度改定や機能追加によって変更される可能性を考慮し、それぞれの境界と接続ポイントを可視化(ココを変えるとコッチに影響するよね、というのがわかり易くなっている状態)しておくこと。そして仕様を変更する際は必ずドメインモデルの最適化を行うこと。
  • SOLID原則などの原則論に沿って実装すること。
  • テストコードをちゃんと書くこと。
  • PRレビューによって複数人の目を通すこと。

などです。(当たり前のことではありますが大事なので例に挙げました)

これらは行動規範や規約として設けることは大事ですが、それだけでは人に依存してしまいます。新たなメンバーを迎え入れたときにスムーズにキャッチアップできるよう、可能なものはCIや静的解析などの機械的な仕組みで担保するようにしています。

2023年4月現在、請求機能リプレースはまだ完了しておらず鋭意開発中です。そのため今回のリプレースの決断と取り組み内容の良し悪しは、まだ評価できません。もちろん現時点では良い決断・良い取り組みだと信じているわけですが、最終的な評価はまだ先になります。

リプレース後に、ユーザーから使いやすくなった等の嬉しい声をいただく、カイポケの利用者が増加するといった目に見える成果がでる、または数年後の私たちが「リプレースしたお陰で開発しやすい」と感じることができたら良い決断だったと言えるでしょう。

最後に

今回お話しした請求機能のリプレースの成功は、私たちのゴールではなく一つの中継地点でしかありません。

解決したい課題や実現したいアイデアはまだまだあります。今後も新しいアイデアは出てくると思います。その時に一緒に考えて課題を解決するための仲間はまだまだ足りていないです。

今回はあまり技術的な内容に触れませんでしたが、今回のリプレースは以下の技術要素で開発中です。

  • Kotlin x Spring Boot
  • TypeScript x Vue3
  • AWS Fargate
  • Aurora Serverless v2(PostgreSQL)

これらの要素にご興味があり、「ユーザーに多くの価値を提供したい!」と考える人がいらっしゃいましたら、ぜひ一緒に働きたいと思っております。

We are hiring! Join our team!!