規模感の違う脱レガシーで必要なこと

「レガシー」を保守したり、刷新したりするにあたり得られた知見・ノウハウ・苦労話 by Works Human Intelligence Advent Calendar 2022 の 15日目の記事です。

qiita.com


筆者は過去に、中〜小規模のWebアプリケーションでレガシーフロントエンドの改善作業を業務でやっていた。その経験を元に技術同人誌を作成し、それがきっかけで「レガシーフロントエンド安全改善ガイド」という書籍を出した。

初版から数年経ってしまい、詳細な利用技術などの説明は少し古くなってしまっているのだが、ベースとなる考え方の部分は今でも変わっていないと思う。

一方で自分自身は、その経験が他の環境でも通用するのかを試してみたくなり、転職して一年強ほど大規模なフロントエンド刷新に関わっていた。

あまりにも規模が大きいため完遂を見届けたわけでもないが、現段階でも学びや得られたものは多くあったように思う。それらを踏まえて

  • 規模感関係なく必要だったこと
  • 大規模刷新で新たに必要になること

について、自分なりに考えてみた内容を整理してみる。

話の内容的に、中〜小規模と大規模の両方で得られた知見をベースに書いているため、多くの人に何かしらの部分でマッチする内容になっているはず(と信じたい)

なお、客観的な数値などに基づく事実ではなく、個人の感覚としての部分も多く書いている。そのため、あえて個人ブログに書く形とした。環境によっては大きく違う意見になる可能性もあるが、あくまでも個人の所感として見て頂ければと。

目次

前提

この記事内で説明する「規模感」については、筆者が経験した次のような規模を想定している

  • 中〜小規模
    • 改善対象のコード分量が10万行未満程度
    • ある程度の時間をかければ、個人で全体を把握できる
  • 大規模
    • 改善対象のコード分量が50万行を超える
    • 全体を把握するためにはかなりの時間と労力を要する

規模感関係なく必要だったこと

過去に経験した中〜小規模のレガシーフロントエンド刷新の経験で得た学びで、大規模になったとしても基本的には同じ考えが必要だと感じた部分。少し違う部分もあったりするが、知っておいて良かった・この考えは変わらず持っておいた方がいいな、と思ったようなもの。

改善自体のリスクを把握する

あらかじめ改善作業のリスクを把握することが重要になる。レガシー=悪ではなくて、誰も求めてない改善であればやらないほうがいいかもしれないし、やるなら納得のできる理由がいる。メリット・デメリットを天秤にかけて着手したほうがよい。

これは規模感に関係なく同じで、むしろ規模が大きいほうがユーザーを含めた影響範囲も大きくなるため、むしろ重要度は上がるかもしれない。

把握しておいたほうがよいリスクをいくつか紹介する。

改善のリスク: 挙動の破壊

当たり前ではあるけど、バグを埋めたり既存の動作をぶっ壊してしまう可能性はある。もちろんこれによってユーザー影響が出るのは怖い事態だが、さらに「リスクを取るぐらいなら改善作業はやめておこう…」みたいな空気感になる恐れがある。そういった心理的な障壁は組織に染み付いたらなかなか払拭できるものではないと思われる。

現在筆者が経験している環境ではE2Eテストや非常に優秀なQAチームの皆さんの存在があるので、そもそもの振る舞いを根底から破壊するリスクはかなり軽減されている。逆に言えば「これが無かったら…」と考えるとわりとゾッとする。(無かったとしたら、まずはE2Eを書こう!と強く言っていた気がする)

やはり、まずは安全のために何ができるかを考えてから進めるのは規模感問わず大事。

改善のリスク: 中途半端な状態での頓挫

改善は長く続く可能性があり、さまざまな事情により途中で頓挫してしまう可能性がある。

その場合、改善前後のコードが入り混じった状態になる。これはメンテナンス対象が増えるだけで、かえって複雑化した結果になってしまう恐れがあり、これは規模感に関係なく存在するリスクだと思う。

頓挫する理由は、メインのメンバーが退職してしまったり、組織の変更によって改善作業の優先度が下がってしまったり、色々考えられる。ただ、大規模な刷新の場合は期間が長くなることもあるため、そういった「きっかけ」に遭遇する頻度も上がることになる。

改善のリスク: 改善後の状態が共有できていない(自己満足で終わる)

アーキテクチャをまるっと刷新した場合、刷新後のコードベースに触れる人は新しいアーキテクチャを理解する必要が出てくる。これには一定のコストが必要になる。

「技術が変わるなら学習するのはそりゃ必要だよね」という気持ちになるかもしれないが、ここで大事なのは “腹落ち感” で、なぜ変更するのか・何に変更するのか、といった点が納得できているかどうかで、だいぶモチベーションが変わると思う。

このあたりを雑にやると「改善したと思ったら開発コストめっちゃ上がりました」なんてことになりかねない。規模が大きいと人数も増えるため、このあたりの影響も大きくなる。

ちなみに、筆者が過去にやった場合は、事前にADRを書いて認識を確認したり、刷新後も勉強会を開いたりという対応をしていた。

現在筆者が関わっている大規模刷新の環境においては、刷新チームを立ち上げるタイミングで、旗振り役をしてくれている方がきっちりと思想の部分を文書として見える形にし、さらに丁寧にMTGを重ねて共有をしてくれた。また、数ヶ月に1度程度のタイミングで全メンバーが集まって意識を揃える場が設けられている。そのおかげで、個々の小さいチーム単位では目標が変わったりすることはあっても、刷新チーム全体でのベースの思想や目的みたいなところは安定している印象がある。このあたりはあまり関われてなかった部分なので、今は「すごいなぁ」と横で思いつつ、今後の糧にしていきたい。

まずレガシーコードをちゃんと理解する

いきなりコードに触るのではなく、ちゃんとレガシーコードを理解するところから始めたほうが良い。

特に歴史が長いサービスの場合はコードを読み解くのもかなり苦労する。だが、理解できないものは刷新することもできないので、ある程度時間をかけて把握していく必要がある。

また、規模が大きくなると、”レガシーコードの理解” の範疇に人やチームの概念が頻繁に登場してくる印象を持った。純粋にコードを読んで理解すれば良いだけではなく、変更において影響を受ける関係者が誰なのかを意識する必要が生じる。

アジャイル開発においてインセプションデッキを作ったことがあると、その中で「ご近所さんを探せ」という項目があるが、それに近い感覚。プロジェクトに関係するメンバーをきっちり洗い出しましょうね、という話なのだが、規模が大きくなるとさらに重要になってくる印象を持った。

レガシーコードを読み解いていくなかで「これはなぜこんなことに…」みたいな仕様が顔を出すこともあり、関係者が把握しきれていない場合、このあたりが迷宮入りしてしまう恐れがある。

ちなみに、筆者は書籍の中では「できれば理解した内容は資料化もするといいよ」と書いていたが、これもやはりそのまま同じ考えのほうが良いと思った。期間が長いと必然的にメンバーの入れ替わりも一定数発生するため、その際に資料が残っているメリットは大きい。また、新規メンバーに限らず、そもそも書いた本人も数ヶ月とか時間が経つと普通に内容を忘れるので、未来の自分のためにもなる。また、”ご近所さん” に確認してもらうタイミングでも資料はあったほうがよい。

改善で得たいものを明確にする

改善したいということは、何らかの得たいものがあるはずで、それをちゃんと明文化したほうがいい。これは色々あるはず

  • 開発速度を効率化したい
  • 魅力的な職場にしたい
  • ページのパフォーマンスを上げたい
  • などなど…

作業を進めていく中で、優先順位をつけて取捨選択する機会は頻繁に訪れる。その際に、自分達が何のためにこの改善作業をやっているかがわかっていれば、判断軸の一つになる。

また、段階的に改善が進んでいったときに、思い描く理想のゴールが見えていれば、それに対してどれだけ近づいたのかもわかるため、モチベーションにもつながってくる。

大規模な場合、チームが複数に分割されることも考えられるため、全体として目指すものが何かをきちんと明文化しておかないと、チームがそれぞれ的外れな方向に進んでしまうかもしれない。

小さく進める

