RAKSUL TechBlog

ラクスルグループのエンジニアが技術トピックを発信するブログです

ハコベルソリューションチームでのモブプログラミングについて

はじめに

はじめまして!2021年に新卒で入社した横山です!現在はハコベル事業本部 ソリューションチームでハコベルコネクトというサービスの開発を行っています。

ハコベルコネクトは一般貨物の荷主と運送会社との間の配送依頼をWebで行えるようにしたサービスです。車両や依頼先運送会社の管理、請求管理などの配車にまつわる業務をデジタル化することで業務工数を削減することができます。

我々のチームではさらにユーザーの配車工数を削減することをミッションとして日々開発に取り組んでいます。その中で日常的にモブプログラミング(以下モブプロ)やペアプログラミング(以下ペアプロ)を行っているのですが、実際に行っている背景であったり、良かったこと、改善していきたいことなどを紹介します!

> モブプログラミングとは複数人で集まって1つの画面を見ながら書く人と指示を出す人に別れてプログラミングを行> う開発手法です。詳しくは以下の記事が参考になると思います!

モブプログラミングへのいざない | Raksul ENGINEERING

 

背景

ソリューションチームでモブプロを活用しはじめた背景は大まかに2つあります。

1つ目は僕自身が入社してからのキャッチアップに苦労したことです。入社してのオンボードでドメインモデルや既存機能の説明をしていただいたのですが、長年作り上げてきているので複雑になってきており、古くからある機能はドキュメントも少なかったのでキャッチアップがとても大変でした。最近は新しいメンバーが増えてきて、今度は自分がオンボードしないといけない立場にもなってきているので、オンボードフローを改善できないかと考えました。

2つ目は特定の人しか把握していない仕様があることです。初期のサービス開発に携わったメンバーが少なくなってきており、既存機能の実装の背景やドメインモデルに対するドキュメントがなく、知識が属人化していました。新メンバーが加入する頻度も増えてきて、さらに知識や暗黙知の平準化が必要になってきています。

以上のような背景があり、どうすれば改善できるかチームで話し合った結果、普段の開発やオンボードにモブプロを組み込もうとなりました。

 

やってること

サーバーサイドエンジニア同士、フロントエンドエンジニア同士はもちろんのこと、サーバーサイドエンジニアとフロントエンドエンジニア、サーバーサイドエンジニアとQAエンジニアでも行います。

また、新メンバーのオンボードにもモブプロを組み込んでいます。

モブプログラミングの様子

 

サーバーサイドエンジニア同士、フロントエンドエンジニア同士

一番頻度多く行われています。新機能の実装時にはその機能におけるコアの部分を中心にモブプロで実装します。また、新機能でなくても実装が複雑で共有やレビューに時間がかかりそうなものに関してはモブプロで行います。

サーバーサイドエンジニアとフロントエンドエンジニア

フロントエンドとサーバーサイドのエンジニアは基本的にはそれぞれの領域をメインに開発を行いますが、軽微だけどお互いの領域に被って変更しないといけないようなものなどは一緒にペアプロで修正したりします。

サーバーサイドエンジニアとQAエンジニア

RSpec などのテストを対象にモブプロを行っています。古い機能でテストがなくQAエンジニアの手動テストで品質が担保されているような機能を自動でテストできるようにモブプロでテストを追加していっています。

新メンバーオンボード用のモブプロ

新規に入ってきたメンバーにはまずサービス画面を見ながら全体の機能のオンボードと、ドメインモデルに対するオンボードを行います。さらにその後に、オンボード用のタスクをペアプロ・モブプロで行ったり、加入時点でチームで開発している機能のペアプロ・モブプロに参加してもらいコード全体のオンボードを行っています。

良かったこと

新機能のコアとなる部分に対する共通認識ができる

機能のコアとなる部分を議論しながら作るのでこの時点で機能に対する解像度や、実装方針に対する共通認識が生まれます。その結果、後に控えている細々して量の多い作業を同じ認識を持って分担して進めることができるので作業速度も上がりました。また、都度チームでの認識すり合わせを行うので大きな手戻りも少なくなっています。

仕様が複雑な既存機能に対する知見の共有が行えている

