家がクリニックに!? レバレジーズが挑んだ新規事業「レバクリ」開発の裏側を大公開

はじめに

 こんにちは。レバレジーズ株式会社システム本部の田中です。

 2022年11月から新規事業の立ち上げメンバーとして開発業務に携わっており、2023年6月にレバクリをリリースしました。社内では初となる大規模かつ決済を伴うtoCサービスであり、様々な挑戦をしながら開発を進めてきました。

 レバクリは「あなたの自宅をクリニックにする」をコンセプトに、オンラインで診療予約、診察、決済が完結し、自宅に薬が届くオンライン診療プラットフォームサービスです。「医療のあり方を変え、日本の医療における問題解決の主体者となる」ことをミッションとし、提携している医療機関と連携しながら、患者と医療機関の双方への最適な体験を提供できるサービスの実現を目指しています。

 レバレジーズではエンジニア一人ひとりが要件定義などの上流から実装まで幅広く担当することはもちろん、マーケティングやデザイン、オペレーションなど様々な領域の業務に関わることがあります。特に新規事業の開発においてはエンジニアに限らず少人数チームで始まることが多いため、エンジニアとしてではなく立ち上げメンバーとして様々なことに主体的に取り組むことができます。この記事では新規事業『レバクリ』の開発にあたって私が取り組んだことについて、以下二つの観点で紹介していきたいと思います。

  • 技術的側面
  • プロダクトマネージメント的側面

 レバレジーズでの新規開発でエンジニアがどのように活躍、成長できるのか、どんな形で貢献できるのか、少しでもイメージが鮮明になると幸いです。

サービスやチームの特徴をベースとした自由な技術選定

 技術選定といえば、新規事業のプロダクト開発の際の醍醐味の1つだと思います。レバレジーズでは技術選定は各チームに任されているので、事業の特性やチーム構成、メンバーの経験などをベースに行うことができます。

 今回、レバクリ開発チームでは「最速でのリリース」と「開発者体験」を考えた技術選定を行いました。チーム発足からリリース予定まで7ヶ月あまりと短かったことから、できるだけ開発速度が出せるように、またチームメンバーの開発体験をできるだけ高めることができるようにという意図でした。

言語

 言語はフロントエンド、バックエンドともにTypeScriptを採用しました。

 選定理由はかなり一般的な部分になりますが、

  • 社内でも標準技術となりつつある
  • 実装時に型チェックが効いてエラーを未然に防げる
  • フロントエンド、バックエンドで同じ言語が使える

 ことが挙げられます。

フロントエンド

 TypeScriptで開発できるFWとしてNext.jsを採用しました。

 Next.jsはFWの大きな特徴として

  • ReactベースでTypeScriptとの相性がいい
  • アップデートやリリースが高頻度でコミュニティも活発
  • キャッシュ戦略やReact Server Component対応など、高パフォーマンスのアプリケーションを実装するためのベストプラクティスが用意されている

 ことが挙げられます。

 また、私自身入社してから1年半Next.jsを使ったサービスの開発をしていたため、新規プロジェクトへのスムーズな導入が期待できたことがありました。他にNext.jsの経験があるチームメンバーはいませんでしたが、VueやNuxtの経験はあったため順応にさほどコストがかからないと判断しました。

技術面の特徴としては

  • bulletproof-reactベースのディレクトリ構成
    • featuresディレクトリ内で機能ごとに分けることで、機能間の結合を避けて無駄な共通化を考えずに開発速度を高めることができる
  • GraphQL Code GeneratorApollo Clientを組み合わせてデータ取得を実装
    • バックエンドのスキーマ定義から型を生成できる
    • 自動生成されたApollo ClientのHooksを使ってデータ取得処理やキャッシュ管理の実装工数を削減
  • App Routerを一部導入
    • v13.4でstableになったことを受け、一部の機能でApp Routerを採用

といった具合です。

バックエンド/API

 TypeScriptで開発できるNestJS、APIはGraphQLを採用しました。

 NestJSは

  • TypeScriptで開発されたFW
  • GraphQLと相性がいい
  • Express(もしくはFastify)がベースで実装手法が近い
  • 拡張性を残しつつ、FWとしてほしい機能が一通り揃っている

 といった特徴があります。私自身はTypeScriptでのバックエンド開発経験がほとんどなく、Expressを少し触ったことがある程度でしたが、ドキュメントが充実していて実装方法に癖があまりないのでスムーズに実装に入ることができました。

 GraphQLは

  • 単一のエンドポイントで1リクエストから複数リソースを取得できる
  • 取得する内容をフロントエンドで指定できる
  • バックエンドで定義したスキーマを型としてそのままフロントエンドで使うことができる

 特徴があり、ページ数が多く、同じデータを複数箇所で使ったり少し形を変えて取得したりするプロダクトの特性にフィットしていると判断しました。また、バックエンドとフロントエンドで型が一致することは開発者体験を非常に向上させるものとなりました。

技術面の特徴としては

  • オニオンアーキテクチャベース
  • NeverThrowを使って型安全にエラーハンドリング
    • try-catchでエラーに型がつかない問題をResult型を返すことで解消する
  • ORMとしてPrismaを採用
    • 多機能ではないが、直感的で実装が簡単なNode.js用のORM
    • GraphQLのN+1問題も解消してくれる

といった具合です。

社内スタッフ向けCMS

 記事などの動的コンテンツの管理にはStrapiというHeadless CMSを採用しました。

 Headless CMSというとあまり聞いたことがなかったり、知っていても使ったことはない方も多いかもしれませんが、表示部分(Head)以外の管理画面機能やデータ配信機能(API)を備えたものです。SEO流入獲得のために記事ページを展開する上でCMSの開発は必須ですが、リソースや保守を考えて0からの自作は避けたかったため、カスタマイズ性は確保しつつ実装を最小限に抑えられるCMSを探していました。

 Strapiは

  • TypeScriptに対応している
  • オープンソースなので無料で構築できる
  • REST apiもGraphQL apiもどちらも利用可能

 という特徴があります。自前で環境構築が必要ではありますが、料金がかからずコードを書けば簡単にカスタマイズや拡張ができる点からStrapiを選択しました。

 Strapiについて詳しく書くと長くなるので省略しますが、社内利用に制限されていて機能も最低限の管理画面とAPIが必要な程度だったため、想定よりも手軽に運用に持っていくことができました。

外部サービス

 認証に関しては、有名なIDaaSとしてCognitoAuth0Firebase Authenticationがありますが

  • 料金が比較的安い
    • Firebase Authentication < Cognito < Auth0
  • インフラをAWSで構築しているので親和性が高い
  • セキュリティ的な懸念があまりない

といった特徴からCognitoを採用しました。フロントエンドはAmplifyと組み合わせることで簡単に実装できるのと、サーバーの処理もAWS Admin SDKを使ってシンプルに実装が可能でした。また、AWSでインフラを構築しているので権限周りの設定も楽に行うことができました。CognitoとAmplifyを合わせた実装については別のスライドで簡単に説明しているのでそちらも合わせてご覧ください。

 決済プラットフォームはStripeを採用しました。実装するサービスやプロダクトの特徴によって大きく変わってくるので一概にはいえませんが、StripeはAPIが充実しており開発者向けのドキュメントも豊富なため、高いカスタマイズ性を求める場合に非常に相性がいいです。

ユーザー体験を第一に考えてサービス設計を主導

 技術選定はもちろんですが、新規事業の立ち上げメンバーとしてサービス設計も主導しました。オンライン診療事業としては大きな競合が2社ありました。それらのサービスの機能やフローを分析した上で必要な機能を洗い出し、より良いユーザー体験を届けるためにどうしたらいいか、どの機能がクリティカルで優先すべきかを整理しました。そして、最適なユーザー体験を第一にサービス設計を主導しました。

 ここでは特に設計に工夫をしたtoCのメールアドレス認証とtoBの診療画面について紹介します。

メールアドレス認証

 メールアドレス認証自体は機能として一般的ですが、社内の他サービスでは導入しているものが少なく、導入してCVRが下がった例もあったため、メールアドレス認証を入れるべきかどうかの議論からスタートしました。

 レバクリは基本的に登録したメールアドレスを使ってユーザーとサービス側がコミュニケーションをとる場面が多く、ログイン時のIDとしても使用する場合があるのでメールアドレスが存在しなかったり誤って入力されてしまうことはサービス運営上大きな障壁となります。また、セキュリティ面でもなりすましや第三者にメールが届いてしまうリスクにつながります。医療に関係するサービスであるため、受診歴や問診の回答内容が流出してしまうと大きな問題になってしまいます。ユーザーに安全にサービスを使用してもらうためにもメールアドレス認証は有効な手段でした。

 エンジニアとしてはセキュリティリスクを最小限に抑えるためにメールアドレス認証が必要と判断しましたが、事業サイドのCVRにおける懸念がある以上、セキュリティリスクを説明して理解を得る必要があります。以下のようなフローチャートを作成し、リスクを最小限に抑えるためのパターンについて提示した上で、認証を挟むポイントとしてどこがベストか議論をしました。

 レバクリには複数の機能がありますが全て診療の予約が起点となります。言い換えると診療を予約するまでは流出がクリティカルになるような情報やなりすます機会はないため、診療予約が完了するまでにメールアドレスが認証できていれば最低限のセキュリティ要件を満たすことができます。ユーザー登録に必要な情報を登録してもらい、最後に予約を確定するタイミングにメールアドレス認証を要求するステップに工夫しました。