規模感に関係なく、いろんなものを小さくしていくほうがよい。

コードの変更量を例にとっても、1回の変更が大きいほうがコンフリクトのリスクが上がっていく。大規模刷新の場合は複数チームが並行して同じコードベースを触っていることも多く、リスクはより高くなる。

ちなみに、筆者が思っていたより特に重要だったと気付かされたのは “リリースサイクルの短さ” だった。

リリースサイクルが短いことのメリットは多くの書籍などで語られており、もはや誰しもが知るところだと思われるため割愛するが、なによりもメンバーのモチベーションに直結している印象があった。

筆者は大前提として「改善作業はやらなくていいなら誰もやらない」という認識を持っているのだが、これは目に見える形でのユーザーへの価値提供を感じにくいから、というのもある。

ただでさえそういった性質の作業にも関わらず、対応した作業が長期間に渡ってリリースされないと「俺は一体これだけの期間なにを・・・(ここで記憶が途絶える)」みたいなことになる。

ただ、リリースサイクルはサービスの性質によっては簡単は変更できないケースも多い。もし調整できるなら短いサイクルでのリリースとしていくとよいが、厳しければ、自分たちで何らかのマイルストーンを設定し、きちんと進んでいる実感を得られるようにすることが大事なのかもしれない。実際筆者の環境はそんな感じでやっていて、「ここまでできれば実質リリースと同じ」みたいなラインをチームで設定することで、ある程度細かくかつ短いスパンで進められるようにしている。

一度に複数のことをやらない

改善をやってると、その中でいろんなことが目についてきて、複数の改善を並行してやりたくなってくるが、できれば避けたほうがいい。

先に挙げた “小さく進める” と相反してしまうことになり、1回1回の作業ボリュームが増えてしまう。「○○が終わった!」というまでの期間も長くなる。成果の得られない作業が続くのは結構ツラいと思う。

「どうせ改善をやるならついでに○○もやろう」みたいな気持ちで、小さな機能開発やデザインの変更なども一緒にやりたい気持ちになるかもしれないが、脱レガシー以外の作業を一緒にやるのはさらに強い気持ちで回避したほうが良い印象がある。

そもそも脱レガシーとそれ以外の作業では大きく文脈が異なり、関係者も違えば影響範囲も異なる。それを混ぜてしまうと、自分たちが何を目的として作業しているのかを見失ってしまう。また、トラブル発生時に、どちらに原因があったのかの追求も難しくなる。最終的なゴール達成までの工程や手順も同じではない可能性があり、作業プロセスの改善もしづらい。

もちろん作業環境などに応じて背景や事情はあるため、「そうはいってもな…」となるかもしれないが、できるだけひとつに集中して片付けてから次に行ったほうが懸命。

大規模刷新で新たに必要になること

ここからは、大規模ならではで必要になると感じた部分。

「規模が変わるとこういうケースもあるよ」と気をつけておいた方がいいと思ったもの。

チームや関係人数も「小さくする」

先に述べた通り、以前から筆者は「小さく進めましょう」というのを重要視している。一度に進めるものが大きいほどリスクが高まる。修正するコード量からPRのサイズ、作業サイクルやリリース間隔など、さまざまなことに対して言えると思う。

これが大規模なものだと、さらに「チームや関係者の数」という概念が出てくる。そもそも刷新作業に参加するメンバー数が多く、伴って外部関係者の数もかなり多くなる。

一つ一つの作業量を小さくしようと思っても、関係者が多すぎるとそれ自体が困難になる。手こぎボートなら1メートル単位で調節して船を進めることも容易だが、巨大客船ではなかなかそうはいかない。

このあたりは、現在のチームで輪読会などもやったチームトポロジーにおける「認知負荷」の考え方から得られたものも大きいように感じる。

大規模刷新で人数が多い場合、何らかの形で小さなチーム単位で分割し、それぞれがオーナシップを持って動けるようにするのが重要だった。どうしてもコード上での重複などは発生してくるが、体感的にコミュニケーションコストのほうが圧倒的に高い。適切に権限が委譲されていれば、それぞれのチームで責任を持って進めることができ、意思決定が速くなる。

全体を加速させる取り組み

小さい規模の場合、極端な話 “めっちゃ凄い数人がゴリ押しで刷新を終わらせる” みたいなパワープレイもできてしまう。全体像も見えやすいし、終わってみてから「結果的に○○ヶ月で終わりました!」で済むことも多い。

一方で規模が大きいと、24時間365日コードを笑顔で書くようなGODエンジニアでない限り、個人の力で直接的に影響させられる範囲には限界がある。

多くのメンバーが長い時間関わることを考えると、一人がパフォーマンスを出すだけではなく、周りが加速するための取り組みが求められてくる。いままではレベル高い人がパワーで殴れば敵を倒せていたものが、メンバーにバフをかける役割の重要度が上がってくる、みたいな感じ。

具体的なところでは

  • チーム間でのコミュニケーションを円滑化させる(ツール導入や会議体をうまく設定する)
  • そもそも普段の開発効率を上げる(CI高速化とか)

みたいな部分が該当してくると思う。

筆者がやってみた取り組みとしては、レガシーコードの解読を加速させるために、Chromeで使える DevTools を作ったりVSCode Extensions を作ったりしてた。

モチベーション維持がより重要になる

脱レガシー作業において最悪な事態は何かと考えると、それは「脱レガシーをやる人が誰もいなくなる」だと思う。人がいなければそこで終わりです。

大規模なものは期間も長いし、困難も多い。モチベーションが維持できないとそこから崩れていく可能性がある。「仕事なんだからモチベーションとか甘えたこと言わずにやれよ」と思う人もいるかもしれないが、筆者は「仕事なんだからモチベーションを保つ努力をしましょう」という意見です。

ちなみに、現在関わっている大規模刷新では、わりときっちりとしたスクラムを組んで進めており、それがモチベーション維持にも有効に働いている面があるような印象を受けている。複数チームが存在し、チーム単位でスクラムマスターがいる。

このあたりは、初期段階で社内でのスクラム神みたいな方が入って一通り整理してくれたのが大きかった。傍から見ていて手腕がすごかった。これが神かという感じ。

正直なところ、最初は「脱レガシーみたいな刷新作業とスクラムって相性良いのだろうか?」みたいな気持ちも少しあったのだが、実際やってみると、経験も多種多様なメンバーが長期間に渡って協力して進めていくなかで、チームが消化できるベロシティを測定して進めていくことは結構重要に感じた。ベロシティが数値として見えないと全然現実的な予測が立てられない。

きっちりとバックログとして見積もりを立てて消化していくと、チーム内で一定の目標やマイルストーンも上手く設定できるようになってくる。「こんだけ進んでるぞ!ウォー!!!」となるだけで、ある程度は楽しくやれる。

「戦略的撤退」が難しくなる

小さく進めていくことの一つの理由として「途中での戦略的撤退を可能にしておく」という点をメリットに感じていた。

脱レガシーは途中で立ち行かなくなる可能性があるため、その際に更なる負債を増やしてしまう可能性をできるだけ小さくする意味でも、「ここまでやったら一旦終わることができる」というチェックポイントを設けるのは一つの手だった。

これは改善が複数テーマにわたる場合には規模感関係なく有用だと思う。たとえば、Lintもテストも型もないようなコードベースを改善する場合、「ひとまずLintは入れた。組織体制が変わってしまったので一旦これで撤退」みたいな判断ができる。やっていることが単純なものであれば、ロールバックも可能かもしれない。

しかし、大規模の場合は、期間も修正量も大きいため “取り返しがつかない” といった凶悪な事態を引き起こす可能性が出てくる。単純な話として、年単位の時間をかけた大勢の手による変更を全部ロールバックできるか?と言われると現実的に厳しいものがある。

一人で隣町まで行っただけなら帰り道も辿れそうだが、みんなで宇宙に行ったら簡単には地球には帰ってこれない。ちゃんと次の惑星に辿り着かないといけない。撤退という選択肢がどこかのタイミングで難しくなってくる。

