この記事はニーリーアドベントカレンダー2024の20日目 シリーズ2の記事となります。
こんにちは。グロース開発チームのエンジニアの西村です。
この記事では、事業成長に伴い増大しているオペレーションの効率化を目指した開発の一例について紹介しようと思います。
ニーリーでは、月極駐車場のオンライン契約サービスであるPark Direct(パークダイレクト)を展開しています。
パークダイレクトでは、ソフトウェアとオペレーションを組み合わせることで、管理会社様や借主様に価値を提供しています。そのため、パークダイレクトの機能は管理会社様や借主様だけでなく、オペレーションを行うニーリーの従業員も利用しています。
「ソフトウェアとオペレーションを組み合わせる」という点が、先日の記事↓でもあったようにプロダクトとして面白いポイントで、SaaSでありながらオペレーションの効率化が重要になってくるのもこの構造に起因します。プロダクトエンジニアがビジネスサイドと協力しながら、いかにクイックに効率化を進めているかの手触り感を少しでも感じていただけたら幸いです。
開発対象: 見込める効果で決める
効率化の対象とするオペレーションについては、ビジネスサイドと協議しながら、以下の3つの条件を満たすものを選定しました。
- オペレーションが型化されていること
- オペレーションの頻度が高いこと
- 開発による効率化の効果が高いこと
効率化したいオペレーションは本当にたくさんあるのですが、開発リソースにも限りがあるため、事前に効果が見込めるものを優先的に開発対象としました。
開発方針: 70点で始める
パークダイレクトのオペレーションはイレギュラーケースが多岐にわたるため、すべてを100%自動化すると開発コストが膨大になります。そのため、「機能が70〜80点の段階でリリースする」ことを意識し、要件定義・設計・開発を進めました。
そう考えた理由は2つあります。
- エッジケースやイレギュラーケースをすべて考慮し、完璧に作り込んでからリリースすると、価値提供までに時間がかかってしまうため
- 70点程度の機能であっても運用に載せ、現場からのフィードバックを受けながら機能やオペレーションを磨き込むほうがより良いものを効率的に作れると考えているため
特に、型化しきれていないエッジケースやイレギュラーな業務を機能化しようとすると、業務にフィットしないリスクが高まり、結果として開発が無駄になる可能性があると考えています。
実際の開発の例
いくつかの業務効率化の機能開発をしてきましたが、今回は具体例として「料金変更機能」を取り上げます。
パークダイレクトでは、管理会社様からのご要望などに応じて、駐車場の料金を変更することがあります。その際、以下のようなオペレーションが行われます。
- 借主様に料金変更の了承をいただく
- 契約条件、および借主様に対する請求金額を変更する
- 新しい料金で賃貸借契約書を再作成する
- 再作成した賃貸借契約書を借主様に送付する
このステップのうち、今回は2〜4の部分について自動化を行いました。
70点の機能をリリースするための戦略
70点の機能でアウトカムを出すために、以下の2つの戦略を取り入れて開発を進めました。
1. 使用頻度の高い機能から順番にフェーズ分けする
料金には複数の種類がありますが、ビジネスサイドへのヒアリングを通じて、変更頻度が高いものから順に開発を行いました。
具体的には以下の3つのフェーズに分けて対応しました。
- 賃料・月額保証/管理料
- 更新料・更新事務手数料・更新管理料
- 敷金・事務手数料・初回管理料
2. イレギュラーケースは手動オペレーションで対応
イレギュラーが発生した際、「イレギュラーがあったかどうか」や「どのような内容か」が明確でないと、確認のために別業務が発生してしまいます。そのため、イレギュラーの発生状況や内容をビジネスサイドにフィードバックし、手動オペレーションで適切に対応できる仕組みとしました。
イレギュラー対応の仕組み
仕組みの説明の前に、どのようなイレギュラーがあるのか、具体例をご紹介します。
イレギュラーケースの具体例
①借主様がメールアドレスを持っていない場合
新しい賃貸借契約書をメールで送付できないため、必要に応じて郵送対応が発生します。
②過去の請求金額に対する変更履歴が複数回存在する場合
過去分の請求金額を単純に変更するケースはイレギュラーではありませんが、さらに過去に別の変更が行われている場合、再度の変更時に意図した金額を自動的に算出することが難しくなります。 そのため、人手による確認が必要となります。
仕組み
ニーリーでは、開発部門だけでなくビジネスサイドでもJiraを活用してタスク管理を行っています。 その仕組みを活かし、イレギュラーが発生した際にはJira APIを利用してチケットを自動起票し、ビジネスサイドで手動対応してもらうフローを構築しました。
アーキテクチャ
設計はアーキテクチャチームやSREチームと議論を重ね、理想的な形を描きながらも、まずは軽量な形で実装しました。 今回はバックエンドの処理の中にモジュールとして切り出して開発しましたが、 将来的には、Jira起票サービスをバックエンドから切り離し、Lambdaなどを用いて構築することも視野に入れています。
理想像は描きつつもまずはスリムにリリース、というのは業務効率化に限らずいたるところで行われています。「過剰になり過ぎない開発」がニーリーの文化として根付いていることを感じます。
Jira起票のサンプルコード
呼び出し側
def __create_jira_ticket_for_xxx(self): jira = JiraTicket('XXX') summary = 'hoge' description = f'fuga' custom_fields = PROJECT_CUSTOM_FIELDS.get('XXX', {}) transaction.on_commit( lambda: jira.create_jira_ticket(summary, description, custom_fields=custom_fields) )
呼び出し先
def create_jira_ticket( self, summary: str, description: str, custom_fields: dict = None, ): """JIRAにチケットを作成する - summary: チケットのタイトル - description: チケットの説明 - custom_fields: カスタムフィールドの辞書(任意) """ ...
ビジネスサイドの理解
この開発が順調に進められたのは、ビジネスサイドの理解と協力があってこそです。 具体的には、以下の点で大きなサポートをいただきました。
- ステップごとのオペレーション変更を許容してもらえたこと。
- 手動対応が残ることに対し、「0か100か」ではなく、「80が効率化されるなら、残りの20は手動で対応する」という柔軟な考え方を受け入れてもらえたこと。
まとめ
「70点〜80点で機能をリリースする」事例を紹介しました。 今回は業務改善の話でしたが、他にも事業KPI向上の施策や、新機能・新サービスの開発など、多種多様な開発案件があります。
急成長中のニーリー開発組織に興味を持っていただけたら嬉しいです。