$30 off During Our Annual Pro Sale. View Details »

Rails for backend of fresh EC platform "Cookpad Mart"

Rails for backend of fresh EC platform "Cookpad Mart"

2020.05.13に開催された「オンライン開催!【シューマイ】Tech Lead Engineerから最新技術を学べ!Rails編」で話した「生鮮ECプラットフォームの
バックエンドを支えるRails」についてのスライドです。

Ryo Katsuma

May 13, 2020
Tweet

More Decks by Ryo Katsuma

Other Decks in Technology

Transcript

  1. 生鮮ECプラットフォームの
    バックエンドを支えるRails
    クックパッド株式会社
    買物事業部部長
    勝間 亮

    View Slide

  2. •勝間 亮 (かつま りょう) @ryo_katsuma
    •2009~ クックパッド入社
    ‣レシピ領域バックエンドエンジニア
    ‣レシピ領域マネージャー
    •2018~ 買物事業領域立ち上げメンバー
    ‣副部長 兼テックリード
    ‣2020~ 部長

    View Slide

  3. View Slide

  4. クックパッドマート
    •2018年〜買物領域の新規事業
    •生鮮食材のEC
    ‣ 半分正しい、半分正しくない

    View Slide

  5. クックパッドマート
    •インターネットで生鮮食材を扱う上での課題
    1. 生鮮食材の流通の課題
    2. 生鮮ECの課題

    View Slide

  6. 生鮮食材の流通の課題

    View Slide

  7. これまでの流通網
    生産・出荷組合
    ¥120
    市場・直売所
    ¥130
    仲卸・問屋
    ¥150
    小売店
    ¥150〜198
    生産者
    ¥50~80
    • お届けまで数日〜数週間
    • 中間業者が通るたびに利益が乗る構造
    • 生産者の手取りは小売価格に比べて少ない

    View Slide

  8. 解決アプローチ
    クックパッド
    マート
    ¥120〜150
    生産者
    ¥80~100
    •当日集荷、当日配送
    • 生産者直売で地域で一番安く買える(= 生産者の手取りを増やせる)
    • 生産者直売でお届けまでのリードタイムが短い(= 新鮮なままお届け)

    View Slide

  9. 生鮮ECの課題

    View Slide

  10. 現状の生鮮EC
    •個配の配送コスト問題
    ‣ 多くのECサービスは最低注文金額3,000~5,000円
    ‣ まとめ買いをせざるをえない
    •再配達問題
    ‣ 肉・魚などナマモノは宅配Boxや置き配を適用しづらい
    ‣ お届け時間に必ず家にいないといけない制約

    View Slide

  11. 解決アプローチ
    •敢えて個配をしないピックアップ型EC
    ‣ 生活動線上に受取り場所を作って自分で好きな時間で取りに行く
    ‣ 再配達問題を解決
    •集荷配送コストの圧縮
    ‣ 複数人の注文をまとめて配送することで配送コストを1/N
    ‣ 生産者の集荷場所も一元化することで集荷コストも1/M
    ‣ 最低注文金額を0円に

    View Slide

  12. View Slide

  13. View Slide

  14. クックパッドマート
    •生鮮ECサービス
    •生鮮ECプラットフォーム

    View Slide

  15. クックパッドマート
    •生鮮ECサービス
    •生鮮ECプラットフォーム

    View Slide

  16. クックパッドマートの
    バックエンド

    View Slide

  17. バックエンド
    •Rails 6.0.2
    •Ruby 2.6

    View Slide

  18. 可能なかぎり素朴なRailsに
    •MVC以上のレイヤーは極力増やさない
    ‣ app/services
    • 複数Modelをまたがる処理
    ‣ app/resources
    • RESTful APIレスポンスのClassを定義するModelのラッパー

    View Slide

  19. モノリシックなサービス
    ‣ ユーザー向けモバイルアプリAPI
    ‣ 販売者向けWebアプリ
    ‣ ドライバー向けモバイルアプリAPI
    ‣ スタッフ向け管理Webアプリ
    ‣ ハードウェアキッティング会社向け管理Webアプリ

    View Slide

  20. モノリシックなサービス
    •新規事業なので変化がかなり大きい
    ‣ サービスをまたいだ実装を単純化
    ‣ アプリ分割によるModel層の管理の煩雑化を避けたい (DBは共通)
    •必要になればサービス分割を検討
    •必要な外部サービスは適宜利用
    ‣ 決済: Stripe / Push通知: Firebase

    View Slide

  21. 実装も素朴
    •の、ように見える

    View Slide

  22. 実装も素朴?
    •の、ように見えるかもしれないが。。。

    View Slide

  23. 現実世界を反映した
    設計と開発

    View Slide

  24. 物体と概念のmodel設計

    View Slide

  25. 受け取り場所(マートステーション)

    View Slide

  26. モデル設計
    • ステーションは複数の冷蔵庫を
    • 冷蔵庫は複数のコンテナを
    • コンテナは複数の注文商品を
    • 注文商品は商品にひも付き

    View Slide

  27. モデル設計
    • Location has_many LocationFridges
    • LocationFridge has_many LocationFridgeContainers
    • LocationFridgeContainer has_many OrderItems
    • OrderItem belongs_to Item

    View Slide

  28. モデル設計
    • Location has_many LocationFridges
    • LocationFridge has_many LocationFridgeContainers
    • LocationFridgeContainer has_many OrderItems
    • OrderItem belongs_to Item

    View Slide

  29. コンテナの内容は日毎に変わる
    「ある日のコンテナ状況」を再現するときにSQLだけで解決したい

    View Slide

  30. モデル設計
    • Location has_many LocationFridges
    • LocationFridge has_many LocationFridgeContainers
    • LocationFridgeContainer has_many DeliveryLocationFridgeContainers
    • DeliveryLocationFridgeContainer has_many OrderItems
    • OrderItem belongs_to Item
    5/10付

    View Slide

  31. モデル設計のポイント
    •現実世界のものをそのままモデリングしても駄目
    •現実世界と結びつく「概念」をどう表現するか
    ‣ 例) モノは同一でも時系列で状況が変わるもの
    ‣ 表現をミスるとデータ取得が困難に

    View Slide

  32. モデル設計のポイント
    •とはいえ何度も設計はミスってる
    •DB設計ミスに気づいたら積極的に
    リファクタリング
    ‣ 作り直しは許容
    ‣ 2度目はさすがにうまくいく

    View Slide

  33. 物理制約の設計

    View Slide

  34. 一般的ECの購入時チェック
    •在庫が存在するかどうか
    •ユーザー情報が正しいかどうか
    ‣ 決済情報、住所など

    View Slide

  35. 集荷からお届けまで

    View Slide

  36. 集荷冷蔵庫
    集荷からお届けまで

    View Slide

  37. 配送車
    集荷からお届けまで

    View Slide

  38. 受け取り用冷蔵庫
    集荷からお届けまで

    View Slide

  39. 注文処理ではこれらのチェックが必要

    View Slide

  40. 受け取り冷蔵庫のキャパシティ
    •注文商品はコンテナに入る必要
    ‣ order_items.sum(&:volume) 

    ɹ<= delivery_location_fridge_container.available_capacityɹ
    ‣ を満たすコンテナがあるかを確認

    View Slide

  41. 商品毎の重さや体積測定

    View Slide

  42. 配送車のキャパシティ
    •ステーションのコンテナが全て車に入る必要
    •配送資材(シッパー)にコンテナを入れて配送
    ‣ delivery_location_fridge_containers.size 

    <= distribution_routing_shipper.available_capacity
    ‣ を満たす車内のシッパーがあるかを確認

    View Slide

  43. 集荷用冷蔵庫のキャパシティ
    •集荷用冷蔵庫にコンテナが入る必要
    •配送コンテナを設置する空き棚があるか
    ‣ CollectionSpotFridgeAddress

    .where.not(id: already_assigned_address_ids)

    .merge(collection_spot_fridge: collection_spot_fridges)
    ‣ を満たす空き棚があるかを確認

    View Slide

  44. 採番処理
    •注文された商品に
    ‣ どの配送先冷蔵庫のどのコンテナに入るか
    ‣ どの配送車のどの資材に入るか
    ‣ どの集荷元冷蔵庫のどの棚に入るか
    •の情報(= nanika_id)を付加する採番処理を行う

    View Slide

  45. 物理制約の設計のポイント
    •制約の実装は複雑になりがち
    ‣ 現実世界を表現すると仕方なし(と思ってる)
    •制約を採番処理と見立ててServiceClassにまとめる
    ‣ DeliveryLocationFridgeContainerAssignerService
    ‣ DistributionRoutingShipperContainerAssignerService
    ‣ CollectionSpotFridgeAddressAssignerService
    •採番ができない場合は物理制約にひっかかったと見なしてraise

    View Slide

  46. 物理制約のValidation

    View Slide

  47. 一見、採番成功していても注意
    •タイムセール施策
    ‣ 継続率向上
    •特定の商品への注文が短期間に集中
    ‣ 同一データに対してread/writeが集中

    View Slide

  48. 実際にあった話
    •注文時の採番処理は完了
    •早朝にドライバーへの集荷指示データ作成時にraise

    View Slide

  49. 実際にあった話
    •注文時の採番処理は完了
    •早朝にドライバーへの集荷指示データ作成時にraise
    •ドライバー稼働開始までにデバッグのタイムアタック

    View Slide

  50. View Slide

  51. ここから9:00までにデータ不整合を直して
    ドライバーに指示データを作成しないと集荷が間に合わない

    View Slide

  52. 起きたこと
    •決済サービスへの通信も挟まり、transaction処理を
    行いづらい
    •受け取り場所Aの注文データに対して
    受け取り場所Aには巡らない配送車の資材IDが採番
    ‣ データとしてはIDは採番されている
    ‣ 採番されるべきでないデータでコンテナが奪われる

    View Slide

  53. 要するにこうなっていた
    •DBのデータ的にはValidationはOK
    •物理世界を考慮したビジネスロジック的にはNG

    View Slide

  54. 対応方針
    •定期データチェックバッチ
    •DBのデータが
    ビジネスロジック的に正しいか
    ‣ 未来の全注文データを定期チェック
    ‣ 最悪raiseしても落ち着いて対応

    View Slide

  55. まとめ

    View Slide

  56. まとめ
    •流通を愚直に表現すると
    ‣ 物理と概念を的確に紐付けた設計する必要
    ‣ 物理世界の制約を表現する必要
    ‣ ビジネスロジックを満たすデータかチェックする必要

    View Slide

  57. まとめ
    •愚直に実現することは(ご覧の通り)複雑
    •が、それはそれで面白い
    ‣ 普通のRailsアプリではない技術的な楽しさ

    View Slide

  58. View Slide

  59. https://www.wantedly.com/projects/300736

    View Slide

  60. ご清聴ありがとうございました

    View Slide