仕様が複雑だけど、実装時の背景や実装方針などのドキュメントが残っていない機能に対する機能追加やリファクタリングは読み解くのもつらいですが、得られた知識を他のメンバーに再分配するのも大変です。そのような機能の改修をモブプロで行うことで、互いに理解度を高めながら実装することができ、同時に共有にもなります。

QAエンジニアしか知らなかった仕様などの共有ができた

QAエンジニアの手動テストによって品質が担保されてきたような機能はサーバーサイドエンジニアも把握できていないようなものが多く、テスト追加のモブプロを行うことで仕様の共有になっています。

テストケースの考え方などQAとサーバーサイドの知見が共有できた

「こうゆう場合もテストしておいた方が良いのではないか」とか「この場合のテストはそこまで重要ではない」という議論が、サーバーサイドエンジニアとQAエンジニア両方の視点からの提案で行われるので、テストケースの考え方の知見共有にもなっています。

担当領域を超えた変更も行えるようになった

フロントエンドエンジニアがサーバーサイドのコードを変更したりなど、お互いが書ける、読める範囲が広がることでちょっとした変更などをさくっと実装したりできるようになりました。

新メンバーの立ち上がりが早い

新メンバーのオンボードをモブプロで行うことによって、コード全体の大まかな流れをざっと追うことができたり、分からない事はすぐその場で解決できたりします。また、チームの開発スタイルの共有にもなっており新メンバーの立ち上がりに大きく貢献できていると感じます。

改善していきたいこと

モブプロに参加しなかった人、今後新たに入ってくる人への共有

モブプロに参加した人同士での共通認識や知見の共有は行えています。基本的に共有が必要とされるメンバー全員で行っているので現状では問題はないのですが、得られた情報を永続化はできておらず、その場限りの共有になってしまっています。今後入ってくるメンバーやモブプロに参加してなかった人へも共有する方法などは模索する必要があります。

人によってペースが異なるので深掘りしにくい

特にオンボードにおいてこの問題は発生しました。モブのペースで開発が進むので、途中途中で深ぼってコードを読み込むことができないという意見がありました。モブプロの時間と1人で作業をする時間のバランスやモブプロそのものの進め方を改善していかないといけません。

時間がとられて進捗が遅いように感じる

モブプロを多く行った週は複数人で1つの作業を行うので、リソース効率的には悪くなりベロシティも下がってしまいます。しかし、共有やレビューの時間を短縮できていると考えて許容しています。

まとめ

今回はソリューションチームで行っているペアプログラミング・モブプログラミングの取り組みについて紹介させていただきました。課題に感じていた部分を解決できチーム内の知見共有にはとても役立っています!

ハコベルではエンジニアを絶賛募集中です!

物流業界のDXを加速させる!ハコベル事業を牽引するテックリード候補を募集! | ラクスル株式会社

Datadogを活用したRailsアプリケーションのパフォーマンス改善のススメ

はじめに

こんにちは、ハコベル事業本部 ソリューションスクラムチームの池松です。RAKSUL Advent Calendar 2021 13日目の記事になります。

まだ入社4ヶ月目ですがこういった記事をかかせていただき感謝。

本日は、直近で実施したDatadogを活用したシステムのパフォーマンス改善に関するお話をしたいと思います。

 

背景

ソリューションスクラムチームで開発するハコベルコネクトは、物流における配車業務のデジタル化により、業務自動化・情報一元化を行い、顧客の業務コスト削減を図るサービスです。

ありがたいことに、認知度ランキングでも一位を獲得させていただいており、導入社数も順調に増えてきています。

また、運送業界では12月はクリスマスやお正月などイベントが集中しており、1年で最も忙しい時期で、ハコベルコネクトへのアクセスもが多いときで通常の2〜3倍になることがあります。

こうしたユーザ数の増加や繁忙期の影響で、これまで違和感なく利用できていた機能も徐々にパフォーマンスが悪くなり、UXを著しく下げてしまう問題がありました。

そこでソリューションスクラムチームでは、ハイピークを迎える前にパフォーマンス改善を行うべく、既存の処理のパフォーマンス劣化を引き起こす原因の特定から行うことにしました。