toB診察画面

 診察を行う医師やクリニックの事務作業を行うスタッフが使用する画面をtoB画面と呼んでいます。toB画面も診察の一覧表示や診察、薬の発送に関する画面など複数の機能が存在していますが、事業の状況やチーム構成によってユーザーが変化する可能性があります。例えば一人で診察から発送まで行う場合と、作業を複数人で分担する場合では導線はもちろん必要な画面の種類や数まで変わってきます。そのため、集客やサービス運営が安定してくるまでに細かい変更が簡単にできるように、あまり作り込まずに最低限の機能を用意してリリースすることを目指しました。

 初期のスコープは医師が全て対応するのを基本線として、提携クリニックの医師にヒアリングをしながら設計しました。医師が普段の診察時に使っているシステムについて知見のあるメンバーがほとんどおらず、リファレンスもなかなか見つからずに難しいタスクでしたが、適宜画面の構成や機能についてすり合わせたり、プロトタイプを触ってもらってフィードバックを受けながら進めました。

 現在はCSチームが設置されたり、作業者の分担があったりと事業の状況も変わってきていて、初期はスコープから外していた検索機能を利用シーンにあった形で実装したりと日々アップデートが行われています。

今後の課題

 最後に今後の課題として取り組んでいきたいことについてご紹介します。

開発組織の体制整備

 チーム発足からエンジニア正社員2名+業務委託数名で開発を続けており、初期スコープではあらかじめ全て設計してから進めるウォーターフォールの形で開発していました。現在はチームメンバーも徐々に増え、複数機能を並行して設計、開発、リリースするアジャイル開発に近い形になっていますが、整備されているわけではないのでタスクの管理工数の増大やチームとしてパフォーマンスを最大化できていません。社内で導入しているチームが多いスクラム開発を含めて、機能開発を進めながら開発組織の体制も整備していきたいと考えています。

プロダクトとして競合に対する優位性の確立

 レバクリはオンライン診療サービスの中では後発になるため、現在は競合のレベルに追いつくための機能開発が中心になっています。着実に機能開発が進んできており、年内には機能として競合に遜色ない状態になる見通しとなっているため、今後は追いついた先で市場1位をとるためにプロダクトの強みを伸ばしていく必要があります。具体的には、予約やオンラインでの診察といった基本機能だけでなく、医薬品の服用をリマインドしたり服用の中での副作用への不安をサポートできるような機能や、診察の結果や自らの健康状態を確認できる機能など、プロダクトとして何度も使ってもらえるような仕組みを作っていくために、ビジネスサイドに食い込んで事業成長に貢献していけたらと考えています。

さいごに

 最後までお読みいただきありがとうございました。レバクリを一番選ばれる最高のサービスにしていくことを目指して、これらの課題に取り組み、より強い開発組織を作っていきたいと考えています。現在、私たちと一緒に挑戦してくださるエンジニアを募集しています。ご興味のある方はぜひ採用サイトをご覧ください!

MLOps1年目 - SageMakerを使う中で苦労した課題解決とこれからの展望

はじめに

 テクノロジー戦略室MLOpsチームの古賀です。MLOpsチームでは、レコメンドエンジンのMLOps基盤の構築や、AWS PersonalizeなどのMLサービスやLLMなどML活用を、企画から構築まで進めています。本テックブログでは前者のMLOps基盤構築の取り組みを紹介します。

 以前投稿したテックブログにあるように、AWS SageMakerとStep Functions Data Science SDKを導入し、データサイエンティスト主導のMLモデル改善フローを構築できました。しかし、ゴールというわけではなく、まだまだ改善の余地がありました。

 そこで、本テックブログでは、課題の洗い出しや分析、解決のための取り組みを紹介します。そもそもMLOpsを行う背景は以前投稿したテックブログの「背景」に記載しているので、興味ある方はご確認ください。

以前のテックブログまでにやったことと課題

 まず前提として、今までのMLOpsシステム構成を知る必要があります。下記のような構成になっています。説明の都合上、図を書き直していますが、構成は一緒です。

 一連のMLプロセスがパイプライン化されているため、データサイエンティスト主導でモデル改善フローを実行できます。また、学習-推論時で前処理を共通化しているため、Training-Serving Skewを改善出来ています。

 一方で課題がいくつかありました。

  • 特徴量作成
    • 特徴量を再利用できない
  • 学習:開発時、学習パイプライン(前処理から評価まで)の実行時間が長い
  • デプロイ:単一モデルのデプロイフローしか整備されていない
  • 全体
    • パイプライン実行の複雑化
    • PoCからシステムへの初期導入のリードタイムが長い

各課題とその解決策の分析

 各課題を分析し、必要な解決策を説明します。

特徴量の再利用性の低さ

 現状S3に特徴量を出力しています。S3に特徴量を格納している場合、作成者以外の人が特徴量の利用を判断するのが難しくなります。理由は、S3には特徴量のメタデータ管理やバージョン管理の機能がないからです。これらの機能がない状態で作成者以外の人が利用判断するためには、その特徴量が信頼できるデータソースから正しい変換処理により作られているかをソースコードから読み解き確認し、その結果作られる特徴量が正しいかも確認する必要があります。

 そこで、特徴量のメタデータ管理機能やバージョン管理機能を持ったデータストアに格納する必要があります。

学習にかかる時間の長期化

 学習パイプラインの実行による動作確認に時間がかかっていました。理由は2つあります。

  • 不要なステップも実行されるため。例えば、評価の処理を変更した場合、評価ステップのみ実行すべきですが、前処理ステップから実行してしまいます。
  • SageMaker Processingの起動に時間がかかるため。1つあたり5分程度かかるため、全て実行すると起動だけで15分程度かかります。

 これらの課題を解決するためには、必要なステップだけ実行し、起動時間を減らす必要があります。

単一モデルデプロイフローしか整備されていない

 単一モデルのデプロイのみ実装しており、複数モデルのオンライン評価の仕組みが用意されておりませんでした。そのため、複数モデルのデプロイとそれらのオンライン評価の仕組みが必要です。

パイプライン実行の煩雑化

 デプロイパイプライン以外の動作確認手順が煩雑でした。例えば、ライブラリをインストールし特徴量変換処理を変更した場合、下記の作業が必要でした。

  • 動作確認用のAWSリソースを作成(データ取得パイプライン、S3バケット)
  • Dockerイメージのbuildとpush
  • 動作確認用のデータ取得パイプライン実行notebookを実行

変更するたびに、動作確認手順が変わるのは認知負荷が高い上、対応漏れも発生します。加えて、変更箇所によっては、AWSリソースは他のパイプラインやLambdaの作成も必要になります。これらの課題を解決するには、変更箇所によらない動作確認手段が必要になります。

PoCからシステムへの初期導入のリードタイムの長期化

 レコメンドプロジェクトを下記のように進めていました。

 MLOpsとして最優先で解決したいのは、SageMakerへの載せ替えの長期化です。長期化している理由は2つあります。

  • プロジェクトごとに一からインフラ構築しているため
  • PoC後にMLエンジニアが構築したパイプラインに載せ替えているため

 特に後者の工数が大きく、PoCではPoC後の移植を想定したコードを書いておらず、スパゲッティコードのような状態で移行が大変でした。加えて、載せ替えにあたり、データサイエンティストとMLエンジニアのコミュニケーションコストもかかっていました。

 これらの課題を解決するためには、データサイエンティストの開発スピードを落とさず、作ったモデルをそのままシステムに組み込めるような基盤が必要になります。

これまでの取り組み

 上記課題の中で実際に取り組んだことを紹介します。特徴量の再利用性についてはFeature Store + Dataflowの検証までになりましたが、他の課題はある程度解決できました。Feature Store + Dataflowの検証についても紹介します。

特徴量の再利用性の低さ

 AWS SageMaker Feature StoreとGoogle Cloud Dataflowを選択し、検証を進めています。AWS SageMaker Feature Storeを採用した理由は下記の通りです。

  • 特徴量のバージョン管理機能やメタデータ機能があり、特徴量の再利用性を高められるため

