Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Webフロントエンドのリプレースを支えるテストの考え方 / JSConf JP 2021

B04bd8797ce182483a5ded98f7cada6f?s=47 berlysia
November 27, 2021

Webフロントエンドのリプレースを支えるテストの考え方 / JSConf JP 2021

JSConf JP 2021 でトークしたスライドです。

トークのアーカイブはこちら
https://www.youtube.com/watch?v=5H3Sswp5qYg&t=1155s

https://jsconf.jp/2021/talk/testing-approach-to-support-web-front-end-replacement

スライド中のイベントのリンクはこちら https://dwango.connpass.com/event/230731/

B04bd8797ce182483a5ded98f7cada6f?s=128

berlysia

November 27, 2021
Tweet

More Decks by berlysia

Other Decks in Programming

Transcript

  1. Webフロントエンドの リプレースを支える テストの考え方 @berlysia / JSConf JP 2021

  2. 誰 - berlysia (べるりしあ、と読む) - Webとアイマスが両本業 - 株式会社ドワンゴ所属 教育事業のWebフロント担当 -

    Webフロントをやる人 - Webフロントのためにいろいろやる人
  3. お品書き 1. 宣伝 2. 誰に向けて話すか 3. 結論 4. ここで扱う「リプレース」とはなにか 5.

    リプレース時に役立つテストとは何か 6. 実例
  4. 宣伝:ドワンゴ教育事業の採用目的イベントやります ドワンゴ EdTech Talk - connpass

  5. 再掲)お品書き 1. 宣伝 2. 誰に向けて話すか 3. 結論 4. ここで扱う「リプレース」とはなにか 5.

    リプレース時に役立つテストとは何か 6. 実例
  6. 誰に向けて話すか - これから「リプレース」をやっていこうとしている人へ - 重要な動作を壊さずに仕事をやりとげたと自信をもてるようになりましょう - テストがないところからでも多分何とかなります、実例を置いておくので参考に - 使えるものは何でもつかうために、どんなテストが役立つのかみていきましょう -

    リプレースに飛び込む前にやるべきことも示しておきます - すでに「リプレース」をやりとげた人へ - ここでは「それはそう」みたいなことをたくさん言います - こういう整理の仕方をしたんだなとか思ってもらえたら嬉しいです - こういう状況でこうして乗り切ったよ、みたいな事例をぜひ教えてください - 上記を含むすべての人へ - 多くの人にとっては普通にテストを書く上でも役に立つことが含まれていると思います
  7. 結論 Webフロントエンドのリプレース時のテストは シナリオベースで画面操作を想定した結合テスト に注目すべし なぜなら: 1. (ここを) 2. (うめていきます)

  8. 「リプレース」❓

  9. よくある「リプレース」 - ◦◦(歴史あるライブラリ・フレームワーク)で書かれているものから ××(最近話題のライブラリ・フレームワーク)に載せ替える - ◦◦(サーバーサイドメインの WAF)の view にべったりなフロントエンド実装をひっぺ がす

    - etc...
  10. 周辺の言葉 『レガシーソフトウェア改善ガイド』 曰く: - リファクタリング →コードの構造をメソッドやクラスのレベルで変更する - リアーキテクティング →モジュールやコンポーネントのレベルで行うリファクタリング -

    リライト →可能な限り高いレベルで行うリファクタリング - ビッグ・リライト - 全てを一気に書き直し、置き換える - インクリメンタルなリライト - 小さい単位でリライト、徐々に置き換える - 進め方によってはリアーキテクティングに限りなく近づく - リプレース →サードパーティのソリューションに置き換える
  11. 周辺の言葉 『レガシーソフトウェア改善ガイド』によれば…… - リファクタリング →コードの構造をメソッドやクラスのレベルで変更する - リアーキテクティング →モジュールやコンポーネントのレベルで行うリファクタリング - リライト

    →可能な限り高いレベルで行うリファクタリング - ビッグ・リライト - 全てを一気に書き直し、置き換える - インクリメンタルなリライト - 小さい単位でリライト、徐々に置き換える - 進め方によってはリアーキテクティングに限りなく近づく - リプレース←これの話ではなさそう →サードパーティのソリューションに置き換える
  12. 最近のWebフロントエンドの「リプレース」 - コンポーネント単位で◦◦を導入、徐々に全体に広げました →リアーキテクティング的なリライト - ルーティング・画面単位で◦◦に置き換えていきました →インクリメンタルなリライト - 全部一気に書き換えました👊 →ビッグ・リライト

    「リプレース」とは、おおむねリライトのことと言えそう 少なくともリファクタリングの一種ではありそう
  13. 「リプレース」≒ リライト 「リプレース」 ⊂ リファクタリング ということにして、今後は「」を外して呼ぶことにする ここでは、『レガシーソフトウェア改善ガイド』の言葉のもとで……

  14. ところで:そのリプレース、機は熟しているか 『レガシーソフトウェア改善ガイド』曰く、リライトは難しい - すべての新規開発時におこるリスクをふたたび負うことになる - 作ったものが役に立たないかも・性能要求を満たさないかも - 新規に立ち上げるオーバーヘッドを軽視しやすい - 開発期間が長くなりやすく、オーバーヘッドの甘い評価以上に、見積もりよりも時間

    がかかりやすい - そもそも仕様が複雑だったことが原因なら書き直しても難しいままになる
  15. リプレースを選ぶ条件 『レガシーソフトウェア改善ガイド』曰く、次のふたつを満たすとき: 1. リファクタリングを既に試みて失敗している - 必ず最初にリファクタリングを試みて、どれくらい効くか確かめる 顕著な改善が得られないとわかってからリライトを考え始める - コードに十分詳しくなってからの方が、リライト後へのよい洞察が得られる -

    調査的リファクタリング 2. パラダイムシフトを取り込みたい - 人材事情でのリライト、より軽量なWAFへのリライトなどが例示 - 宣言的なUI記述を中心にした思想は、これにあたるかも? - WAFべったりから独立したいというのも、これにあたるかも?
  16. 再掲)よくある「リプレース」 - ◦◦(歴史あるライブラリ・フレームワーク)で書かれているものから ××(最近話題のライブラリ・フレームワーク)に載せ替える - ◦◦(サーバーサイドメインの WAF)の view にべったりなフロントエンド実装をひっぺ がす

    - etc... ライブラリ名やフレームワーク名に目が行きがち その選択に至る原点の「つらさ」は多種多様
  17. よくあるつらさ - いまの開発規模に合っていない - いまの開発体制に合っていない - 世の中のデファクトから意図せず外れている - 採用の問題 -

    新しい道具に乗りづらい問題 - 安心して修正・拡張できない - ライブラリ更新がこわい - パフォーマンス改善の前にやることがいっぱい - 見通しが悪くて変更が難しい - 経緯を知っている人がいなくなって手探り - etc...
  18. よくあるつらさ - いまの開発規模に合っていない - いまの開発体制に合っていない - 世の中のデファクトから意図せず外れている - 採用の問題 -

    新しい道具に乗りづらい問題 - 安心して修正・拡張できない - ライブラリ更新がこわい - パフォーマンス改善の前にやることがいっぱい - 見通しが悪くて変更が難しい - 経緯を知っている人がいなくなって手探り - etc... その問題が解けるように よく計画しましょう リアーキテクティングくらいに 落とせるかも まず何をやっているか 調べつくした方が良い 上側のつらさに分解しよう その過程でだいぶ綺麗になるかも
  19. 再掲)リプレースを選ぶ条件 『レガシーソフトウェア改善ガイド』曰く、次のふたつを満たすとき: 1. リファクタリングを既に試みて失敗している - どうにかして手ごろなリファクタリングに落とせないか、まず試す - 既存コードに十分詳しくなってからでも遅くない - 調査的リファクタリング

    2. パラダイムシフトを取り込みたい - 人材事情でのリライト、より軽量なWAFへのリライトなどが例示 - 宣言的なUI記述を中心にした思想は、これにあたるかも?
  20. 再掲)結論 Webフロントエンドのリプレース時のテストは シナリオベースで画面操作を想定した結合テスト に注目すべし なぜなら: 1. リプレースとは、ふつうのリファクタリングには既に失敗していて、パラダイムシフト を乗り越えるために、新たに書き直すことだから。 2. (つぎはここをうめます)

  21. 「リファクタリング」❓ ところで

  22. リファクタリングに欠かせないもの 『リファクタリング(第2版)』によれば: 「外部から見たときの振る舞いを保」つために、テストが不可欠 リファクタリング(名詞) 外部から見たときの振る舞いを保ちつつ、理解や修正が簡単になるように、ソフトウェアの内部 構造を変化させること。 リファクタリングの第一歩 リファクタリングを行うとき、最初にすることは常に同じです。対象となるコードについてきちんと したテスト群を作り上げることです。テストは不可欠です。(略

  23. 1. ない 2. 役に立たない 3. 書きづらい リプレースしたいコードのテストにありがちなこと

  24. リプレースではどんなテストが欲しいのか リファクタリングのお伴になる 十分素早く実行できるテスト 置き換えの前後で動作を保つことを 検証できるようなテスト もしテストが不十分なときは 誰でも比較的容易に作れるテスト そこまで多くない数でも 機能の信頼度を高めてくれるテスト ?

    ? ? ?
  25. テストの分類いろいろ - 工程による分類 - ex) 単体テスト・結合テスト・システムテスト・受け入れテスト - 実行方法による分類 - ex)

    動的テスト・静的テスト - テスト技法による分類 - ex) ブラックボックステスト・ホワイトボックステスト - 結合度による分類 - ex) 単体テスト・◦◦結合テスト・E2Eテスト - 依存するリソースと実行時間による分類(Test Sizes) - ex) スモール・ミディアム・ラージ
  26. よく見る図:The Test Pyramid - 図に書いてあること - - この図にいま学ぶべきことは - この図を読むときの注意

    - もしより上位のテストが十分に高速で メンテナンスが容易であるならば 低レベルのテストは省いてよい The Practical Test Pyramid TestPyramid より下位のテストは実行速度が速く メンテコストも低い 結合度の高いテストはより少ない数でも 効果を発揮する
  27. 再掲)リプレースではどんなテストが欲しいのか リファクタリングのお伴になる 十分素早く実行できるテスト 置き換えの前後で動作を保つことを 検証できるようなテスト もしテストが不十分なときは 誰でも比較的容易に作れるテスト そこまで多くない数でも 機能の信頼度を高めてくれるテスト 結合度が低いテストは

    実行速度が速い ? ? 結合度が高いテストは 少なくても効果を発揮する
  28. 私たちはこれから実装を置き換える 新 旧 旧 外側 外側

  29. 1. E2Eなテスト 旧 旧 外側

  30. 2. 置き換える単位への結合テスト 旧 旧

  31. 3. 置き換える単位より内側のテスト 旧

  32. 4. 置き換える単位へのホワイトボックステスト 旧 モック

  33. 再掲)私たちはこれから実装を置き換える 新 旧 旧 外側 外側

  34. 役に立つテストを全て選べ

  35. 役に立つテストを全て選べ

  36. 役に立つテストを全て選べ 置き換える単位より外側の ブラックボックステストが欲しい

  37. 再掲)リプレースではどんなテストが欲しいのか リファクタリングのお伴になる 十分素早く実行できるテスト 置き換えの前後で動作を保つことを 検証できるようなテスト もしテストが不十分なときは 誰でも比較的容易に作れるテスト そこまで多くない数でも 機能の信頼度を高めてくれるテスト 結合度が低いテストは

    実行速度が速い 置き換える単位より結合度が上の ブラックボックステストが良い ? 結合度が高いテストは 少なくても効果を発揮する
  38. 図:The Testing Trophy from Static vs Unit vs Integration vs

    E2E Testing for Frontend Apps - より下位がコスト低・高速なのは同じ - より上位のテストは より大きい問題に関心がある - 障害点が多く壊れやすい? →より多くのコードをテストしているから - エッジケースはより下位のテストで拾う より上位の実際の使い方に近いテストは より多くの信頼度をもたらしてくれる 統合テストは信頼度とコスト・速度の バランスが良いので多くするとよい
  39. 再掲)結論 Webフロントエンドのリプレース時のテストは シナリオベースで画面操作を想定した結合テスト に注目すべし なぜなら: 1. リプレースとは、ふつうのリファクタリングには既に失敗していて、パラダイムシフト を乗り越えるために、新たに書き直すことだから。 2. リプレースはリファクタリングの一種なので、書き直しの前後で変わらず信頼できる

    テストが、手ごろな速度で実行できるべきだから。
  40. 1. ない 2. 役に立たない 3. 書きづらい 再掲)リプレースしたいコードのテストにありがちなこと

  41. 再掲)結論 Webフロントエンドのリプレース時のテストは シナリオベースで画面操作を想定した結合テスト に注目すべし なぜなら: 1. リプレースとは、ふつうのリファクタリングには既に失敗していて、パラダイムシフト を乗り越えるために、新たに書き直すことだから。 2. リプレースはリファクタリングの一種なので、書き直しの前後で変わらず信頼できる

    テストが、手ごろな速度で実行できるべきだから。
  42. 再掲)リプレースではどんなテストが欲しいのか リファクタリングのお伴になる 十分素早く実行できるテスト 置き換えの前後で動作を保つことを 検証できるようなテスト もしテストが不十分なときは 誰でも比較的容易に作れるテスト そこまで多くない数でも 機能の信頼度を高めてくれるテスト 結合度が低いテストは

    実行速度が速い 置き換える単位より結合度が上の ブラックボックステストが良い ? 結合度が高いテストは 少なくても効果を発揮する
  43. 例えばこういうのでいい

  44. スナップショットを撮ってもいい/メンテは大変

  45. スナップショットを撮ってもいい/メンテは大変 リプレースのために必要な信頼度を 一時的にでも稼ぐようにしよう

  46. 実例@N予備校の教材フロントエンド

  47. どういう実装か - Railsのviewの結果に対してJSが動作している状況 - 規約で縛られたHTMLと教材のメタデータが与えられており、JS実装はjQueryで DOMを書き換えて、動作を与える - ベースになるHTMLは一定の規約に則っているくらいで、教材ごとに異なる

  48. 何がつらかったか 調査的リファクタリングの結果わかったことは: - JS実装の見通しが悪い - 関連する実装の凝集度が低い - 各所で機能の有無が論理的凝集によって隠れており、どこで何をサポートすべきか見づらい - CSS実装の見通しが悪い

    - 歴史的経緯が残りっぱなしの SCSSがそのまま残っている - 要素セレクタや子セレクタが濫用されていて変更に著しく弱い - 外観用の class と動作用の class が一部共通になっていて CSS を不用意にいじれない - テスト - ほぼない - 抵抗を示すような単体テストが地道に書かれていた
  49. リスク検討 壊すとどうなるか - 利用いただいている方々へのご迷惑、はもちろんのこと…… - 2万人のN高・S高生が単位を取るための学習を進められなくなる - 期末試験の時期にはとくに紙試験へのフォールバックや再調整などで現場を泣かせる パフォーマンス -

    ログイン前提なのでSEO観点は除外できる - 比較的高頻度にロードされるのでリーズナブルな範囲で求められる - バンドルサイズはほぼ問題にならないスケール
  50. リプレースの方針 まず、調査的リファクタリングの結果を解消するリファクタリングを行う - DOM周りで関連するコードの凝集度を上げる - 制御結合をやめ論理的凝集を解消、呼び出し側が命じる作りに統一する - 実装外部との結合面を整理し、滑らかにする その後、実装を画面ごとに置き換える -

    あとは各個撃破👊 - ここには別にドラゴンが潜んでいる
  51. テストの方針 - シナリオテストで教材の一連の操作を検証したい - 進行不可系の不具合は絶対に出したくなかった - CSSには基本的に干渉せず、classも変更しないことを前提にする - 外観崩れの検証はDOMレベルで一致していればよいとわかる -

    構造レベルでは書き換えてしまうのでより上位のテストが必要 - 単体テストは書けなかった
  52. 私たちはこうして無からテストを作った 1. jestでjsdomを使ってDOMが扱える状態を作る 2. ユーザーの操作を模してtesting-libraryで操作する 3. 操作前後の特徴になる部分でDOMのスナップショットを撮る 4. 一連のDOMスナップショットの連なりでシナリオテストを構成する

  53. 再掲)スナップショットを撮ってもいい/メンテは大変

  54. 再掲)結論 Webフロントエンドのリプレース時のテストは シナリオベースで画面操作を想定した結合テスト に注目すべし なぜなら: 1. リプレースとは、ふつうのリファクタリングには既に失敗していて、パラダイムシフト を乗り越えるために、新たに書き直すことだから。 2. リプレースはリファクタリングの一種なので、書き直しの前後で変わらず信頼できる

    テストが、手ごろな速度で実行できるべきだから。