対応策は何だろうと考えてみたが、アプリケーションを機能単位などでうまいこと分割して境界を作り、影響範囲を境界内に閉じていくことかもしれない。やはり「小さくする」というのは重要になってきそう。あとはもう、具体的でもなんでもない話になっちゃうが、ある程度は「覚悟」みたいなものが必要になるのかもしれない。

「手伝う」には限界がある

これは自分が関わったチーム・組織固有の話の部分もあるが、最初は特定技術分野に特化した横断チームで脱レガシーを「支援」するという形を取っていた。規模が小さければ、支援チームだけで文字通り「手伝う」形でガッと改善対象をやり切ることも可能かもしれない。

ただ大規模になるとこのスタンスでは厳しいものがあることを学んだ。

冷静に考えると当然なのだが、多くの人々が長い期間かけて作り上げた巨大なコードベースに対して、支援チームが片手間でやれることには限界がある。何かやろうにも、どうしても ”チームのできる範囲でできることだけやる” というところで終わってしまう。

現在では完全に刷新チームが立ち上がり、それを手伝うというよりも完全に中に入って一緒に作業を進めていく形を取っている。より踏み込んだ話もできるし、改善作業におけるコードベース以外のプロセスなどの課題点も見えてくるのは大きい違いがあるように感じる。

総合して → 知見やノウハウは対象規模とセット

いろいろと書き綴ったが、総合してまとめるとこれに集約されそう。

脱レガシー作業というのは常に需要があり、流行りの言語やFWを使っていたとしても、時間が経てば結局レガシーになる。脱レガシーは世の中の至る所で実践されており、それらは発表資料やブログ、書籍などで多くの事例が出てくる。筆者が書いた本もその一部でしかない。

それらから知見やノウハウを得る場合、そもそもどういった規模感を対象にした情報なのか留意する必要がある。「3人の脱レガシーチームで、ツールを使うことで1ヶ月で全体を置き換えました。」みたいな情報があったとき、単純に「ツール使えば簡単にできるんや!!」と思ってやってみると、全然思った通りに進まずに事故るかもしれない。

知見やノウハウをそのまま鵜呑みにするのではなく、どういった前提が置かれているのかも注意が必要になる。具体的に幾つか例を挙げると次のようなものがありそう。

  • 全体のコード量やユーザー数はどの程度なのか
  • サービス性質として、軽微な不具合がどの程度許容されるのか
  • どの程度古いコードが対象だったのか
  • 脱レガシーで影響を受ける他のエンジニアはどの程度の人数いるのか
  • など

なお、これは “既存の情報が役に立たないことがある” という話をしたいわけではなく、”あなたがその知見やノウハウの対象ではない可能性がある” 点に気をつけた方がいいという話。これはまさに筆者自身が自分で書いた書籍と現実の内容とでギャップを感じた部分でもある。

ただ、前提とされている対象に近づくことができれば、知見やノウハウが実践可能になるケースもあることも同時に感じた。中〜小規模の経験に基づくものでも、チームを少人数規模に分割する・機能単位でコードをメンテナンスできる体制を整える、みたいなことができれば適用できる部分が出てくる。このあたりの前準備が必要になることも併せて意識しておくと良さそう。


というわけで、規模感の違いによる脱レガシーの話でした。

だいぶ個人の感想っぽいものを長々を書いてしまったが、誰かの役に立ったのなら嬉しいです。

📝 Vue Fes Japan Online 2022 / 見たセッションメモ

vuefes.jp

一日セッション見つつメモを残したので、個人ブログに放り投げておく。

殴り書きなので何の清書もしてないし、誤字脱字もチェックしてないです!!!

Keynote | The Evolution of Vue / Evan You

https://vuefes.jp/2022/sessions/yyx990803

  • 0.x系の Pre バージョン時代の話
  • ES5のみのFeatureを前提にする必要があった
  • 1.0のコードネームってEvangelionだったのか..
  • 2015-2016でのコアなライブラリ群の追加が多かったらしい。Vue Router とかVuex
    • 大規模SPAアプリケーションの構築の解決狙い
  • Vapor Mode
    • Virtual DOM への依存がない
    • パフォーマンス特化でのプリビルド
  • 今後
    • Vue2→3の移行期という認識
    • 30%が Vue3, 25%が 2.7らしい
    • Composition API と script setup は 50% 超えてるらしい
    • 暫くは大きな変更がない状態で使ってもらい、変更があっても既存機能は使える状態にする
    • Resumable Hydration (Inspred Qwik)

突然 Qwik が出てきてビビるが、未来の新しい姿がチラ見えしてた。

メドピアのサービスにおけるテスト戦略の過去と未来 / メドピア株式会社

https://vuefes.jp/2022/sponsor-sessions/medpeer

  • kakari というサービスのテスト戦略
  • RailsMPA & クライアント側で Vue の SPA のハイブリッドな構成
  • Jestでカバレッジが50%以下 → 現在はコンポーネント数が倍以上でカバレッジ60%切る程度
  • Storybookでの開発とreg-suit
  • が、Storybookはうまく運用に載せられず破棄したとのこと
  • 計画的なテストやツール導入が大事だよという話だった

Storybookを後々破棄したというのは悲しい話であった。 ただ導入するのではなく、運用周りとかまで考慮しないと上手くいかないのかも。 テストとの乖離があったとのことだったが、そのあたりは composeStories とか使うと少しは軽減できるのかもな〜とかを考えてた。

Evan you に聞こう

  • Q: 他FWと比較した場合のVue.jsの良さ
  • A: Vueが一番 Approachable。ドキュメントの充実や、とっつきやすさ。Vueに馴染みがないメンバーでも学習コストが低く戦力になれる。
  • Q: こういうユースケースでは Vue がいいよ、という例はあるか
  • A: ユースケースがわからないような場合にとりあえずVueを使う、というほうがわかりやすいかも。 Progressiveという意味として、小さく初めて大きくする。 Javaで作られてるようなアプリケーションとかにビルドステップなしで導入ができたり、 大規模なJavaScriptアプリケーションにも導入できる
  • Q: SFC で JSX のように複数 template を変数化する未来は来るか?
  • A: 技術的には可能で、RFCでDiscussionもある。ただ、SFCの場合は影響が大きい。 Closedなシンタックスで作って影響が閉じるようにすれば技術的にはできそう。 将来的に、Discussionの中で有用なユースケースが出てくれば可能性はあるが、それ以上の回答はできないのが現状。
  • Q: Options API は今後もサポートされる?
  • A: いまのところ大きな変更は予定してない。Options / Composition API 両方いい形に落ち着いている。 Options API に機能が追加されなくとも、裏側では Composition API は使われている。 今後しばらくは Options / Composition API ともに大きな変更は予定されてない。
  • Q: ハマっているアニメはありますか?
  • A: 実はアニメあんまりみない。漫画は読む。呪術廻戦
  • Q: 仕事とOSS貢献を両立するコツは?
  • A: 実際Vueを始めたときはGoogleにいて、仕事しながらOSSするのは最悪のワークライフバランスへの近道。 なんのためにOSSをやってるのかで、ワークライフバランスが大事なら趣味としてやるといい。 コミュニティにスタンスをオープンにしておくと気持ち的にも楽になる。 キャリアを意識してフルタイムでやるなら、ワークライフバランスを犠牲にする必要もでてくる。 自分の中でOSSを何のためにやるのか?を把握してやっていくのが重要。
  • Q: Nuxt3が未だにRCバージョンだが、VueのLTSに影響を与えることはあるか?
  • A: NuxtもVueも独自のタイムラインで動いていて、基本的には関係はない。 Vue2は来年の年末がLTSとアナウンスしていて、Nuxtとすり合わせて調整するなども考えてはいない。 補足すると、Extend Support (延長サポート)というプランを計画している。これはスポンサー企業等向けの有償サポートになる。
  • Q: デザイナーはどうOSSに貢献できるか。ドキュメント以外でコントリビュートできるか?
  • A: 非常に興味深い質問。いまのところVueにデザインに関する大きなニーズは無い。 ドキュメントもリデザインは終わってる。ただ、イラストレーションがあったらいいな、という話はある。ブランディングも含め様々なテイストがあって一旦話は流れた。 デザインは顧客中心にニーズなども考えて入っていく必要がある。 「プロダクトが好きでやれることはある?」と聞いてみるのは良い。 いきなりロゴをデザインして投げてみるなどは迷惑になることが多い。 プロダクトが求めていることを把握する、というステップを踏むのは良いと思う。
  • Q: ViteがDenoで動くようになってきてDenoが整いつつあるが、Vue本体でも準備していくか?
  • A: いまのところViteでDenoが動いてるなら動くはずだが、SSRがキーになる。 Cloudflareで動いてる例などを見たことがあり、おそらく動くはず。
  • Q: SolidJSにインスパイアされたVaporなど、今後サポートする領域が増えるとリリースに時間がかかるなどの影響がありそうといった懸念があるが、どう考えているか?
  • A: 基本は自然な流れだと思ってる。どのプロダクトでもユーザーが増えると速く動けない。 ミッションクリティカルな部分で使われてるケースもあり、責任もある。 Vue2からVue3への新しい書き方の紹介での反応から学んだこともある。 リリースに対して慎重にならざるを得ないのはそうかなと思うが、人が少ないとかそういった理由で遅くなっているわけではない。
  • Q: 何があなたをVue.jsに駆り立てるのですか
  • A: 情熱やモチベーションはフェーズによっても変わってきた。 最初は趣味で、技術的に新しいことをやってみたかった。 途中から Vue の認知が増え、もっと大きなものになるかも?という野心的な思いがあってやっていた。 今は責任感が非常に大きい。コミュニティの強力がなければVueは今の場所にはない。 今の生活がかかってる、というのもある。 責任感もあるが、技術者として新しいアイデアを見つけるなどバランスにも気をつけている。今Vueに関われて新しい挑戦もできているのは幸せな点。

エモかった。 キャリア意識するならワークライフバランスを犠牲にする判断もあるぞ、と言ってたのは強かった。個々人で判断するならたしかにそれもアリよな。

負債が溜まったレガシーフロントエンド画面を Vue.js でリプレイスした話

https://vuefes.jp/2022/sessions/t0yohei

  • 10年前に生まれた Rails + jQuery のアプリケーション
  • 見た目を変えたいのにRailsを触る必要があるなどの課題
  • 優先順位つける → 将来的に改善可能性が高い画面から
    • 変更頻度はみない。バナー変更などによる変更の可能性もあるため
  • StorybookやVRTによる担保
    • 一括リプレイスのため、E2Eは考慮から外した
  • むずかしさ
    • jQuery→Vue.js (命令的UI→宣言的UI)の置き換えの難しさ
    • A/Bテストの残骸など、使われているかわからないコードがある
    • 実は元々壊れてた場所
  • 本体リリースに先駆けて整理した
  • Container Component を使い統制を取る
    • styleを持たず。バックエンドとのやり取りをする
  • script を持たない Layout Component で整理
  • 「どうして…?」というコードがあった
    • HTMLがAPIで返ってきちゃう
  • 既存のAPIのレスポンスに、UI側に制御を委譲するために必要な値(例だとID)を追加することで既存影響を減らす
    • APIレスポンスにHTMLが残ったままになるけどいいのか?
    • → 将来的に独立化を検討し、一旦はOKという形で進めた
  • 目的を明確にしてやらないことを決めるのが大事 + やめないこと

JSからTSへ移行したVue.jsプロダクトの型チェックを漸進的に強化する

https://vuefes.jp/2022/sessions/kawamataryo

  • TS化が不完全なVue.jsプロダクトの型チェックをどう強化していくか
  • TS & Vue の歴史と現場の話。今はVue.jsのTS対応は充実してる
  • LAPRAS … Django & Vue.js。Vue.js SFC が 680ファイル。TS 750ファイルほど。
  • TS化が不完全
    • lang="TS" ではない SFC
    • strict: true ではない
    • CI で型チェックできていない
    • エディタがエラーで真っ赤になる
  • 実行時エラー回避や開発体験・保守性向上に加え、Vue3更新への布石も踏まえ更新をしたい
  • Design Doc の作成からやった
    • なぜ・何のために・どのように進めるかを記す
    • 背景、設計、トレードオフ、リスクなどを整理
    • 必要なければ無理に script=setup に書き換えない
    • TS → SFC Script → template の順番に順次型エラーを直す
    • 新規に型エラーの混入を防ぐため、まずはCIでの型チェックを導入する
  • TS化のジレンマ → CIでチェックしたいが、既存コードの型エラーが多すぎて型チェックを強くできない
  • 静的アセットのビルド結果比較
  • TS化の進捗を可視化するDashboardを作成

十数万レコードに耐えうるVue.jsプロジェクトを実現するためのパフォーマンスチューニング

https://vuefes.jp/2022/sessions/tbashiyy

  • 大量データ(4000人)を入れてみたらめちゃくちゃ重くなった
  • 4000 x 40属性で16万件入る
  • 初回アクセスですべてのデータを Vuex に格納してるため
  • 画面ごとに必要なデータを取ればいいが、修正影響が大きい
  • 既存アーキテクチャを変えずにパフォーマンス改善をしたい
  • Chrome DevTools を用いた計測から
    • Peformance計測から、時間のかかっている処理とメモリ使用量の多い部分を調査
  • Object.freeze を利用し、リアクティブを回避
  • 大量の"組織"の描画
    • 一部から描画されるように対処する
    • 画面範囲外はレンダリングさせない … Intersection Observer API
    • 画面外は枠だけ描画して対処
  • まずは計測

なるほどVueコンポーネント

https://vuefes.jp/2022/#naruhodo-vue-component

Options API → Composition APIコンポーネント開発はどう変わったか?

  • Options API がオブジェクトスタイルで書いていたのに対して、Composition API では関数ベースで書ける
  • 置き換えしてみて大変だったことはある?
    • 置き換えツール的なものを利用した
    • 型については Vue.extend → defineComponent でいけたが、単純に物量のつらさ
  • 置き換えツール的なものについて
    • SFCを入力に、script部をAST解析してCompositionAPIに変換する
  • Options API は複数コンポーネントで共通部の抽出がつらい
    • computedの共通化とか。Mixinがあったけど、Mixinつらい
  • コンポーネント単位が大きくなりがち
  • Composition API ではテストが書きやすくなった

Vueで作るアクセシブルなコンポーネントについて

  • STUDIO のアクセシビリティについて
    • 詳しい人じゃないとわからない、というのが難しい部分
  • Vueならではの大変さ
    • Vue特有みたいなものはないが、HTMLの構造を変えないといけないシーンがあったりする

(疲れてしまってこのあたりで少し離脱した。老い)

From Zero to One

https://vuefes.jp/2022/sessions/Atinux

  • Nuxt Web について
  • Nuxt Labs 創業者 Sebastien Chopin によるセッション
  • Nuxt は 5200万DL されており、35万以上のサイトで利用されてる
  • Nuxt2 と Nuxt3 の比較
    • Web Server: connect → h3
    • Bundler: Webpack 4 → Vite or Webpack 5
    • UI Framework: Vue2 → Vue3
    • Routing library: Vue Router 3 → Vue Router 4
      • ルーティングが必要ない場合ライブラリごと除去される
    • Meta management: Vue Meta → VueUse Head
      • Server(less) packager → Nitro
  • Hello world アプリケーションで比較した場合、Nuxt2→Nuxt3でサイズが1/3 (30kb程度)
    • Next 12 と比較しても小さい
  • Nitroが生み出してるコードは何?
    • 以下が、約8kbに含まれる
      • Hydration用コード /
      • <Suspense> を使ったルートコンポーネント
      • Head 系の composable / コンポーネント
      • Universel & lighweight router
      • $fetch
      • デフォルトのエラーページ
      • Hook システムなど
  • Nuxt3
    • Edge Side Rendering
      • CDNのノード上で動作させる。制約として、たとえばサイズ制限(5MB)など、Node.js や ブラウザ API は使えない。Nuxt3 はこれらを回避できる。
      • NITRO_PRESET=cloudflare npx nuxi build でビルドできる
      • https://vuefes.nuxt.workers.dev/ でデモを見れる
      • Cloud Flareworkers / Vercel Edge / Netlify Edge / Deno Deploy / Lambda Edge などなどで動く
    • Nuxt Image (現在はβ)
    • Hybrid rendering: Server + SWR + Pre-rendering
    • Full static generation
    • Component Islands
    • PWA
    • i18n
    • など
  • 現在 41 のモジュールが存在する
    • content モジュールとかが人気
  • Nuxt Themes
    • Docus と呼ばれるもの
  • Nuxt 2.16 も止まったわけではない
    • Vue 2.7, Next Bridge(beta) など

Vite 3 and Beyond

https://vuefes.jp/2022/sessions/patak

  • Viteは Vue 3 での推奨になっており、Nuxt 3 でも利用されてる
  • Slidev, Vitest など..
  • Larabel が Vite をデフォルトで採用した
  • Vite 3 の新機能
    • Node 12 ドロップ
  • ドキュメントが新しくなった
  • スターターテンプレートを整理
  • 最初のロードに時間がかかってしまう問題について
    • 通常は Code Spliting で対応する
    • 事前に分析して依存パッケージをesbuildでバンドル
    • 2.6 以前は、スキャンと最適化はサーバ起動前にやってた
    • 2.9 時点では、並列で処理できるようにはなってたが、プラグインが依存関係を注入するなど、見つからないコードがあると解決に失敗するため、その場合はフルリロードが必要だった。これによって、特定のプロジェクトでは起動が2倍遅くなる
    • 3.0 ではこれが改善、かつ依存がキャッシュされるため、2回目以降の起動は特に速い
  • ESMがデフォルトに。現状CJSのためのレイヤーは提供しているが、将来的にすべてESMになるのを想定。
  • Vue 3.1も既にリリースされてる
    • HTMLパーサーを parse5 に移行
    • Rollup の新しい機能(Stage)が使える
  • バンドルサイズも削減
  • Vite 4 の話
    • HMR Partial Accept
    • ESBuild Deps Optimazation at build time
      • デフォルト有効化されるかも
    • Rollup 3 への更新
      • これは Vite 4 を待たずに更新されるかも

Component Testing

https://vuefes.jp/2022/sessions/Jess

変更時の再ロードがめっちゃ速い。常に画面見ながら開発できるのは体験として良さそう。 ブラウザ起因の不具合とかも起きづらそう。

ただ、途中の激しいメソッドチェーンはちょっと読みづらいかもなぁという感想だった。

今ならPlaywrightでも類似のことができるはずなので、導入検討するならそちらも見たほうが良さそう。

Patterns of VueUse

https://vuefes.jp/2022/sessions/anfu

  • VueUse 開発から学んだベストプラクティス
  • unref による ref かどうかに関わらない値の取得
  • 引数で取る場合には MaybeRef 型が使える
  • VueUse 9.0
    • computed を渡すのではなく、単純な getter 関数を渡すと内部で computed にしてくれる
    • "Reactivity Getter" と呼ぶらしい
  • effectScope
    • onScopeDispose を使うことで、一括した破棄処理などができる。 onUnmounted 時も呼ばれる

effectScope は把握してなかった。 onScopeDispose との組み合わせで、汎用 Composable 作るときにクリーンアップ処理を柔軟にかけるの良さそう。

Peephole

まだ公式じゃないが、実験的に開発している機能などを紹介のコーナー

unplugin-vue-router

  • Vue Router の型を定義できるようになってる
  • auto complete などが使える
  • FileSystemルーティングでのルーティングでの型推論が効く
  • vue-router/auto
  • 追ってRFCでユーザーの意見も聞いていく
  • パスの絞り込みを行うと、paramsの方も絞り込まれてtype safe になる

pinceau

  • (パッソ) / フランス語でブラシの意味らしい
  • https://github.com/Tahul/pinceau
  • CSS in TS framework
  • こちらも unplugin 配下らしい
  • Nuxt とか Vite とかで使える
  • Configuration フェーズと Painting フェーズ がある
  • 設定の定義としては、Design System に則って設定する。CSSだけを定義するだけでなく、スクリプトとかも登録する
  • <style scoped lang="ts"> の中でCSSをTSで書く
  • auto complete が効き、native css のものは使えるし、事前に定義したものも使える
  • 設定ファイルから消すと、IDE上ではエラーになるし、型としてもエラーで検知する
  • 複数プロジェクトで同じデザインシステムを使ってる場合に、変更を検知でき、堅牢に定義できる
  • computed style
    • 関数を渡すことができる
    • 関数から props を利用したスタイリングもできちゃうし、型チェックも効く
  • テンプレートの中でオブジェクトを渡して使い分けることもできる (sm/md/xl とかで設定を分けるとか)

computed style は styled-components みたいだなって思った

reTypewriter

https://github.com/antfu/retypewriter

  • Typing Simulator
  • コードの変更を再生するソフトウェア
  • デモでコードを書いたときに誤字もあって、成功するまで収録しなおすのがつらい
  • VSCode Extension で使えるようになってる
  • 適宜スナップショットを撮る
  • 共通部分は再利用するような感じで動く。ホントにType Writer みたいな
  • 一度スナップショットを作れば、reTypewriter側の修正で順番を入れ替えたりもできる
  • ミスのない発表ができるぞ!!

かんそう

数年前に台風を食らってしまったVuefesのときは本当に残念だな〜と思ってたので、ただの参加者だが感慨深い感じがあった。

仕事でVueは使わなくなってるが、順調に進化しているな〜という印象。 型周りがツラいと言われてた気がするが、今やそんなことはないのでは?という感じがした。

🏏 素振り: React Hook Form

あーはいはい、React Hook Formね、知ってる知ってる(知らない)

そんな状態なので素振りしておく。


React Hook Form

https://react-hook-form.com/get-started

React Hook Form の重要なコンセプトの一つは、非制御コンポーネント (Uncontrolled Components) をフックに登録(register) し、フォームフィールドの値を検証と収集できるようにすることです。

DOMベースに値を持つコンポーネントを主体に、いい感じにフォーム管理ができるものという理解をした。 自分がReactを書くときは今のところ制御コンポーネントを使うケースが多いので、React Hook Form 向けに脳をスイッチしないといけなさそう。

useFormregister

特に重要なのは useFormregister の2つ

const { register, handleSubmit } = useForm();

<input {...register("firstName")} />

register から UseFormRegisterReturn 型の値が返ってくる。 非制御コンポーネントで必要になる ref や、onChange, onBlur なんかも一通り含まれるので、これをprops適用するだけで一通り input タグのセットアップが終わる。

既存フォームへ適用する際は、register そのものを渡すか、 forwardRefref を透過的に扱う。

❓ 状態管理する場合の例として、状態管理への書き込みをonSubmit に仕込んでる。現実問題他のタイミングのほうが多そうだけど、値をサッを全部取ったりはできない?

getValues 呼べばok

TypeScript との組み合わせ

https://react-hook-form.com/get-started#TypeScript

useForm に対して型定義を指定するだけだった。 getValues とかもいい感じに型がついた。

バリデーション

❓ バリデーションといえばzodを思い浮かべたけど、連携できるのか?

人類が考えることは同じだった。先駆者の皆様ありがとう

react-hook-form と zod でバリデーションのその先へ React Hook FormとZodを組み合わせて利用する|食べログ フロントエンドエンジニアブログ|note

どうやら Resolver という仕組みがあり、バリデーションライブラリであればシームレスに統合できるらしい。

https://react-hook-form.com/api/useform/#resolver https://www.npmjs.com/package/@hookform/resolvers

zod であれば @hookform/resolvers/zod でいける。

FormData と型定義が重複してツラいのかと思ったけど、 z.infer で型に変換すればいいだけだった。

https://github.com/colinhacks/zod#type-inference

const schema = z.object({
  firstName: z.string().min(1),
  gender: z.enum(["female", "male", "other"]),
});

type FormData = z.infer<typeof schema>;
<input {...register("firstName")} />
{errors.firstName?.message && <p>{errors.firstName?.message}</p>}

完全に理解したので、ほかのAPIとかをみてみる。

useForm

register 以外で気になったやつを見てみる

formState

フォームの状態に関する色々を含んだ state らしい。 - isDirty で変更されてるか / dirtyFields で変更されたフィールド値 - defaultValues で初期値 - valid かどうか みたいなものが取れる。