ただ、原因の特定といっても、アクセスが集中するタイミングなどでたまたま重くなるパターンなどもあり、単一のアクセスログなどから調査・改善を進めても、全体への効果としてはイマイチなことが想像されたため、今回はDatadogを活用しました。

初めて利用しましたが想像以上に便利で、もはやDatadogなしでは生きられないぐらいになったので、今回はその機能や使い方について紹介させていただければと思います。

 

要約

  • Datadog APMでは、エンドポイント単位/クエリ単位のパフォーマンス監視が可能
  • それぞれの監視において、合計消費時間の上位から調査・改善していくことで、効率的なパフォーマンス改善が可能
  • 様々な統計情報がわかりやすく可視化されており、パフォーマンスの劣化を引き起こす原因を素早く特定できる
    • エンドポイント単位の監視においては、各リクエストの処理内容・処理時間が可視化されていて、支配的な処理を容易に確認可能
    • クエリ単位の監視では、各クエリがどのエンドポイントから実行されたものかという確認も可能
  • Datadog LogsやMonitorなど他の機能とも連携ができ、運用コストの削減にも効果的

 

 

Datadogとは

SaaS向けのデータ分析プラットフォームで、詳細については公式サイトをご確認いただければと思いますが、今回のパフォーマンス改善という目的では、以下のような機能を提供してくれます。

  • ログ集約・検索
    • すべてのサービス、アプリケーション、プラットフォームからログを自動収集
    • ログ、メトリクス、リクエストトレース間をシームレスにナビゲート
    • ログデータを可視化、アラート表示
  • パフォーマンスの可視化
    • 分散したシステム全体のリクエストをトレース
    • エラー率やレイテンシーのパーセンタイル統計 (p95、p99 など) をグラフ化およびアラート

本記事の解説内容

実際に分析を行う前のインフラ設定やアプリケーション側の設定など、必要な作業はいくつかありますが、本記事ではあくまで導入したときの作業イメージや効果にフォーカスしてお伝えできればと思います

改善の流れ

Datadogの機能の一つであるDatadog APM (Application Performance Monitoring) では名前の通りアプリケーションのパフォーマンス監視を行えます。

Railsインスツルメンテーションを有効にした場合、リクエスト、データベース呼び出し、テンプレートのレンダリング、およびキャッシュの読み取り/書き込み/削除操作をトレースすることができます。

この状態で行える監視は主に2つあります。

1つは、エンドポイント単位のパフォーマンス監視、

もう1つは、クエリ単位のパフォーマンス監視です。

エンドポイント単位のパフォーマンス監視

こちらが画面の全体像です。

主要な可視化機能としては、以下になります。

  • 時間帯毎のリクエスト数
  • 時間帯毎のエラー数
  • 時間帯毎のレイテンシ
  • 時間帯毎の消費時間比率
  • レイテンシの分布
  • 指定期間内のエンドポイント別の統計情報
    • リクエスト数
    • 合計時間
    • P50, P99
    • エラー数・エラーレート

どれも有用な指標ですが、今回特に利用したのが指定期間内のエンドポイント別の統計情報です。

パフォーマンス改善は、やればやるほど効果はでるけど、基本的にはキリがなく、より少ない労力で高い効果を得られることが求められると思います。

そこで、エンドポイント単位でトータル時間の降順に並べ、上位に来るものの中でリクエスト回数が少ないものが、パフォーマンス改善すべき要素が多い可能性が高く、かつ効果が高いと判断して、それらを優先して見直すことにしました。

上記の指定期間内のエンドポイント別の統計情報から特定のエンドポイントを選択すると下記のようなエンドポイント別の統計情報ページに遷移します。

こちらでも時間帯ごとの各種指標やレイテンシ分布が見れ、かつ、以下のような情報も確認できます。

  • エンドポイント内の各種処理ごとの実行時間と処理全体における割合
    • DB/Webなどでの絞り込みも可能
  • 対象のエンドポイントの各リクエストの発生時間帯とそれらのレスポンスタイム等
    • レスポンスタイム順でソートすることができ、最も時間のかかったリクエストも確認可能

