Developers Summit 2014 「Play2/Scalaでドメイン駆動設計を利用した大規模Webアプリケーションのスクラム開発の勘所」

94,358 views

Published on

http://event.shoeisha.jp/devsumi/20140213/session/407
以上の発表の発表内容となります。

Published in: Technology
0 Comments
347 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
94,358
On SlideShare
0
From Embeds
0
Number of Embeds
53,719
Actions
Shares
0
Downloads
384
Comments
0
Likes
347
Embeds 0
No embeds

No notes for slide

Developers Summit 2014 「Play2/Scalaでドメイン駆動設計を利用した大規模Webアプリケーションのスクラム開発の勘所」

  1. 1. Play2/Scalaでドメイン駆動設計を利用した 大規模Webアプリケーションの スクラム開発の勘所 株式会社ドワンゴ ニコニコ生放送 吉村 総一郎 (@sifue)
  2. 2. 吉村 総一郎 (@sifue) • 元々は、製造業の業務改革をメ インとするシステムコンサル ティングで働くSE • 趣味はゲーム実況 (最近はFF14) とプログラミング • 好きな言語はJava • 2012年4月、趣味のゲーム実況 やゲーム用ツール開発が高じて ドワンゴへ
  3. 3. 今日はニコニコ生放送をScalaで書き直している話
  4. 4. そもそもなぜ書き直さねば ならなかったのか?
  5. 5. 2012年12月
  6. 6. コードの技術的負債 • PHPのコード行数 300万行に対し • コピー&ペースト数1万ヶ所 • 潜在的不具合数(PMD警告値)が 4500ヶ所 • 循環的複雑度600超メソッドがいく つも存在 • IDEサポートができない文字列のリ フレクションの多い、grep不能な PHPのコード
  7. 7. 循環的複雑度600超メソッドは 例えるなら終盤のジェンガ • 人類の英知を結集しても不具 合を入れずに不具合改修する ことが困難なレベル • 循環的複 雑度 10以下 今も解消されていない 30以下 • 不具合修正をする数よりもそ 複雑さの状態 バグ混入確率 非常に良い構造 25.00% 構造的なリスク あり れによって発現する不具合の 方が多くなってしまうとい 50以下 う、まさに負債 75以上 テスト不可能 いかなる変更も 誤修正を生む 40.00% 75.00% 98.00%
  8. 8. なぜこのような事に なってしまったのか? • 企画の要件と締切優先で、ソフトウェアの内部品質や プロセス品質を疎かにする開発体制 • 多くの人員が追加されていたが、根本修正を恐れる余 りパッチワーク的な修正が多く実施された • 結果、コピペばかりの1万行のクラスや4000行のメ ソッドが生まれ、300万行のいたる所に暗黙の影響範 囲を持つコードベースになった
  9. 9. このような状況に対して 打ち出した緊急対応
  10. 10. 1. 各人のタスクを見える状況にして、効率よくリソー スを配分できるようにする 2. いらない機能を削って保守コストを下げる 3. カーボーイ個人開発からアジャイル開発体制へ移行 してチームの利点を活かせるようにする 4. 長期案件、突発対応、改善活動の3つのチームに分 割し、安定して改善活動を行えるようにする
  11. 11. 3ヶ月間の対応の結果 1. 大規模な障害と休日出社が減った 2. コード行数の増加が止まった 3. メンバーが休んでもチームが回るようになった 4. 離職が減った
  12. 12. とはいえ、既に終盤のジェンガに は現状維持が精一杯だった
  13. 13. そして、ニコ生を書き直す ニコ生2プロジェクトが発足
  14. 14. 目的は継続的な大規模配信に耐えられるよ うにするため以下の性能を担保すること 1. スケーラビリティ 2. 安定性・フォールトトレラント性 3. 保守性と拡張性 4. パフォーマンス 以上の順番の優先順位で目標を設定することとなった。今の設計で はサーバーを足すのに大きなシステム変更コストが必要であり、今 後容易にスケールアウトできることに主眼をおいた。
  15. 15. 2013年4月に4人でプロジェクトスタート 左端が担当部長の鈴木圭一さん、右4人がメンバー
  16. 16. スモールスタート/スモールリリース プロトタイプ開発完了から実際のリリースまでを6ヶ月以内に設定し、要件を絞る ために、要件の少ない広告型サイズのプレイヤーとして開発することにした
  17. 17. プロトタイプ作成をしながら常にそこまで の成果を2週間に一度ショーケースで紹介 • 常に全ての関係者がプロジェクトのここまでの成果を確 認できるショーケース環境を作成。上のスライドはただ の絵だが、実際に6月に動くものをそこで紹介した。
  18. 18. 結果10月中には無事、 広告型プレイヤーのリリース成功 • 記念すべき最初の番組はチンアナゴでした
  19. 19. 最終的にメンバーは13名まで増え、 12月の年末特別番組を生2で実施 • 大規模の接続が想定された年末の小林幸子さんのカウントダウン番組で 生2のプレイヤーを利用した放送を実施、無事成功に終わる
  20. 20. 今日のお話はここから、 このプロジェクトの裏側を紹介します。
  21. 21. Play2/Scalaでの 大規模Webアプリケーション開発
  22. 22. なぜScalaを選択したのか?
  23. 23. • Java, Scala, PHP, Rubyからの選択 • 保守性の観点から静的型付けの言語を使いたかった • パフォーマンスの懸念はプロトタイプ作成後に判断す ることに • 幸いプロトタイプを作ったメンバーは全員Java/Ruby/関 数型言語などの経験があり、Scalaに抵抗はなかった • ただし、途中から加わったPHPしかやってこなかったメ ンバーがScalaをやるにあたっては辛い面があった
  24. 24. PHPしかやってこなかったメンバーが Scalaをやるにあたってネックになる知識 1. アルゴリズムとデータ構造 2. 純粋関数型プログラミング 3. valとvar 4. implicit 5. 並行プログラミングの知識 6. JVMとJavaライブラリの仕組み
  25. 25. 1.アルゴリズムとデータ構造 • PHPは本当に素晴らしい言語で、基本全てのコレクションを arrayで扱うため、データ構造等に詳しい必要がなかった • 今までPHPのarrayしか使わなかった人に、Scalaで配列と連 結リストとツリーセットとハッシュマップ…またこれらの不 変、可変、並行コレクションを使い分けさせるのは難しい • 対策としてプログラミングコンテストチャレンジブックを利 用して勉強会を開催。半年で20名に実施した。
  26. 26. プログラミングコンテストチャレン ジブック初級編の勉強会 • 第1回 再帰関数と深さ優先探索 • 第2回 スタックとキューと幅優先探索 • 第3回 貪欲法 • 第4回 動的計画法とメモ化 • 第5回 プライオリティーキュー • 第6回 Union-Find木 • 第7回 ダイクストラ法
  27. 27. 2. 純粋関数型プログラミング • 無理に適用しない • コード自体もほとんどこのスタイルで書かれておらず、 ベターJavaとして利用している側面が強い • 使う分には簡潔にかけることもあり便利
  28. 28. 3. valとvar • valを徹底 • 可変コレクションも基本的に使わない • 徹底したからと言ってそんなに困ることはない • サーバーでメモリリークが発生せず素晴らしい
  29. 29. 4. implicit • ライブラリ層を除いては極力利用しない • 特にimplicit converterをガリガリ使った部分が負債になり やすい • ひとつぐらいなら良いが3~4個読み出したり、スコープ ごとに違うコンバーター呼び始めると大変… • 冗長な記述は減らせて良いが、多くの値がimplicitだとpull requestでのコードレビューでわかりにくくなる
  30. 30. 5. 並行プログラミングの知識 • Actorのトラブル解決にどうしても必要になる • 今も課題で、今後、Java並行処理プログラミ ングの勉強会を開催したい • 実際はActorを純粋な分散コンピューティン グのフレームワークとしては使わず、ワー カースレッドパターンを使うライブラリとし て使っている側面が強い
  31. 31. 6. JVMとJavaライブラリの仕組み • 業務の中で少しずつ学べばOK • チームに1人はJavaのエキスパートがいれば持っていな くても大丈夫
  32. 32. プロトタイプ開発で模索した ニコ生2のアーキテクチャ
  33. 33. インフラメンバーにデイリースタン ドアップに参加してもらった • やはりコミュニケーションが重要 • 最初からインフラの制約などを細かく確認していくために コミュニケーションコストを払った • ドワンゴではインフラ運用とアプリ開発で部署が分かれて おり現在は席を近くにする等の運用もされている • デスクレビューを実施する際にも気軽にインフラメンバー 呼べて助かっている
  34. 34. クラウドではなくオンプレミスという選択 • IOパフォーマンス • 費用 • 社内方針として • だが世の中の流れ的にWebの構築にクラウドを利用したりす るようになっており、データセンターや大規模Webのインフ ラ構築に関するノウハウがレアになり、人材育成、人材確保 が課題になっている
  35. 35. DBの水平分割と垂直分割 • DBにはMySQLを利用 • 水平分割 • 64bitのIDの中にシャードID(12bit)やデータタイプID(10bit)な どを組み込んで、DBのシャーディングが容易になるようにし ている • InstagramのID設計、PinterestのID設計、Twitterのsnowflake などを参考にした • 垂直分割は、サイズが小さくシャーディングが不要な共有DBに のみ適用している
  36. 36. 2つのキャッシュ 中央redisとローカルredis redis web twemproxy redis redis redis redis • キャッシュで利用するローカルredis群と中央で複数のwebインス タンスから利用する速いデータストアとしての中央redis群との使 い分け。ただ中央redisはデータ最小化のため工夫している。
  37. 37. 冗長化方法 • MySQLはMHAで冗長化 • 当初、GTIDを用いた方法も模索したがフェイルオーバーのダ ウンタイムがMHAの方が短かったため • • 運用としては、VIPを利用して切り替えて対応 redisはSentinelで冗長化 • 中央redisのみ • マスター昇格の際に全てのデータのコピーが走るのでダウン タイムを少なくするためにデータを小さくする工夫が必要
  38. 38. 外部環境から負荷を分離する アプリケーション構成 web用 データ バッチ用 ストア クライ 管理ツール用 アント websocket用 外部リソース中継用 メッセージサーバー • 配信系 高負荷時は、webかwebsokcetが非常に重くなるためその他 の機能をできるだけ逃す構成となっている
  39. 39. websocketアプリ1インスタンスで、 5万ユーザーの視聴管理を実現 • nginxとNettyサーバーで非同期IOを利用することで最大接続数が改善 • REST APIからWebsocketを利用することによって接続コストが低減 • 結果、CPUバインドの部分では既存の生放送の4倍の効率を実現 • パフォーマンス測定方法 • gatlingが素晴らしいストレスツール、レポートが綺麗 • ただしwebsocket部分はプラグインのパフォーマンスが出ず、結局 node.jsでストレスツールを自作。node.js素晴らしい。
  40. 40. ドメイン駆動設計の導入
  41. 41. ニコ生2でDDDをするにあたって 最低限徹底したこと 1. ユビキタス言語 2. モデルを使って議論するということ 3. レイヤードアーキテクチャ 4. 正しいモジュール化を行い、変更時に読ま なきゃいけないコードを減らす 1. コアの蒸留 2. 汎用サブドメインの分離 5. エンティティと値オブジェクトの使い分け UI層 依存方向 アプリケーション層 依存方向 ドメイン層 依存方向 インフラ層 図: レイヤードアーキテクチャ ※ DDD: Domain-Driven Design
  42. 42. Play2/ScalaはDDDを実践するには とても良いフレームワーク • CoCがきつくなく好き勝手フォルダが掘れる • マルチプロジェクト機能でサブモジュールの依存関係を作れ、レイヤー ドアーキテクチャの強制できる • • ドメイン層、インフラ層はplayに依存しないただのjar case classがエンティティと値オブジェクトの作成のコストを下げる • 例えば、インフラ層ORMのマッピングクラスとドメイン層のエンティ ティを分けることなどが苦にならない。 • play2を捨てられるように開発することが可能。 ※ CoC:「設定より規約」(CoC:Convention over Configuration)
  43. 43. とは言え、ドメイン駆動設計自が 導入ハードルが高い
  44. 44. エリック・エヴァンスのドメイン駆動設計 に入る前にメンバーに読んでもらいたい本
  45. 45. 多いし、どれも値段が高い! 手に入りにくいものもある...
  46. 46. 仕方がないから社内で講習会
  47. 47. そんな時の強い味方
  48. 48. Youtubeに上がっているDevLoveで 都元さんがDDDを解説した時のムービー • 社内でこれを見る上映会が3度開かれるほど素晴らしい映像 (42分) • http://youtu.be/FNEfk-dlIKU
  49. 49. だがユビキタス言語の醸成には、日々モデルや概 念について企画、インフラを交えての議論が必要 • 近い座席と雑談 • 会議体も重要 • • • デイリースタンドアップ ショーケース 日々細かく確認、議論
  50. 50. DDDを実践する価値とは
  51. 51. DDDではないコードの例 • StreamModel.class.phpの議論は難しい... (1万行) 番組であり 番組を作るものであり 番組をコピーしたり更新したりバックアップをとったりするものであり ストリームであり 生放送であり タイムシフトであり タイムシフト予約のリストを見れるものであり メッセージサーバーを割り当てるものであり 多国籍化をするものであり キャッシュとの通信をするものであり DBとの通信をするものであり
  52. 52. 神クラスについての議論は難しい It’s difficult to talk about a “God class”. ?
  53. 53. ユビキタス言語が導入されると、 複数のチームで共通の言語を使って会話ができる • ストーリーの内容について、チーム内、チーム関係者との議論がしやすくなる • 結果として、システム内の作りについてのチーム全体と理解度が高まる • Programというクラスは番組であるだけである • Streamというクラスがストリームであるだけである • Liveというクラスが生放送であるだけである • 生放送がうまく作れないとか、ストリームが割り当てられないとかそれが コード上のどこのはなしかわかりやすい • 無論ユビキタス言語ができる際には直接、またはIRCでしっかり相談する必要 あり
  54. 54. コードと普段要件について話している言語の 乖離が少なくなり、リファクタ性能があがる • ただし、ドメイン層だけ • ドメイン層へのビジネスロジックの集約に対する意識が根付く • 結果、ビジネスロジックの変更のリファクタに強くなる • 何度か生放送の配信インフラやメッセージサーバーの利用の要件が変わ る度にリファクタリングを行ったが、問題なく行えた • 過去はこういうことをやろうとした際、いろいろな場所にビジネスロ ジックが飛び火していて、大仕事、デグレも多かった • ただ、うっかりするとビジネスロジックがドメイン層から逃げて、アプリ ケーション層やインフラ層に行きがちなので、コードレビュー、設計レ ビューでの入念な監視と継続的なリファクタリングが必要である
  55. 55. アプリケーションの運用と チーム開発
  56. 56. Capistranoによるデプロイ • Playの設定のテンプレート化をerbとymlで実現 • いろんなインスタンスに同じことを書く設定に有効 • 設定プロパティが配列に対応していないが、数を動的 に変える必要がある設定に有効 • capistranoへの処理の集約 • minaにしようとしたが分散デプロイ機能がなくて断念 • 他に良い物があれば移行したいと考えている
  57. 57. コード規約としての Scala Guide/ Effective Scala • Effective Scalaを守らせるScalastyleを作ってgithubで公開中 • • https://github.com/dwango/scalastyle CPD (Copy and Paste Detector)によるコピペチェックも実施
  58. 58. 開発環境は IntelliJ IDEA Ultimateに統一 • 細かい作りこみや安定性が良い • 会社がチームメンバーに導入 • 理論上はどんなソフトウェアでもメモ帳では作れるが… • 開発環境を統一することで、環境構築ドキュメントなどを高 品質にできる良さがある • vimmerにも好評なideavimがある
  59. 59. JenkinsのCI/CD運用 • メインジョブは、ビルド、テスト、メトリクス、パッケー ジ作成、自動デプロイをしている • Github:eにおけるプルリクエスト元のブランチの自動 チェックもしている。失敗してると警告が…
  60. 60. CI/CDの成果 • 現在は5万行で、Scala 重複コード0、scalastyle警告0、自 動テストでの行ベースコードカバレッジ52% • とはいえど、数値を常によく保ち続けるにはリーダーや CIのメンテナーの啓蒙活動が重要 • 検証期間の大幅な工数削減 • 検証期間に自動ビルド、自動テスト、自動デプロイの工数 削減効果がわかりやすい。ビルド職人とデプロイ職人をな くせることは大きい。
  61. 61. Play2/Scala開発の難点 1. sbtが遅すぎる • proxyを作ったり、良いマシンを使うぐらいしかない 2. Play2のscalaテンプレートが、コンパイル遅く、文法がデザイナー にやさしくない仕様 • Groovyテンプレートで作成。 github/dwangoでフォークしたも のを公開中 3. テストで困るobjectとtraitと関数引数 • specs2のmockitoの制約。objectのモック作れない、traitはmixin が必要、ジェネリクスパラメーターが付いた関数引数のメソッド を拡張できない。
  62. 62. スクラムの導入
  63. 63. 自身のウォーターフォール開発とアジャ イル開発のプロジェクトマネージャ経験 1. 過去4度のフォーターフォール開発と、大失敗の経験 • 要求が変更されてしまうと地獄 • 不確定要素に対応するためのバッファ重要 • 最後のしわ寄せは品質に 2. 要件が確定できない、また、要求の優先順位が日々変わる場合 • アジャイルとスクラムの考えが良い • 日々変わるチームの目標への柔軟な対応が必要なWeb開発
  64. 64. アジャイル導入までの大変さ • みんなガントチャートがわかりやすくて好き、という問題 • 啓蒙活動はやはりフェイストゥフェイス (スライド作ったり) • 実際の現場にあるマネジメント問題の根本は、アジャイルとか ウォーターフォールとか関係ないことが多い • 問題の発見、目的や目標の設定をし、チームでのPDCAの実行 ができていれば良いのだがそれができてないこともある • カーボーイ開発にも良さがあるので強要しないほうが良いことも • 進 確認が高コストで、ドキュメントは残らないが、個人の パフォーマンスを引き出せる
  65. 65. スクラムはリーダーを育てるのに 素晴らしい開発手法 • 会議体が固定 • JIRA/GreenHopperなどのサポートツール • 書籍が充実している • プランニングポーカーでの見積もりが、スクラムマスターを孤立 図: GreenHopperの画面 させない • 全員が全ての帽子をかぶるので段階的にスクラムマスターにさせ ることが可能
  66. 66. とはいえ、スクラムマスターとしての基礎 知識は必要で別途座学の講座を開いている 対象 メンバー及びスクラムマスター アジャイルサムライ スクラムマスター アジャイルな見積もり スクラムマスター • 教科書 ドラッカーのマネジメント マネジメントを通じてメンバーを活かす、というドラッ カーの考え方は、アジャイルと相性が良い
  67. 67. スクラム開発の課題 • コニュニケーションコストがとにかく高いので密なコミュニケーションが負 担にならない仕組みが必要 • メンバーの要件定義の能力が身につきにくい • 要件定義という仕事がストーリーの管理として簡略化されている反面、 階層化が不十分だったり抜け漏れが発生しやすい • 要求や要件が深いコンテキスト付きのドキュメントにまとまることが少ない ため(ストーリーは短い文書)、ユーザーの要求の理解には個々努力が必要 • 要求が日々変わるのでリッチなドキュメンテーションが変更時に負債になり がち • 沢山の帽子をかぶれる人ほど多忙になりがち
  68. 68. ニコ生でのスクラムで 重視していること
  69. 69. ユーザーの要求理解に対して 時間をかける • ストーリーの漏れや背景にあるユーザー要件の見落 としを防止するため • 具体例: • ユーザーインタビュー • twitterのモニター • 要望掲示板や不具合掲示板の内容の共有 • 超会議へのスタッフでの参加
  70. 70. ストーリーのポイント数を 大体2~3日以内で終わる量にしている • 1スプリントで達成ポイントが0という状況は、個人に ショックが大きい • 無論、個々人のポイント数をおおっぴらに出したり評価 することはないけれども...
  71. 71. みんなでお菓子を食べたり、一緒に ゲームをやったりするよう心がけている • 密なコミュニケーションのストレスをできるだけ減らす • 具体例: • • ボードゲーム、ネトゲ • • お菓子神社 できるだけIRC (社内チャット) で済ます ほんとは誰ともフェイス・トゥ・フェイスのコミュニケー ションを取らず開発していたい人もいるので...まだ課題
  72. 72. スクラムマスターが常にプレイング マネージャーであれるようにする • ストーリーの理解や分割のために技術背景の知識が重 要、できるだけ実装機会があるようにする • 専任スクラムマスターが必要なほどの大きすぎるチーム にしない。目安は4~7名。
  73. 73. ゆとりを持った開発計画 • 1スプリントの目標ポイントをギリギリにするとチーム が疲弊する • 余裕のないスケジュールは達成されない
  74. 74. 企画と相談するときには、不確定な 時期と優先順位と一緒に持ち込む • 「2∼3スプリント内には開発完了するような優先順位付 けになっているがどうするか?」というような持ち込み 方をするように心がける • 重要度ではなく常に要件の優先順位で議論する
  75. 75. インフラチームや他チームとの共同 作業は合流バッファを考慮する • ストーリーの合流には問題がつきもの、バッファのない のコラボレーションは極力しない • 見積もりの際に見落としがちなコミュニケーションコス トや要件漏れの発見などのリスクも加味しなくてはいけ ない
  76. 76. ニコ生でのスクラムで 重視していること 1. ユーザー理解に対して時間をかける 2. ストーリーのポイント数を大体2~3日以内で終わる量にしている 3. みんなでお菓子を食べたり、一緒にゲームをやったりするよう心がけ ている 4. スクラムマスターが常にプレイングマネージャーであれるようにする 5. ゆとりを持った開発計画 6. 企画と相談するときには、不確定な時期と優先順位と一緒に持ち込む 7. インフラチームや他チームとの共同作業は合流バッファを考慮する
  77. 77. まとめ • Play2/Scalaは大規模Webサイトでも十分通用する • Scalaは良い言語だがある程度の技術力を要求する • Play2/Scalaとドメイン駆動設計による開発は相性が良い • ドメイン駆動設計は保守性に貢献する • スクラム開発はリーダーを育成するのに良い開発手法
  78. 78. 以上 ご清聴ありがとうございました
  79. 79. 質疑応答

×