au Web ポータルにおける
フロントエンドの取り組み

未学習領域におけるチーム{学習,プレイ}とは

2019-04-17 BIT VALLEY -INSIDE- Vol.8

Who

  {
    "name"  : "武田 諭",
    "social": "@tkdn",
    "from"  : "株式会社 mediba",
    "dept"  : "CD本部創造開発部/ものづくり推進部",
    "work"  : "フロントエンドエンジニア",
    "word"  : "ブラウザが主戦場"
  }

Who

  • 1980年生まれ, 38歳
  • 2003〜2013 俳優業
  • 2013〜2017 エンジニア転向、受託開発など
  • 2017〜 mediba, 入社2年目

今日の話は

  • au Web ポータルのリニューアルにおける取り組み
  • 未学習領域におけるチーム学習

チームにおける学習に必要なものはなんだろう

テクニカルなことにはあまり触れません

アジェンダ

au Web ポータルリニューアルに際して、

  1. 何を変えたか
    開発チームの体制, チーム再編による技術刷新
  2. どう取り組んでいったか
    学習における課題, 具体的な取り組み
  3. チームは, わたしは何を学べたか

何を変えたか #1
開発チームの体制

From

Front-End : Server-Side = 4 : 8

To

Front-End : Back-End = 9 : 3

比率の変更の理由

  • 事業成長に伴う施策はフロントエンドがメイン
  • 人的リソースの効率化を行うため, 比率の変更
  • 技術的な成長要素と市場価値の創出

フロントエンド?

  • ブラウザ・クライアント
  • アプリケーションコード
  • BFF(API)
  • クライアントサイドのトラブルシュート

までの範疇を広義のフロントエンドととした

何を変えたか #2
チーム体制変更による技術刷新

From

  • Server-Side: Yii Framework(PHP)
  • Front-End: jQuery, Backbone.js
  • Server: apache, and other middlewares
  • Infra: self-uncontrollable な環境

チーム体制変更に見合った技術選定

  • 広義のフロントエンド領域において境界を失くす
  • 言語の違いによるコンテキストスイッチを減らす
  • 共通言語によりappコミュニケーションコストを下げる

To

  • ✏️ : TypeScript
  • 🏗 : Next.js
  • ⚛️ : React/Redux, w/ reselect, redux-thunk
  • 🌐 : express
  • 🌐 : graphql-yoga, express-based
  • Infra: AWS へ移管, ECR + ECS/Fargate...
  • TypeScript, 全員ほぼ未経験
  • React/Redux, 全員ほぼ未経験
  • Node.js によるフロントサーバ, 全員未経験
  • GraphQL, 何それ美味しいの

どう考えても風呂敷広げすぎ問題
さてどうしていくか… 🤔

どう取り組んでいったか #0
チーム学習における課題を考える

考える前に

各スキルセット整理
旧フロントエンド 👩‍💻👨‍💻

  • 渉外的なやりとりにおいてバリューを発揮
    コミュニケーションブリッジとなるシーンも多い
  • app エンジニアとしてのハードスキルが不足

各スキルセット整理
旧サーバサイド 👩‍💻👨‍💻

  • 経験値・ハードスキルが高い
    サーバサイド PHP を触っていた人たち
  • クライアント・ブラウザについては弱い

どのように学習していくかを考える

バックグラウンドが違うメンバーが
ゼロベースの新しいスタックに
どう効率的に学習していくのか

初手: とにかく伝搬

自ら吸収したものをとにかく伝搬しまくる

  • ドキュメントを和訳して Slack で展開
    =>届け、誰かに
  • PoC を実装, コードで展開
    =>読んで、コードを
  • 突然あらわれるライフサイクルメソッドおじさん
    ※ React 16.3~ lifecycle method が deprecated になるタイミング
    =>ついてきてー

知っていることを提供できても
メンバーに伝播できているとは限らない

さて二手目、どうしようか…🤔

どう取り組んでいったか #1
がんばらない TypeScript