上記からエンドポイント全体で時間のかかった処理を統計的に判断できるとともに、局所的に重くなっているリクエストの詳細を確認することなどもできます。

更にリクエストを一つ選択すると、下記のようなリクエスト単位で視覚的にどの処理にどれくらいかかったかわかるような画面が表示されます。

実際みてみるとあるモデルのActiveRecordのインスタンス生成で44%ほど使っていることがわかります。

(モザイクしているので見にくいですがなんとインスタンス数まで表示されます)

例えばこのパターンだと不要なインスタンス生成を行っていないかといった調査につなげることが可能です。

クエリ単位でのパフォーマンス監視

これだけでも十分なのですが、またクエリの観点から改善対象を調査することができます。

こちらがその画面の全体像です。

基本的にはエンドポイント単位でのパフォーマンス監視と同様ですが、クエリ単位での統計情報がこちらには表示されます。

こちらも同様にTOTAL TIMEで降順にならべて、上位の中でリクエスト数が少ないものに注目して調査を行いました。

実際に見てみると、対象のクエリがパルス的に発生していることがわかり、

また下記のようにこのクエリがどのエンドポイントからどれくらい呼ばれているか確認できる機能があるのですが、ある特定のエンドポイントからだけ発生するクエリだということがわかります。

結果として、このクエリ自体重かったので別途処理の改善は行うとともに、別サーバから定期的にAPIが叩れていることが判明し、それらの連携方法を改善することでパフォーマンスの向上につなげることができました。

余談ですが、パフォーマンス改善が行われるとDatadogからお祝いしてもらえたりします。

(watchdogという機能があります)

その他Datadogの活用

今回はAPMに関する説明をメインでしましたが、Datadogには他にもLogsやMonitorなど様々な機能が提供されています。

軽くだけ紹介させていただくと、Datadog Logsはログの集約・検索を行うもので、ログのパース設定などを適切に行うことで検索したいログへのアクセスと統計情報の表示を簡単にできるようにしてくれるものです。

なんとこのLogsとAPMは相互連携可能で、先程のAPMのリクエスト詳細画面からLogsのリンクをたどることで、具体的にどんなリクエストパラメータが付与されていたかなどの確認ができるようになっています。逆にLogsからAPM側にたどることもできるので問い合わせ対応などをより効率的に行うことができます。

Datadog Monitorは、事前に設定したルールに基づき、その条件を満たした場合にアラートを出すことができる機能です。アラートはslack通知することも可能です。例えばですが、私達は5分おきに全エンドポイントに対して特定の秒数を超えるリクエストが発生した場合にアラートを出し、slack通知を送るようにすることでパフォーマンスの劣化を検知できるようにしています。

今後導入を検討している機能としてはDatadog Databasesがあり、こちらはDBと直接agentをつなげることで、クエリの実行計画なども収集することができるものになります。

ほんとDatadogすごいです...

ありがとう...Datadog...

また機会があればこのあたりも紹介させていただければと思います。

おわりに

ハコベルチームでは一緒に働くメンバーを募集しています!

興味ある方はぜひこちらからご応募ください!

物流業界のDXを加速させる!ハコベル事業を牽引するテックリード候補を募集! | ラクスル株式会社

RSpecのformatterをクリスマス仕様に

始めに

こんにちは。ハコベルのサービス開発を担当しているマッチングスクラムのtakiです。RAKSUL Advent Calendar 2021 11日目の記事になります。

 

マッチングスクラムは、ハコベルの中でも荷主と運送会社をつなぐ運送マッチングシステムを開発しているスクラムです。運送マッチングシステムとは、優良ドライバーのみをネットワークすることで、低価格で高品質の配送サービスをマッチングするシステムです。

 

また、開発で主に使用する技術は、Ruby、Railsになります。テストコードでは、RSpecを使用しています。今回は、Advent Calendarということですので、formatterをクリスマスらしくカスタマイズする事例をご紹介します。

デモ

まず、デモをお見せします。bundle exec rspec integer_spec.rb --require ./christmas_formatter.rb --format ChristmasFormatter を実行しました。--requireでカスタムフォーマッターが定義されているファイルを選択し、---formatterで、使用するフォーマッターを選択します。