watch

変更に応じて再描画をトリガーさせたい時に使えるらしい。 なんか迂闊に使うとめっちゃパフォーマンスへの影響がある気配を感じた。

reset

リセットするらしい。 コンポーネントのライフサイクル的にリセットが必要なケースでは役に立ちそう。

trigger

バリデーションを発火させるらしい。メソッド名 validate とかじゃないのね

useController

他のフォームコンポーネントライブラリを使う時に、register だと適用できないので、useController を使うことで独自にマッピングできるぽい。 基本的に register を使っておいて、どうしようもないときの手段と理解した。

useFormContext

コンポーネントってフォームも含めてネストするのは容易に発生するので、その時に Context 使っていい感じに子孫に受け渡せる。便利そう。 実際には FormProvider でラップする。

でもテスト書く時とかどうなるんだろ。

useWatch

watch での再描画のスコープをフックの範囲に閉じ込めるものぽい。 迂闊に watch 使うと再描画激して死ぬみたいなシチュエーションで、子コンポーネントだけに再描画範囲を閉じ込めたりできそう。ナルホド

useFormState

useForm で生成される状態のうち、一部の状態のみに絞り込んでSubscribeできるようになる。 FirstNameInput みたいなコンポーネントを作った時に、 useFormState 経由で firstNameだけ購読させれば、レンダリングの抑制ができるぽい。

useFieldArray

配列系のフォームの操作で使える。 みんな大好き ToDo アプリの行操作とかを作ろうと思ったら使いそう。 普段の開発でも登場シチュエーションは多そうな気配を感じた。


所感

便利そう。導入されるケースが多い理由が少し理解できた気がする。 APIも多すぎず、かつシンプルで理解しやすかった。

TypeScriptとの親和性もあって、zodでバリデーション組んだりできるのも良さそうだった。フォームの初期化とかもサクっとできるのはよさそう。

一方で、 useController とかでUIコンポーネントと繋ぎこみとかし始めると結構カオスになっていきそうな気配も感じた。なんでもかんでも便利そうだからと言って突っ込むと死ぬのはお約束なので、まあ自己責任ではありそう。

IE11が去った後に使える機能一覧を確認するサイトを作った

IE11の考慮が不要となった場合に、特定のブラウザバージョン以降で使えるようになる機能一覧を列挙して表示するサイトを作った。

the-world-after-ie-left.vercel.app

リポジトリはこちら github.com

デフォルトでは

以降で使える機能を確認できる。

※ ちなみに雑にVercelにデプロイしてるので、レスポンスが巨大すぎるとVercel自体の制限に引っかかって死ぬことがあるので、落ちる場合は絞り込み用のブラウザバージョンをちゃんと入れてください。

IE卒業式という社内イベント

先日、IE卒業式というイベントが開催された。これ自体は公のイベントで、とてもいい内容だった。

それとはまた別で、社内でも似たようなIEサポート終了に伴うちょっとしたイベントが開催され、その中でLTをすることになった。お題としては「IE11を考慮から外すと◯◯ができるよ!」といったものをリクエストされた。

最初は単純に MDN のドキュメントからいくつかの機能を感覚でピックアップして終わろうかなと思っていたが、実際調べていくと、山のように機能があることに気付いた。

「これはそもそも機能を洗い出すこと自体に何らかの仕組みが必要では??」という考えに至り、LT用にサイトを作ってみることにした。5分の発表のために私は一体何を。

仕組み

至ってシンプルで、MDNのドキュメントのベースにもなっている mdn/browser-compat-data のデータをもとにフィルタリングして表示しているだけです。

github.com

ちなみに最初はリポジトリ内に含まれるデータのJSONファイルを全てパースして、JavaScriptで取り扱いやすいデータオブジェクトを作って、かつ型定義も自分で書いて頑張ってたが、実は mdn/browser-compat-data はそもそも npm パッケージとして公開されており、データも型も全部公開してくれていることに後で気付いて「ウワー!!!」ってなった。ちゃんとリポジトリの中を確認しましょうね、という学びを得た。

(ちなみに、意外と自分で書いた型定義は概ね正しかったようで、パッケージ提供のものに差し替えたあともすんなり型チェックがパスしてビックリした)

作ってみて

単純に機能を眺めているだけでも結構おもしろかった。

普通に知らない機能もあったし、Transpile/Polyfillを当然のように使ってたので、たとえば Array.prototype.findIndex とかは「そうか、IEってコレも使えなかったのか...」みたいな気持ちになった。

公開したままにしとくので、興味があれば見てみてください。

おわり

リモートワークスタイルチェック用サービスをつくった #リモートワークスタイルチェック

リモートワークスタイルチェック

リモートワークスタイルに関する質問に答えることで、リモートワーク比重・文化がどういった具合かを確認・共有できるサービスを作った。

remote-work-style-check.mugi.dev

こんな感じ↓の質問にぽちぽち答えるだけで良いので、すぐ終わる。簡単。

全部答えると↓のような全てをまとめたいい感じの1枚画像を表示してくれる。

もし忙しくなければチェックをやった上で、結果ページから結果をツイートして拡散してもらえるととても嬉しい。

チェック結果の画像も誰でも自由に使ってOK。

サービス内での項目は以前公開した "リモートワークスタイルチェック" の内容に沿っている。

🔗 リモートワークスタイルチェック · GitHub
🔗 "リモートワーク"の認識ズレ解消のためにリモートワークスタイルチェックを作ってみた - memo_md

チェックに答えた結果を表示するだけではあるので、サービスというと少し大げさかもしれない。

作ったモチベーション

リモートワークスタイルチェック自体は、"リモートワーク" という言葉に関しての認識の齟齬を減らしたいという気持ちがあって作った。

本当にありがたいことに、実際に一部の企業さまがこれを利用してチェック結果をブログなどで公開していただいた。嬉しい。

永和システムマネジメントさん
blog.agile.esm.co.jp

Arentさん
note.com

チェックを通じて、個人・企業の双方で「リモートワークも色々あるんだな」という気づきを一人でも多くの人に与えたいというのが根底にあるので、似たような形でより多くの人にチェック結果をアウトプットして欲しいな〜と思っている。

しかし、実際チェック項目は12個ほどあり、ちゃんと内容を読み込むと結構めんどくさいし、それをさらにアウトプットしろと言われるともっと手間ですよね、というのはわかる。

そこで、カジュアルに誰でも簡単にチェックしつつ、かつ結果を共有できる仕組みが必要だな〜と思い、このサイトを作った。

みんなのリモートワークをより良いものにするためにぜひ使ってみて。

技術的な話

特徴的なところでは次のようなものを使ってる

チェック自体はさほど難しくないReactアプリをRemix上に構築している。Remixを使わないといけない理由は皆無であり、使いたかっただけである。

OGP画像生成

結果ページやSNS共有のために利用するOGP画像については、チェック結果内容に応じて動的に生成している。

これは、画像を見た目となる要素をHTMLで構築し、それをPlaywrightから参照したうえで、要素のスクリーンショットを撮影することで生成している。Remixの一部ルーティングを画像用に用意しており、そこにアクセスするとPlaywrightが起動して結果を返すようになっている。PlaywrightではローカルのHTMLも開けるので、その際にクエリパラメータを付与し、それをスクリプトから参照することで値を切り替える。

ただ、さほど要素の多くない画像用のHTMLとはいえ、さすがにDOM構築を手でやるのは面倒。専用にビルド環境を構築しても良かったが、せっかくなので触ったことのない petite-vue で作ってみた。 petite-vue は Vue.js の超軽量サブセットで、ビルドなどを必要とせずにすぐにVue.jsの基本的な機能を導入できるものと思ってもらえればよい。

感想としては、まさにこういう用途のためのものだなという感じだった。雑に突っ込めば即Vue.jsが動くので手っ取り早い。余計なファイルも増えない。ただできることもかなり限定的なので、少しでも複雑なことをするとあっという間に破綻しそうなので、使い所は慎重に。

デザイン的なところ

TailwindCSSで気合いで構築した。