Why TypeScript ?

  • クラスベースの OOP 言語なら
    サーバーサイドの人も入りやすいはず
  • 既存のフロントエンドはJSを触ってきている
    (TypeScriptは JS のスーパーセットやろ クチャクチャ

触ってみて

  • 型定義、なにそれ美味しいの?
  • 全然型通らない…なぜコンパイルできない…
  • VSCode が赤くなって何がなんだかわからない…

プロジェクト初期 @__gfx__ さんに相談した

< 型付けをがんばらない

がんばらないTypeScriptのはじめ方 - 角待ちは対空

  • any でもいいじゃない。詰むより作る、前に進む
  • 慣れてくると良さや勘所がだんだんわかってきた
  • any で逃げたところもきっちり型付けしだした

TypeScript…これはいいものですね

静的なコンポーネントから

  • Atomic Design で構成したコンポーネント tsx を静的に実装
  • Props, ローカル State の型付け, interface の規約などを作り慣れていった

序盤で TSLint ルール整備

  • pre-commit hook によりコードの一貫性は最初から保てた

ある程度慣れてからの
メンバーの TypeScript への感想

JavaScriptというゆるふわな言語を TypeScript がガチッとフォローしてくれて良い
Flow を書いていた時よりもガッツリと型を書いている感じがあって最高
VSCode の補完が最高すぎて生産性が爆上がりした
型定義する時に逃げることがあった(any でもOKという安全性も大事)

  • 厳格なスタートを切らない
  • 学習序盤からゆるふわでスタートしても
    最終的に変更・修正できる容易性の方が重要

どう取り組んでいったか #2
Redux とペアプロ

"Redux は学習コストが高い" 知ってる

2, 3名のチーム別に伝達するフェーズ

  • Redux おじさんによる概念説明
  • アプリケーションをグローバルに状態管理できる Pub/Sub パターン!
  • カスタムイベントあるじゃないですか!?
  • イベント来たら反応するめっちゃ便利なオブザーバー!
  • なんかすごい便利なやつ(語彙力

概念的なものは伝わったという意味では
効果はあったのかもしれないが
実装レベルに落とせていない

これは思ったより実装までのリーチがだいぶ長いのでは…?

React / Redux の習熟度が高いメンバーがジョイン

習熟度の高いメンバーを中心にペアプロを行った

※ 一般的なペアプロとは乖離があるかもしれません。

  1. 朝会で機能ベースでペアを決める
  2. ペアで時間を決めて自由にスタート
  3. VSCode LiveShare を使う
  4. ドライバー・ナビゲーターはなんとなく
  5. 3,4 時間使って集中的に

👬 広義のFEチーム内でペアプロをする利点

  • 得意なフィールドによって交代できる
  • 得意なフィールドであれば検索能力も高く
    参考資料として Slack にURL貼り付け
  • GraphQL 側の Logicって? Resolver って?
    違うフィールドへの理解を深められるメリット
  • 適宜交代することで得られるスピード感もある

👄 雑談から得られる利点

  • Tech な話題が多くなり自然とそんな会話になりやすく雑談の質が上がる
  • 共通関数作りたくなる派, 時期尚早まだ共通化しない派など個人の特性がわかる
  • 考え方の違いが出てきたりなど初めて知る部分も多い

⏱ 時間的な制約の中で得られる利点

  • 機能実装の本質に効率的に近づける
  • 個人でやるとリファクタしたくなるところを、今は機能を実装しようというスタイルになる
  • 一人で出来ることは後回し、機能実装を優先できる
  • 一人だと不要な yak shaving をやってしまいがちだが抑止できる

デメリット

  • 口頭伝承スタイルになるのでドキュメントが残らない
  • 知見がどうしてもペアを組んだエンジニア同士で留まってしまう
  • PR も合意が得ているのでレビューを通さないようなスタイルだった

それら度外視しても、ペアプロいいものですね

ある程度慣れてからのメンバーの感想

Redux関連で詰まってることが多かったので LiveShare / ペアプロで進捗がかなり上がった
理解してくると便利に思えてきた
自分はペアプログラミングが結構効いている、質問する時間も省けたり、会話しながらだと理解力も全然違ってとにかく効率良く学べた

  • 自学自習には限界がある
    対話しつつ機能を作っていくほうが
    チームには効率的なシーンがある
  • 雑談、めっちゃ大事
  • ペアプロ、めちゃくちゃいいものですね

どう取り組んでいったか #3
React client tuning と信頼

dev 環境も出来てきたしデプロイしてみたら

  • 👎 インタラクションがもっさりしている…
  • 👎 リニューアル前のサクサクした感じがない…
  • 👎 スクロールによるメモリ不足でブラウザタブが落ちる始末…

機能実装優先で
細部のパフォーマンスまで意識出来ていなかった

計測によるもっさり検出



  • もっさりの感覚値をきちんと確認
  • Chrome DevTools Performance タブ
  • ユーザインタラクションが発生した後に出ている violation(違反)をまず拾い上げる
  • 不快感は遅延したフィードバックが主な原因(200msから違和感)

いつ violation が出る?

  • ユーザイベント(click, touchend, scroll...)によるハンドラ実行完了まで時間がかかった
  • JavaScript 実行時に強制的に reflow が走った
  • document.write を使用した
  • イベントに対して非効率なハンドラのアタッチが行われた ... etc

メンバーに伝搬

  • 習熟度の高いメンバーがサンプルになるようなPRを作成
  • 勘の鋭いメンバーにチューニングの肝を伝搬
  • 計測・仮説(改修実装)・検証、根気のいる作業なので単独作業とし成果をPRでレビュー

violation どう潰す?

  • インタラクションに紐づくイベントへアタッチされた処理から見ていくことにした
  • Performance タブで採取した情報を元手にハンドラを追っていく
  • 詳細計測はUser Timing API を使った計測(React v16から可能)
  • パフォーマンスを意識せず富豪実装していった結果
  • ほとんどがコンポーネントのムダなアップデート
  • 主だった要因としてはスタティックなコンポーネント実装時にすべて FC で実装していたため

マズそうなコンポーネントを洗い出し

  • 適宜 React.memo 化、ムダなアップデート抑止
  • shouldComponentUpdate で適切にアップデートを抑止
  • onClick に arrow-function をそのまま渡していないか( tslint-react: jsx-no-lambda rule)
  • shallow equal の比較よりも FC で再レンダリングした方がコストが低い場合があるので注意 ... etc

勘所を抑えたメンバーが大改善

  • UI コンポーネントから大量に作ったのが仇となった
    後半でパフォーマンス等の整合性取るのはなかなか大変
  • 信頼ベースでタスクを委ねる

チームは, わたしは何を学べたか
learn and delegate

個人の気づき

  • 伝播だけでは空回りしてリーチしない

自分が独習できた環境とは何かを思い出した

  • 人は最初から自学自習できるわけではない
  • 外的要因や環境の上で学習できたに過ぎない

ゼロベースからの
チーム{学習,プレイ}とは

導入を容易に、障壁を軽減させる環境を
整備することから始めよう

1.最初からルール立てて厳格なスタートを切らない

学習序盤からゆるふわでスタートしても
最終的に変更・修正できる容易性の方が重要

2.ペアプロ、めちゃくちゃいい

個人の自学自習には限界がある
対話しつつ機能を作っていくほうが
チームには効率的なシーンがある
雑談、めっちゃ大事

3.後半は信頼ベースでタスクを委ねよ

リニューアル自身の成功・失敗
少しだけクライアントパフォーマンスの話

au Web ポータルですが
実は現在クライアントサイドで
React が動いていません

CSR はリニューアル以前の Backbone.js, jQuery で動いています

理由

  • リニューアル後の事業売上=広告収入が減少
  • クライアントパフォーマンスの影響と思われる
  • 売上としての選択からReact による CSR から以前のスタックへ

何が問題だったか

  • React.hydrate によるイベントへのアタッチ、クライアントで必要な Fetch に時間がかかり UI が遅延
  • それらと広告 3rd party スクリプトとの共存においてどうしてもクライアントサイドのパフォーマンスを上げられなかった

リニューアル後のパフォーマンス値
実は数字が良かったりする

  • 👍 TTFB の向上 => CDN に Akamai を選択
  • 👍 FirstPaint FCP/FMP ともに向上 => React SSR
  • 👎 TimeToInteractive の低下 => アタッチ, Fetch による UI 遅延 e.g. タブ遷移

身内自慢

  • DataStudioとGASでWebPagetestの計測結果をグラフ化する | mediba Creator × Engineer Blog
  • gas-webpagetestでWebPagetestのパフォーマンス計測を自動化、可視化する | Web Scratch

広告表示の優先度を上げるために

事前知識: おおよそ 3rd party はメインスレッドの処理ブロックを引き起こす(`document.write` など)
  • アプリケーションコードをコールバックキューに積んで遅延実行
    => 効果はある。UI 遅延を生む。それはそう。オススメしない
  • <link rel="preload"> で 3rd party を投機的読み込み
    => 効果大。ブラウザの実行優先度を理解するのが良いかも

Priority on Browser(Chrome)

AddyOsmani.com - JavaScript Loading Priorities in Chrome

数値としてはどのくらい盛り返せたのか

リニューアルリリース、その後チューニング for 広告、CSR等変更してリリース
左:リニューアル前, 右:諸々変更を加えてのチューニング後リリース

  • 初期描画, FCP/FMP いずれも向上
  • 元々 Akamai の TTFB が早かったのでさらに後続の数値が良くなる
  • UI 完了も早いので準じて広告描画との棲み分けが最適化
  • 広告売上も4月に入ってきて回復している(まだ経過観察中)

悔しい。あきらめねーぞ

  • React CSR に戻すためには
  • React Concurrent Mode = Async Rendering
  • Scheduling in React

UI = メインスレッドをブロックすることなく
コンポーネントの描画を適宜スケジューリングできるとみんな幸せそう

以上
ありがとうございました

🍜

  • 天下一品 高円寺店 (てんかいっぴん) - 高円寺/ラーメン
  • づゅる麺池田 (づゅるめんいけだ) - 目黒/つけ麺
  • 自家製麺 MENSHO TOKYO - 後楽園/つけ麺

宣伝

フロントエンドランチ

  • ここ 8F でフロントエンドランチを毎週水曜やってます
    (去年6月から初めて今日で39回目でした)
  • Slack にてチャンネルを共有できます
    参加のご希望があれば声かけてください!
  • フロントエンドランチ - mediba

We are hiring.

  • Wantedly, Findy... FE 募集してます