テストが成功した場合、クリスマスツリー、失敗した場合、ロウソク、ペンディングの場合、星を表示しています。

実装方法

ChristmasFormatterの実装は、以下の通りです。

example_passedexample_failedexample_pendingを定義し、RSpec::Core::Formatters.registerで登録しています。

よく使うNotificationの種類は、以下の通りです。

  • start(一連のテストを実行する前に、通知されます)
  • example_passed(テストが成功した時に、通知されます)
  • example_failed(テストが失敗した時に、通知されます)
  • example_pending(実行しようとしたテストが、ペンドされている時に、通知されます)
  • dump_summary(テスト結果の一覧を表示する時に、通知されます)

詳細は Module: RSpec::Core::Formattersを参照してください。

まとめ

RSpecに独自のフォーマッターを追加するのは、記載した通り簡単です。皆様も独自のフォーマッターを定義して、楽しんでみてはいかがでしょうか?

私たちと一緒に物流DXをソフトウェアの力で推進してくださるエンジニアをラクスルでは積極採用中です!ラクスルでは物流以外の分野でも、業界の仕組みやオペレーションの理解を深めつつ開発を進めることを大事にしています。

興味ある方はぜひこちらからご応募ください!

ラクスルのアドベントカレンダー全編はこちらから

Debeziumを利用したDBを同期する仕組みづくり

はじめに

こんにちは、ラクスル事業所属で現在はグループ会社である株式会社ダンボールワンで開発をリードしている岸野です。

今回はモノリスなシステムをマイクロサービス化していく際に生じるデータベースの分離・移行という頭を悩ませる課題に対して、Debeziumというソフトウェアを利用することで少し楽にしてみようという試みについてご紹介します。

課題背景

ラクスルではRPP(Raksul Platform Project)としてモノリスで巨大なPHPのシステムをマイクロサービスに切り分けるということを行っています。一般的にデータベースを複数アプリケーション間で共有することはバッドプラクティスと言われており、ラクスルでもマイクロサービス化と同時にデータベースの切り出しを行っております。

そういったモノリスなシステムのデータベースを切り出す際に問題になることとしてデータの移行や同期が挙げられます。

例えばもともとモノリス側にある機能と新しく切り出したマイクロサービス側の機能をバチッと切り替えるとモノリス側にある既存データが失われてしまいます。失われても良いデータであれば問題がありませんが注文履歴など移行後も参照を続けたい場合に困ります。

この問題の解決策には様々な物があると思いますが、この記事では事前にデータの移行と同期を行ったうえで実際に動かすシステムを新システム側に切り替えるというパターンについて言及します。

データの移行・同期と言ってもこちらも様々なやり方があるでしょう。

  • データベースのダンプ・リストア
  • 定期バッチによる差分更新
  • ストアドプロシージャ・トリガーによる変更検知とデータの移行プロセスの呼び出し
  • モノリスシステムから新旧両方のデータベースに対して書き込む

例えば新旧でデータベースエンジンが異なる、テーブルスキーマが異なる、よりリアルタイムに変更を同期する必要があるといった場合に上記の手段では難しいかもしれません。

そこで今回ご紹介するのがDebezium https://debezium.io/ というソフトウェアを使ったデータ同期の仕組みづくりです。

Debeziumとは

RedHat社が開発しているオープンソースソフトウェアで既存データベース上の変更を即座に検知しイベントとしてKafkaに記録することができます。Debezium自体はKafka connectとして実装されておりMySQL、PostgreSQL、MongoDBなど様々なデータベースエンジンに対応しています。

特徴として既存アプリケーション・データベースに手を加えること無くDebeziumを導入することができるので既存システムの再構築・移行に向いています。

例として以下のように構成することでモノリスDB側の変更を即座に新システムDBに反映する仕組みを作ることができます。

Railsプロジェクトに導入してみる

構成

それでは実際に2つのRailsアプリケーション間でデータベースの同期を行う仕組みを作ってみます。サンプルコードはこちらです https://github.com/YusukeKishino/debezium-rails-sample

サンプルコードは以下のような構成になっています。

Debeziumを用いることで異なるデータベース間でのデータ同期が行えるためold_appにはPostgreSQLを使用しnew_appにはMySQLを使用しています。

