Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
生鮮ECプラットフォームの バックエンドを支えるRails クックパッド株式会社 買物事業部部長 勝間 亮
Slide 2
Slide 2 text
•勝間 亮 (かつま りょう) @ryo_katsuma •2009~ クックパッド入社 ‣レシピ領域バックエンドエンジニア ‣レシピ領域マネージャー •2018~ 買物事業領域立ち上げメンバー ‣副部長 兼テックリード ‣2020~ 部長
Slide 3
Slide 3 text
No content
Slide 4
Slide 4 text
クックパッドマート •2018年〜買物領域の新規事業 •生鮮食材のEC ‣ 半分正しい、半分正しくない
Slide 5
Slide 5 text
クックパッドマート •インターネットで生鮮食材を扱う上での課題 1. 生鮮食材の流通の課題 2. 生鮮ECの課題
Slide 6
Slide 6 text
生鮮食材の流通の課題
Slide 7
Slide 7 text
これまでの流通網 生産・出荷組合 ¥120 市場・直売所 ¥130 仲卸・問屋 ¥150 小売店 ¥150〜198 生産者 ¥50~80 • お届けまで数日〜数週間 • 中間業者が通るたびに利益が乗る構造 • 生産者の手取りは小売価格に比べて少ない
Slide 8
Slide 8 text
解決アプローチ クックパッド マート ¥120〜150 生産者 ¥80~100 •当日集荷、当日配送 • 生産者直売で地域で一番安く買える(= 生産者の手取りを増やせる) • 生産者直売でお届けまでのリードタイムが短い(= 新鮮なままお届け)
Slide 9
Slide 9 text
生鮮ECの課題
Slide 10
Slide 10 text
現状の生鮮EC •個配の配送コスト問題 ‣ 多くのECサービスは最低注文金額3,000~5,000円 ‣ まとめ買いをせざるをえない •再配達問題 ‣ 肉・魚などナマモノは宅配Boxや置き配を適用しづらい ‣ お届け時間に必ず家にいないといけない制約
Slide 11
Slide 11 text
解決アプローチ •敢えて個配をしないピックアップ型EC ‣ 生活動線上に受取り場所を作って自分で好きな時間で取りに行く ‣ 再配達問題を解決 •集荷配送コストの圧縮 ‣ 複数人の注文をまとめて配送することで配送コストを1/N ‣ 生産者の集荷場所も一元化することで集荷コストも1/M ‣ 最低注文金額を0円に
Slide 12
Slide 12 text
No content
Slide 13
Slide 13 text
No content
Slide 14
Slide 14 text
クックパッドマート •生鮮ECサービス •生鮮ECプラットフォーム
Slide 15
Slide 15 text
クックパッドマート •生鮮ECサービス •生鮮ECプラットフォーム
Slide 16
Slide 16 text
クックパッドマートの バックエンド
Slide 17
Slide 17 text
バックエンド •Rails 6.0.2 •Ruby 2.6
Slide 18
Slide 18 text
可能なかぎり素朴なRailsに •MVC以上のレイヤーは極力増やさない ‣ app/services • 複数Modelをまたがる処理 ‣ app/resources • RESTful APIレスポンスのClassを定義するModelのラッパー
Slide 19
Slide 19 text
モノリシックなサービス ‣ ユーザー向けモバイルアプリAPI ‣ 販売者向けWebアプリ ‣ ドライバー向けモバイルアプリAPI ‣ スタッフ向け管理Webアプリ ‣ ハードウェアキッティング会社向け管理Webアプリ
Slide 20
Slide 20 text
モノリシックなサービス •新規事業なので変化がかなり大きい ‣ サービスをまたいだ実装を単純化 ‣ アプリ分割によるModel層の管理の煩雑化を避けたい (DBは共通) •必要になればサービス分割を検討 •必要な外部サービスは適宜利用 ‣ 決済: Stripe / Push通知: Firebase
Slide 21
Slide 21 text
実装も素朴 •の、ように見える
Slide 22
Slide 22 text
実装も素朴? •の、ように見えるかもしれないが。。。
Slide 23
Slide 23 text
現実世界を反映した 設計と開発
Slide 24
Slide 24 text
物体と概念のmodel設計
Slide 25
Slide 25 text
受け取り場所(マートステーション)
Slide 26
Slide 26 text
モデル設計 • ステーションは複数の冷蔵庫を • 冷蔵庫は複数のコンテナを • コンテナは複数の注文商品を • 注文商品は商品にひも付き
Slide 27
Slide 27 text
モデル設計 • Location has_many LocationFridges • LocationFridge has_many LocationFridgeContainers • LocationFridgeContainer has_many OrderItems • OrderItem belongs_to Item
Slide 28
Slide 28 text
モデル設計 • Location has_many LocationFridges • LocationFridge has_many LocationFridgeContainers • LocationFridgeContainer has_many OrderItems • OrderItem belongs_to Item
Slide 29
Slide 29 text
コンテナの内容は日毎に変わる 「ある日のコンテナ状況」を再現するときにSQLだけで解決したい
Slide 30
Slide 30 text
モデル設計 • Location has_many LocationFridges • LocationFridge has_many LocationFridgeContainers • LocationFridgeContainer has_many DeliveryLocationFridgeContainers • DeliveryLocationFridgeContainer has_many OrderItems • OrderItem belongs_to Item 5/10付
Slide 31
Slide 31 text
モデル設計のポイント •現実世界のものをそのままモデリングしても駄目 •現実世界と結びつく「概念」をどう表現するか ‣ 例) モノは同一でも時系列で状況が変わるもの ‣ 表現をミスるとデータ取得が困難に
Slide 32
Slide 32 text
モデル設計のポイント •とはいえ何度も設計はミスってる •DB設計ミスに気づいたら積極的に リファクタリング ‣ 作り直しは許容 ‣ 2度目はさすがにうまくいく
Slide 33
Slide 33 text
物理制約の設計
Slide 34
Slide 34 text
一般的ECの購入時チェック •在庫が存在するかどうか •ユーザー情報が正しいかどうか ‣ 決済情報、住所など
Slide 35
Slide 35 text
集荷からお届けまで
Slide 36
Slide 36 text
集荷冷蔵庫 集荷からお届けまで
Slide 37
Slide 37 text
配送車 集荷からお届けまで
Slide 38
Slide 38 text
受け取り用冷蔵庫 集荷からお届けまで
Slide 39
Slide 39 text
注文処理ではこれらのチェックが必要
Slide 40
Slide 40 text
受け取り冷蔵庫のキャパシティ •注文商品はコンテナに入る必要 ‣ order_items.sum(&:volume) ɹ<= delivery_location_fridge_container.available_capacityɹ ‣ を満たすコンテナがあるかを確認
Slide 41
Slide 41 text
商品毎の重さや体積測定
Slide 42
Slide 42 text
配送車のキャパシティ •ステーションのコンテナが全て車に入る必要 •配送資材(シッパー)にコンテナを入れて配送 ‣ delivery_location_fridge_containers.size <= distribution_routing_shipper.available_capacity ‣ を満たす車内のシッパーがあるかを確認
Slide 43
Slide 43 text
集荷用冷蔵庫のキャパシティ •集荷用冷蔵庫にコンテナが入る必要 •配送コンテナを設置する空き棚があるか ‣ CollectionSpotFridgeAddress .where.not(id: already_assigned_address_ids) .merge(collection_spot_fridge: collection_spot_fridges) ‣ を満たす空き棚があるかを確認
Slide 44
Slide 44 text
採番処理 •注文された商品に ‣ どの配送先冷蔵庫のどのコンテナに入るか ‣ どの配送車のどの資材に入るか ‣ どの集荷元冷蔵庫のどの棚に入るか •の情報(= nanika_id)を付加する採番処理を行う
Slide 45
Slide 45 text
物理制約の設計のポイント •制約の実装は複雑になりがち ‣ 現実世界を表現すると仕方なし(と思ってる) •制約を採番処理と見立ててServiceClassにまとめる ‣ DeliveryLocationFridgeContainerAssignerService ‣ DistributionRoutingShipperContainerAssignerService ‣ CollectionSpotFridgeAddressAssignerService •採番ができない場合は物理制約にひっかかったと見なしてraise
Slide 46
Slide 46 text
物理制約のValidation
Slide 47
Slide 47 text
一見、採番成功していても注意 •タイムセール施策 ‣ 継続率向上 •特定の商品への注文が短期間に集中 ‣ 同一データに対してread/writeが集中
Slide 48
Slide 48 text
実際にあった話 •注文時の採番処理は完了 •早朝にドライバーへの集荷指示データ作成時にraise •
Slide 49
Slide 49 text
実際にあった話 •注文時の採番処理は完了 •早朝にドライバーへの集荷指示データ作成時にraise •ドライバー稼働開始までにデバッグのタイムアタック
Slide 50
Slide 50 text
No content
Slide 51
Slide 51 text
ここから9:00までにデータ不整合を直して ドライバーに指示データを作成しないと集荷が間に合わない
Slide 52
Slide 52 text
起きたこと •決済サービスへの通信も挟まり、transaction処理を 行いづらい •受け取り場所Aの注文データに対して 受け取り場所Aには巡らない配送車の資材IDが採番 ‣ データとしてはIDは採番されている ‣ 採番されるべきでないデータでコンテナが奪われる
Slide 53
Slide 53 text
要するにこうなっていた •DBのデータ的にはValidationはOK •物理世界を考慮したビジネスロジック的にはNG
Slide 54
Slide 54 text
対応方針 •定期データチェックバッチ •DBのデータが ビジネスロジック的に正しいか ‣ 未来の全注文データを定期チェック ‣ 最悪raiseしても落ち着いて対応
Slide 55
Slide 55 text
まとめ
Slide 56
Slide 56 text
まとめ •流通を愚直に表現すると ‣ 物理と概念を的確に紐付けた設計する必要 ‣ 物理世界の制約を表現する必要 ‣ ビジネスロジックを満たすデータかチェックする必要
Slide 57
Slide 57 text
まとめ •愚直に実現することは(ご覧の通り)複雑 •が、それはそれで面白い ‣ 普通のRailsアプリではない技術的な楽しさ
Slide 58
Slide 58 text
No content
Slide 59
Slide 59 text
https://www.wantedly.com/projects/300736
Slide 60
Slide 60 text
ご清聴ありがとうございました