Google Cloud Dataflowを採用した理由は下記の通りです。

  • データ変更後、リアルタイムに特徴量に変換して格納するため
  • pandas互換のAPIをサポートしており、データサイエンティストも扱えるため
  • 他チームでRDSからBigQueryにETL処理するためにGoogle Cloud Dataflowを導入予定で技術を標準化するため

 現在は下記の構成の検証を進めています。

白抜き部分の実装は概ね完了したので、これから検証 / 本番環境にデプロイし問題がないか確認していきます。問題がなければ、稼働中のレコメンドプロジェクトにも導入していく予定です。

学習にかかる時間の長期化

 SageMaker Pipelinesを導入し解決しました。導入した理由は下記の通りです。

  • キャッシュモードが存在し、不要なステップの実行をスキップできるため
  • ローカルモードが存在し、SageMaker Processing Jobの起動時間を短縮できるため

処理を変更したステップのみ実行できるので、最小限の実行時間にできました。

単一モデルのデプロイフローしか整備されていない

 複数モデルをデプロイできるようにし、推論エンドポイントであるSageMaker Endpointの前段に配置しているキャッシュサーバーにトラフィックを振り分ける処理を実装しました。なお、トラフィックを振り分ける際は、ユーザーに対して推論するモデルを固定しました。

 まず、ユーザーごとにモデルを固定した理由は下記の通りです。

  • ユーザーを困惑させないため。レコメンド機能を使うたびに結果が変わると、ユーザーが混乱するため。
  • 分析を簡単にするため。もしトラフィックをランダムに振り分けると、どのモデルが推薦したか追う必要があります。この方法よりは、ABテスト期間内でユーザーごとにモデルを固定した方がシンプルで分析しやすいと判断しました。

 次に、キャッシュサーバーに実装した理由は、SageMaker Endpointのトラフィック振り分け機能はランダムな振り分けしかなく、ユーザーごとにモデルを固定できないためです。そのため、SageMaker Endpointの前段のサーバーに振り分けロジックを実装しました。

パイプライン実行の煩雑化

 どのファイルを変更しても、Github Actionsワークフローを動かせば動作確認できるようにしました。加えて、Model Registryに登録された評価結果を承認し、対象のモデルをデプロイできるようにしました。

 Github ActionsワークフローはDockerイメージのbuildとpush、Lambda関数の作成 / 更新、データ取得と学習パイプラインを作成 / 更新し実行します。どこを変更しても、このワークフローを動かせば確認できるため、認知負荷を減らせました。加えて、必要な時のみDockerイメージの構築やLambda関数の更新を実行しているため、不要な実行時間はありません。

 Model Registryに登録されたモデルを承認し、デプロイパイプラインを実行します。このようなフローにしてる理由は、人間が評価結果を確認してからデプロイしたいためです。ただし、この判断基準を明確なルールにできるならば、Github Actionsワークフローでデプロイまで実行しても良いと考えています。

これからやりたいこと

 短期的には、レコメンドプロジェクトの開発効率を高めるために、解決できてない課題を解決したいです。

  • 特徴量を他プロジェクトで再利用できない
    • Feature Store + Dataflowを本格導入したいです。パフォーマンスに問題が無いことを確認する、他の機能との優先度の兼ね合いなどありますが、実現していきたいです。
  • PoCからシステムへの初期導入のリードタイムの長期化
    • MLOpsフレームワークの構築、または、標準構成のテンプレート化などで短縮させたいです。PoCする段階からSageMaker上で開発することで、SageMaker移行の工数を無くすためです。

 長期的には、開発効率だけでなく、ビジネスサイドがレコメンドが事業に与える影響を直感的に分かるようにし、ビジネスサイドとデータサイエンティストのコミュニケーションも効率化させ、レコメンドの精度改善スピードを向上させたいです。

まとめ

 以前のテックブログ執筆時の課題と解決のために、提案し実行した取り組みを紹介しました。まだGoogleが提唱する MLOps レベル1に達してないですし、使い勝手も改善していく必要があります。加えて、今回は紹介できませんでしたが、ML活用も推進しています。レバレジーズではMLOps基盤やML活用を企画から考え構築までやりたいエンジニアを募集しています。興味のある方の応募をお待ちしています。

「日本を、IT先進国に。」に向けて、レバテックCTO室を設立。「日本一のデータとシステムを持つ事業とそれを支えるアーキテクチャ」を目指して、組織・システムの改革を進める。

はじめに

こんにちは、レバテック開発部でテックリードを担当している河村です。 私はレバテック全体のシステム設計を担当しており、今後の事業拡大に向けて、理想のシステムを目指して、技術的負債の解消などの推進を行っています。

レバテックはこれまで、マイクロサービス化を主体においた技術スタックの刷新を行ってきました。これからはユーザー体験、業務プロセス、技術的負債を含めて「痛み」となっている部分の解消を進めていき、プロダクトやサービスとしての最適解を探索していきます。 そこで、今回はレバテックのシステム課題である「分散されたモノリス」の状態から「日本一のデータとシステムを持つ事業とそれを支えるアーキテクチャ」を目指してどのようなことを行おうとしているのか、そこに合わせて新設されるCTO室がどのような活動を行うとしているのか、レバテックの現状と課題を踏まえてご紹介します。

CTO室が設立された背景

レバテック - 事業ポートフォリオ

レバテックは現在、フリーランス・派遣・就転職、新卒の各領域を軸に様々なサービス・事業を展開しています。

※ 主なサービス、関わるシステム

  • レバテックフリーランス、レバテッククリエイター
    • ITフリーランスとしてのキャリアの可能性を広げるエージェントサービス
  • レバテックキャリア、レバテックダイレクト
    • 正社員としてのキャリアの可能性を広げる転職エージェント・スカウトサービス
  • レバテックルーキー
    • ITエンジニアを目指す学生の可能性を広げる就活エージェント・スカウトサービス
  • レバテックプラットフォーム
    • レバテックに登録いただいたITフリーランスのスカウトから、参画後の契約管理までを実現するプラットフォームサービス
  • レバテックID
  • 上記レバテックのサービスを支えるマイクロサービス群

レバテック - 事業進捗・サービス展望

レバテックは5年後、10年後の事業拡大に向けて、様々な事業展開を計画しております。

今までは営業とマーケティングの強みを生かして事業展開を行ってきましたが、今後は開発とデータを活用して事業展開を計画しており、開発とデータが強い組織・システムを構築しなければなりません。そのためにも、「日本最大級のIT人材プラットフォームの進化を支える」組織やシステムを構築する必要があり、ユーザー体験、業務プロセス、技術的負債の改善に向けて取り組んでいます。

レバテック - 現状のシステム全体像

レバテックの各サービス・事業を支えるシステムは上記のようになっています。 各システム間の連携や営業支援システム、外部サービスとの連携があり、レバテックに関連したレポジトリだけでも200個以上あり、大規模なシステムになりつつあります。

その中でもシステムとして最も課題としているのが「分散されたモノリス」のような状態(参考記事:What is 分散モノリス(Distributed Monolith))です。すべての機能がマイクロサービス化されているわけではないので、一般的な「分散されたモノリス」の状態というわけではないのですが、発生している問題としては近い状態です。

上記の図のようにシステムは各サービス・事業ごとに分散されています。ですが、この分散されたシステムは理想的な分割ではなく、既存システムの複製で作られたシステムであったり、人が増えたことにより出来上がったシステム、システムの本来の責務を超えた機能をもっていたりと理想のシステムとかなりギャップがある状態です。

そこで、「分散されたモノリス」となってしまっている原因として以下の問題があります。

  • 密結合なシステム
    • 人材や企業のデータも重複して保持している状態でかつDB直参照やバッチサーバ連携で行っているため、システムの追加や変更を意識して開発しなければならない
  • 非構造化データの存在
    • 文字列やEAVパターンを利用した暗黙的なリレーション構造が存在し、DBに格納される文字列を変更するだけでシステムの障害のきっかけとなり得る
  • マスタデータ(職種やスキルなどのリファレンスデータ)の分散
    • 各システムでマスタデータのIDや項目が異なり、マッピングをして連携や分析を行っている

上記の問題は2、3年前から顕在化していました。ですが、いきなりすべての問題に取り組むのは難しく、また、当時の技術スタックも古い状態で稼働していました。なので、まずは技術スタックの刷新やマイクロサービス化の導入から進めてきました(参考記事:マイクロサービス化を中心においた技術刷新とその狙いレバテックの未来に向けた開発組織の取り組み)。技術スタックの刷新により、静的型付け言語であるTypeScriptをベースとしたシステムにすることができ、負債を貯めにくい・解消しやすい設計手法であるクリーンアーキテクチャやDDD(ドメイン駆動設計)の導入が行いやすくなり、計画的な負債の解消を進めやすい状態にすることができました。