また、スキーマが異なるテーブル間でもnew_app側でスキーマの変換を行えるので以下のような2つのテーブルを用意しました。

old_app/db/migrate/20211203083448_create_users.rb

class CreateUsers < ActiveRecord::Migration[6.1]
  def change
    create_table :users do |t|
      t.string :name

      t.timestamps
    end
  end
end
new_app/db/migrate/20211203084401_create_users.rb

class CreateUsers < ActiveRecord::Migration[6.1]
  def change
    create_table :users do |t|
      t.string :first_name
      t.string :last_name

      t.timestamps
    end
  end
end

基本的にold_appもnew_appもrails new —minimalrails g scaffold user name:stringで作成した簡単なCRUDアプリケーションになっています。

karafka gem

Kafkaに貯められたデータを取得(consume)するために利用しているのがkarafka gem https://github.com/karafka/karafka になります。karafkaはKafkaベースのRubyアプリケーションの開発を容易にするためのフレームワークです。karafkaはRailsベースのアプリケーションをはじめどのようなアプリケーションにも組み込めます。

使用方法の細かい説明は省きますが以下のようにKafka上のtopicとそれに対するconsumerを紐付けるような形で使用します。

new_app/karafka.rb

...
consumer_groups.draw do
  topic 'old_app_development.public.users' do
    consumer UserConsumer
  end
end
...
new_app/app/consumers/user_consumer.rb

class UserConsumer < ApplicationConsumer
  def consume
    params_batch.each do |message|
      puts "Message payload: #{message.payload}"
      data = message.payload['payload']['after']
      puts data

      name = data['name'].split(' ')
      user = User.find_or_initialize_by(id: data['id'])
      user.assign_attributes(first_name: name.first, last_name: name.last)
      user.save!
    end
  end
end

この例ではold_appではnameの1カラムにまとまっている名前をnew_appのテーブルスキーマであるfirst_nameとlast_nameに分けて保存する実装になっています。このようにconsumer側でテーブルスキーマの差異を吸収できるのでデータ移行に向いているのではないかと思います。

Debeziumの設定

Debeziumの起動後はAPIを用いて操作します。Debeziumにはconnectorという概念があります。connectorにはどのデータベースのどのデータをどのようにキャプチャするかなどを設定します。

  • どのデータベースを: データベースエンジンや接続情報の設定
  • どのデータを: データベース全体や特定のテーブルに絞るなどキャプチャ範囲の設定
  • どのように: 新規の変更のみや既存データ含めすべてのデータなど同期方法の設定

詳細はドキュメントを参照ください。https://debezium.io/documentation/reference/1.7/

以下の例ではold_appのPostgreSQLデータベースに対して既存含めすべてのデータを同期するような設定を行っています。

curl --location --request POST 'localhost:8083/connectors/' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data-raw '{
    "name": "test-connector",
    "config": {
        "connector.class": "io.debezium.connector.postgresql.PostgresConnector",
        "tasks.max": "1",
        "database.hostname": "postgres",
        "database.port": "5432",
        "database.user": "raksul",
        "database.password": "password",
        "database.dbname": "old_app_development",
        "database.server.name": "old_app_development",
        "plugin.name": "pgoutput"
    }
}'

デモ

それでは実際に動かしながら挙動を見てみます。

まず各アプリケーションを立ち上げるとold_appにはTarou RAKSULYusuke Kishinoの2つのレコードがあり、new_app側にはレコードが存在していない状態です。

(分かりづらいですが3000ポートがold_app, 3001がnew_appになります。)

ここでDebeziumに対してold_appのデータをKafkaに同期するように上記curlコマンドを実行します。そうすると既存データの内容がKafkaに連携されkarafkaでは以下のようなデータを受け取ることができます。こちらも詳細は省きますがテーブルの構造情報や現在のデータの内容が記載されています。

