2022年に駆け出しエンジニアがフロントエンドを学ぶとしたら(やるべきこと)
Every LayoutでCSSによるレイアウトのパターンを学ぶ
Every Layout (日本語版もあります)というテキストで、CSSを使ったレイアウトの方法を学びます。
注意点: Tailwind CSSと組み合わせては使えない(たぶん)
Every Layoutで説明されているレイアウトのパターンは、継承などのCSSの特徴を最大限に活かして、最小限のスタイル定義で済むようになっています。近年のフロントエンド開発で積極的に採用されているTailwind CSSでは、そのまま使えないパターンが多いでしょう。
Every Layoutの本文においては、utility-first CSSについて以下のように言及されています。
In a utility first approach to CSS, inherited, universal, and element styles are not really leveraged at all. Instead, combinations of individual styles are applied on a case-by-case basis to individual and independent elements.
There may be reasons, under specific circumstances, why one might want to go this way. Perhaps there is a great deal of detail and disparity in the visual design that benefits from having this kind of granular control, or perhaps you want to prototype something quickly without context switching between CSS and HTML. Every Layout's approach assumes you want to create robustness and consistency with the minimum of manual intervention. Hence, the concepts and techniques laid out here leverage axioms, primitives, and the styling algorithms that extrapolate from them instead.
CSSへのユーティリティファーストアプローチでは、継承されたスタイル、ユニバーサルスタイル、および要素スタイルは実際にはまったく活用されません。代わりに、個々のスタイルの組み合わせは、個々の要素と独立した要素にケースバイケースで適用されます。
特定の状況下では、なぜ人がこの道を進みたいのかという理由があるかもしれません。ビジュアルデザインには、この種のきめ細かなコントロールの恩恵を受ける細部と格差がかなりあるかもしれませんし、CSSとHTMLの間でコンテキストを切り替えることなく、何かをすばやくプロトタイプ化したいかもしれません。すべてのレイアウトのアプローチは、最小限の手動介入で堅牢性と一貫性を作成したいことを前提としています。したがって、ここで説明する概念とテクニックは、公理、プリミティブ、およびそれらから外挿するスタイルアルゴリズムを活用しています。(翻訳はDeepLの結果をそのまま載せています)
現実的な判断としては、実際のフロントエンド開発においてはCSSを直接書かずにTailwindを使うことになると思います。ですので、Every Layoutのパターンを習得しても実際のプロジェクトには使えないということになります。とはいえ、Tailwindのようなアプローチが今後永遠に主流であり続けるかどうかはわかりませんし、TailwindはCSSに基づいているので、Tailwindよりもまず素のCSSの使い方を覚えたほうがいいのでは?と思います。Every LayoutとTailwindの両方をやります。二度手間になっても、確実で正しい学習順序を取る方針です。
Follow-up
テキストを読んだ後は、こちらの課題を実践します。
Every Layoutの日本語訳『Every Layout—モジュラーなレスポンシブデザインを実現するCSS設計論』の監訳者の一人である、Yuhei Yasudaさんによる関連記事を見つけました。
Every Layoutを使ったCSSレイアウトの実践
Every Layoutで説明されているレイアウトのパターンを実際に練習します。CSSの一番低いレベルの課題です。
題材
最初はTailwindを使わないでCSSを練習すると宣言しましたが、レイアウトの練習をするための素材としてはTailwindに関係するものが豊富です。たとえば以下のTailwind UIというライブラリのサイトでは、実際のウェブサイトやアプリケーションで用いられる豊富なレイアウトのパターンが、Marketing、Application UI、Ecommerceというカテゴリーに分類されてサンプルと一緒に示されています。これらのパターンを実装できるようになることが、CSS習得の主要な目標の一つであるはずです。
Tailwind UI - Official Tailwind CSS Components
レイアウトの素晴らしいショーケースであるTailwind UIですが、これを実際にCSS初心者が練習のために実装しようとする場合、以下の難点があります。
- 一部のサンプルについては、本物のHTMLではなくキャプチャした画像として示されている。そのため、ウィンドウの幅を変更したときのレイアウトの変化などがわからない。
- 粒度(fidelty)が高すぎる。厳密に同じ見た目のものを作ろうとすると、design tokensも用意しなければならないため、レイアウトの練習という目的を逸脱してしまう。
なので今回は、代わりにTailblocksのレイアウトをCSSで再現する練習することにしました。これならどのレイアウトも本物のHTMLが見本として示されているので、ウィンドウの幅を変更したときにどんな振る舞いをするように実装しなければならないかを確認できます。しかもどの見本も「粗い」ので、細かいことは気にせずにレイアウトだけに集中できます。(ちなみにこんな感じのテンプレート集は、20+ Free Tailwind CSS Templates And Tools - UIdeck で多数紹介されています。)
手順
余白や文字サイズ、breakpointなどは適当に、レイアウトだけを再現していきます。(もちろん実際のプロジェクトでは適当にやったらだめです。最初の練習だけです。)
練習用のプロジェクトをセットアップするには、Reactの場合はViteを使うのが簡単です。CSSの表示確認をするだけなので、React + TypeScriptの最小限のテンプレートで十分です。とはいえ、Reactはscoped CSSが組込みではないので、単にCSSを書いてimportしていくだけだと複数のページのスタイルが混ざってしまいます。今回の練習にはSvelteを使うほうがいいかもしれません。
反省
Tailblocksのレイアウトはブレークポイント(@mediaクエリ)を多用しています。Every Layoutにおいては、ブレークポイントを使わずにレイアウトを切り替える Switcher というパターン (The Flexbox Holy Albatrossに詳しい説明があります) が紹介されており、このテクニックを使うことで概ね同じレイアウトを再現できるのですが、それでもTailblocksと全く同じレイアウトを再現することはできないことがわかりました。
というのも、Tailblocksの見本は文字を中央揃えにしたり、グリッドのカラム数が偶数値になるように固定値を指定したりといったように、ブレークポイントに応じて細かいスタイルの制御をしています。試してみましたが、@mediaクエリ(または@containerクエリ)やJavaScriptを一切使わずに、viewportの幅を変えたときの振る舞いを忠実に再現するのはどうやら無理そうだということがわかりました。
また、Tailblocksの見本のほとんどは同じパターンの繰り返しなので、始めてみるとすぐに飽きます。各カテゴリーから1個ずつ拾って練習してみようかと思いましたが、そこまでやる意味さえもなさそうなので、この課題は中止にします。
今回の課題をこなす中で、flexboxとgridがどんな場面で使えるかはわかるようになりました。Every Layoutのすべてのパターンに習熟できたかというと、一度も使ったことがないパターンもあり、練習は足りていません。Tailblocksの見本だけでは問題のバリエーションが足りないと思います。本格的なアプリケーションUIを実装していれば、どのパターンもいずれは使う機会があるのでしょう。
いずれにせよ、ここからスキルを上げるには、スタイルガイドやアセット等が準備されている正式の練習課題をこなす必要がありそうです。以前 16 front-end projects (with designs) to help improve your coding skills - DEV Community の課題をこなそうとしたときは、まだ基本的なスキルが足りていないと思いましたが、今なら取り組めそうです。
今回Tailblocksの見本においては、Cardが多用されていました。Cardは実際のアプリケーションUIにも非常に多く見られます。以下のチュートリアルのようにChakra UIを使ったり、Tailwindで実装したりすることになるでしょう。早くTailwindに慣れたほうがいいと思いました。
How to Create Modern Cards in Chakra UI & React JS ⚡️
Cardのコンポーネントは画像やビデオが含まれていることが多く、テキストの長さによってレイアウトが崩れたりもします。Every Layoutに挙げられている基本的なレイアウトパターンの知識だけでなく、以下の記事で説明されているようなUX上の配慮が必要になると思われます。
Developer Decisions For Building Flexible Components — Smashing Magazine
Follow-up
Every Layoutに特化した(?)練習は終わりです。
まだCSSの練習は足りていないので、16 front-end projects (with designs) to help improve your coding skills - DEV CommunityのNewbie〜Junior、もしくは同等の課題をこなす必要があります。Tailwindを使わずに素のCSSを書く場合は、Every Layoutのパターンを使う機会もあると思います。(Tailwindを使う場合も一部はEvery Layoutの考え方を応用できると思います。)
追記
Follow-upに書いた通り、16 front-end projectsに挙げられているFrontend Mentorの課題を何個か拾って取り組んでいます。たとえば Pricing Component with Toggle は以下のように実装できました。(動画がちらついていますが、私の収録環境の問題でありCSSのせいではありません)
以下のリソースで勉強すれば、このレベルの課題に必要なスキルはほぼ習得できます。
JavaScriptを使わずに年額と月額の金額表示を切り替える方法はググりました。フォントもMontserratが私のLinux環境にインストールされていなかったので、フォントにリンクするためのコードをGoogle Fontsで生成して貼り付けました。デザインと若干違う点もありますが、練習なのでこれでよしとします。
実際のプロジェクトに取り組むとしたら、Figmaなどのデザインを参照しながらコーディングしていくことになるので、Figmaなどのツールの使い方を修得する必要があります。(Frontend Mentorでは月12ドルのProプランを契約すればSketchとFigmaのファイルも月5個までダウンロードできるようです。)
あとは保守性を考えるとCSSの管理が問題です。BEMやITCSS、CUBE CSS、RSCSSといった、2010年代から提案されてきたCSS方法論で命名規則やファイル構成を統一したり、Tailwind CSSやCSS-in-JSなどのフレームワークを導入してスタイルを直截に指定していくなどの方法があります。
今はcomponent-drivenの時代ですし、コンポーネントのスタイルはコンポーネントになるべく近いところに記述し(Vue.jsやSvelteならばscoped CSSも組み込みで備わっている)、その他のスタイルはstyle guide + design tokensとして集中管理する(全体としてdesign systemを構成する)という方針で大雑把には決着がついているようですが、依然としてニュアンスは残ります。どうやって開発を進めていくかという組織的な問題や技術選択とも関係するので、判断には経験が必要でしょう。
UIデザインの原則を学ぶ
Refactoring UI を読み、エンジニアでも見栄えのするデザインをするために必要なテクニックを学びます。
本の値段が高い
Goodreadsで現在4.68点という高評価を得ているRefactoring UIですが、値段が99ドルと高いです。これに9.99ドルの税金を加え、1ドル約130円の現在の為替レートにクレジットカードの為替手数料を加えると、なんと15,000円近くにもなってしまいます。デザインの本は全体的に値段が高い気もしますが、それにしても高いです。もっと安い本で、同等の内容を網羅しているものがあれば、そのほうがいいと思います。
デザインしなくても知っておくべき
ウェブ制作のプロジェクトに入ると、コーダーはデザイナーがデザインしたものを忠実に実装することが要求されます。恥ずかしながら私は不得意だったので、私にはこのタスクはほとんど振られませんでした。CSSのコーディングを専門にしたいとは思いませんが、デザインのコーディングができないと、フロントエンドエンジニアとしてできる仕事が限られてしまいます。一人で全部できない人は使いにくいです。つまり失業につながります。
Refactoring UI を読んでみて、これはデザインしない人も前提知識として押さえておくべき内容だと思いました。たとえばCSSには box-shadow というプロパティがありますが、CSSの仕様を知るだけでは、どう使うべきかわかりません。Refactoring UIではデザインとCSSの対応が示されています。
ネットで調べれば資料はたくさんあるでしょうが、初心者が手探りで学ぶのは厳しいものがあります。
あの本よりは充実している
エンジニアに推薦されるデザインの本というと、00年代から Non-Designer's Design Book が有名です。私も読んだことがあります。内容は出版物の余白やtypographyに関することが主であり、UIデザインに関することはほとんど書かれていなかったと記憶しています。なぜこの本がおすすめされているのか不思議でした。
Non-Designer's Design Book と比べると、 Refactoring UI はちゃんとUIデザインに関することが書かれています。デザインについて全くの素人がフロントエンドエンジニアを目指すのであれば、一冊目として手に取る本として Refactoring UI は全く見当違いな本ではなさそうです。
Follow-up
この本で解説されているテクニックを、CSSを使って実装する練習をしようと思います。(詳細未定)
WAI-ARIA
WAI-ARIA Authoring Practices 1.2 を読みます。
新たにARIA Authoring Practices Guide Homeのサイトができ、Authoring Practicesのドキュメントは廃止されたようです。
WAI-ARIAとは
WAIは Web Accessibility Initiative の略称であり、World Wide Webのaccessibilityを改善するための活動をしています(参考文献)。
ARIAは accessible rich internet applications の略です。Accessible Rich Internet Applications (WAI-ARIA) 1.2 がARIAのモデルを定義する仕様であり、Authoring PracticesはHTMLのマークアップについて説明しています。
No ARIA is better than Bad ARIA
Authoring Practices第2章のRead Me Firstには、“No ARIA is better than Bad ARIA”として、以下のように述べられています。
Functionally, ARIA roles, states, and properties are analogous to a CSS for assistive technologies. For screen reader users, ARIA controls the rendering of their non-visual experience. Incorrect ARIA misrepresents visual experiences, with potentially devastating effects on their corresponding non-visual experiences.
機能的には、ARIAの役割、状態、およびプロパティは、支援技術のためのCSSに類似しています。スクリーン・リーダーのユーザーにとって、ARIAは、非視覚的な体験のレンダリングを制御します。不正確なARIAは、視覚的体験を誤って表現し、対応する非視覚的体験に壊滅的な影響を与える可能性があります。(翻訳はDeepLの結果をそのまま載せています)
accessibilityは視覚障害者をはじめとする障害者にもウェブを閲覧できるようにしようというものですが、ARIAの機能を正しく理解しないで間違った使い方をしてしまうと、健常者には想像しがたい苦しみを与えてしまうことになるようです。
ARIA対応のコンポーネントを使う
ARIAを使ったコンポーネントは、第3章にて色々と紹介されていますが、これを実装するのは大変そうですし、間違った実装は障害者にとって大変危険です。
一般的に推奨されているのは、ARIA対応のライブラリを使うことです。You Don’t Need A UI Framework — Smashing Magazineでは、以下のライブラリがおすすめされています。
この中で私は(Reactプロジェクトの場合)React Ariaを使うのがよさそうだと思いました。コンポーネントライブラリというよりはReactのフックの集まりであり、コンポーネントの見た目は自由にできます。Radix Primitivesもスタイルは自由にできますが、React AriaはAdobeが開発しており、ドキュメントが非常に詳細です。accessibilityについて厳格な品質基準を適用しなければならないプロジェクトには特に、React Ariaのほうがよさそうです。
Headless UIはTailwind CSSのTailwind Labsから出ているので、Tailwindの熱心な支持者にはアピールするかもしれませんが、コンポーネントの数が少なく(これでも大抵のプロジェクトには十分かもしれませんが)、Radix Primitivesのほうがよさそうに見えます。
ちなみにHacker Newsにも半年前のスレッドがあり、以下の通りReact Ariaは高評価です。
I've been using react-aria on a personal project, as well as building a UI library at work based on TailwindCSS+React Aria. I generally really like the combination. The maintainers are super responsive+helpful on Github and really know how to engage constructively with criticism. I really appreciate what they're doing. The combination of TailwindCSS+React Aria provides one with a pretty great template/scaffolding for building out a fully featured component library.
私は個人的なプロジェクトでreact-ariaを使い、また仕事ではTailwindCSS+React AriaをベースにUIライブラリを構築しています。私はこの組み合わせをとても気に入っています。メンテナはGithub上で非常に反応が良く、手助けしてくれますし、批判に対して建設的に取り組む方法を本当によく知っています。彼らがやっていることには本当に感謝しています。TailwindCSS+React Ariaの組み合わせは、フル機能のコンポーネントライブラリを構築するための非常に優れたテンプレート/足場を提供します。
react-aria is awesome. You structure your DOM and css however you want, and react-aria provides hooks that return props to spread onto your elements to make them come alive. These same hooks also give you visibility into and control of the component state, so you can also easily blend in your own custom logic for the component. It is about as flexible as a headless ui library can get. But it's also lower level and so harder to use than, say, radix primitives.
react-ariaは素晴らしい。DOMとCSSを好きなように構成し、react-ariaはプロップを返すフックを提供し、要素を生き生きとさせることができます。これらのフックは、コンポーネントの状態を可視化し、コントロールすることもできるので、独自のカスタムロジックをコンポーネントに組み込むことも簡単にできます。ヘッドレスUIライブラリの中では、最も柔軟性の高いものです。しかし、低レベルなので、例えばradixプリミティブのようなものよりも使いにくいです。
Authoring Practicesのドキュメントは第3章以外一通り目を通しましたが、実際の開発にはライブラリを使うことにします。
Follow-up
練習のプロジェクトでReact AriaとTailwind CSSを組み合わせて使ってみることにします。もしHacker NewsのスレッドでコメントがあるようにReact Ariaが使いにくければ、Radix Primitivesのほうがいいかもしれません。
Anti-Design
2022年から顕著になってきた新しいデザインの流れとして、 anti-design があります。
Designers are taught that simple, intuitive and frictionless design is the key to a good user experience. The idea is that, while users want to see aesthetically pleasing websites, they don’t want to be distracted or have obstacles put in their way that could disrupt their journey on the website. Any extraneous design elements should be avoided.
Anti-design is an approach that bucks the rules of conventional design in favor of challenging, experimental layouts. In web design, this means doing away with the clean, symmetrical, grid-based layouts so commonly seen in today’s websites in favor of loud colors, crowded, asymmetrical design. Anti-design encourages exploration and experimentation, and is meant to push the boundaries of what it means to be a useful and engaging website.
これまでのデザインはユーザの邪魔をしないことを重視してきましたが、 anti-design は観客に印象づけるために奇抜なことをしてみようという試みであるようです。
具体的には、以下の記事で紹介されているようなデザインが新たに流行しています。
- Graphic design trends 2022: Kinetic typography, anti-design and risograph-like backgrounds | Depositphotos | Open Mic | The Drum
- 22 inspiring web design trends for 2022 | Webflow Blog
関連する技術としては、 Variable Fonts や CSS Text Animations などがあります。
20年以上昔に人々が Flash を使って実現していたことを繰り返しているような感もあります。今度はCSSで実装されているので accessibility の問題は発生しないでしょう。とはいえ、 UI/UX で有名な Nielsen Norman Group の Kate Moran 氏はこのトレンドに反対しています。
機能性を重視するエンジニアが手を出すべき領域ではないと思いますが、デザインと実装技術の両方に通じたアーティスト(?)みたいな人たちは興味を持つかもしれません。
React の基礎知識
Reactでアプリケーションを書き始める前に、Reactについての基礎知識を確認します。アプリケーションの中心はデータであるという信念に基づき、まず初めにReactとデータの基本的な関係を理解します。
React とは何なのか
Reactの最初のバージョンがリリースされた2013年には、Reactの開発チームはReactを次のように定義していました。
React isn’t an MVC framework. React is a library for building composable user interfaces. It encourages the creation of reusable UI components which present data that changes over time.
Why did we build React? – React Blog
ReactはUIを組み立てるためのライブラリであり、最も一般的な使い方は、"React as a view library"、つまりReactをデータを表示するためのライブラリとして使うということであるようです。
React単体としてはMVCフレームワークではないものの、たとえばReactとReduxを組み合わせることでMVCフレームワークを構成することができます。
Reactの世界では、"UI is a function of state"という見方もあります。Reactにおいてそれぞれのコンポーネントは、プロパティを引数として取りマークアップを返す関数です。
UI=F(S)
一方Reduxのreducerは、状態とアクションから新しい状態を返す関数です。ReactとReduxを組み合わせることで、UIは、初期状態、状態遷移の関数、およびコンポーネント関数として定義することができます。
S=R(S0, action)
UI=F(R(S, action))
先日の Reactathon 2022 では、 Goodbye, useEffect と題したスピーチがありました。発表者である David Khourshid は、状態機械 (statecharts) を中心とした状態管理のライブラリであるXStateを開発しているStatelyの創業者です。Davidもまた、UI is a function of stateの見方を受け入れています。このスピーチで紹介されていたのは、UIの状態遷移に関する次の図式です。
(state, event) -> (nextState, effects)
既に示したReact+Reduxのモデルと比べてこの図式が優れているのは、状態遷移に伴うUIの変化や様々な副作用をeffectsとして捉えている点です。UI is a function of stateであり、状態は前の状態とaction/eventの関数ですが、実際のアプリケーションのコンポーネントは、単に状態に対するマークアップを返すだけでなく、イベントハンドラを管理したりといった様々なお仕事を担っています。既に示したReact+Reduxのモデルではこれを捉えきれておらず、モデルとして不完全でした。
私が最近のウェブアプリケーションに関して抱いているささやかな不満は、フロントエンドの些細なバグが多いことです。もちろん大規模なサービスであれば致命的な不具合のほとんどはすぐに解決されるでしょうが、通知状態が正しく更新されないといったバグはGAFAMのサービスでも案外残っていたりします。これらのアプリケーションのフロントエンドはReactなどで実装されているはずです。原因はUIの状態の不整合であり、広義にはデータの同期の問題でしょう。
Davidは状態管理(state management)を発展させたstate orchestrationという概念を提示しています(下画像)。XStateが解決策であるかどうかは判断できないものの、モデルとしてはより包括的で一貫しています。データを中心とした一貫したモデルに基づく宣言的なプログラミングは、フロントエンドにおいても理想であるはずです。Davidのこの見方を前提として踏まえたいです。
レンダリングとデータ取得の仕組み
Reactでperformantなフロントエンドのコードを書くためには、Reactのレンダリングの仕組みを理解しておくことが望ましいです。Reactの仮想DOMとレンダリングの仕組みについては次の記事が詳しいです。
もう一つ重要なのは、データ読み込みの戦略です。大きく分けて以下の3種類があります。
- Fetch-on-Render (Render-Fetch Waterfall)
- Fetch-Then-Render
- Render-as-You-Fetch
以下の図で示されているように、最初のレンダリングまでの時間はFetch-Then-RenderおよびRender-as-You-Fetchが速く、ユーザ体験が優れています。RemixではFetch-Then-Renderがデフォルトです。
(出典: How to improve developer experience with React Suspense in Concurrent Mode - LogRocket Blog)
Reactの外側の部分、というより一般的なウェブページのレンダリングはどうなっていたかというと、Critical Rendering Pathのようになっていました。UXの重要な指標であるCore Web Vitalsを改善するためにやるべきことの一つとして、このCritical Rendering Pathに基づいて最適化を実施する方法があります。
近年はブラウザの機能がますます高度になり、 Multi Page Application (MPA) においてもページ遷移を速く滑らかにするための様々なテクニックを利用することができます。Turbolink 改め Turbo のようなプロジェクトもあります。ユーザ体験のために必ずしもSPAにしなければならないという時代ではなくなりつつあります。
Follow-up
これらの知識を踏まえた上で、React標準のhooksの使い方を確認します。
練習問題
React Docs Betaというウェブサイトを見つけました。LearnはReactのドキュメントと比べて網羅的ではないもののより実践的な説明をしている上に、Try out some challengesという練習問題もついています。React標準のhooksの使い方を確認するにはよさそうです。
React.cloneElement, React.Children, etc.
ReactのAPIはhooksだけではありません。
Advanced composition in React: cloneElement, HOCs and renderProps | by Asís García | Trabe | Medium では、Reactのコンポーネントを組み合わせるための方法として、以下の3種類のAPIおよびテクニックが紹介されています。
React.cloneElement については、Using the React.cloneElement() function to clone elements - LogRocket Blogにて詳しく説明されています。 React.cloneElement と組み合わせて使われるAPIとして、 React.Children (React.Children.map
) があります。
React.cloneElementのパフォーマンスについては、(古めの情報ではあるものの)以下のリソースにて言及があります。cloneElementを使うことで、パフォーマンスをさらに高速化できる場合があるかも知れません。
どのように練習すべきなのか、何ができるべきなのか
Practicing Programming
Amazon、Google、Grab (シンガポールにおけるUberのような会社)などでソフトウェアエンジニアとして勤務し、現在は退職生活を送っているSteve Yeggeは、Practicing Programming(これ自体は2005年に書かれた古い記事ですが、現在でも当てはまるという認識です)にて彼が推奨するプログラミングの練習方法を紹介しています。
そもそも練習が必要なのか?ですが、彼は次のように語っています。
Contrary to what you might believe, merely doing your job every day doesn't qualify as real practice. Going to meetings isn't practicing your people skills, and replying to mail isn't practicing your typing. You have to set aside some time once in a while and do focused practice in order to get better at something.
I know a lot of great engineers – that's one of the best perks of working at Amazon – and if you watch them closely, you'll see that they practice constantly. As good as they are, they still practice. They have all sorts of ways of doing it, and this essay will cover a few of them.
また彼は、彼自身の経験を交えて、プログラミングの練習を楽器の練習になぞらえています。
I've had a fair amount of classical music training, so I know how musicians practice – and what differentiates the good ones from the bad ones. Because I used to be an extraordinarily bad one.
How does the average guitarist practice? In the years before I started getting serious about lessons, I played a lot – 6 to 8 hours a day for about 5 years. I learned a lot of songs, all by memorization, and I had to play them constantly to keep them in memory, so at least 2 hours of every day was wasted just running through the pieces. Through brute-force effort I eventually started to sound like I knew what I was doing. Fooled myself and most of the people around me, anyway.
Practice, Practice, Practice
O'Reillyから2009年に刊行されたApprenticeship Patternsは、様々な局面においてプログラミング学習者が取るべきactionを示しています。
たとえばPractice, Practice, Practiceは、次のような局面(context)に関わりがあります。
You want to get better at the things you do and you want to develop Concrete Skills in new areas.
現在多くの求人において応募者には「最新技術にキャッチアップすること」が要求されていますが、これも新しい領域におけるスキルを習得することに含まれるでしょう。つまり、最新技術へのキャッチアップも、Practice, Practice, Practiceがカバーする範囲です。
新しい領域におけるスキルを習得するには、業務経験だけでは十分でないということが次のように説明されています。
In an ideal world we would use the technique of “deliberate practice” as described in K. Anders Ericsson’s research, and a mentor would assign you an exercise based on her understanding of your strengths and weaknesses. When you finished the exercise, the mentor would work with you to rate your performance using an objective metric and then work with you to devise the next exercise. Your mentor then would use her experience of teaching other students to devise new and more challenging exercises that would encourage you to reflect on your skills, find more effective work habits, and develop the ability to “see” in terms of ever more abstract “chunks” of knowledge. Over time, this chain of exercises would hone your strengths and correct your weaknesses. Sadly we do not live in an ideal world, and apprentices must fall back on their own resources to achieve the same effect.
Beginners learn by doing, not through lecture. They practice, and practice, and practice…. By repeating and repeating these same exercises, we sharpen our skills, we train our bodies and our minds to respond to the disciplines of TDD and simple design. We wire, and rewire, and rewire, and rewire our neurons to react in the right way.
練習においてはフィードバックが重要である一方、"Practice makes perfect"は間違いで、正しい練習方法が重要であるとも述べられています。少しずつ違うことを試して、ごく単純なスキルにおいても精妙なニュアンスを理解することが大切であるようです。
Short feedback loops need to be incorporated into your practice sessions. While practice is good in theory, if you’re not getting periodic feedback you’re probably developing bad habits. This is the beauty of the coder’s dojo: public performance within the context of a tight-knit community of craftsmen. This need for constant feedback lessens as you grow as a craftsman, and is gradually replaced by your duty to take on the role of a senior apprentice, modeling good habits by practicing with less experienced developers.
One of the reasons that the masters described by George Leonard love to practice is that they do something a little bit different each time an exercise is performed. The point is not to hone your memory, but to discover the nuances in even the simplest skilled activity. Your grandmother may have told you that practice makes perfect. She was wrong. In fact, practice makes permanent. So be careful what you practice, and constantly evaluate it to ensure you haven’t gone stale. Choosing the right thing to practice every day is a skill almost as important as the act of repeated practice.
具体的な練習方法としては、Dave ThomasのCode Kataや、アルゴリズムとデータ構造の古典であるProgramming Pearlsなどが挙げられています。現在ではもっと優れた代替があるかもしれませんが、ここでは深掘りしません。
この本が書かれた2000年代と現在で異なる点といえば、オンラインのコミュニティ活動が多彩になったことでしょうか。ビデオチャットが普及し、オンライン勉強会が盛んに開催され、学習者がそれらのイベントにアクセスできるようになりました。
Yes, But(個人の感想です)
しかし、私にはこういう話もどこか遠い世界のことであるような気がします。アルゴリズムとデータ構造が重要であることはずっと昔から話に聞いていましたし、Big O Notationは最初期に覚えましたし、フロントエンド開発においてアルゴリズムが重要である状況も私自身多くはないものの過去に経験したことはあります。それでも、私のこれまでの大半の仕事はそんなものでありませんでした。私が今までやってきたのはコーダーであって、エンジニアではないと思っています。ただコードを書くだけならengineeringの要素はないと思っています。そういう意味で私は「駆け出しエンジニア」でさえありません。
90% of software engineering is integrating janky APIs, and I love it - DEV Communityでは、ソフトウェアエンジニアには次の2種類の仕事があると述べられています。
- Software engineering as “inventing” bytes
- Software engineering as copying bytes
Copying bytesとはどんな仕事であるかというと、次のように説明されています。
One is what I call "copying bytes". You get input bytes, relevant to the business in some way. As a software engineer, your job is copy these input bytes to their specified destinations.
For example, you receive an order from the customer (line items + shipping address), and you have to forward these line items to the fulfillment department, recording a few log entries along the way. You might calculate some tax or apply a coupon along the way, slightly modifying those bytes, but roughly, you are just sending them along the way god designed them.
そして、copying bytesは大半の凡庸なソフトウェアエンジニアの仕事でもあります。
If you are not in the business of thinking clever ideas or making pretty things like video games, but in the business of making money, you probably fall into the "copying bytes" category of software engineering.
You might think it's inane: you learned how to balance trees, how to schedule processes, and how to do some differential curve geometry; how to write compilers, how design database engines and how to implement distributed consensus; why don't you get to write all those beautiful algorithms as part of your day job? Thing is, clever people have already done so, and often they made a business out of it. Now you can pay them for their clever thinking and their diligent work, hoping that they were indeed more clever than you, and go back to calling APIs to copy whatever bytes have just been computed.
ライブラリ作者でないフロントエンド開発者を指す言葉として、「JSON色付け係」という言葉が浸透して久しいですが、JSON色付け係であるフロントエンドエンジニアの仕事は、まさにcopying bytesであるといえるでしょう。
プログラミング界隈のいわゆる「強い人」たちは、最近はRustでOSや言語処理系を実装したりしていますが、これらはcopying bytesの対照であるinventing bytesに当てはまるでしょう。
Concrete Skills
現実のsoftware developerのお仕事の大半がcopying bytes・JSON色付け係であるとして、ひとまずそんな仕事に就くにはどうすればいいのでしょうか。実務経験がない未経験者は、最低限何ができるべきなのでしょうか。
求人の応募要項を見れば要件を知ることはできるのですが、必ずしも具体的なことが書かれているわけではありません。Apprenticeship PatternsのConcrete Skillsによると、エンジニアが最初の仕事を見つけるために習得すべきスキルの一つの軸は自動化スキルであるようです。
Unfortunately, that team has no incentive to risk hiring someone who may not be able to directly contribute to the team’s workload. The team also faces the possibility that you may not even be able to indirectly contribute, such as by automating some simple manual tasks.
The point is that you will often require hiring managers to take a leap of faith in choosing you. Concrete skills (which are ideally discrete enough that you can bring toy implementations to an interview) allow you to meet them halfway. The concrete skills you possess are your answer to the question: “If we hire you today, what can you do on Monday morning that will benefit us?” A deep understanding of Your First Language will help establish your credibility and should prove to be extremely useful to your team.
やはり新人の仕事は雑用・便利屋・下働きです。具体的にどんなものがあるのか、確認してみます。
YAGNIとPAGNI
現在では多くの人々が聞いたことがあるであろうYAGNI (You Ain't Gonna Need It) ですが、未経験者は開発に加わらなければチームに貢献することのできるスキルが必要な状況が生まれませんし、必要ないから取り組まないのであれば、いつまでもスキルが身につかないということになります。オープンソースプロジェクトならば誰でも参加することはできますが、誰かのスキル形成の都合を考慮してもらえるわけではありません。馬鹿なことをやり過ぎると、自分自身の信用を毀損するというリスクもあります。
Practicing YAGNIでは、YAGNIを当てはめるべきでない場合の代表例として次の4点を挙げています。
- Learning something new: You should take the time when evaluating a new technology. You'll gain the time back later, and mitigate the risk of losing more time by making the wrong decision.
- Current design decisions based on future needs: YAGNI shouldn't handicap or sabotage our efforts. In these scenarios, make the future-proof design decision, but only implement enough to fulfill the current need. This allows us to limit rework, without completely undermining YAGNI.
- Abstracting external dependencies: External dependencies add complexity to your project. Inline with the previous examples, taking the time to abstract these dependencies will avoid rework and decrease the complexity.
- Testing, Security, Scale, and Business Requirements: Sorry, but YAGNI is not a free-pass on writing tests, secure code, considering scale, or business requirements.
1は技術選定、2はDDD、3はコーディングテクニックの話であるようです。4は様々な工程の話が混在しているようです。工程を超越したスーパーエンジニアなのでしょう。
環境構築やアプリケーション設計の文脈でいうと、YAGNIの対照としてPAGNI (Probably Are Gonna Need It)という概念があり、CI/CDやログ収集などが挙げられています。
- YAGNI exceptions - lukeplant.me.uk
- PAGNIs: Probably Are Gonna Need Its
- Probably Are Gonna Need It (PAGNI)
フロントエンドに関していえば、Enterprise ReactJS Large Scale Application Good React Structure. Fundamentals of ReactJS React at scale. Enterprise ReactJS | JavaScript in Plain Englishで次の20個のessential partsが挙げられています。
- Project Structure
- Global Store
- Routing
- Multiple Environment
- Form Handling
- Styling
- UI Library
- HTTP Query
- Documentation
- Multi-Language Support
- Animation Library
- EsLint and Prettier
- Typescript
- Analytics
- Testing
- SEO Performance
- Utility
- Docker
- Continuous Delivery
まだ必要とされていない機能を実装しないYAGNIと、UXや運用を視野に入れて構成を決めるPAGNIは、対立する概念ではなくむしろ表裏一体の関係にあります。
システム vs. 個別
今から1ヶ月半ほど前、私は以下のように目標を定義しました。
Reactのフロントエンドエンジニアとしてプロジェクトの開発タスクをこなすために必要なスキルを習得する。フロントエンドに関して他のエンジニアのサポートに頼らずに、開発環境の初期構築からリリースまでイテレーションを回せるようになる。(細かいところは後で実プロジェクトをこなしながら習得する。)
私が上のような目標を立てた理由の一つには、何かをスクラッチから書くことに興味があり、フロントエンドもその中に含まれるから、というのがあります。Reactを選んだのは、現時点ではエコシステムが豊かで仕事がたくさんあるからというのが理由であり、もう一方ではReact後の時代も陳腐化しないような、なるべくWeb標準に寄せた知識を習得したいという気持ちがあります。
この目標に対して、上で挙げられていた20個のessential partsは指標であるということになります。複数のフロントエンドアプリケーションを実装する場合、これらをすべて毎回セットアップするか、テンプレートリポジトリとして用意することになりますが、初学者は練習のために少なくとも複数回手動セットアップを経験したほうがいいでしょう(個人プロジェクトなので、毎回全部をやる必要はないにしても)。初心者には信頼できるテンプレートを作ることも難しく、エコシステムの変化が激しいフロントエンドではメンテナンスも困難です。フロントエンドプロジェクトの完全なテンプレートというアイデアは、限られた状況でしか機能しないように思えます。
現在主流のフロントエンド技術では、上に挙げられていたような環境構築を経て、ようやく個別の機能の実装に取りかかることができます。本来は個別の機能の実装のほうが主であるはずです。とはいえ、フロントエンドが憎まれる理由、フロントエンド開発の苦しみの中で、こんなのはまだほんの序の口です。その後の個別の機能の開発にも苦しみはあり、ずっと続いていくでしょう。
理想的には、既存機能と衝突しないような形で機能を追加することのできるアーキテクチャを手に入れたら、一つのプロジェクトを複数チームで並行開発することもできるはずです。実際には想定外のシナリオが発生して、思ったほど拡張が容易でないとわかるかもしれません。設計レベルの誤りを後で直すのは困難ですし、一つのプロジェクトの中で基準が複数併存するのもまずいです。公正な見方を養うために、システムと個別の両方に取り組むことが必要そうです。実プロジェクトを実験台にすると後が大変になってしまいますので、新規プロジェクトを作り出す人には、拡張容易な設計についてあらかじめ十分な見識が必要であることがわかります。これもまた、練習の中で養っておかなければならないということになります。
終了のお知らせ
このスクラップを更新するのは終わりにしようと思います。
6月には技術面接対策のほか、Nx + Next.js + Prisma + Supabaseでフルスタックアプリケーションを書こうとしていましたが、いきなり複雑になりすぎてしまったので中止しました。代わりに、Bulletproof Reactを参考に、mswとStorybookを使ったTDDのワークフローを確認することを主な目標に(状態管理とfetchはRedux Toolkit + RTK Query)、SPAから書き始めることにしました。
このように試行錯誤や手戻りがあるので、インプットとアクティビティは一対一で対応していません。一つの直線的な物語のように見せかけようとすると嘘になってしまいます。一つ一つのトピックの掘り下げが浅く公益に資さないし、単純に私自身に時間がない(もっと手を動かしたい)ので、この計画はbad ideaだったと思います。
状態管理ライブラリや、application holotypeおよび技術選定のトレードオフ、REST vs. event-driven vs. RPCといったアーキテクチャスタイルの違いなど、話題はたくさんあったのですが、単に資料を羅列するだけなら、GitHubでawesomeリストのような形で公開してもいいですから。
私の採用が決まったら、勤務開始時点で終了します。残念ながら私がどこにも採用されずに諦めてしまう場合も途中で終了します。
と言っていたのですが、私の求職活動が終わるより前に企画が終了することになってしまいました。
Gen 3: 体験を中心とした今後のWeb技術への見通し
最後に、駆け出しエンジニアのために技術トレンドの過去・現在・未来を紹介(?)して、この企画は終わりです。
GoogleにてAngularの開発に12年間従事したIgor Minarは、これまでのWeb技術の変遷を以下のように振り返っています。
- Gen 0: 静的HTMLおよびサーバサイドで生成されるHTML (CGI, .NET, Java, Python, PHP, Ruby on Rails)
- Gen 1 (2010年代初頭〜): SPA
- Gen 2 (2010年代中盤〜): メタフレームワークおよびJAMStack (Gatsby, Hugo, Next.js, Nuxt, SvelteKit, etc.)
IgorはGen 2の技術が抱えている課題を指摘した上で、それらの課題を解決するGen 3(Web3ではない)への道筋が現在以下のようなトレンドによって切り開かれつつあると述べています。
It started with increasingly sophisticated workarounds that utilized the Gen 2 solutions in novel ways focused on the server-side and decomposition of monolithic architectures — the island architecture, AstroBuild, React Server Components.
And even more recently, Remix and Qwik showed up, respectively exploring the server-first and html-first Web framework space. These are the solutions that pave the path for many more Gen 3 solutions to come in the future.
What might surprise many developers is that marko, Phoenix LiveView, a Google-internal framework called Wiz, and other less well known solutions have been pursuing the server-first approach for a long time but due to various reasons have not been able to get much love from mainstream Web developers. There are lots of lessons to be learned from the wisdom accumulated by these projects.
Gen 3時代のフレームワークが備えるべき特徴として以下の内容が挙げられています。
- JavaScript-based
- Server-first
- Planet-scale
- Portability of code and data
- Distributed architectures
- Streaming
- Hyper-context-aware
Igorは現在、Googleを退職してCloudflareで働いています。Cloudflareといえば最近相次ぐ新プロダクトの発表で話題をさらっていた企業ですが、Gen 3を実現するプラットフォームに現在最も近い位置にいるようです。