Share
Embed
Transcript
30 slides
-
認知コストが高く、保守性が乏しい HTMLファイル ファイル数: 139 総行数: 11160行 1番行数の多いファイル: 749行 CSSファイル ファイル数:
44 総行数: 13754行 1番行数の多いファイル: 1517行 JSファイル(jQuery) ファイル数: 47 総行数: 28381行 一番行数の多いファイル: 5397行 React移行前: 2022年2月 ×モジュール管理 😥 ×コンポーネント分割 😥 -
$(“#area_1”).on(“click”, function (e) { // IDセレクタイベントの登録 ... } $(“#area_2”).on(“click”, function
(e) { // IDセレクタイベントの登録 ... $(“#area_1”).trigger(“click”); // 別セレクタのイベント発火 ... } $(“#area_1_1”).on(“click”, function (e) { // IDセレクタイベントの登録 ... e.stopPropagation(); // イベントの伝播をやめる ... } $(“.container”).on(“click”, function (e) { // クラスセレクタイベントの登録 ... } $(“#area_2”).addClass(“container”); // クラスの付与 課題1: イベント管理の複雑化 area_1_1 area_1 area_2 何でも書けてしまうが故に、メンテナンスが難しい 😥 認知コストが高く、変更容易性は低い 😥 レガシーコード(jQuery) -
$(“#area_1”).on(“click”, function (e) { // IDセレクタイベントの登録 ... } $(“#area_2”).on(“click”, function
(e) { // IDセレクタイベントの登録 ... $(“#area_1”).trigger(“click”); // 別セレクタのイベント発火 ... } $(“#area_1_1”).on(“click”, function (e) { // IDセレクタイベントの登録 ... e.stopPropagation(); // イベントの伝播をやめる ... } $(“.container”).on(“click”, function (e) { // クラスセレクタイベントの登録 ... } $(“#area_2”).addClass(“container”); // クラスの付与 課題1: イベント管理の複雑化 どのHTML要素に、どのイベントが紐づいているかわかりやすい 😄 const AreaButtons = { funcA, funcB, funcC, }: prpps) => { return ( <button id=”area_1" onclick=funcA /> <button id=”area_2" onclick=funcB /> <button id=”area_1_1" onclick=funcC /> ) } レガシーコード(jQuery) React -
global変数, var, letの乱用 😥 型がわからない 😥 /* global global_variable_a, global_variable_b,
global_c, function_a, promise_function_a */ /* exported variable_d, function_b, $element_a */ let variable_a = null; var variable_b = 0; const default_value = 100; ... function abc() { variable_a = “xxx”; if (varible_b == “yyy”) { varible_b = default_value + 10; } } ... abc(); 課題2: 状態管理の複雑化 レガシーコード(jQuery) -
const, 型で安心 😄 /* global global_variable_a, global_variable_b, global_c, function_a, promise_function_a
*/ /* exported variable_d, function_b, $element_a */ let variable_a = null; var variable_b = 0; const default_value = 100; ... function abc() { variable_a = “xxx”; if (varible_b == “yyy”) { varible_b = default_value + 10; } } ... abc(); 課題2: 状態管理の複雑化 export const funcA = ( variable_a: number, fvariable_b: number, ) => { const default_value = 100; const variable_c = variable_a + fvariable_b; const [showSomething, setShowSomething] = useState(false); const funcABC = () => { if (variable_c > default_value) { setShowSomething(true); } }; return { variable_c, funcABC, }; }; レガシーコード(jQuery) React -
課題3: UIロジックと状態管理ロジックの混在 UIを生成するロジックと、状態管理のロジックが混在することにより可読性と保守性が下がる 😥 テストが書きづらい 😥 function abc() { let
first_name = $(“#area_1”).data(“first_name”); if (first_name == “”) { first_name = “default_first_name”; } let last_name = $(“#area_1”).data(“last_name”); if (last_name !=) { last_name = last_name + “ san”; } $('<div/>') .data(“first_name”, first_name) .data(“last_name”, last_name) .appendTo('#area_1'); } レガシーコード(jQuery) -
課題3: UIロジックと状態管理ロジックの混在 function abc() { let first_name = $(“#area_1”).data(“first_name”); if
(first_name == “”) { first_name = “default_first_name”; } let last_name = $(“#area_1”).data(“last_name”); if (last_name !=) { last_name = last_name + “ san”; } $('<div/>') .data(“first_name”, first_name) .data(“last_name”, last_name) .appendTo('#area_1'); } それぞれの関心ごとでファイルを分割することで、可読性と保守性が上がる 😄 テストが書きやすい 😄 // index.tsx const componentA = ({firstName, lastName}) => { const [updatedFirstName, updatedLastName] = useComponentA(firstName, lastName); return ( <div id="area_1"> <div data-first-name={first_name} data-last-name={last_name}></div> </div> ); } // hooks.ts export const useComponentA = (firstName: string, lastName: string) => { const updatedFirstName = firstName || "defaultFirstName"; const updatedLastName = lastName || "defaultLastName"; return { updatedFirstName, updatedLastName, }; }; React レガシーコード(jQuery) -
Django (+ jQuery) As-Is, To-be Django (+ React) S3 (React)
nginx nginx CloudFront あるべき姿 現状 -
Django (+ jQuery) As-Is, To-be Django (+ React) S3 (React)
nginx nginx CloudFront あるべき姿 現状 今回の範囲 -
Django側(HTML, jQuery) 移行するページやコンポーネントに対して、任意のidを適用する React側 付与したidから要素を取得し、それをReact rootとしDOMを構築する const domNode = document.getElementById(”rootA”);
const root = createRoot(domNode); root.render( <ComponentA/> ); 移行方法(静的) <div id="rootA"></div> HTML, jQuery React -
Pub/Subで、動的なイベントをハンドルする react_main.jQueryEventHub.publish({ eventName: “ChangeEvent”, data: { message: “sampleMessage” } })
移行方法(動的) useEffect(<T extends GuidanceKeys>() => { const deviceAlertSubscription = jQueryEventHub.subscribe<{ message: string; }>('ChangeEvent', (event) => { const message = event.data.message; if (message == “sampleMessage”) { showMessage(message); } }); return () => subscription.unsubscribe(); }, []); HTML, jQuery React -
移行の現状 (jQuery → jQuery+React) HTMLファイル(index.tsx) ファイル数: 499 総行数: 63550行 1番行数の多いファイル:
1308行 CSSファイル(style.ts) ファイル数: 347 総行数: 22409行 1番行数の多いファイル: 432行 JSファイル(hooks.ts) ファイル数: 369 総行数: 47998行 1番行数の多いファイル: 2671行 HTMLファイル ファイル数: 139 総行数: 11160行 1番行数の多いファイル: 749行 CSSファイル ファイル数: 44 総行数: 13754行 1番行数の多いファイル: 1517行 JSファイル ファイル数: 47 総行数: 28381行 一番行数の多いファイル: 5397行 HTMLファイル ファイル数: 104 総行数: 7264行 1番行数の多いファイル: 959行 CSSファイル ファイル数: 31 総行数: 13554行 1番行数の多いファイル: 2468行 JSファイル ファイル数: 34 総行数: 28782行 1番行数の多いファイル: 7743行 レガシーコード レガシーコード React 2022年2月 2026年2月(新機能含む) -
良かったこと 新機能を開発しやすい 1ファイルあたりの行数が抑えられている 可読性, 変更容易性が向上 チームや組織でデザインの基準を合わせられる コンポーネント管理, 再利用可能 テストコードが増える 主にロジック(hooks.ts)のテストが増える
保守性が向上 トラブルやバグが発生した時に、テストを書いて修正ができる AIの進化 今後、より簡単に移行が進められる可能性がある -
苦悩・課題感 教育・キャッチアップコスト jQuery中心だったエンジニアの学習コスト 他チームへの教育・知識共有 レガシーコード移行の難しさ 仕様が曖昧な既存コードの存在 元のコードがレガシーだと、移行後のコードもレガシー 移行に伴う工数増加 既存コードの理解に時間を要する 肥大化したファイルの分割・移行コスト
ユーザーへのインパクト 単なる技術的な移行では、コストの割にインパクトが少ない ビジネスメンバーの理解を得づらい -
これからのテスト自動化:作成〜運用をAIがサポート MagicPod Autopilot ユーザーの指示に基づき、テスト を自動で作成します。既存テスト の修正などにも幅広く対応しま す。 画面の内容やテキストを理解し、 従来は人間が検証する必要があっ たテスト項目も自動化します。
UIに変更があった場合に、AIがテ ストケース側の修正を提案・修復 します。 AIアサーション AI自動修復 テスト作成 結果確認 テストメンテナンス MagicPodは、テスト作成のMagicPod Autopilot、結果確認のAIアサーション、 メンテナンスのAI自動修復と、AIの力で自動テストを幅広くサポート。 -
結果が期待通りかどうか、AIが合否判定 「表示された商品がすべてクリスマス関連 のものであること」をAIで確認 ハロウィーン関連の商品が 表示されています! 整合性を確認するテスト ネットショップで、検索ワードに対して正しい商品一覧が表示されているかを確認する。 例 1 2
3 検索欄に「クリスマス雑貨」を入力 「検索」ボタンを押す Failed! Failed! クリスマス雑貨