{
  "schema" => {
    "type" => "struct",
    "fields" => [
      {
        "type" => "struct",
        "fields" => [
          {
            "type" => "int64",
            "optional" => false,
            "default" => 0,
            "field" => "id"
          },
  ...
  長いので中略
  ...
  },
  "payload" => {
    "before" => nil,
    "after" => {
      "id" => 1,
      "name" => "Tarou RAKSUL",
      "created_at" => 1638963127972413,
      "updated_at" => 1638963127972413
    },
    "source" => {
      "version" => "1.7.1.Final",
      "connector" => "postgresql",
      "name" => "old_app_development",
      "ts_ms" => 1638963144898,
      "snapshot" => "true",
      "db" => "old_app_development",
      "sequence" => "[null,\"23547008\"]",
      "schema" => "public",
      "table" => "users",
      "txId" => 564,
      "lsn" => 23547008,
      "xmin" => nil
    },
    "op" => "r",
    "ts_ms" => 1638963144898,
    "transaction" => nil
  }
}

この情報をもとにnew_app側でデータを更新してあげることで以下のように既存データの移行に成功しました。

 

次は新規データの追加と更新を試してみます。

新規データの登録と既存ユーザー情報の更新を行いました。するとこの場合も同様にKafkaに変更が連携され、new_app側で処理をすることで以下のように最新の状態に追従することができました。

レコードが削除された際の実装は今回行っていませんが削除された際の挙動をConsumerに実装すれば問題なく動くと思います。

終わり

このDebeziumを使用したデータベース同期の仕組みは現在検証段階でこれから本番利用を試みようとしている段階です。それによりさらなる知見を得る事ができたら、またご紹介をしたいと思います。

ラクスルではエンジニアを募集しています!

ラクスルのアドベントカレンダー全編はこちらから

物流効率化システム開発で学んだYAGNIの原則の効果

世の中にはプログラミングのベストプラクティスとして紹介される原則があります。例えばDRY, KISS, SOLIDなどが挙げられます。

ハコベルのサービスを作ってきた歴史を振り返ってみると、YAGNIの原則に近い意思決定だったなと思うものがありました。その判断もたらした影響を、YAGNIの原則に従うメリットの事例として紹介したいと思います。今回紹介する事例と現在我々が取り組んでいること、両方が物流の効率化に関わるものとなっています。当時の想定と現在の取り組み、その違いと今後の展望についても併せて紹介していきます。

YAGNIとは

Wikipediaでは以下のように定義されています。

機能は実際に必要となるまでは追加しないのがよいとする、エクストリーム・プログラミングにおける原則である。 https://ja.wikipedia.org/wiki/YAGNI

"You ain't gonna need it" のアクロニム(頭字語)でYAGNIです。

実体験の紹介

ハコベルについて

まず背景として、ハコベルのサービスについてざっと紹介します。

現在ハコベルでは大きく2つの分野に向けてサービスを提供しています。一般の方も利用していただける物流リソースのマッチングサービス、企業の運送部門・運送会社の方の物流DXを支えるソリューションサービスの2つがあります。

https://www.hacobell.com/matching

https://www.hacobell.com/solution

今回はそのうちDXソリューション、企業向けのサービスの開発においての体験談です。

概要・背景

物流において重要な情報としては、依頼主、届け先、荷物の内容、集荷・配送日時が挙げられます。依頼主が品物を配送する依頼をするのがスタートです。集荷日になるとトラックは集荷地に向かい、荷物を積み、届け先に向かいます。届け先は1つの場合もあれば、複数地点が指定され順番に届けて回るケースもあります。

作らなかった機能

開発初期に、トラック運行の効率化のために注文を結合する機能を作るアイディアがありました。運行にかかる時間とコストを減らすことにつながり、機能として提供することでユーザーがサービスに魅力を感じるのではないかとする仮説です。例えば運送会社が複数の顧客注文を受け、そこに同じ配送先への配送があった場合、同じトラックに積み、まとめて納品をするようなケースを想定していました。

しかし、サービスのローンチに向けて、その機能は複雑なのでリリース時点からはスコープから外すことにしました。これはYAGNIの原則に従った決定だったと言えます。

後に与えた影響

後になってスコープから外した影響について考えてみたところ、サービス、技術両方の点で大きな影響があったとこに気づきました。

サービス面の影響

企業向けの物流においては、依頼主は製造業の物流部門担当者であるケースが多いです。彼らは自分のコストが低くなるよう考えた上で発注をしています。トラックを手配するのであれば、できるだけ積載率が高くなるように組み合わせて発注します。つまり、運送会社が注文を統合しようにもトラックにほかの注文の荷物を積めるスペースがないのです。

物流の品質の上でもリスクがあります。誤配送や配送遅れが起きる可能性が、配送の内容が複雑になることで高まります。またその場合リスクを誰が負うのか、再配送などのコストを負担するのかの問題も出てくるでしょう。

仮に注文結合の機能を作っていたとしたら、全く使われない機能となり開発に費やした時間が無駄になっていたでしょう。それだけではなくコードの複雑さが増すことで、機能の追加が難しいという問題を抱えていた可能性もあります。

後に述べますが、ハコベルでは物流における注文の最適化については現在別の方向からアプローチをしています。業界の理解を深めてから進めれる状況になった点でもYAGNIの原則に従った良い影響だったと言えるでしょう。

技術面の影響

同時に技術の観点、特にデータの構造の面でもこれまでの開発に対して良い影響を与えてくれました。データベースのテーブルの構造にこのYAGNIな機能を反映しなかったことで「注文」の単位がはっきりし、余計なデータ属性を持たない状態となりました。以下は当時の資料のイメージになります。詳細はぼかしていますが、複雑なデータになっていた可能性があるということをご理解いただけるのではないでしょうか。

このような複雑さをデータ構造に持ち込まなかったことで、テーブルごとの指す範囲が分かりやすく、拡張の難易度が上がらずに済んでいるように思います。

注:もちろん注文の結合機能を作っていてもデータ構造をシンプルにするこは可能でしょう。しかし機能の取捨選択により、シンプルさをより保ちやすい状況になっていたと考えています

DBの寿命はアプリより長い、ともいいます。

参考:DBの寿命はアプリより長い! 長生きするDBに必要な設計とリファクタリングを実践から学ぶ - エンジニアHub|Webエンジニアのキャリアを考える!

データ構造についてはすぐに「まだ不要」と判断するよりもドメインの分割、イベントとリソースへの分類などの整理などはしっかりやっておくのが拡張しやすいシステムとなるように感じます。YAGNIの定義でも「機能」と書いていることはとても示唆的に思えますね。

技術的に初期投資リターンが大きい、後から変更するコストが大きい場所に集中できるのも、YAGNIの原則を意識することのメリットです。

注:実際の開発の中ではチームで取り組み、ディスカッションを経て決断をしています。今回は分かりやすさのためにその経緯などは省略してお伝えしてきました。
また、結果的に切り捨てましたが、その機能についてディスカッションをしたこと自体を批判するものではありません。モデルの設計をより拡張可能にする過程だったと捉えています。

ハコベルが目指す物流の効率化

初期にはフォーカスしてプロダクトを開発し、機能を少しづつ増やしてきた結果、利用いただいている企業様も増えてきました。その中で物流業界についての理解も深まり、視野も広く持てるようになってきたように思います。

その過程で学んだ結果として、現在我々は依頼主が発注する段階で効率化することが物流の効率化に強く影響するポイントだと考えています。それを実現できるサービスを提供をするべく開発を進めており、NTTロジスコ様と共同で「輸配送計画自動化システム」の開発を行うなど成果が出始めています。

ハコベルとNTTロジスコが「輸配送計画自動化システム」の実証実験を実施

とはいえまだまだやることは山のようにあります。引き続きソフトウェアの力を活用して物流業界のDXと効率化、それをユーザーが快適に利用できるようなシステムを、高いレベルで提供することを目指しています。

この物流の効率化の仕組みに少しでも興味を持っていただける、私たちと一緒に物流DXをソフトウェアの力で推進してくださるエンジニアをラクスルでは積極採用中です!ラクスルでは物流以外の分野でも、業界の仕組みやオペレーションの理解を深めつつ開発を進めることを大事にしています。

興味ある方はぜひこちらからご応募ください!

https://hrmos.co/pages/raksul/jobs/HIU-TECH9

ラクスルのアドベントカレンダー全編はこちらから

https://qiita.com/advent-calendar/2021/raksul