今後は「分散されたモノリス」から「それぞれのシステムとデータが”独立化”し”疎結合化”された状態」を目指して、現在のTypeScriptをベースとしたシステムのリニューアルを行い、今後のレバテックを支える組織・システムを構築していきます。

つまり、今まで行ってきた「リプレース」を生かして、今後は「それぞれのシステムとデータが”独立化”し”疎結合化”された状態」に向けて「リファクタリング」「リプレース」「リニューアル」を計画的に進めていきます。

※ リファクタリング・リプレース・リニューアルの定義

  • リファクタリング
    • 現在のシステムをI/F(IN/OUT)やふるまいを変えずにコードを変更すること
      • 例:MVCからレイヤードアーキテクチャに移行する
  • リプレース
    • 現在のシステムをI/F(IN/OUT)やふるまいを変えずに別のシステムに載せ替えること
      • 例:PHPがベースで動いているシステムをTypeScriptベースのシステムに載せ替える
  • リニューアル
    • 現在のシステムをI/F(IN/OUT)やふるまいを変えて、新しい価値を生み出すこと
      • 例:システム・データの拡張性を向上させるため、ユーザー登録の仕組みや業務プロセスから改善を行う

CTO室で実現したいこと

レバテック - CTO室ミッション

上記のレバテックにおけるシステム・データの課題を解決をリードしていくため、この度、CTO室を立ち上げることになりました。

大規模なシステムになってきたレバテックの関連サービスを支え、今後の事業拡大に向けて、総合的なアーキテクチャや設計が求められることになります。特に、最も難しいと考えているのが、今のレバテックにおけるユーザー体験、業務プロセス、技術的負債の中で最も「痛み」となっている部分の特定とその「痛み」の解消です。 すべての課題をいきなりすべて解消できる規模ではなく、今後の事業拡大を鑑みて、最も「痛み」となる部分を分析・特定し、経営や他職種を巻き込んで、この「痛み」を計画的に解消を進めていく必要があります。なので、ただ単純に技術的負債を解消を進めていくということではありません。現状のユーザー体験や業務プロセスを含めて最適解を探索する必要があります。

レバテック - CTO室が目指す先

レバテックは現在、登録者数50万人、契約社数1万社を突破し、IT人材の2.5人の1人が登録するサービスになっております。上記の「分散されたモノリス」な状態を脱却し、レバテックにおけるユーザー体験、業務プロセス、技術的負債の中で最も「痛み」となっている部分を解消し、目指す先は「日本一のデータとシステムを持つ事業とそれを支えるアーキテクチャ」を作ることです。

レバテック - コア要素『D-POS』のAsis-Tobe

「日本一のデータとシステムを持つ事業とそれを支えるアーキテクチャ」になるために上記のTobeのような状態が必要だと定義しています。つまり、データを軸にプロダクト/オペレーション/システム(Data→Product/Operation/System)を再設計していく必要があると考えています。

ここまでをまとめると、

  • レバテックは5年後、10年後の事業拡大に向けて、様々な事業展開を計画している
  • そのためには、「日本最大級のIT人材プラットフォームの進化を支える」組織やシステムを構築する必要がある
  • 現在、組織・システムとして「分散されたモノリス」という状態の課題を抱えている
  • 理想を「日本一のデータとシステムを持つ事業とそれを支えるアーキテクチャ」と定義
  • そこに紐づくTobeを目指してレバテックを再設計していく

CTO室の今後

今後、CTO室は上記の課題から以下の軸をベースに強化していきます。まだまだ具体的な目標などは決められていませんが、以下を軸にCTO室の役割を拡大していけたらなと考えております。

  • 事業戦略に紐づいたシステム戦略のリード
  • テクニカルとドメインを掛け合わせたドメインの最適化
  • 事業横断した組織・システムの最適化
  • 開発者生産性の向上

事業戦略に紐づいたシステム戦略のリード

CTO室は、今後ますます事業戦略に連動したシステム戦略を主導する役割を果たします。この取り組みにより、技術戦略がビジネスの長期的な目標と一致し、我々の競争力を向上させ、新たな市場機会を探求します。「日本最大級のIT人材プラットフォームの進化を支える」組織やシステムを構築し、戦略的な成長を支えることを目標に進んでいきます。

テクニカルとドメインを掛け合わせたドメインの最適化

テクニカルな専門知識とビジネスドメイン知識を融合させて、ドメインの最適化に取り組みます。このアプローチにより、特定のドメインに特有の課題に対処するための優れたソリューションを提供します。そこで、レバテックの事業/開発双方の戦略及び戦術に基づく特定のテクニカルドメイン領域における信頼されるスペシャリストを多く輩出していき、新たな可能性を切り拓きます。

事業横断した組織・システムの最適化

CTO室は、組織とシステムを結びつけ、情報共有と協力を促進し、事業全体での最適化を実現します。これにはイネイブリング、SRE、QA、アジャイルCoEによる事業を横断した組織・システムの強化が必要です。冗長性の排除やリソースの最適利用、可観測性の向上により、より効果的に運営し、ビジネス目標の達成を目指します。

開発者生産性の向上

CTO室は開発者生産性の向上に注力します。新しいツール、プロセス、トレーニングを提供し、開発者がより効果的に作業できる環境を整備していきます。これにより、イノベーションが促進され、プロダクト開発をより支援できたらと考えています。 ゆくゆくはエンジニアが選ぶ「開発者体験が良い」イメージのある企業「Developer eXperience AWARD 2023」ランキング上位5にランクインに向けて取り組みを進めていきたいと考えております。

さいごに

これらの目標を達成するために、CTO室は積極的な取り組みを進め、テックカンパニーとしてより高いレベルの開発組織にしていきたいと考えています。現在、一緒にCTO室を推進していただけるエンジニアを募集しています!ご興味のある方はぜひこちらからご連絡ください!

アプリケーションの処理を40倍高速化!効果的な最適化手法と実践事例の紹介

レバレジーズ株式会社 HRテック事業部の桐生です。

アプリケーション開発において、重たい処理の高速化は避けては通れない課題の一つですが、なんとなくで取り組んであまり良い結果が得られなかったり、そもそもどこから手をつけていいか分からなかったりすることもあるかと思います。

本記事では、処理の高速化を上手に行うための流れと、各ステップで抑えるべきポイントをご紹介します。

実際に私が携わっていたプロダクトでも、今回ご紹介する流れに則って高速化に取り組み、最終的に処理時間を40倍以上高速化することに成功しました。こちらの具体的な事例も含めて詳しくご紹介しますので、ぜひ最後までお読みいただければと思います!

なお、こちらは6月に開催されたレバレジーズ テックフェスにて発表させていただいた内容と同じものです。

大まかな流れ

以下の流れで処理の高速化を行っていきます。

  1. 無駄を含む処理を見つける
  2. 処理の遅い原因を特定する(計測)
  3. 高速化のための手段を考え、実装する
  4. 実装した高速化の効果を測定する

「無駄」を含む処理を見つけるには?

遅い処理を目の前にした時に、まず考える必要があるのは「この処理に削れる無駄は残っているか?」ということです。当たり前の話ではあるのですが、既にリソースを十分に使い切っている処理を高速化するのは難しいためです。

「無駄」が存在していることを判断するのに重要なのが、処理内容から考えてどのくらいの時間がかかりそうかを予測し、それを実際の処理時間と比較することです。「こういう処理だからこれくらいの時間がかかりそう」という予測を精度良く行うことで、無駄を見つけることができるようになります。

処理の性質ごとにかかる時間を計算する

処理時間を見積もる際には、「どんなリソースで」「どれくらいの量の」処理を行っているかに着目します。例えば、多くの処理で使われるであろう「CPU」「ストレージ」「ネットワーク通信」は、以下に示すように1回の操作にかかる時間が非常に大きく異なります。

このため、処理の性質によって以下のように見積もりを変える必要があります。

計算処理が中心の処理の場合、時間がかかると感じるには少なくとも数百万回〜数千万回程度の計算ステップが必要になります。ソート処理や大規模な文字列処理、および画像処理等はこれに該当することがありますが、一般的な業務アプリケーションでこのレベルの計算負荷を求められる場面は比較的まれといえます。 逆に、ストレージ・ネットワークアクセスが中心の場合、もっと小さな数字でも時間がかかる場合があります。

処理時間を概算してみる

上記を踏まえて、実際に処理時間を見積もってみましょう。例として、以下のような処理を想定します。

  • 1000件/ユーザーのデータを、100ユーザー分集計する
  • 集計は単純な平均・合計等
  • データはDBサーバーから取得する

この場合、行われる処理は以下のように分類できます。

  • CPUでの計算: 1000×100 = 10万のオーダー → 1秒は決して超えない
  • データ取得: NW通信1回 + 読み出しに1秒〜数秒?

これらのことから、どんなに長くても数秒〜10秒程度で完了することが予想できます。よって、これよりも遥かに長い時間がかかっている場合はほぼ確実に無駄が潜んでいると考えられるわけです。

このように、処理内容から想定の処理時間を見積もることで、無駄を含んでいる処理を見分けることができます。

計測せよ!

無駄を含んでいそうな処理を特定できたところで、次はこの処理を速くしようという話になるわけですが、ここでやってしまいがちなのが「何となくここが遅そう」という推測だけで高速化に手をつけてしまうことです。しかし、これは次に示すように、可能な限り避けるべきです。

ロブ・パイクのプログラミング5カ条

プログラミング界隈で有名なロブ・パイクの「プログラミング5カ条」より、処理時間に関する2つのルールをご紹介します。

  • ルール1: プログラムがどこで時間を消費することになるか知ることはできない。ボトルネックは驚くべき箇所で起こるものである。したがって、どこがボトルネックなのかをはっきりさせるまでは、推測を行ったり、スピードハックをしてはならない。
  • ルール2: 計測すべし。計測するまでは速度のための調整をしてはならない。コードの一部が残りを圧倒しないのであれば、なおさらである。