猫の画像については、DOTOWN の画像を利用させていただいた。

dotown.maeda-design-room.net

素敵なかわいいドット絵がクレジットなしで利用させていただける。神である。


そういうわけで、どの程度流行るかはわからないけど、もし暇なら試してみて貰えると嬉しい。

"リモートワーク"の認識ズレ解消のためにリモートワークスタイルチェックを作ってみた

ふと思い立って "リモートワークスタイルチェック" というものを作ってみた。

→ 🔗 リモートワークスタイルチェック · GitHub

"リモートワーク" という言葉の認識の齟齬

最近、Meetyを使ってカジュアル面談をちょいちょいやっていて、いろんな方とたくさん話をさせてもらった。その中で、自分が地方に住んでるのもあってか、リモートワークが話題に上がることが多かったのだが、人によって "リモートワーク" の認識が大きく異なっている印象を受けた。

meety.net

「雑談が減っちゃう」という意見もあれば、「静かで集中できる」という方もいた。「通勤が無くて楽」という方もいたし「たまにはオフィス行きたい」という話も聞いた。

同じような環境だとしても、人によって捉え方は大きく違ってた。

また、これは個人だけの話だけではなく、企業でも同じことが言えると思う。1年ほど前に転職活動をしたときに、さまざまな会社と話す機会があり、似たようなギャップを感じることがあった。

これは一例だが、とある「フルリモート可能です」という会社との面談の中で色々と掘り下げて聞いていった結果、実際には「いまはコロナ禍もありフルリモート可能だが、将来的に制度が変更されて出社必須になる可能性はある」ということが後から解った、といったことがあった。途中で制度が変わることはあまり想定していなかったので、認識に大きな齟齬があったことになる。

誤解を招かないように補足しておくと、"後から言いやがって〜" などとその会社のことをどうこう言うつもりはない。その会社にとっては "リモートワーク" はオプショナルな働き方のひとつでしかなかったが、自分にとっては "リモートワーク" は人生に関わる部分なのでかなり重要な要素だった、というだけなので、どちらが正しい・間違っているという話ではない。

ともあれ、これらを踏まえ、あまりにも "リモートワーク" という言葉に情報を含めすぎているなぁという印象を受けた。

リモートワークにはさまざまなスタイルがあり、企業・チームによってスタンスが大きく異なる。リモートワークに全振りしてる会社もあれば、社会情勢を鑑みて限定的に許可しているケースもある。

個人側の "リモートワーク" に求めるものも多種多様で、自分のように地方在住なので基本的にフルリモートで1年中働きたい人もいれば、普段は出社で良いが家庭事情による突発的な在宅勤務を許可してくれればOK、という人もいるはず。

ただ、これらの結果で一番怖いのが、"認識の齟齬があるまま入社してしまった" という可能性が潜んでいる点だと思う。お互いに気づかずに採用が確定してしまうと、

  • 「リモートで静かに仕事できると思ってたのに、毎日オンラインMTGだらけじゃん!」
  • 「定期的に出社必須とか聞いてないんだけど〜」
  • 「入社して1年したらリモートワークがなくなったんだけど...」

といったおぞましい結果が待ってる恐れがある。

リモートワークスタイルの確認観点がほしい

リスクを減らすためにどうしたらいいか?と考えた時に、リモートワークについて確認すべき観点がどこかに列挙されており一般化されている必要があるな〜という結論に至った。

作ってみたチェック観点

実際に用意してみたチェック観点は次の通り。

※なお内容については、自分と同じように地方から長くリモートワークを経験している Toyama.rb の @kunitoo にも意見をいただいた。感謝

比重度と文化

まず大きく "比重度""文化" の2つに大きく分けている。

比重度は、どの程度リモートワークに重きを置いて業務を回しているかを判断する。

比重が大きいほどにリモートワークを前提とする社内制度が充実したり、何か課題があった場合も全員の課題となり解決しやすくなる。代わりに、常にリモートワーク独自の問題と向き合い続ける必要も強まったり、"オフラインのほうが手っ取り早いよね" という解決策を取りにくくなる。

スタイルチェック内にも書いたが、あくまでも「比重」を見るものであり、優劣ではない。より積極的にリモートワークを導入してるから良い、そうでないから悪い、という話ではない。 企業の属性や何を重要視するかなど、価値観はそれぞれである。リモートワーク全振りになることでむしろ働きづらく感じる人もいると思う。

一方で文化のほうは、リモートワークをどのようなポリシーで導入しているかを見る。

主にコミュニケーションに関わる項目が多く、オンライン上での会話量や、時間を合わせた同期的な仕事をどの程度必要とするかなどが対象。

「ある程度は直接人と話さないとつらいです」という人はビデオ会話が多い方が良いはずだし、「静かにもくもくと自分のペースで仕事したい」という人は真逆になると思う。

比重度の項目

リモートワークの導入期間

どの程度リモートワークを導入しているか。

シンプルに、期間が長い方が組織としてリモートワークへのノウハウが蓄積されているはず。また、長期的な実施ならでは課題にも向き合う必要が出ていると思われる。

スポット的な導入というケースもありうるため、期間が継続 or 累積によって判断を分けている。継続的に導入している方が比重が高いと判断している。

リモートワークの導入ポリシー

リモートワークを一時的なものとして導入しているか、恒久的に取り扱うか。 また、内容の変更がどの程度ありうるか。

「もう会社の制度としてがっつり組み込まれているので廃止とかは絶対ないです!」という導入なのか、「社会情勢を鑑みて一時的に使えるようになってます」という導入なのかを見る。

リモートワークのマジョリティ度合い

全メンバーのうちどの程度がリモートワークに関わっているか。 リモートワークの課題が全員のものとなるか、「リモートワークのひと」の課題となるかの違いがある。

リモートワークを全員で実施してるか、一部のメンバーだけが実施しているかで大きく扱いに違いが出てくる。「会議室のマイクの音質が絶望的に悪い...」みたいなケースも、リモートワークをするメンバーが多数派であれば全員の課題になりやすい。

申請・許可の必要性

リモートワークを行うために何らかの手続きが発生するかどうか。 また、申請が必要な場合にはどの程度の頻度で申請を行う必要があるか。

高頻度で申請が必要なほどにリモートワークがオプショナルな選択肢である割合が強くなり、リモートワークを実施するために何らかのコストが発生することになる。また、申請が必要=却下の可能性も出てくる。

リモートワークの適用範囲

リモートワークが利用可能なのは誰か。

利用のために何らかの条件が設けられているかどうか。

誰でも自由に利用できるケースと、出社可能なメンバーは出社必須なケースでは大きな隔たりがある。 また、社員は利用できるが業務委託の人はダメです、みたいなケースでも、実際に仕事をする上では不都合が出てくる可能性がある。

出社義務

業務上必須とされる出社がどの程度発生するか。 「義務」としての出社のみ数える。出社が伴うイベントだとしても個々の判断で出社せずにオンライン参加が可能なケースなどは含めない。

出社の頻度。頻度が高ければ高いほど居住地などにも制約が出てくる。 また、突発的な出社が発生する可能性がある場合、それは出社待機状態と変わらないため、考慮が必要。(@imunolionさんにご意見頂きました、ありがとうございます!)

リモートワークで必要なサービス・アプリケーションの取り扱い

リモートワーク・非リモートワークで利用するサービス・アプリケーションに差異があるか。

リモートワーク向けにサービス・アプリケーションを最適化しているかどうか。 クラウド移行などが全く実施されていない場合には、日常業務で支障が出る可能性もある。また、将来的に移行する見込みがあるかどうかも大事。

情報のアクセス範囲

リモートワーク時と非リモートワーク時に、アクセス可能な情報量にどの程度差があるか。 また、差がある場合にはそれをカバーする手段が用意されているかどうか。

リモートワーク時に手に入らない情報がどの程度あるか。 すべて同条件で手に入るか、リモートワーク向けに専用で議事録を用意してあげる必要があるか、まったくアクセスできないか、など。「オフィスでしかアクセスできない...」みたいなケースが多いほど出社頻度や、非リモート側の共有コストが生じる。

その他

その他リモートワークに関する制度や特徴的な情報など

