サービス開発速度に着目したソフトウェアアーキテクチャ/Software architecture for effective service development at Cookpad

サービス開発速度に着目したソフトウェアアーキテクチャ/Software architecture for effective service development at Cookpad

東京大学 メディアコンテンツ特別講義I

6f8e101c016fa7ebbe58e693dbd86b7d?s=128

Issei Naruta

June 15, 2018
Tweet

Transcript

  1. サービス開発速度に着目した ソフトウェアアーキテクチャ 成田 一生
 クックパッド株式会社 執行役 CTO 2018/06/15 ϝσΟΞίϯςϯπಛผߨٛ*

  2. ੒ాҰੜ ͳΔ͍͍ͨͬͤ  !NJSBLVJ ΫοΫύουגࣜձࣾࣥߦ໾$50 ೥ੜ·Ε Ѫ஌ݝग़਎

  3. 4/4 ࡱӨ ˞ൃදࢿྉ͸ࣄޙެ։͠·͢ γϟολʔԻ ✔ ✔ ✗ ͝͸Μ ✔

  4. 今日話すこと • サービスを素早く開発し、
 長く運用するということ • サービスや組織の成長に合わせて
 どのような技術投資をしてきたか

  5. None
  6. 毎日の料理を楽しみにする Make everyday cooking fun ! Since 1997

  7. ྉཧϨγϐ౤ߘɾݕࡧαʔϏε

  8. શੈք
 ݄ؒར༻ऀ਺໿ઍສ ༗ྉձһ໿ສਓҎ্ ˞೥݄࣌఺ !" # ! શੈք໿ສϨγϐ

  9. 会員事業 広告事業 Revenue sources (ユーザー向け:月額280円) (クライアント向け) ˞੫ൈ͖

  10. 100ヶ国でNo.1を目指して

  11. 英語

  12. インドネシア語

  13. スペイン語

  14. アラビア語

  15. 食文化の数=言語の数?

  16. スペイン語が公用語 25%以上の割合で話されている 10 - 20%の割合で話されている 5 - 9.9%の割合で話されている スペイン

  17. 食文化の数≠言語の数 • 国や地域が異なれば
 気候 / 食材 / 味の好み / 信仰


    などが異なる
  18. 23言語 / 68か国 対応 ※2018年6月時点

  19. None
  20. 歴史

  21. 

  22. 

  23. 

  24. 

  25. %$ 

  26. ΤϯδχΞ਺ͷมભ # ######## ######## ### ########## ########## ########## ########## ##########

    ########## ########## ########## ########## ##########  ਓ  ਓ͘Β͍  ਓ͘Β͍
  27. Japan Indonesia Lebanon Hungary Spain US Cookpad Developers are in:

    UK Taiwan and more… Greece India Russia ೥݄࣌఺
  28. None
  29. ೥ೖࣾ౰࣌ɺ ΤϯδχΞ͸ਓఔ౓

  30. μΠχϯάςʔϒϧͰશһू·ΕΔ

  31. ࠓ ਓఔ౓
 ʢܙൺणΦϑΟεʣ

  32. શһ෼ͷ੮͸ͳ͍

  33. 

  34.  શੈք໿ઍສϢʔβ݄ 

  35. 組織・サービスの成長と 技術の関係?

  36. 「開発しやすさ」 への投資

  37. 初期から
 「素早い開発サイクル」を
 経営レベルで重視していた →なぜ?

  38. サービス開発は
 難しい

  39. サービス開発は とにかく難しい

  40. サービス開発の難しさ ゴールが分からない Ϣʔβͷཉٻ͸ຊਓΛؚΊͯ୭ʹ΋Θ͔Βͳ͍ Ϣʔβͷཉٻ͸࣌ؒͱͱ΋ʹมΘ͍ͬͯ͘ 今いる場所がわからない ։ൃऀ͸ࣗ෼ͷαʔϏεΛਖ਼͘͠ཧղͰ͖ͳ͍

  41. ΰʔϧ͕نఆͰ͖Δ ੡඼ઃܭ ΰʔϧ͕نఆͰ͖ͳ͍ αʔϏε։ൃ

  42. Measure Learn product idea data Build 仮説から
 プロダクトに プロダクト
 からデータに

    データから 仮説に BML ループ
  43. サービス開発の必殺技は無いけど、
 学びのサイクルを仕組みにすることは
 できる →いかに高速に失敗できるか

  44. 技術選定

  45. サービス開発と技術選定(1) 早く作って早くリリースできること 実際のユーザに当てない事には、 仮説の価値は分からない

  46. サービス開発と技術選定(2) コードの寿命が長い 作って終わりではなく、長い改善の道 環境の変化への追従(技術、人) 技術的負債になりにくくするには?

  47. サービス開発と技術選定(3) 組織・事業継続性 来年もその技術って存在するの? エンジニアに嫌われる技術を選ぶことの意味

  48. サービス開発に必要な技術 速く書けて、みんなが読めて、
 長期間のメンテがしやすい言語/フレームワーク

  49. そんなのあるのか

  50. Ruby on Rails はギリギリそう

  51. 

  52. Rails? 当時は事例も少なく、
 そこまで流行っているわけではなかったが… 記述量が少なく、可読性が高い
 アジャイル開発に向いているとされていた 現在ではコミュニティが成熟し、定番に

  53. 「レールに乗る」

  54. IUUQTCBTFDBNQDPN

  55. IUUQTTQFBLFSEFDLDPNB@NBUTVEBUIFSFDJQFGPSUIFXPSMETMBSHFTUSBJMTNPOPMJUI 

  56. None
  57. 恒例の rake stats ൛ +----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines |

    LOC | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 32806 | 26480 | 311 | 2746 | 8 | 7 | | Helpers | 13384 | 10888 | 17 | 1234 | 72 | 6 | | Models | 74920 | 59022 | 1303 | 6642 | 5 | 6 | | Mailers | 1727 | 1389 | 40 | 170 | 4 | 6 | | Workers | 0 | 0 | 0 | 0 | 0 | 0 | | Chanko units | 6401 | 5333 | 2 | 160 | 80 | 31 | | Libraries | 33764 | 28140 | 381 | 2463 | 6 | 9 | | Feature specs | 44276 | 35545 | 0 | 177 | 0 | 198 | | Request specs | 781 | 615 | 0 | 0 | 0 | 0 | | Routing specs | 406 | 328 | 0 | 0 | 0 | 0 | | Controller specs | 49339 | 40751 | 6 | 77 | 12 | 527 | | Helper specs | 4152 | 3431 | 0 | 9 | 0 | 379 | | Model specs | 65320 | 53596 | 2 | 55 | 27 | 972 | | Worker specs | 0 | 0 | 0 | 0 | 0 | 0 | | Chanko unit specs | 3012 | 2400 | 0 | 1 | 0 | 2398 | | Library specs | 16327 | 13544 | 17 | 78 | 4 | 171 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total |346615 |281462 | 2079 | 13812 | 6 | 18 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 131252 Test LOC: 150210 Code to Test Ratio: 1:1.1
  58. 1,300 models

  59. でかいと何が起こるのか 起動に時間がかかる テストに時間がかかる 静的解析系ツールが動かない ライブラリが動かない デプロイが大変 レールに乗れない

  60. コードや環境の老朽化

  61. ͳͥਓ͸ 全部書き直しͨ͘ ͳΔͷ͔

  62. 2010頃 全リニューアル計画

  63. リニューアル計画 (2010) • エンジニア15人くらい • コードが巨大・複雑すぎて、新機能の実装が困難 • そもそも今のサービスはこれでいいのだろうか? • コードもサービスも理想的な状態にした、


    俺たちの考えた最高のクックパッドにしよう w Α͠ϑϧεΫϥονͰॻͧ͘
  64. リニューアル大失敗

  65. 何が起こったのか 「サービスのコアバリューを抽出する」 「綺麗なコードでイチから書き直す」 の両方を同時にやろうとした ˠ͍ͭ·Ͱܦͬͯ΋࣮૷͕ऴΘΒͳ͍

  66. 仕様の整理と リファクタリングを 同時にやらない方がいい ֶͼ

  67. 手遅れになってから やらない ֶͼ

  68. 2007年の Rails 移行は
 なぜうまくいったのか エンジニア5人 Rails に詳しい社員 0人 それほど日本で流行ってない

  69. 当時の関係者の証言 • サービスの機能がまだ少なかった • すでにぼろぼろだったから、
 それ以上失敗しようがなかった • そもそもそんなに成功していなかった ‣ (移行はしたが、当初かなり不安定だった)

    • 若かった
  70. ではどうすればいいのか

  71. 本当に欲しいものは
 何だったのか?

  72. なぜ書き直したかったのか • サービスの継続的な改善がしたかった ‣ 謎の複雑なレガシーコードが多すぎて
 機能の改善や追加が困難

  73. ϨΨγʔίʔυΛ
 શ෦ॻ͖௚͞ͳͯ͘΋
 ։ൃ଎౓Λམͱͣ͞
 ܧଓతͳվળ͕Ͱ͖ΔΑ͏ʹ ͢Ε͹͍͍ͷͰ͸

  74. ϦχϡʔΞϧࣦഊ͕ੜΈग़ͨ͠ Chanko

  75. Chanko 本番環境でのトライ&エラーを
 支援する Rails 用 gem Unit という単位で既存コードへのパッチを記述 IUUQTHJUIVCDPNDPPLQBEDIBOLP

  76. ৽σβΠϯ

  77. 既存コードの書き換え • レガシーコードをいじるリスク • 雑に書くと予期しないエラーになる場 合があるかも • 新デザインを気軽に検証したいだけな のに!

  78. " # 既存のコード A を、スタッフユーザのみに対して ベータ版のコード B に置き換えたい ただし、B は冒険的な実装なので、例外が発生するかもしれない

    既存の Controller のコード ベータ版のコード
  79. ελοϑͳΒ# #Ͱྫ֎͕ى͖ͨΒ" ελοϑҎ֎ͳΒ" ϑϥάͰ෼ذ͍ͤͯ͘͞ͱίʔυ͕ԚΕ͍ͯ͘

  80. ベータ機能の Unit 既存の Controller のコード " # Chanko では、Unit というファイルにベータ機能のロジックを記述する

    invoke 条件を満たした場合に、既存ロジック (A) の代わりに Unit (B) が実行される B が例外を起こした場合は、元の A が実行されるため、ユーザにはエラーが返らない JOWPLF৚݅
  81. 無事に価値が認められたら 本番の品質のコードに仕上げる 既存コードを書き換え、Unit ファイルを消す
 (通称 Un-chanko)

  82. Chanko • 既存のコードをほぼ汚さずに機能の置 き換え実験ができる(Chanko Unit) • もし Unit 内で例外が起きたら、既存の コードが実行される

    • Chanko Unit は汚く書いてもいいけ ど、Un-chanko 時にはリファクタリン グしようね、という運用
  83. Measure Learn product idea data Build プロダクト
 からデータに データから 仮説に

    BML ループ 仮説から
 プロダクトに
  84. Chanko で実現したこと • 本番環境をステージングのように
 使えるようになった • 本物のデータ、本物のユーザ • 「スタッフ限定」「10%限定」で
 サービスの価値検証

  85. すばやく開発しつつ すぐに本番で検証 しかもコードは汚れにくい (消しやすい)

  86. コード品質

  87. コード品質はビジネスに 影響するか?

  88. クックパッドの答え: YES

  89. コードの品質 • 可読性 • メンテナンス性 • バグの有無 • セキュリティ

  90. コードの品質が影響するもの • 開発効率 • 属人性 w ίʔυͷण໋

  91. どこまでやるべきか? やりすぎない 「綺麗なコード」を書くこと自体が目的ではない 事業フェーズにとって必要な品質までを目指す

  92. コードレビュー 質の高いコードレビューがコード品質を ある程度担保する 負の遺産を残しにくくなる

  93. コードレビューアンチパターン • 些細な文法の好みで揉める ‣ インデント、括弧など ‣ とにかく不毛

  94. コード規約があると コードレビューの効率が 良くなる ֶͼ

  95. IUUQTHJUIVCDPNDPPLQBETUZMFHVJEF

  96. None
  97. 特徴 そんなんどっちでも いいだろというのも 結構決めてる

  98. 3年くらい運用してみて • 最初は反対意見も多かった(僕も) • ビジネスのコードレビューなのに文法の しょうもない論争が展開される、
 みたいなのを見かけなくなった ‣ 文法の論争はスタイルガイドの方で
 やればよい

    • あってよかったスタイルガイド
  99. J04"OESPJEͰ͸ࣗಈίʔυϨϏϡʔCPU %BOHFS Λར༻ IUUQEBOHFSTZTUFNT

  100. 自動レビューbot • コーディングスタイルの Lint • 静的解析によるバグ検知 • OSSライセンス情報のチェック • アプリのビルド

    • deploygate 等への配信
  101. ˞೥݄࣌఺ ࠓिͷϨϏϡʔίϝϯτ਺ ࠓिͷ13਺

  102. コードレビューの
 生産性は
 開発効率において
 死活問題

  103. 効率よく開発しつつ メンテナンス性を保てる ようにするための工夫

  104. マイクロサービス

  105. IUUQTTQFBLFSEFDLDPNB@NBUTVEBUIFSFDJQFGPSUIFXPSMETMBSHFTUSBJMTNPOPMJUI 

  106. 「モノリシック」な
 サービス

  107. None
  108. None
  109. サービス分割のイメージ API

  110. API 認証 ユーザ 基盤

  111. API 認証 ユーザ基盤 決済

  112. API 認証 ユーザ基盤 決済 動画基盤 レシピデータ

  113. API 認証 ユーザ基盤 決済 動画基盤 レシピデータ Web

  114. マイクロサービス # # 決済 動画基盤 Web ## # # #

    αʔϏεΛҙຯͷ͋Δ୯ҐͰ෼ׂ͢Δ͜ͱͰ ҰͭҰͭ͸খ͘͞ɺ։ൃ͠΍͘͢ͳΔ
  115. メリット • 小さなアプリケーションとして
 開発できる • メンテナンスしやすい • 責任感が持ちやすい • 組織のスケーラビリティ

  116. デメリット • 結合テストが困難 • システム全体が爆発的に複雑に ‣ 障害の伝播問題 ‣ 管理の困難さ ‣

    監視、可視化
  117. API 認証 ユーザ基盤 決済 動画基盤 レシピデータ Web

  118. API 認証 ユーザ基盤 決済 動画基盤 レシピデータ Web

  119. API 認証 ユーザ基盤 決済 動画基盤 レシピデータ Web

  120. API 認証 ユーザ基盤 決済 動画基盤 レシピデータ Web

  121. None
  122. 世の中の流れは マイクロサービスへ • Docker を中心としたエコシステムが 急速に発達 • 技術的な「定石」ができつつある

  123. サービスメッシュ • マイクロサービス同士を
 適切に連携させて、
 うまく制御する技術

  124. &$4UBTL LTQPE サービスA サービスB サービスC αʔϏε͝ͱʹϓϩτίϧΛ࣮૷͢Δඞཁ͕͋ͬͨ ίϯςφ

  125. αΠυΧʔͱͯ͠ಈ࡞ͤ͞Δɺ
 ϚΠΫϩαʔϏε޲͚ϓϩΩγ

  126. &OWPZͰαʔϏεؒͷ௨৴Λந৅Խ ɾαʔΩοτϒϨʔΧʔ ɾϩΪϯάɺ؂ࢹ౳ͷڞ௨Խ サービスA サービスB サービスC

  127. 1SPNFUIFVT QSPNWJ[ʹΑΔαʔϏεؒ௨৴ͷՄࢹԽ ʢ࣌ؒʹ༨༟͕͋Ε͹σϞʣ

  128. 進捗

  129. rake stats +----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines | LOC |

    Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 53487 | 43106 | 578 | 4326 | 7 | 7 | | Helpers | 16467 | 13482 | 19 | 1544 | 81 | 6 | | Models |109238 | 86118 | 1938 | 9700 | 5 | 6 | | Mailers | 2259 | 1821 | 47 | 209 | 4 | 6 | | Workers | 797 | 678 | 23 | 38 | 1 | 15 | | Chanko units | 12737 | 10967 | 20 | 373 | 18 | 27 | | Libraries | 52295 | 43235 | 649 | 3954 | 6 | 8 | | Feature specs | 56569 | 45583 | 0 | 192 | 0 | 235 | | Request specs | 46276 | 39906 | 0 | 18 | 0 | 2215 | | Routing specs | 614 | 495 | 0 | 0 | 0 | 0 | | Controller specs | 64188 | 53000 | 6 | 128 | 21 | 412 | | Helper specs | 84918 | 70300 | 3 | 71 | 23 | 988 | | Model specs |163524 |135337 | 5 | 130 | 26 | 1039 | | Worker specs | 1156 | 959 | 0 | 1 | 0 | 957 | | Chanko unit specs | 9214 | 7596 | 0 | 11 | 0 | 688 | | Library specs | 26054 | 21809 | 25 | 125 | 5 | 172 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total |699793 |574392 | 3313 | 20820 | 6 | 25 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 199407 Test LOC: 374985 Code to Test Ratio: 1:1.9 
  130. rake stats +----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines | LOC |

    Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 32806 | 26480 | 311 | 2746 | 8 | 7 | | Helpers | 13384 | 10888 | 17 | 1234 | 72 | 6 | | Models | 74920 | 59022 | 1303 | 6642 | 5 | 6 | | Mailers | 1727 | 1389 | 40 | 170 | 4 | 6 | | Workers | 0 | 0 | 0 | 0 | 0 | 0 | | Chanko units | 6401 | 5333 | 2 | 160 | 80 | 31 | | Libraries | 33764 | 28140 | 381 | 2463 | 6 | 9 | | Feature specs | 44276 | 35545 | 0 | 177 | 0 | 198 | | Request specs | 781 | 615 | 0 | 0 | 0 | 0 | | Routing specs | 406 | 328 | 0 | 0 | 0 | 0 | | Controller specs | 49339 | 40751 | 6 | 77 | 12 | 527 | | Helper specs | 4152 | 3431 | 0 | 9 | 0 | 379 | | Model specs | 65320 | 53596 | 2 | 55 | 27 | 972 | | Worker specs | 0 | 0 | 0 | 0 | 0 | 0 | | Chanko unit specs | 3012 | 2400 | 0 | 1 | 0 | 2398 | | Library specs | 16327 | 13544 | 17 | 78 | 4 | 171 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total |346615 |281462 | 2079 | 13812 | 6 | 18 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 131252 Test LOC: 150210 Code to Test Ratio: 1:1.1 
  131.     NPEFMT   NPEFMT

  132. 分割方針 • 開発が活発な部分を切り出す • サービスとして再利用性が高い部分を 切り出す • チームの境界で切り出す • 完璧より実利を目指す

  133. おわりに

  134. おわりに (1/5) • 開発効率への技術的投資を
 クックパッドは
 組織的・戦略的に行ってきた • (ただし失敗もある)

  135. おわりに (2/5) • クックパッドは「毎日の料理を楽しみ にする」サービス開発の会社 • サービス開発はめちゃくちゃ難しい • 最高の道具を使ってやっと
 打席に立てる程度

  136. おわりに (3/5) • サービスに「完成」はなく、
 事業が続く限り
 ずっと開発し続けるものである ‣ BML ループ •

    そのために必要なことはなにか?
  137. おわりに (4/5) • サービス開発の技術選定で大事な要素 ‣ 早く作って、早くリリースできる ‣ 捨てやすい ‣ スケーラビリティ


    (組織、トラフィック) ͓ΘΓ
  138. おわりに (5/5) • マイクロサービス? ‣ 組織のスケーラビリティのために
 やむを得ない選択 ‣ 世の中のインフラがマイクロサービス
 前提になりつつあり、いいタイミング

    ͓ΘΓ
  139. IUUQTUFDIMJGFDPPLQBEDPN

  140. ԠืకΊ੾Γ ΫοΫύουɹΠϯλʔϯ