(引用元: http://www.lysator.liu.se/c/pikestyle.html )

ここで述べられている通り、処理の重さが具体的に何に起因するのか、推測によって特定するのは非常に困難です。このため、推測によって作業に手をつけると、全く遅くない箇所を一生懸命高速化するという事態に陥る可能性があるのです。

このように、高速化を行う際には「どこが遅いのか」を計測して特定し、処理時間の占める割合が大きいところを削っていく必要があるのです。

処理時間の計測のための手法はいろいろと存在しますが、ここでは代表的なものを2つご紹介します。

タイマーによる計測

一つ目は非常に愚直な方法で、処理の前後の時刻(タイマーの値)を記録することで処理時間を計測する方法です。

例として、JavaScriptのDateクラスを使って処理時間を計測する方法を示します。

function run() {
  // 開始時の時刻を記録
  const startTime = Date.now();

  someHeavyWork();

  // 終了時の時刻を記録
  const endTime = Date.now();

  // 経過時間は、終了時時刻 - 開始時時刻 で求められる
  const elapsedTime = endTime - startTime;

  console.log(‘someHeavyWork:’, elapsedTime, ‘ms’);
}

Date.now()を呼ぶことで、その時点での時刻(ミリ秒単位)を記録することができます。今回は例としてJavaScriptの機能を用いましたが、他の言語でも現在時刻のタイムスタンプを取得する関数(PHPのmicrotimeやRubyのTime.now等)を用いることで同様に計測できます。これを利用して処理の開始時・終了時の時刻を計測し、その差を取ることで、間に挟んだ処理にどのくらいの時間がかかったかを知ることができます。

※なお、JavaScriptの場合はconsole.timeという関数を用いることでより簡単に時間を計測することができます。詳しくはMDNの該当ドキュメントをご参照ください。

このような時間の記録処理を、重い可能性のある処理の前後に挟むことで、実際に重い部分を絞り込んでいきます。(最初は大きめの範囲を挟んで、徐々にその範囲を狭めていく)

この方法は非常に原始的なので、どんな処理にでも適用できるという良さはあるのですが、その反面、計測処理を手動で挟んでいく必要があるため手間がかかります。次に紹介するプロファイルを用いると、手動で処理を挟まずに時間を計測することができます。

プロファイラの活用

プロファイラとは、関数ごとの処理時間を自動で記録してくれるツールです。プロファイラを用いると、プログラム実行中の関数呼び出しを追跡して、時間のかかっている部分を特定することができます。大抵のプラットフォームではそれぞれのプラットフォームごとに専用のプロファイラが存在しており、例えばNode.jsプロファイラを使って計測を行うと以下のような出力を得ることができます。

各関数の中でかかった時間が帯状に表示されています。また、グラフの上下関係は関数の呼び出し関係を表しています。下側にいくほど関数の呼び出し階層が深くなっていっています。

今回用いたNode.jsプロファイラの使い方の参考記事: Node.js の CPU プロファイリングでボトルネックを特定する

–-

今回は処理時間を計測する方法を2つご紹介しました。これらを用いて実際に遅い箇所を特定したら、ついに実際の高速化作業に取り組むことになります。

高速化に王道なし

いよいよ実際の高速化作業を行うわけですが、プログラムが遅い原因というのは実に様々で、そのため、高速化のための普遍的な手法も存在しません。ただ、それだけで説明を済ませてしまうのも寂しいので、今回は私が実際に関わった高速化の事例をご紹介して、高速化作業のイメージを掴んでいただこうと思います。

事例:月次処理の高速化

1つ目にご紹介する事例、給与計算ソフトにおける月次の勤怠締め操作の高速化です。こちらは会社ごとの全社員の勤怠データを集計して給与額を計算する処理なのですが、会社あたりのユーザー数が増加すると、計算完了まで何分もかかってしまうという問題がありました。

処理時間の見積もり

まずは、本来の処理時間を見積もってみます。具体的にかかっていた時間ですが、例えば300人程度の会社ですと7分以上かかっていました。ただ、実際に処理するデータの量を考えると以下のようになり、大きな乖離が生じています。

  • 300人 * 30日 = 9000個の勤怠データの集計 + 過去の有給使用データ(300人 * 数十件 = 数千〜1万件)の集計
    • 集計は基本的には時間を累積していくのみ
    • 実際は営業日は30日もないので多めに見積もっている
  • データの取得等含めて考えても何十秒もかかるのですらおかしい
    • 数万件のデータの取得(数秒) + データ処理(1秒以内) + 数万件のデータの書き戻し(数秒)にしかならないはず

これを踏まえると、この処理はまだ高速化の余地があると判断できます。

遅い箇所の特定

次に、実際に何が遅い原因となっているかを計測して調査します。処理部分にログを仕込んで計測した結果、DBのデータ読み書きに大半の時間を費やしていることがわかりました。

さらに詳しくコードを調査した結果、以下の2つの原因が判明しました。

  • 特定のテーブル(大きめ)にインデックスが張られていなかった
  • 1ユーザーの処理ごとに大量のクエリを発行していた

それぞれ詳しく説明します。

テーブルにインデックスが張られていなかった

今回の遅かった箇所の一つが、勤怠集計データを保持するRDBテーブルからのデータ読み込みです。読み取っているデータはユーザーごとに数十件程度なのですが(1ヶ月分のデータしか読み取らないため)、読み取りに異常に時間がかかっていました。これは当該テーブルに必要なインデックスが張られていなかったことが原因です。

データベースから条件で絞ってデータを取得する場合、何も設定しないとテーブル全体を検索するため、テーブル全体のデータ量に比例した時間がかかってしまいます。このため、通常は検索したいカラムにインデックスを張ることでこの時間を一定に抑えるのですが、今回操作していたテーブルでは検索対象のカラムにインデックスが張られていませんでした。このテーブルには過去の全ての勤怠データが保持されており、その総レコード数は数十万にも及んでいたため、不要なデータに対して検索をかけており時間がかかっていたのです。

対処法としては、単純に検索対象のカラムに有効なインデックスを張るだけでした。この対処だけで処理時間が元々の3分の1程度にまで減少しました。

1ユーザーごとに多数のクエリを発行していた

もう一つの原因が、1ユーザーごとにデータの取得・書き出しクエリを発行していたことです。今回の実装においては、1ユーザーごとに必要なデータを全てデータベースから取得しており、また結果データの書き込みも1行ずつ行っていたため、結果的にユーザーあたり100以上のクエリを発行しており、トータルで何万件ものクエリを発行してしまっていました。これによりネットワーク通信待ちとクエリ実行のオーバーヘッドで大きく時間がかかってしまい、何分も処理に時間がかかってしまっていました。

対処法としては、予め処理対象のユーザーのデータをまとめて取得することによりクエリ発行回数を減らしました。また、書き戻しの際もある程度まとめて書き込みクエリを発行するようにしました。


上記2つの施策を行ったことにより、計算アルゴリズムには一切手を加えませんでしたが、最終的に10秒程度まで処理時間を短縮することに成功しました。

事後の計測を忘れずに

高速化作業を行った後は、それが本当に高速化に寄与したかどうかを必ずチェックするようにしましょう。特に、2つ以上の変更を行った場合は、両方の変更に効果があったかどうかをそれぞれ調べないと、効果のない変更を入れ込んでしまうことがあります。実際に自分が高速化を行った際にも、片方の変更は高速化に寄与していたが、もう一方の変更はむしろプログラムを遅くしてしまっていた、という場合がありました。

高速化のためのコード変更というのは一般的にコードをより複雑にしてしまうものなので、効果のないコードはなるべく排除するようにしましょう。

まとめ

ここまでで、処理高速化のための大まかな流れを一通りご紹介しました。見積もりと計測に基づいて高速化作業に取り組むことで、より高い精度で作業を行うことができるようになるはずです。

本記事の内容が少しでも皆様のお役に立てば幸いです。最後までお読みいただきありがとうございました!

レバレジーズテックフェス 2023 春レポート

アイキャッチ

はじめに

こんにちは、レバレジーズ株式会社の堀本・中村です。本記事では私たち2人が運営側として参加したレバレジーズグループ全体のエンジニアが参加するテックフェスの様子をご紹介します。基調講演や、社員によるトークセッションなどについて書いていますので、ぜひ最後までご覧ください。

堀本自己紹介

私は2020年4月にレバレジーズへ新卒入社し、グループ会社であるレバテックでの法人営業を2年間経験したあと、レバレジーズのエンジニアに異動しました。現在は社内業務効率化のツールを開発しています。

中村自己紹介

私は2022年4月にレバレジーズに中途入社し、医療介護領域のオウンドメディアを中心に開発に携わってきました。現在は、レバウェル事業部にてSRE業務に取り組んでいます。

テックフェスとは

レバレジーズグループに所属するエンジニアを対象に、社内で半年に一度行われている技術の祭典です。エンジニアが新しい技術に興味を持ち、勉強をするきっかけを作ることを目的とし、グループ全体の技術力向上を目指します。6月7日に「急がば品質。ワンランク上のレバクオリティへ」というテーマでテックフェス2023春を開催しました。

基調講演

概要

基調講演については堀本がお話ししていきます。 「いかに開発効率と品質を高めるか:ドメイン駆動設計と組織パターンの視点から考える」という題名で、現代のソフトウェア開発に求められる効率性と品質の重要な要素である、ドメイン駆動設計(DDD)と組織パターンについて加藤潤一さんにお話しいただきました。

登壇者紹介

ドメイン駆動設計や関数型プログラミング、アクタープログラミング、OSGiなどのモジュラープログラミングを研究しており、執筆活動や講演、OSSの開発などに取り組んでいる。

  • Chatwork株式会社テックリード。ZOZO技術顧問。
  • 技術評論社 WEB+DB PRESS Vol.63~68 再考するJava 執筆。
  • 日経BP社 日経ソフトウエア 特集 特集2 〜5 執筆。
  • 日経BP社 Javaツール完全理解 第2部 最新Eclipseで良いJavaプログラムを書こう 執筆。
  • ライブラリ Baseunits for Scala 作者。

学んだこと

DDDについては、DDDの基本原則や主要な概念の説明から始まり、どのようにアーキテクチャのパターンに影響を与えるか、またDDDが開発の効率化と品質向上にどのように寄与するかを学びました。 その後の組織パターンについては、どのようにドメイン設計と相互作用し、開発効率の向上に寄与するかを詳しくお話しいただきました。 DDDのお話の際には、ユーザ側にとって重要な部分は必ずしもコアドメインに該当しないとおっしゃっていて、事業側とユーザの価値は別であることに気をつけなければならないと思いました。

内容についての感想

講演の終盤では実際の開発現場で、どのように適用して具体的な成果を出すかまで説明していただき、DDD と組織パターンの理解を深め、開発効率と品質の向上に役立てられそうな有意義な内容でした。 加藤さんがテックリードをされているChatworkでの取り組み事例まで知ることができ、具体的にイメージすることができました。

テックバトル

概要

テックバトルとは

テックバトルについては中村がお話ししていきます。 テックバトルとは、エンジニアがチームに分かれて共通の課題に取り組み、そのスコアで競い合うイベントです。テックバトルは以下を目的として実施します。

  • 楽しむこと
  • テーマを意識し、業務改善に活かすこと
  • チームワークの強化

舞台設定

今回は、「品質」をテーマとして課題を作成し、実務でもあり得そうな以下の舞台設定にしました。 ​

皆さんはSFA開発チームのエンジニアです。
流入求職者の情報をシステムへインポートしたいです。
しかし、そのままではインポートできず、変換が必要です。
​
必要な変換処理が他部署のAPIで実装されていたため、
他部署のAPIを利用して変換することにしました。
​
しかし、APIにはバグがありました。
バグにより出力データが意図しない結果となるため、
正しい形に変換するプログラムを作ることになりました。
​
また、APIにバグが多く他部署メンバーも困っているので、
いろいろな入力値でデバッグして協力することになりました。

課題の詳細

以下で、今回取り組んだ課題を紹介させていただきます。 取り扱うAPIは2種類存在しており、それぞれの出力結果に誤りがあります。

課題で扱うAPIの流れ 参加者が、それぞれのAPI出力を正しく修正するプログラムを作成して処理の中に差し込み、修正済み出力結果を回答として提出します。

課題で取り組むデータ補正の流れ また、それぞれのAPIに対して特定の入力値を与えると、あらかじめ用意された例外コードが返却されます。これをできるだけ見つけ出すのも課題の目的になります。

課題で取り組む例外コード調査の流れ 例外コード調査の具体的な例

運営側が用意していない例外を見つけた場合には、報告することでボーナス点が入ります。

想定外の例外提出方法のスライド

上記のルールで、1チーム3〜4人の制限時間2時間で開催しました。

バトル中の様子

各チーム、活発にコミュニケーションをとりつつ、役割分担をして課題に取り組んでいました。修正プログラムの実装とエラー調査で分けているチームが多く、全体統括に人員を割いているチームもありました。

テックバトルに取り組むエンジニアたち 上位のチームは、作業内容の認識合わせを丁寧に行いつつ素早く役割分担をすることでタイムロスを削減していました。これは実務でも活かされる動きですね。

セッション

セッションについては堀本がお話ししていきます。 今回のセッションでは3名の方が、幅広い分野の発表をしました。

speakerdeck.com speakerdeck.com speakerdeck.com

最優秀の発表について

最優秀の発表は Nalysysグループの桐生さんの「その処理、本当に遅いですか? ~無駄を省く達人になろう~」でした。問いかけられる題名から興味を惹かれます。

発表内容

処理高速化のアプローチを下記4段階に分けて説明しました。 「無駄」のニオイを感じ取る 処理の遅い原因を特定する(計測) 高速化のための手段を考え、実装する 実装した高速化の効果を測定する

感想

処理を高速化する方法は原因や状況に応じて異なるため泥臭くやっていく必要があるとした上で、実際に桐生さんが関わった高速化の事例を紹介してくれました。発表で特に印象に残ったのは、無駄を感じ取るためには処理時間の予測精度を上げることが必要で、計算量について学ぶのと、より細かい内部の仕組みを学んで予測するセンスを磨くことでした。もちろんこの後に予測だけで終わるのではなく、計測までするようにとおっしゃっていました。この2つを勉強して、まずは無駄を感じ取る嗅覚を磨いていきたいと思います。

LT

LTについては中村がお話ししていきます。

発表一覧

今回のLTでは6人の方が、幅広い分野の発表をしました。 speakerdeck.com speakerdeck.com speakerdeck.com speakerdeck.com speakerdeck.com speakerdeck.com

最優秀の発表について

品質よりリリース優先した末路 (山城 直輝さん)

概要

こちらの発表では、品質よりリリースを優先して実装すると何が起こるのか3つのケースで紹介いただきました。具体的に紹介されていたケースは、以下の通りです。

  • 不具合修正のために本番環境のコードを直接いじる
    • 過去に修正した不具合が再発する
  • インフラ環境構築をIaC使わずにGUIで作成
    • 手順も残してないため、環境が壊れても再現できない
  • エラーレベルを考えずにエラー通知を設定
    • 通知が多すぎて重要エラーに気づかない

実際にやってしまったり見かけたことがあったりと、身に覚えのあるエンジニアは多かったようです。

学んだ/考えたこと

初めて使用するインフラリソースだと、まずGUIで作ってみてからIaCで再現するという手順を踏むこともあると思います。できることなら一からIaCで頑張るか、GUIでの設定を並行してIaCで書いていくのも一つの対策になると考えました。全体を通して、 「一旦〜」「とりあえず〜」「後で〜」は封印しなければならないと感じました。

DRY原則を誤った結果生まれた技術的負債 (野中 柊さん)

概要

こちらの発表では、「teratail」での事例を元に、単一責務を考慮せずに誤ったDRY原則に従って実装した際の問題点と改善方法を紹介いただきました。 具体的には、一つのコンポーネントに<a>タグと<button>タグを出し分けさせていた事例でした。これにより以下の問題点が生じます。

  • 内部コンポーネント制御用のPropsが際限なく追加される
  • 制御変数が多くなりすぎて内部実装が複雑になる
  • 他のライブラリの組み込みがしづらくなる
学んだ/考えたこと

以前Atomic Designで実装していたプロジェクト参画時に、大量のPropsを持っているボタンに遭遇しました。どこが再利用したい部分なのか分かりづらく、Propsでの制御量が多すぎて一から定義しても変わらないのでは・・・と感じるほどでした。今回の発表に照らして考えてみると、

  • 実は<a>タグなどの別タグとして切り出すべき機能を持っていた
  • ボタンとしても単一責務を考慮してコンポーネント分割できた

という可能性があります。DRYと単一責務はあらゆるところについて回るので、注意して実装を進める必要性を感じました。

懇親会

テックフェス終了後は、懇親会も開催。ピザやお寿司、ケーキを食べながら発表者へ話を聞きに行ったり、他チームの方と交流を深めている様子が見られました。

最後に

今回の記事では、テックフェスから学んだことや感想を書かせていただきました。加藤潤一さんの貴重なお話を聞けたり、社内のエンジニアから普段は聞けない話を聞けて非常に面白かったです。 社内で技術ノウハウの共有を行なうイベントがあったり、外部から著名な方をお呼びして貴重な話が聞ける環境のレバレジーズで皆さんも一緒に働いてみませんか? レバレジーズに少しでも興味を持っていただけた方は、こちらからエントリーをお願いします!

ぼくらのフロントエンド1.0 - フロントエンドエンジニア育成プロジェクト

はじめに

本記事をご覧いただきありがとうございます。レバレジーズ株式会社 レバテック開発部の三浦です。

4月中旬〜6月末までの2ヶ月半にかけて、弊社レバテック開発部にて「フロントエンドエンジニア育成PJ」と題してフロントエンドをリードできる人材を育成するプロジェクトに参画しましたので、その内容についてご紹介します。

背景

現在、レバテックでは理想のシステムを目指して大規模リニューアルを計画的に進めており、フロントエンドをリードできる人材を増やすことで、よりリニューアルの加速を図ろうとしています。

そこで、フロントエンドエンジニア育成PJでは2ヶ月半という期間でがっつり育成にコミットし、まずは自走しつつ一定の品質でアウトプットできるところまで育成対象者のレベル引き上げることをゴールとしました。

方針としては以下の領域(赤線部分)のベースとなる知識を得るために広く浅く伸ばしていくイメージです。

対象領域のイメージ ※「モダンフロントエンド開発者に求められるスキルとは」より引用

実際には、TypeScript + React + Next.js + MUI で実際に開発しつつ、上記の領域を学習をしつつ社内に発信するということをやっていました。具体的な内容については後述します。

利用技術のアイコン

プロジェクトに参画した育成対象のメンバーは私含め4名でした。いずれもフロントエンドの経験が浅いメンバーで、レガシーな環境で開発をしていたメンバーから営業から異動してきたメンバーまでバックボーンは様々です。

私は人から感謝される仕事がしたいと考えていたため、業務としてより人に近いマネジメント業務をメインでこれまで担当していました。ただ、マネジメント業務を経験していく中で、エンジニアとして人から感謝される価値のある仕事をするためには、しっかりとした技術的なバックボーンが無くてはいけないのではと考えるようになりました。

その中で、上長からこのプロジェクトへの推薦をいただいたことをきっかけに参画に至りました。ちなみに、フロントエンドの経験としてはHTML/CSS/jQueryを多少かじったことがある程度でした。

カギとなったのは圧倒的アウトプット量

このプロジェクトで特筆すべきはとにかくアウトプットにコミットし切ったという点です。 ざっくり2ヶ月半でのアウトプットを並べると以下の通りです。

  • GitHubと連携した開発生産性可視化アプリケーションの新規開発(1ヶ月)
  • 既存で稼働している営業支援ツールのリプレイス(1ヶ月)
  • 4冊の書籍とtype-challengesの内容でQiita記事を作成(計48記事)
  • 4冊の書籍とtype-challengesの内容で社内勉強会を開催
  • 週1回のレビュー会での成果物のプレゼン

開発生産性可視化アプリケーションの新規開発

まず最初の1ヶ月で以下のような開発生産性を可視化するアプリケーションを開発しました。 ここ最近で弊社の開発組織では開発生産性を可視化したいという気運が高まってきており、その流れを汲んで社内向けにTypeScript + React + Next.js + MUIで構築しました。

生産性可視化アプリケーションのキャプチャ

このアプリケーションはGitHubと連携しており、GitHubから取得したデータをもとにFour Keys Metricsやその他PR数などの生産性に関わる指標をグラフで可視化できるようにしています。

営業支援システムのリプレイス

開発生産性可視化アプリケーションを社内リリースした後の1ヶ月で、以下のような既に稼働している営業支援システムのリプレイスを行いました。

営業支援システムのキャプチャ

こちらはレバテックキャリアに登録した求職者が、求人に応募したりエージェントから求人の提案を受けたりすることができるシステムですが、こちらもTypeScript + React + Next.js + MUIの構成でリプレイスしました。

前述した開発生産性可視化アプリケーションでは社内向けということもあり比較的シンプルな仕様でしたが、こちらは実際にサービスとして長らく本番稼働しているシステムであったため、プロダクションコード特有の複雑なロジックの実装を経験することができました。

Qiita記事の作成

上述した2つのシステム開発と並行して、type-challengesと以下の4冊の書籍を学習しその内容をQiitaの記事としてまとめました。

  • プロを目指す人のためのTypeScript入門 (通称 ブルーベリー本)
  • TypeScriptとReact/Next.jsでつくる実践Webアプリケーション開発
  • フロントエンド開発のためのテスト入門
  • フロントエンド開発のためのセキュリティ入門

書籍のイメージ

作成した記事は計48記事で、個々人が1ヶ月に6記事を開発と並行して作成した計算になります。作成された記事は社内に公開されており、React や Next.js を採用している開発チームでも技術のキャッチアップで利用されています。

社内勉強会の開催

学習した内容をもとに、社内で勉強会を開催しました。育成メンバーは全員登壇し、各々で学習した内容をプレゼンしました。

speakerdeck.com

このようなスライドをもとに発表しましたが、弊社ではTypeScriptを採用している開発が多いため、特にtype-challengesの内容が反響がよかったです。

週1回のレビュー会でのプレゼン

これまで述べた開発と学習に関して、記事の作成や勉強会とは別に週1で成果物のレビュー会も実施しました。 こちらは実際の様子を写真等でお見せできず残念ですが、組織のマネージャーとテックリードを招き開発した機能をデモで見せたり、学習した内容についての学びや気づきを共有し、アドバイスをもらうことを実施しました。

育成チームの成果物を週次で社内にSlackで公開し、アウトプットした成果も共有しました。

Slackのキャプチャ

弊社は挑戦する人を否定せず讃える文化が浸透しており、Slackなどで多くのポジティブなリアクションをもらうことができたため、最後までモチベーション高くやり切ることができました。

プロジェクトを通して見えた可能性

私自身、このプロジェクトに参画する前は、開発でフロントエンドに絡む課題や要求が発生した際は解決策がわからず、現場の業務委託や他チームの有識者に技術的なアドバイスやヘルプをよく求めていました。

しかし実際にプロジェクトを終えてみて、フロントエンドに対する自己効力感が明らかにつき、大抵のことは自走して解決できるようになった実感があります。これは、2ヶ月間フロントエンド開発にどっぷり浸かり、とにかく多くのアウトプットを出しまくったことから生まれた自信や成長によるものだと考えています。

現在は新しいプロジェクトに参画し、チームメンバーと日々設計に関する議論を交わしつつ、Next.jsのApp Routerを利用した開発に取り組んでいます。

フロントエンドエンジニア育成PJを通して得た経験はあくまでもきっかけでしかないと思っています。組織のフロントエンド開発の先頭に立ち、もっとエンジニアリングのアツい組織にしていけるよう盛り上げていきます。

おわりに

ご覧いただきありがとうございました。弊社では今組織としてエンジニアリングへの積極投資を進めており、フロントエンドエンジニア育成PJもその文脈にある取り組みです。

前述の通り挑戦を否定せず賞賛する文化があり、やりがいという面でもポジティブにチャレンジできる環境があります。 この記事を通して少しでも弊社に興味を持って下さった方はぜひ採用サイトをご覧ください!

エンジニアのためのGitHub Copilotガイド:レバレジーズの全社導入過程で見つけたノウハウ大公開

はじめに

 こんにちは、レバレジーズ株式会社テクノロジー戦略室室長の竹下義晃です。 エンジニアの生産性を高めよりよいサービスを提供するために、エンジニア全員にGitHub Copilotを導入しました。今回は導入過程でわかったGitHub Copilotを使いこなすための知見を赤裸々に公開していきたいと思います。

GitHub Copilot全エンジニア導入背景

会社の方針

 レバレジーズでは主要サービスであるレバテックレバウェルCareerTicketWeXpatsなどの人材サービスをはじめ、最近ではオンライン診療サービスのレバクリをリリースするなど国や業界に関わらず事業拡大を進め、理念である「顧客の創造を通じて、関係者全員の幸福を追求し、各個人の成長を促す」を追求しています。そのために、開発組織を強化し、より早くより良いサービスの実現を目指しています。

 近年、GitHub Copilotを始め、OpenAI ChatGPTGoogle Bardなど様々なGenerative AIが登場しており、AIを業務に取り入れることで、業務の効率化が様々な分野で進んでいくと考えられます。我々は現在パラダイムシフトの真っ只中にいると考えており、この新しい技術をいかに使いこなしていくかが今後の成功の鍵を握っていると考えています。そのため、まだ評価の固まっていない技術ではあるものの、社内でAIガイドラインを策定し、最大限AIを活用していきたいと考えています。

GitHub Copilotの選定

 GitHub Copilotを選定したのは、Generative AIの中で現時点で最もエンジニアリングの効率化に効果が高いと考えたためです。 主な理由は以下の4点です。

  • フローを維持できるため、業務効率を下げず、開発者体験の向上につながる
  • (おそらく)コード生成AIとして最も性能が良い
  • GitHubが出した調査結果も、良好な結果
  • 個人でも使っているがとても便利

フローを維持できる

 導入した結果業務効率の低下が起きてしまうと意味がありません。GitHub Copilotは各種IDEのプラグインが提供されており、弊社で利用しているVS CodeやIntteliJ、PHP Stormを始め主要なIDE、テキストエディタに対応しています。そのため、IDEの中だけで完結するため、エンジニアのフローを妨げません。Copilot不慣れな場合でも、普通に使うだけで強力な補完機能として利用開始できるため、業務効率を下げる可能性は低いです。

 また、ChatGPTなどのWebサービス型のGenerative AIの場合は、ブラウザと言ったり来たりするためフローを崩してしまい、業務効率を低下させてしまう可能性があります。さらに、適切なタイミングで適切なプロンプトを記述して質問を投げるスキルも必要なため、ある程度のAIリテラシーが無いと効率が上がりきらない可能性もあります。

コード生成AIとして最も性能が良い

 コード生成AIとしては、他にはAmazon CodeWhisperが有名です。性能比較はしていないのですが、こちらの記事だと日本語が怪しかったり、動きがもっさりだったりするようで、アルゴリズムもChatGPTで、学習データとしてもGitHubのデータをファーストパーティーとして使えるGitHub Copilotが最も性能が良いと判断しました。

GitHubが出した調査結果

 データとしても、GitHubの調査結果が公開されており、そこでも開発効率が上がったとレポートされています。

個人でも使っている

 GitHub Copilotが出た直後から個人で趣味の実装時に使っていました。体感値としてもGitHubの調査と乖離もなく、かなりコーディングの効率が上がった実感がありました。

導入過程

 とはいえ、レポートが外部の情報しかなく、いきなり全エンジニアに展開するのは難しかったため、まずは一部のチームにだけ提供し効果測定を行いました。チーム単位でいくつかのチームに導入し、3週間ほど試用してもらった上で定性評価のためのアンケートの実施を行いました。その結果、開発効率が下がったという人はおらず、9割以上の人が開発効率が上がったと回答したため、全エンジニアへの導入に踏み切ることにしました。

アンケートから見えた開発効率を高める方法

分析手法

 分析のために、試用してもらったチームメンバーへアンケートをとりました。アンケート項目は、効率化したかどうかより、高い効率化に成功した人がどのような使い方をしているか、またはどのような環境、状況で使用しているかを見つけることに焦点を当てて作成しました。

 アンケートでは以下の項目を聞きました。

items

 アンケート結果は、python+pandasを使用し数値化と、one-hot encoding(ダミー化)処理を行った後、Googleスプレッドシートで、平均値等の統計分析や、各アンケート項目同士の相関値マップを作成しました。(pandasではこんな感じの処理してます )

結果

統計値

 Copilotの継続利用は評価1~5で、平均4.51でした。また、コーディング効率が上がったかどうかは、下がったと答えた人は0人、1,2割以上上がったと答えた人は全体の70%に達しました。

rating
coding_efficiency

カラム間相関値マップ

corel-map

赤枠で囲った列が、コーディング効率との相関を示しています。黄色く囲ったあたりが相関値が高く出ており

  • 生成コードを、レビューはするが修正はせずに利用
  • テストコードの作成での効率が上がった人

それぞれ、0.5、0.4程度の相関値になっています。

そのため、次のことが言えると考えています。

GitHub Copilotの生成コードをそのまま使っている人ほどコーディング効率が向上する
テストコード生成に使った人がコーディング効率が向上する

フリーテキストからの考察

 高い効率化ができたと感じている人のコメントだけを抜き出し、共通項を探しました。そうしたところ、コメントを書いてコードを生成、または、コードからコメントを生成している人が多くいました。

結論

結果を箇条書きにすると

  • 9割の人が導入に満足している
  • GitHub Copilot導入により開発効率は下がった人はいない
  • 7割以上は体感できるぐらいコーディング効率が高まった
  • GitHub Copilotの生成コードをそのまま使えている人ほどコーディング効率が向上する
  • テストコード生成に使った人がよりコーディング効率が向上している
  • 効率が大幅に上がった人は、コメントを書いてコードを生成、または、コードからコメントを生成に利用している

 現時点でGitHub Copilotを上手く使うコツとしては、テストコードの生成や、コメントからのコード生成、コードからのコメント生成などを中心に、人が修正しなくても良いコードを上手くGitHub Copilotに生成させられれば、高いコーディング効率の向上を見込めるということが言えるかと思います。

余談

GitHubのActivityはまだ分析できていない

 GitHubのActivityも収集し分析も進めていますが、まだ定量的な結果までは出せていません。今後も継続してデータ収集していきたいと考えています。一応、「Copilotを使うチームの出すPullRequest数が、Copilotを使っていないチームより多くなった」ことに有意差は出ていました。定量的な結果とは言えず、データの正確性も検証しきれていないので、参考までにお願いします。

費用対効果(クソ雑概算)

 GitHub Copilot for Businessは月額$18で年間$216、執筆時点の為替1ドル142.46円では日本円にして30771.36円です。

 一方、日本のITエンジニアの平均年収は442万円となるため、その平均から算出される年間3万円分の効率化達成には、 3 / 442 = 0.006 = 0.6%となり、0.6%以上効率が上がるならGitHub Copilotを使うほうがお得となります。定量評価は難しいものの、0.6%以上の作業効率は上がると確信しています。

よりGitHub Copilotを使いこなすためのネクストアクション

全エンジニアでのノウハウの共有の取り組み

 個々で見つけたコツや使い方を共有し、昇華していければと考えいくつかの施策も継続予定です。

常設アンケートと、テクノロジー戦略室による使い方のコツのサマリー共有

 常にGitHub Copilotを上手く使うコツを収集するアンケートを用意し、そこに投稿された内容を毎月サマリーして共有していく予定です。

ノウハウ共有LTの開催

 また、ノウハウ共有の強化としてLT大会も開催を考えています。ライブコーディングなどを通じて、文章だけでは伝わりづらい使い方も共有していければと考えています。

追加分析

 

全エンジニア拡大後に再度アンケート実施

   全エンジニア展開後に再度アンケートは実施予定です。

GitHubでのActivityの分析の継続

 定量的な分析も引き続き行っていきたいと考えています。アンケートからだけでは分析できにくい、言語やドメイン領域など様々な観点からの分析や、アンケート結果の裏付けを行っていければと考えています。

おわりに

 GitHub Copilotの全エンジニア導入により、ユーザーにより早く、より良いサービスを提供できるようになるだけでなく、エンジニアにとっても、開発者体験の向上によってより楽しくサービス開発してもらえると良いなぁと思っています。

 今回はGitHub Copilotの採用とはなりましたが、他にも様々なAIサービスが登場しています。また、社内現在のAIを取り巻く環境はどんどん進化を続けており、もっと良いサービスも出てくるかもしれません。なので、今後もトレンドを追いつつ(追い抜きたい)、どのようにAIを活用すればよいかを探求し続けたいと思っています。

We Are Hiring!

 レバレジーズ株式会社ではエンジニアを募集中です。AIを活用しながらの開発や、AIの活用方法を考えることに興味ある方は、是非こちらのページからご応募ください。