段階的なものではなく、YES/NOで判断できるようなリモートワークに関する特記事項。

役員が自ら実施しているかや、手当があるかどうか、など。

文化の項目

同期・非同期コミュニーションの割合

コミュニケーションが伴う業務において、同期・非同期のコミュニケーションはどういった割合か。

同期的(=複数人が同じ時間でのやり取り)と、非同期的(=複数人でタイムラグを許容するやり取り)なコミュニケーションの割合。

同期的な割合が高いほど、働く時間が束縛されることが多くなるが、リアルタイムな反応を得られることになるため、スムーズに進めやすいように感じるかもしれない。 逆に非同期的な割合が高いと、自分のペースで仕事を進めやすくなりやすい。ただし、相手からのレスポンスも遅れることを許容する必要があり、タイムゾーンレベルで違いがある場合には、大きい工夫が必要となる。

テキストコミュニケーションの割合

リモートワークでのコミュニケーション方法において、テキストが占める割合はどの程度か

Slack・Teamsなどのチャットツールやメールのようなテキストベースでのコミュニケーションと、Zoom・Google Meets のようなビデオ・音声会話ツールでのコミュニケーションの割合。

テキストが主体であれば、必然的に文章に会話が残るため後から記録が追いやすくなるが、会話よりも情報量が減りやすく、工夫を伴ったコミュニケーションも重要になる。ビデオ・音声の場合は、テキストにはない表情や雰囲気といった情報を得やすく、心理的な面でのフォローもしやすいが、議事に残らず失われていく情報も多くなる。

コミュニケーション頻度

リモートワーク時に、どの程度他のメンバーとコミュニケーションを取るか (テキスト・ビデオなどの手段は問いません)

コミュニケーションの活発具合。

リモートワークはオフィスワークに比べて雑談が減りがちといった課題がある。それをストレスに感じてしまう場合、コミュニケーション頻度は重要になる。

逆に、余計な雑談などを省いて仕事をしたいと感じている場合には、成果物のみでのやり取りなど最低限のコミュニケーションスタイルのほうがマッチするかもしれない。

働く時間

リモートワークで働くにあたって、どういった時間帯に仕事をするか。 これによって同期・非同期の割合が決まったり、非同期の場合もレスポンス速度が変わってくる。

働く時間がどの程度マッチするのか。

働く時間が特に定められていない場合は自由度が増すが、同期的なコミュニケーションを必要とする場合には、事前調整が必要になるといったコストが発生する。 一方でコアタイムや定時などが定まっている場合には、ある程度で束縛されることになるが、同期的なやりとりは捗りやすい。(生活リズムが整いやすい、みたいなメリットもありそう)


というわけで、リモートワークスタイルチェックを作ってみたという話でした。

リモートワークが世の中に広く普及してきたものの、こういった差分を明確に文章化されたものが見当たらなかったため、悲劇が起きる前に書いておいた方がいいかなぁと思って頑張って作ってみた。

これで完璧な内容だとは思っていないので、TwitterでもGistコメントでもいいので、意見をもらえたら反映するかもしれません。

リモートワーク、むずかしいね!

おわり

Viteのコードを読む - createServer(ViteDevServer生成まで)

前回: Viteのコードを読む - CLI経由でのコア実行の流れ - memo_md

viteパッケージ内部 / サーバー起動部分をよむ

vite dev vite serve などで起動する packages/vite/src/node/server をよむ

ファイル一覧

.
├── __tests__
├── hmr.ts
├── index.ts
├── middlewares
│   ├── base.ts
│   ├── error.ts
│   ├── indexHtml.ts
│   ├── proxy.ts
│   ├── spaFallback.ts
│   ├── static.ts
│   ├── time.ts
│   └── transform.ts
├── moduleGraph.ts
├── openBrowser.ts
├── pluginContainer.ts
├── searchRoot.ts
├── send.ts
├── sourcemap.ts
├── transformRequest.ts
└── ws.ts

CLI からの起動は ↓

const { createServer } = await import('./server')
try {
  const server = await createServer({
    root,
    base: options.base,
    mode: options.mode,
    configFile: options.config,
    logLevel: options.logLevel,
    clearScreen: options.clearScreen,
    server: cleanOptions(options)
  })

  ...

vite/packages/vite/src/node/server/index.ts # createServer が該当

createServer

コンフィグの読み込みとサーバー生成

const config = await resolveConfig(inlineConfig, 'serve', 'development')
  • inlineConfig は CLI の実行時引数などから生成したオブジェクト
  • resolveConfigResolvedConfig 型の値を返す
    • inlineConfig の configFilefalse でなければ loadConfigFromFile で読む (明示的に "使いません!!" としない限りロードする)
    • 次の順番でロードを試みる
      1. configFile でファイル指定がある場合はそれをロード
      2. vite.config.js
      3. vite.config.mjs
      4. vite.config.ts
      5. vite.config.cjs
    • ESM の場合 (package.json の type が module、または設定ファイルが .mjs.ts )は bundleConfigFile
      • esbuildでビルド
      • Pluginとして externalize-depsreplace-import-meta を適用している
      • そういうプラグインパッケージがあるわけじゃなく、ただ名前つけてるだけぽい
        • externalize-deps → 外部パッケージをマーク
        • replace-import-metaimport.meta.url, __dirname, __filename を実体に置き換え
  const httpsOptions = await resolveHttpsConfig(
    config.server.https,
    config.cacheDir
  )
  • vite/packages/vite/src/node/http.ts # resolveHttpsConfig
  • https接続用の ca,cert,key,pfx ファイルをロード
const middlewares = connect() as Connect.Server
const httpServer = middlewareMode
  ? null
  : await resolveHttpServer(serverConfig, middlewares, httpsOptions)
const ws = createWebSocketServer(httpServer, config, httpsOptions)
  • connect でサーバのMiddlewareを作成
  • server設定で middlewareMode が設定されていなければ resolveHttpServer
    • https://ja.vitejs.dev/config/#server-middlewaremode
      • index.html の配布を誰が責務を持つかの話
      • ドキュメント上では ssr or html が設定に渡せるようだが、実際は true false もいける
    • https/proxyの設定に応じて、 http or https or http2 モジュールで createServer (connectで作られたMiddlewareを渡す)
  • createWebSocketServer : HMR用のWebSocketサーバーの準備。基本的に↑で使っているサーバーをそのまま使う
    • Midlewareモードだったりserver.htr.server の設定などによってはサーバーを作る
    • 先に作ったサーバーを利用する場合は、upgrade 要求で WebSocket コネクションを確立する

createPluginContainer

  const container = await createPluginContainer(config, moduleGraph, watcher)
// we should create a new context for each async hook pipeline so that the
// active plugin in that pipeline can be tracked in a concurrency-safe manner.
// using a class to make creating new contexts more efficient
class Context implements PluginContext {
  ...
}

次のようなものを持つ(特徴的ぽい一部だけ抜粋)

  • parse : acornでコードをparse
  • resolve : ID(ファイルのURLやパス)を解決
  • addWatchFile : chokiderの監視対象にファイルを乗せる

都度生成しているケースもあるし、TransformContext のように継承しているケースもある。

最終的に返される PluginContainer は次のメソッドを持つ

  • buildStart : すべてのプラグインを対象に buildStart を呼ぶ
  • resolveId : ID(ファイルのURLやパス)を解決
  • load : すべてのプラグインを対象に id を引数に load を呼ぶ
  • transform : すべてのプラグインを対象に id を引数に transform を呼ぶ
  • close : すべてのプラグインを対象に buildEndcloseBundle を呼ぶ

サーバー停止用ハンドラの生成

const closeHttpServer = createServerCloseFn(httpServer)

ViteDevServer の生成

ここまで作ってきた全てを一通り保持する ViteDevServer オブジェクトを作る 詳細は次回以降。


感想

  • createServer だけでもやってることめっちゃ多かった
  • vite.config 書くときに「tsでも書けて便利〜〜」とか思ってたけど、裏で普通にesbuildしててそりゃそうだよなってなった
  • RollUp用の PluginContainer で複雑なことをやってんだなってのはわかった

次回

createServer 読み終わってないので、続きをよむ