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

berlysia

November 27, 2021
Tweet

More Decks by berlysia

Other Decks in Programming

Transcript

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

    View full-size slide


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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  6. 「リプレース」❓

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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




    View full-size slide

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

    View full-size slide

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

    View full-size slide

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


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

    View full-size slide

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

    旧 旧
    外側 外側

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    旧 旧
    外側 外側

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide