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

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

berlysia
November 27, 2021

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

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

このスライドの内容を文字にしているブログ記事はこちら
https://blog.nnn.dev/entry/2021/12/03/123000

トークのアーカイブはこちら
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/

berlysia

November 27, 2021
Tweet

More Decks by berlysia

Other Decks in Programming

Transcript

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

    View Slide


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

    View Slide

  3. お品書き
    1. 宣伝
    2. 誰に向けて話すか
    3. 結論
    4. ここで扱う「リプレース」とはなにか
    5. リプレース時に役立つテストとは何か
    6. 実例

    View Slide

  4. 宣伝:ドワンゴ教育事業の採用目的イベントやります
    ドワンゴ EdTech Talk - connpass

    View Slide

  5. 再掲)お品書き
    1. 宣伝
    2. 誰に向けて話すか
    3. 結論
    4. ここで扱う「リプレース」とはなにか
    5. リプレース時に役立つテストとは何か
    6. 実例

    View Slide

  6. 誰に向けて話すか
    - これから「リプレース」をやっていこうとしている人へ
    - 重要な動作を壊さずに仕事をやりとげたと自信をもてるようになりましょう
    - テストがないところからでも多分何とかなります、実例を置いておくので参考に
    - 使えるものは何でもつかうために、どんなテストが役立つのかみていきましょう
    - リプレースに飛び込む前にやるべきことも示しておきます
    - すでに「リプレース」をやりとげた人へ
    - ここでは「それはそう」みたいなことをたくさん言います
    - こういう整理の仕方をしたんだなとか思ってもらえたら嬉しいです
    - こういう状況でこうして乗り切ったよ、みたいな事例をぜひ教えてください
    - 上記を含むすべての人へ
    - 多くの人にとっては普通にテストを書く上でも役に立つことが含まれていると思います

    View Slide

  7. 結論
    Webフロントエンドのリプレース時のテストは
    シナリオベースで画面操作を想定した結合テスト
    に注目すべし
    なぜなら:
    1. (ここを)
    2. (うめていきます)

    View Slide

  8. 「リプレース」❓

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  12. 最近のWebフロントエンドの「リプレース」
    - コンポーネント単位で○○を導入、徐々に全体に広げました
    →リアーキテクティング的なリライト
    - ルーティング・画面単位で○○に置き換えていきました
    →インクリメンタルなリライト
    - 全部一気に書き換えました👊
    →ビッグ・リライト
    「リプレース」とは、おおむねリライトのことと言えそう
    少なくともリファクタリングの一種ではありそう

    View Slide

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

    View Slide

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

    View Slide

  15. リプレースを選ぶ条件
    『レガシーソフトウェア改善ガイド』曰く、次のふたつを満たすとき:
    1. リファクタリングを既に試みて失敗している
    - 必ず最初にリファクタリングを試みて、どれくらい効くか確かめる
    顕著な改善が得られないとわかってからリライトを考え始める
    - コードに十分詳しくなってからの方が、リライト後へのよい洞察が得られる
    - 調査的リファクタリング
    2. パラダイムシフトを取り込みたい
    - 人材事情でのリライト、より軽量なWAFへのリライトなどが例示
    - 宣言的なUI記述を中心にした思想は、これにあたるかも?
    - WAFべったりから独立したいというのも、これにあたるかも?

    View Slide

  16. 再掲)よくある「リプレース」
    - ○○(歴史あるライブラリ・フレームワーク)で書かれているものから
    ××(最近話題のライブラリ・フレームワーク)に載せ替える
    - ○○(サーバーサイドメインの WAF)の view にべったりなフロントエンド実装をひっぺ
    がす
    - etc...
    ライブラリ名やフレームワーク名に目が行きがち
    その選択に至る原点の「つらさ」は多種多様

    View Slide

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

    View Slide

  18. よくあるつらさ
    - いまの開発規模に合っていない
    - いまの開発体制に合っていない
    - 世の中のデファクトから意図せず外れている
    - 採用の問題
    - 新しい道具に乗りづらい問題
    - 安心して修正・拡張できない
    - ライブラリ更新がこわい
    - パフォーマンス改善の前にやることがいっぱい
    - 見通しが悪くて変更が難しい
    - 経緯を知っている人がいなくなって手探り
    - etc...
    その問題が解けるように
    よく計画しましょう
    リアーキテクティングくらいに
    落とせるかも
    まず何をやっているか
    調べつくした方が良い
    上側のつらさに分解しよう
    その過程でだいぶ綺麗になるかも

    View Slide

  19. 再掲)リプレースを選ぶ条件
    『レガシーソフトウェア改善ガイド』曰く、次のふたつを満たすとき:
    1. リファクタリングを既に試みて失敗している
    - どうにかして手ごろなリファクタリングに落とせないか、まず試す
    - 既存コードに十分詳しくなってからでも遅くない
    - 調査的リファクタリング
    2. パラダイムシフトを取り込みたい
    - 人材事情でのリライト、より軽量なWAFへのリライトなどが例示
    - 宣言的なUI記述を中心にした思想は、これにあたるかも?

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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




    View Slide

  25. テストの分類いろいろ
    - 工程による分類
    - ex) 単体テスト・結合テスト・システムテスト・受け入れテスト
    - 実行方法による分類
    - ex) 動的テスト・静的テスト
    - テスト技法による分類
    - ex) ブラックボックステスト・ホワイトボックステスト
    - 結合度による分類
    - ex) 単体テスト・○○結合テスト・E2Eテスト
    - 依存するリソースと実行時間による分類(Test Sizes)
    - ex) スモール・ミディアム・ラージ

    View Slide

  26. よく見る図:The Test Pyramid
    - 図に書いてあること
    -
    - この図にいま学ぶべきことは
    - この図を読むときの注意
    - もしより上位のテストが十分に高速で
    メンテナンスが容易であるならば
    低レベルのテストは省いてよい The Practical Test Pyramid
    TestPyramid
    より下位のテストは実行速度が速く
    メンテコストも低い
    結合度の高いテストはより少ない数でも
    効果を発揮する

    View Slide

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


    結合度が高いテストは
    少なくても効果を発揮する

    View Slide

  28. 私たちはこれから実装を置き換える

    旧 旧
    外側 外側

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    旧 旧
    外側 外側

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    結合度が高いテストは
    少なくても効果を発揮する

    View Slide

  38. 図:The Testing Trophy
    from Static vs Unit vs Integration vs E2E Testing for
    Frontend Apps
    - より下位がコスト低・高速なのは同じ
    - より上位のテストは
    より大きい問題に関心がある
    - 障害点が多く壊れやすい?
    →より多くのコードをテストしているから
    - エッジケースはより下位のテストで拾う
    より上位の実際の使い方に近いテストは
    より多くの信頼度をもたらしてくれる
    統合テストは信頼度とコスト・速度の
    バランスが良いので多くするとよい

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    結合度が高いテストは
    少なくても効果を発揮する

    View Slide

  43. 例えばこういうのでいい

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  48. 何がつらかったか
    調査的リファクタリングの結果わかったことは:
    - JS実装の見通しが悪い
    - 関連する実装の凝集度が低い
    - 各所で機能の有無が論理的凝集によって隠れており、どこで何をサポートすべきか見づらい
    - CSS実装の見通しが悪い
    - 歴史的経緯が残りっぱなしの SCSSがそのまま残っている
    - 要素セレクタや子セレクタが濫用されていて変更に著しく弱い
    - 外観用の class と動作用の class が一部共通になっていて CSS を不用意にいじれない
    - テスト
    - ほぼない
    - 抵抗を示すような単体テストが地道に書かれていた

    View Slide

  49. リスク検討
    壊すとどうなるか
    - 利用いただいている方々へのご迷惑、はもちろんのこと……
    - 2万人のN高・S高生が単位を取るための学習を進められなくなる
    - 期末試験の時期にはとくに紙試験へのフォールバックや再調整などで現場を泣かせる
    パフォーマンス
    - ログイン前提なのでSEO観点は除外できる
    - 比較的高頻度にロードされるのでリーズナブルな範囲で求められる
    - バンドルサイズはほぼ問題にならないスケール

    View Slide

  50. リプレースの方針
    まず、調査的リファクタリングの結果を解消するリファクタリングを行う
    - DOM周りで関連するコードの凝集度を上げる
    - 制御結合をやめ論理的凝集を解消、呼び出し側が命じる作りに統一する
    - 実装外部との結合面を整理し、滑らかにする
    その後、実装を画面ごとに置き換える
    - あとは各個撃破👊
    - ここには別にドラゴンが潜んでいる

    View Slide

  51. テストの方針
    - シナリオテストで教材の一連の操作を検証したい
    - 進行不可系の不具合は絶対に出したくなかった
    - CSSには基本的に干渉せず、classも変更しないことを前提にする
    - 外観崩れの検証はDOMレベルで一致していればよいとわかる
    - 構造レベルでは書き換えてしまうのでより上位のテストが必要
    - 単体テストは書けなかった

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide