『フロントエンド開発入門: プロフェッショナルな開発ツールと設計・実装』学習メモ
Part 1 導入編 何故使うかを知る
Ch01 frontend history
- static UI → dynamic UI
- DOM utilityを提供したjQuery
- cross browserや下位互換性を吸収したAPI
- Ajax
- XMLHttpRequest objectを隠蔽し冗長な通信記述を簡略化できる
- Shorthand
- 簡易的なanimationの活用
- pluggable API
- 自身のobjectを拡張できる
- → 周辺のlibraryやpluginを充実させるecosystemを築く
- 自身のobjectを拡張できる
- browserで動作する画面を取り扱う技術者にとって,JavaScriptはinteractionや機能実現のための手段として重要な言語となってきた
- SassといったCSS meta language
- DOM utilityを提供したjQuery
- frontend_engineerという専門職
- single_page_applicationの誕生
- 内部では,applicationの状態管理やroutingのみならず,routingごとのcontrollerやdata_modelingなどが盛り込まれるようになる
- → AngularJSやBackbone.jsなどのsingle_page_applicationを実現するためのall_in_one frameworkが使われだす
- client MVCやrouting, data_modelingにはsoftwareのdesign_patternへの理解が求められる
- → frontend engineer
- single_page_applicationの誕生
- Node.jsによる開発基盤の構築
- server_side JavaScriptとしてNode.jsが発表
- → bundled package managerであるnpmによって開発におけるecosystemが急速に充実する
- → frontendでのlibraryのversion_controlや開発におけるさまざまなタスクの自動化が可能になる
- CommonJS: module system
- ECMAScript規格更新に伴う周辺事情の活性化
- ES6からES5への変換tool: 6to5 → Babelに名称変更
- 新しい仕様をcompileするためのpluginを開発することで,健全にcodebaseに最新仕様を持ち込むことができる
- 現時点でfrontendが誇るすばらしいecosystem
- 止まらないfrontend
- focus
- 昨今の技術要素が何のために必要なのか,何を解決するのか
- 実践的な内容で技術要素を取り扱い必要なことを必要なタイミングで学ぶ
- focus
Ch02 frontend_engineerに求められるskill
- frontend_engineerが取り組む実務
- JavaScriptの成長と要求の変化
- 変容する中で維持すべきdeveloperの姿勢
Ch03 frontendにおける一般的なtools
- Node.jsとその周辺のecosystem
- Node.js: asyncのevent_driven_modelを採用したserver_side向けのJavaScript
- server_sideのscript_languageであることに加えて,開発環境において必要なtoolやlibraryを動作させるために必要不可欠
- core
- V8と,libuvというasync I/OをsupportするC言語libraryなどから構成され,binary化されて配信される
- libuv → async event_driven JavaScript runtimeを実現
- JavaScriptはsingle thread
- main processを進めながら,callback queueとしてasync processを積み上げる
- async/await
- JavaScriptはsingle thread
- package_manager
- npm: JavaScript用のpackage_managerのCLI
- packageを格納するregistryを提供・開発する会社名でもある
- Yarn: npmと同類.Facebookが開発.
- version lock file
- workspace
- 別applicationどうしの依存関係を単一にするarchitectureであるmonorepoを実現する仕組みを提供する
- npm: JavaScript用のpackage_managerのCLI
- Node.jsがもたらす恩恵
- Node.js: frontendのtool_chain, 開発環境構築を支える根幹そのもの
- server_side languageとしても有能
- event_loopやnon_blockingという特性を活かして,高traffic requestをさばいてもperformanceが低下するcaseが少ない
- Backends_For_Frontends layerとbrowserとで同じ言語であるJavaScriptを扱うこともできる
- 共通言語 → 一気通貫のcontextをdevelopment_memberに提供し,言語別に切り替えるストレスなく,継続的なdevelopment processを可能にする
- 技術選定の主軸となるcaseもいくつか存在し,組織的な戦略として候補になりえる言語
- Node.jsにより,JavaScriptが戦術・戦略として価値のある言語になるまで発展
- Node.js: frontendのtool_chain, 開発環境構築を支える根幹そのもの
- Node.js: asyncのevent_driven_modelを採用したserver_side向けのJavaScript
- compiler, module_bundler
- 言語仕様を吸収し,解釈可能な状態で展開・連結する変換器
- Babel
- 構文解析で下位仕様の構文へと変換
- webpack
- file間のmodule解決を行い1ファイルに連結させる機能を提供
- Babel
- compiler: Babel
- 新しいJavaScript構文を環境に合わせて解釈可能な下位構文へとdown_compileするRole
- ECMAScriptが年次策定していく新しい仕様と大きく関係
- T39という団体により策定
- 構成
- 構文解析のためのparserやcompilerとしてのcore機能,それらを補うhelperや変換のためのpluginなど細かなpackage群による
- babel/preset-envという主要な変換用pluginがpreinstallされたpresetを使うcaseが多い
- module_bundler: webpack
- 言語仕様の一部であるmodule機構を実装していない下位環境においての再現(emulate)を担当
- 設定ファイルの柔軟性やloader, pluginというAPIを提供し強力な結合・連結機能を提供することで,周辺のecosystemも充実し,activeに開発が続けられている
- ParcelやRollup.jsなども同じ役割
- module仕様であるES Modulesの実装がすべてのbrowser環境で整うには時間がかかることも,module_bundlerが利用される理由の1つ
- JavaScript module_system
- Node.jsが採用したCommonJSとES2015で採択承認されたES Modulesの2つがあるが,Node.jsはES Modulesへの移行を試験的に実装している
- Can I use: browserでの実装状況を調べるためのDBのdefacto standard
- cross browserの課題解決を目的としたJavaScript toolが利用していることも多い
- Babelは,webpackにおいてbabel-loaderとして変換のRoleを担う
- → ほとんどはwebpackをfrontend code compile環境として選択する
- Babel, webpackが解決すること
- Babelには正式な仕様以外のpluginが作成・使用されてしまったという経緯があることに注意
- → babel/preset-envは,ECMAScriptと歩みを合わせ,developerが実際に取り組むようなcross platformやbrowser要件の問題に対して最適な機能を提供
- optionで互換性をどこまで保って変換するかのtargetを指定可能にする
- → babel/preset-envは,ECMAScriptと歩みを合わせ,developerが実際に取り組むようなcross platformやbrowser要件の問題に対して最適な機能を提供
- まとめ
- 開発において,年次策定される言語仕様の進化と並行しながら開発できる環境を提供できる
- JavaScriptにおけるnative module仕様をemulateし現実的に課題を解決できる
- → 開発において変更可用性,scalingの担保をもたらす恩恵となる
- Babel, webpackを使う場面がなくなっても,codebaseが外的環境の変化に柔軟である点が重要
- Babelには正式な仕様以外のpluginが作成・使用されてしまったという経緯があることに注意
- 言語仕様を吸収し,解釈可能な状態で展開・連結する変換器
- JavaScript代替言語: TypeScript
- AltJSと呼ばれる
- CoffeeScript (with Ruby on Rails) → あまり使われなくなった
- Dart (by Google, with Flutter) → JavaScriptにcompile可能
- Reason (by Facebook)やElmは,TypeScriptと同じく静的型付言語としての特性を持つ
- TypeScript: あくまでJavaScriptの構文を維持し,型annotationなどで拡張された静的型付言語
- 自身が持つ型systemを省いた記述も可能
- JavaScriptにとってのsuper_setとなる存在
- TypeScriptの特徴
- 静的型付言語で,型checkとJavaScriptへのcompileを担う
- 型定義の場所
- interface.typeと呼ばれる型宣言
- 型checkとcompile errorによって,applicationの堅牢性とcodebaseの健全性に恩恵がある
- compilerとしてのTypeScript
- JavaScriptへの出力
- Babelのecosystemとは違った,独自の形でECMAScriptの新しい構文をfollowする
- あくまでもJavaScriptへの変換
- decoratorsは技術的負債になりうる
- ECMAScriptとRoleが重複するものもある
- TypeScriptによって解決できること
- 3 points
- compile errorによって,JavaScriptではfollowできない.script実行前の未然検知を可能にする
- IDEと組み合わせることで型補完やerrorを表示させ開発体験を向上させられる
- ECMAScriptとの歩みの中でBabelとは別のecosystemを築いている.早期的に取り込まれた構文利用には注意する
- applicationの堅牢性を高めたり,team developmentを行う上でcodebaseの健全性を維持することに役立つ
- 意図しない記述を許容しないという強力な安全策になる
- 3 points
- AltJSと呼ばれる
- framework/view library: Vue.js, Angular, React
- 中規模以上のapplication開発においてbackend_APIとの連携を主体に据えたviewの構築が必要であったり,user_experienceを高めるためにstressない画面遷移が求められたり,開発序盤における技術選定の中でframeworkやview libraryの選択が求められることがある
- 中長期的な運用や保守の中でproduct, applicationの特性を踏まえながら技術選定をすることは開発の現場では特に重要
- 混とんとしていた変化の時期と比べ,背後を支えるecosystemが盤石となったことも開発者の学習コストを下げている
- frameworkのbuild機構にはおよそwebpackが存在する
- 過渡期はRequireJS, SystemJSをruntimeで実現する手法もあれば,CommonJSの記法を使いながらBrowserifyがWebのためにバンドルを行う手法もあった
- → 今はapplicationと無関係なことに頭を使う必要がない
- ↑ ECMAScriptによって規格化されたES Modulesの記法で,webpackがそれをemulateするようbundleすれば十分
- frameworkのbuild機構にはおよそwebpackが存在する
- Vue.js
- PHPのbackend frameworkであるLaravelの作者が気に入って,LaravelのCLIによって新規applicationが作成される際,file setにVue.jsが内包されるようになった
- 公式サイトの説明
- UIを構築するためのprogressive framework
- monolithic frameworkと異なり,Vueは少しずつ適用していけるように設計されている
- Single_File_Componentという単一のcomponentにDOM template, style, scriptをまとめて記述しcompileする仕組みを持つことで,すべてJavaScriptのcontextに載せ替えることも可能になる
- 少しずつ適用し,小さなcomponent群を集約させながらscaleできるframework
- HTML template: \<template>
- script template: \<script>
- CSS: \<style>
- scoped
- CSSのscopeをcomponent単位で閉じるapproachは,JavaScriptのcontextで完結するlibraryにはよく見られる
- scoped
- まとめ
- communityの支えるlibraryが数多く存在し実績も多くあるので手に取りやすい
- 状態管理libraryとしてのVuexや,SSRやroutingなどを網羅したNuxt.jsなどもある
- component単位で責務をまとめSingle_File_Componentというファイルに集約することで,視覚的・機能的にcomponentが果たすべき領域を捉えられるようになっている
- 別々に分離されたlayer・責務をcomponentという単位で1つのlayerに統合している点が大きな特徴
- Angular
- by Google
- HTMLとTypeScriptでsingle_page_client_applicationを開発するためのplatform, framework
- version 1.xとして開発されたAngularJSとは互換がない
- 開発におけるひととおりのものがそろっている
- SPAのためのclient routingからfetchしresourceを取得するHttpClientなどapplication開発に必要となるものをmoduleとして最初から持っている
- command line toolによる開発一式も完備し,codebaseの足場を作るscaffoldやtest runner/unit testの仕組みまで網羅
- frameworkの概念やarchitectureは盤石 → file 構成や管理方法,細かなtool chainを組み合わせ選定し調査するといった考慮はほとんど不要
- 公式documentにより指南されたfile構成,style guideが一番参考になる
- software designやarchitectureの文脈で多少前提知識が必要
- decoratorによるDependency Injection
- RxJSでの外部通信など非同期の扱い Observablesといったarchitectureやstreamというsequenceについての理解も求められる
- webpackとの組み合わせで起点となるfile: entry fileと呼ぶ
- 例ではmain.ts
- 起点として階層別にcomponent群を集約する
- NgModule: app.modules.ts
- applicationに必要な外部moduleを整理・集約し,下層layerに分配するRole
- applicationには少なくとも1つのroot moduleが必要になる
- Component: app.component.ts
- Angular componentのinstanceを作成しそれが扱う変数やmethodが指定されるほかdecoratorによる記述がある
- Vueにおけるdata modelやevent handlerなどをobjectとして定義した形と似ている
- HTML: app.component.html
- 一部にMustache構文
- CSS: app.component.css
- 明示なしでstyle定義がcomponent内にとどまる
- まとめ
- Vue.jsと同じく,component baseのUI構築といった構成
- style guideで理想となる構造を示している
- 初手から学習領域が広くなる
- DI, HttpClientなど
- React
- by Facebook
- UI構築のためのJavaScript library
- UI構築にのみ関心
- simple view library
- minimum
- JSX: JavaScriptの拡張としての表現
- virtual_DOMという考え方
- 宣言的な記述がlogicによってのみ更新される
- Vue.js, Angularとの違い・共通点
- ReactはあくまでJavaScriptの文脈上ですべてを成立
- 木構造という概念を意識することなく宣言的なUI表現であるJSXを記述
- 実際にbrowserで表現される際のUIの一貫性を保てる
- 3 points
- all_in_one frameworkではなくUI表現にのみ関心を寄せたlibrary
- HTML templateではなくJavaScript構文で記述
- JavaScript context内で完結し変更差分を意識せずにUIに集中できる
- component指向のframework/libraryであること
- framework/libraryによりfrontend developmentはcodebaseの一貫性を保てる
- frameworkの選定には,user数,communityがactiveであることも重要だが,teamの学習状況やmember のskillにあったlibraryを選定することも考慮が必要
- 捨てやすさ
- 技術的な潮流に求められる柔軟性
- componentを疎結合に構成しいつでも変更できる状態に保つ → 技術的な環境の変化に耐えうる
- frontend developmentに求められる要件
- speed感をもって継続的に変更に対応しながらも,障害やバグを生みにくい堅牢性の高い状態を保つ
- 変更につぐ変更への耐久性のある,捨てやすさ・変更容易性が強く求められる
- component指向であることで解決できること
- framework/view libraryを利用することでteam_developmentにおけるcodebaseの一貫性や保守性を持つことができる
- 疎結合なcomponentであることで技術的な変更に耐えうる,時間とともに古びたり腐ったりしても変更可能な状態を保てる
- speed感あるrelease cycleを求められるfrontend developmentにおいて十分な堅牢性と持続性を発揮できる
- 中規模以上のapplication開発においてbackend_APIとの連携を主体に据えたviewの構築が必要であったり,user_experienceを高めるためにstressない画面遷移が求められたり,開発序盤における技術選定の中でframeworkやview libraryの選択が求められることがある
- state_management/data_layer: Redux
- componentをまたぐような横断的な関心ごとは不可欠
- browserにおけるstate_managementは煩雑
- browserの状況・動作を考慮しながらbrowserで画面遷移を完結させる動的な実装で考慮するcase
- user面で起きうることはなかなか網羅しづらい
- 主たる目的以外に考慮すべき項目が多い
- user event以外にも,deviceや周辺環境の考慮が必要
- user actionのlifecycleが長くなるほど,扱うデータもUIの状態も多岐にわたる → solution必要
- client_MVC
- 極端に抽象化すると,Model: application data model, View: output, Controller: input
- contextごとにRoleが多少異なる
- GUI application
- Model: 監視しViewに通知
- View: Modelの値をuserに適切に表示するdisplay interface
- Controller: user actionを受けてmodelへ変更を伝える
- server_side framework
- Model: data structure(DB entityと同義), data操作method
- View: browserに流すためにModelの値を埋め込んだHTML
- Controller: requestを受けて処理を振り分けデータ操作methodを呼び出す
- GUI application
- 簡易的なclient_MVC
- objectから構成され,singleton instanceが変更される,object_orientedのcode構成
- event_driven, broadcastを利用したapproach
- observer pattern
- View, Controllerがほとんど同義になることも多い
- frontendで抽象化されるModel, 扱う上での課題
- Model: GUI applicationがもつ画面に表示・plotするdata modelであることが多い
- 特にSPAなどでは,一意のendpointから得られるdata source(JSON object)を指したり,それを加工しfrontend用のobjectに整形したりするのが一般的
- client, frontend固有の表現を実現しなくてはならないdata modelも含まれる
- server_side frameworkにおけるMVCと違ってDBのentityだけでなく,UIを表現・操作するための抽象化された固有のdata modelもfrontendには必要になる
- ModelとViewは強く紐づく
- frontendに転写されるModelと対をなすようなserver_sideのDB entityやAPI endpointの改修がapplicationの基幹的なRoleを担うことが多いため,frontendに課題解決がシフトしがち
- 双方向のdata_flow
- 各layerが単一責務を果たすための制約
- 以上の制約は,複雑になったときにどこでどんな変更があったのか・なぜViewが影響を受けたのか認知の範囲を超える危険性がある
- 規模が大きくなった際に抽象化されたdataがlayerをまたいで双方向に行ったり来たりすることは懸念が増える要因の1つ
- Model: GUI applicationがもつ画面に表示・plotするdata modelであることが多い
- RoleがあいまいになるController
- frontendにおいてはRoleがserver_side以上のものになりうる
- Controller ≒ Viewのようになり責務があいまいになって,制御しづらく複雑化しがち
- client_MVCの課題
- Modelにはserver_sideのdata_modelをAPIを通して投射したmodel, frontend固有のUIを抽象化したmodelが含まれ,Viewにおける関心がModelをまたいで複雑に絡み合っている
- ModelとViewの変更において密に相互利用しているため,変更起点が不明瞭になりdata_flowが制御しづらくなる
- ModelとViewは関連性が強い一方で変更が望まれやすく,可用性や変更可能性が求められる
- Controllerの担う責務が多くRoleがあいまいで,管理や制御が困難
- → Flux pattern → Redux
- Fluxというapplication architecture pattern
- by Facebook
- frontendに主軸を置くapplication architecture
- 単一のdata_flowを採用した,MVCとはまったく考え方が異なるarchitecture
- Action → Dispatcher → Store → View → Action
- Actionを起点にして一方向にdata_flow
- 各layer
- Action: Storeに存在するデータを更新するうえで必要な識別子.合わせて関連するデータも送出.
- Dispatcher: データを伴って発行されたActionを補足しStoreに送り出すためのAction hub
- Store: applicationが扱うdata/state. Storeの変更はAction → Dispatcherにおいてのみ変更される.基本的にはJavaScriptにおけるobject
- View: UIそのもの.Storeの変更通知を受けるための接合点が必要.ViewからもActionを発行する.
- Redux: dataの一極管理
- Fluxはarchitecture patternのため,多くの実装が存在する
- Fluxは複数のStoreを許容するが,Reduxは1つのStoreのみ許容する
- single source of truth
- 複数のdata_modelやstateを扱うStoreこそがapplicationが唯一依存すべきtree状のobject
- DispatcherがStoreに大きく紐づいている
- Reducerがいる
- Reducer: 実際にStoreの変更を受け持つ
- 発行されたActionと現State=今のapplication stateを引数にした関数
- Reduxの2つの重要な原理を持つ
- 状態を読み取りのみとして,更新する場合は新しい状態を作成して送出
- : immutable
- debug, test容易
- Reducerは純粋な関数
- 引数によって新しいStateを返却する冪等な処理の関数
- Storeを1つのReducerで管理させるところからスタートしても,applicationの成長とともに適切に切り出すことでscaling〇
- 状態を読み取りのみとして,更新する場合は新しい状態を作成して送出
- ReducerからapplicationのStoreを作成
- Reducer 1つがState 1つとなる対の構成となるケースがほとんど
- combineReducersという複数のReducerを束ねるhelper functionがある
- Reducer 1つがState 1つとなる対の構成となるケースがほとんど
- ViewがどのModelと紐づくかより,application全体における状態の一部を参照し,変更によって再実行されるという構成
- Viewと紐づくrender functionがStoreの値を監視し反映する
- button click時の挙動もModelの直接的な変更ではない
- 識別されるuniqueなActionを発行しStoreに送り出しているだけ
- Storeの変更は監視するrender functionの再呼び出しにより順次Viewに反映していく
- MVC patternのModel/Controllerというlayerの責務・Roleは,Flux/ReduxにおいてはStoreに内包されている
- Reduxは,messageによるbroadcastをより強固にしたevent_driven architecture
- Reduxが解決できること
- 3 points
- ViewをまたがるModelの変更検知という煩わしさはStoreという唯一のstateをViewにbindすることで解決
- Storeの変更は,Actionからしか変更できないという制約により状態変更の見通しが立ちやすい
- Model/Viewの密結合を避けることが可能であるため,可用性や変更容易性に優れている
- ViewであるcomponentはStoreの値にのみ集中できる点から,疎結合で構成されるcomponent指向のlibraryとの親和性が高い
- Redux周辺のecosystemを支えている
- 採用を検討するケース
- 複数のUI componentをまたぐdata_model, stateの共有が増えてきた
- release後に変更が多く発生するにもかかわらず開発コストが大きく感じる
- 3 points
- CSS: CSS meta_language, design手法, CSS-in-JS
- CSSを取り巻く現状
- W3Cがまとめている
- 1~2年単位でmoduleの使用状況をsnapshotとして文書化している
- browser vendorや開発者communityとどう関わりあっているかがECMAScriptよりも追いかけづらい
- 各browserの対応状況について
- Can I use
- 全体として大きな機能を扱う
- CSS Grid Layout Moduleなど機能レベル
- 全体として大きな機能を扱う
- MDN
- 仕様や詳細なproperty levelを扱う
- grid-column, grid-templateなど
- 仕様や詳細なproperty levelを扱う
- npmにlibraryとして公開されている
- Can I use
- CSSの表現力を高めたSass,CSS meta_language
- JavaScriptで作成されたPostCSS
- 構文をparseしAST(Abstract Syntax Tree)を操作するAPIを提供し最終的にCSSを出力するtool
- pre-processだけでなく最適化などを行える
- plugin群で,変数化やネスト構造の実現などの機能をそれぞれ単体で提供
- pluggable, 拡張性が高い
- Sassの一部の機能だけを取り出し個別に組み合わせたいといったケース,CSS module levelがfixしてbrowser実装を完了したが対応していない下位browserに対してfall backしながら変換したいケースなどに有効
- e.g.
- Sassにおける@extendを利用してstyleの継承を行いたい
- postcss-extend-rule
- Sassにおけるnest構造によって親selectorの疑似クラスを記述したい
- postcss-nested
- 新しい仕様を後方互換性をもって下位browserへfall backしながら実装
- postcss-preset-env
- babel/preset-envと名前も役割も似ている
- vendor prefixの問題も解決する
- Autoprefixerというlibraryで,通常のstyle propertyに合わせて,vendor prefixのついたpropertyを追加する変換を担当する
- libraryはCan I useのDBを利用している
- Autoprefixerというlibraryで,通常のstyle propertyに合わせて,vendor prefixのついたpropertyを追加する変換を担当する
- 具体的に対応させたいbrowser, OS versionはBrowserlistのqueryを書く
- postcss-preset-env
- Sassにおける@extendを利用してstyleの継承を行いたい
- CSS design手法
- CSSの大きな特徴であり弱点
- styleをいつでも(後方から)上書きできること
- cascadingと詳細度により意図しないstyle崩れが起きる
- styleをいつでも(後方から)上書きできること
- BEM
- componentという概念とselectorの命名規則を組み合わせたCSS design手法
- uniqueな名前空間とuniqueなselectorによるstyling
- Block
- 独立した構成要素の粒度で1番大きいもの
- Element
- Blockを構成する粒度の細かい構成要素1つ1つ
- Modifier
- Elementを拡張・装飾するvaliation
- 厳格なrule
- styleにはclass selectorを使うことがほとんど
- ID selectorを使わない
- uniqueなsingle selectorを要素のclassに付与しstyleを組み上げる
- HTMLが冗長という負担はあるものの,無記名のHTML要素を廃しそれぞれの要素がuniqueな名前空間を持つことでBlockでまとめたcomponentのscope管理を実現可能にする
- JavaScript framework/libraryとの組み合わせで解決する手法もある
- CSSの大きな特徴であり弱点
- CSSの弱点を補うためには
- postcss-preset-envで利用できるoption: stage
- ECMAScriptの策定におけるステージ制と類似したもの
- postcss-preset-envで利用できるoption: stage
- CSSを取り巻く現状
- static_analysis_tool
- 不整合をsource code実行前に検出し問題を提案するtool
- 実行せずにcodeの欠陥を予測する
- あらかじめrule/coding規約をteamに持つ
- → 無駄な指摘を減らし機械的な指摘ができる
- → source codeに一貫性をもたらし可読性が上がる
- JavaScriptはruntimeでのみerrorを検出するため事前に検出が必要
- Prettier
- 多言語をfollowするJavaScript製のformatter
- EditorConfigでformatする場合もある
- trailingComma, printWidthなど個人のcoding styleによるところが大きい部分をformat
- printWidthは多言語・記述をフォローしている
- この強力な機能がPrettierを選択する理由になる
- codebaseにおける規約やstyleは,teamで合意・納得している状態が,開発を進める中で健全
- ESLint
- codebaseにおける細やかなruleをpluggableに追加可能なlinter
- Lint: 潜在的なerrorを未然に検知し警告すること
- no-cond-assign
- より強力
- .eqeqeq
- prefer-const
- より強力
- no-fallthrough
- typescript-eslint, eslint-plugin-reactなどの追加ができる
- 実行前に警告できる + team ruleを投射
- teamとcodeの成長に合わせて追加できることが重要
- codebaseにおける細やかなruleをpluggableに追加可能なlinter
- ほかのlinter/checker
- npx htmlhint https://example.com
- HTMLの規格への準拠や規格とは別のruleのチェックもできる
- 厳密にはlinterというよりvalidator
- stylelint
- CSSにおけるlinter
- BEMの設計手法に頼らず,cascading/詳細度による意図しないstyleの上書きを防ぐために,stylelintのselector-max-specificityといったruleで詳細度を制御することもできる
- npx htmlhint https://example.com
- static_analysis_toolが可能にすること
- 構文のformatをrule化
- bugの未然検知に役立つような記述ruleやcode styleのrule化が可能になる
- 3 points
- 人間による指摘以前に機械的にcode styleやteamのcoding styleを指摘できる
- code styleの衝突はいつでも起こるもの,事前にteamで取り決めておくことで不要な議論を避けられる
- static_analysisによってscript実行前にbugの芽を摘み取れる
- 本質的な作業に集中することを助ける
- unit_test: Mocha, Jest, Karma
- テストの種類
- unit_test
- programの正常性をmodule単位で検証する
- 多くは言語に合わせてprogrammable toolやtest frameworkを使う
- by developer
- integration_test
- module同士を結合し動作させ,usecaseからtest項目を作成し実施,正常動作を担保する
- by developer, test engineer
- acceptance_test
- Web frontendのGUIからの操作におけるテスト項目を作成し実施し,正常動作を担保する
- by QA, test engineer, tester
- unit_test
- unit_testとfrontend development
- unit_testは品質の担保という側面より,developerが心理的負担のない状態で安全に開発するために存在しているという考え
- 安全に変更できることがメインで,おまけで品質がついてくる
- unit_testは品質の担保という側面より,developerが心理的負担のない状態で安全に開発するために存在しているという考え
- Mocha, Jest, Karmaそれぞれの特性
- range
- Mocha
- test environmentの提供
- test framework
- 監視機能
- Jest
- test environmentの提供
- test framework
- assertionの提供
- snapshot test
- test double
- 監視機能
- coverage計測
- Karma
- test environmentの提供
- 監視機能
- Mocha
- Mocha
- 別にassertion libraryが必要
- assertion: testの合否を確認するためのmethod
- Chaiなど
- describe: test grouping
- it: testcase
- Node.jsのassertion libraryを使った例
- test frameworkは出力結果にテストが通ったことを表示する仕組みや関数を持つ
- 別にassertion libraryが必要
- Jest
- Jestを使うと,実行環境はNode.jsだがbrowser側のWeb APIをfollowすることができる
- 必ずしもこれがJestを選択する目的ではない
- jsdomを利用してWeb APIをfollowしbrowserでの実行をemulateしているため
- expect
- matcherの引数に期待する値を設定したり,引数なしのmatcherで期待する値を表現したりするassertionが一般的
- matcher: chainするmethod
- mock
- spy
- 呼び出された際の引数や結果,呼び出し回数などの情報を格納している
- matcherの引数に期待する値を設定したり,引数なしのmatcherで期待する値を表現したりするassertionが一般的
- 小回りが利きやすくNode.jsのみで実行しやすい
- 便利なall_in_one test framework
- Jestを使うと,実行環境はNode.jsだがbrowser側のWeb APIをfollowすることができる
- Karma
- unit_testでbrowserを変えたい,browserのJavaScript engineで実行したいという需要のため
- Angularが提供するcommand line tool
- AngularはKarma + jasmine
- test frameworkではなく,unit_testの実行環境を起動するためのrunnerのRoleのみ果たす
- test frameworkの変更や実行環境の変更が設定により柔軟
- range
- unit_testやtest frameworkが解決できること
- release後に変更可用性やspeedを求められるのがfrontend
- 変更に耐えうるcodebaseや環境を作るためにunit_testのtest frameworkが必要になってくる
- 必要な部分から必要なだけ始めてみるのもfrontendにおけるunit_test導入のための戦略の1つ
- 変更が頻出する部分など
- テストの種類
Ch04 開発の現場における仕事の進め方
- agileといった考え方
- technologyやlifestyleが刻々と変容していくなかで,柔軟な対応が必要になっている
- source codeやapplicationを変更に耐えうる状態にすること,変更容易性を保った状態にすることが重要
- → agile
- scrumという開発手法
- 個人との対話と他者との協調
- → 学習メモ参照
- communication hubとして
- 誰もが触れることができるbrowserを主務としているengineerであり,操作や機能要望を一手に担うことが多い
- frontend_engineerの責務
- 画面デザインをbrowserで具現化するために実装する
- server_sideから渡ったdataを使ってbrowserにGUIを組み上げる
- browser上で正常にapplicationが動作するようにする
- → team_memberとの合意を経て,browserという職種に依存しないfieldの上で形にしていく必要がある
- → publicに情報を明確にしてteam_memberと相談しながら開発を前に進める,communication hubのような責務を持つ
- 変化に対応しながら提供するサイクルを速くする
- ここまでのまとめ
- 動くproductを速いサイクルで変化に対応しながら提供するために必要な解決策を持っていることがimportant
Part 2 どう使うかを学ぶ
Ch05 development_environment
- 既存applicationのdevelopment_environment構築
- Dockerのinstall
- Node.jsのinstall
- Yarnのinstall
- API serverの起動
- docker-compose build
- docker-compose up -d
- -d: backgroundで実行
- clientの起動
- 既存機能の把握
- どんなapplicationなのかを知る
- まずdata_structureを見る
- 機能を見る
- applicationが抱える課題を探る
- jQueryのcode
- DOMへの影響を常に考慮する必要がある
- すべてのcodeがbrowser event紐づき複雑に絡み合っていく
- → React, Fluxで解決できる
- 文字列内に変数を挿入することで書きづらいcodeになっている
- communityがどれだけ活動しているかやrelease頻度なども技術選定において重要な指標になる
- jQueryのcode
- どんなapplicationなのかを知る
Ch06 設計と実装
- branchの切り替え: git checkout \<branch>
- frontend環境の構築
- TypeScriptの導入
- TypeScriptのinstall
- yarn add typescript --dev
- yarn run tsc --init
- 公式referenceで必要な設定を選択していく
- Babel経由でTypeScriptのcompile
- yarn add @babel/preset-typescript --dev
- 既存コードをTypeScriptで書き換える
- compile errorを解消する
- TypeScriptのinstall
- codeの分割
- 処理を別のファイルに切り出す
- export, import
- 処理を別のファイルに切り出す
- Jestを利用したunit_test
- Jestのinstall
- yarn add jest @types/jest ts-jest --dev
- jest.configの設定
- yarn run jest --init
- 描画されたDOMの検査
- id, classで判別か,それができなければselectorでDOMをたどる
- 仕様をテストコードに入れておく → 改修時の確認コストが大きく下がる
- Jestのinstall
- Reactの導入
- Reactのinstall
- yarn add react react-dom
- yarn add @types/react @types/react-dom --dev
- JSXのためのcompile設定
- yarn add @babel/preset-react --dev
- JSXで要素を表示
- webpack-dev-serverのinstallと設定
- yarn add webpack-dev-server --dev
- fileに変更を加えた際に自動でbrowserに反映
- jQueryで書いたcodeをReactに置き換える
- APIとの通信 → stateに保存 → 画面が再描画
- event_handlerの記述
- yarn add react-transition-group
- yarn add @types/react-transition-group
- react-transition-groupはReact Componentでanimationを実装するためのpackage
- useState(), useEffect()などのHookを使うことで,大量のコードを書かずに動的な画面を構築できる
- 独自のHookの作成もできる → 複数のComponentで再利用したい処理の切り出しもできる
- Reactのinstall
- Enzymeを使ったcomponentのtest
- Enzyme: React_Componentのテストを補助するためのutility
- Enzymeのinstall
- yarn add --dev enzyme @types/enzyme enzyme-adapter-react-16 @types/enzyme-adapter-react-16
- Jestの設定
- jest.config.jsにEnzymeの設定を追加
- setupEnzyme.tsをJestが読み込むように設定
- Jest実行時にJSXのcompileができるよう修正
- yarn add babel-jest --dev
- yarn remove ts-jest
- babel-jestはbabel.config.jsを見にいく
- jest.config.jsにEnzymeの設定を追加
- React_Componentをテストする
- Enzymeのrendering方法
- shallow(): child componentは描画せず,引数に与えたcomponentのみを描画する
- mount(): jsdomなどのDOM emulatorを利用してchild componentを含んだ状態でDOMにmount.React lifecycle methodも呼ぶ
- render(): child componentを含んだ状態で描画するがlifecycle methodは実行されない
- → 表示結果の確認だけならshallow()/render(), lifecycle内で処理した結果をもとにDOMを構築しているようなcomponentではmount()
- mock機能
- mocks/(filename)にmock用のfileを置く
- APIとの通信などにmockを用意する
- act()でEnzymeの描画実行をラップ
- Hookをテスト対象のcomponentが利用していた場合にテストが実行できなくなる問題の回避方法
- Enzymeのrendering方法
- styled-componentsの導入
- componentとstyleをセットで扱う
- styled-componentのinstall
- yarn add styled-components
- yarn add @types/styled-components babel-plugin-styled-components --dev
- babel.config.jsに追加
- CSSからstyled-componentsへの移行
- 目的
- 開発効率を上げてreleaseまでのlead timeを短くするために開発基盤を整備し,開発者が安全にコードを変更し運用していくために型の導入やunit_testを作成している
- まずは足場を固めて自由度の高いcodebaseを作る
- 開発効率を上げてreleaseまでのlead timeを短くするために開発基盤を整備し,開発者が安全にコードを変更し運用していくために型の導入やunit_testを作成している
Ch07 CI/CDによって受けられるmerit
- workflowに自動検出を導入し安定したapplicationを提供しながらどのようなmeritを受けられるか
- CI/CDによって受けられるmerit
- lint, test, compileなどを自動化
- 理由
- developerの手動負担を抑える
- development_processのあり方の変化
- agile
- 安定した定期的なreleaseのためには自動化された安全性の確認が非常に重要
- agile
- 理由
- CI/CDについて
- 各tools
- GitHub Actionsを始める
- ESLintを導入し動作させる
- CIで自動化するmerit
- 手動操作やreviewでの疲弊を回避
- development_processが健全になる
- product code自身も健全性を維持できる
- 安心感
- CI: 安定したapplicationを効率よくuserに届ける仕組みであるとともに,本質的なdevelopmentに集中できる
- lint, test, compileなどを自動化
- performanceと改善
- backendでHTML documentのresponseを返すlatencyが大きい
- ↑ Performance/Network tabで確認
- frontendでJavaScriptファイルのサイズ肥大化やscriptがUI構築のblock要素になっている
- Performance tabで計測後Long taskの警告数が多いかどうか確かめる
- 50ms以上で警告
- performanceの問題とは
- 新規開発
- developerの関心の薄さや非機能要件の認識不足に起因する
- release済
- userの問い合わせで発覚することが多い
- 定期的な計測が必要
- performanceだけを意識する必要はない
- 新規開発
- 基礎的なperformance知識: critical_rendering_path
- 早い段階での画面描画のspeedが重視されている
- conversion rate, 直帰率の低下, 滞在時間の長さ, 同セッションでのpage viewの多さにつながる
- critical_rendering_path: 初期描画に必要なresource/step
- Reactを使ったclient_side renderingの実践では,loading中のUI提供をする限り初期描画が問題になることはあまりない
- critical_rendering_path: CSS
- critical_rendering_path: JavaScript
- 初回画面構築に不要なら,headではなくbody tagを閉じる手前に移す
- async: download後のscript実行時はblock
- defer: 画面構築に影響がないときに〇
- 初回画面構築に不要なら,headではなくbody tagを閉じる手前に移す
- Lighthouseを利用した定期的なperformance計測
- 根本原因を探ることが難しくなることがある
- → 定期的な計測・検知の仕組みを整えて計測結果を得ることが重要
- CIで定期的な計測を実行する
- Core Web Vitals
- Largest Contentful Paint(LCP)
- First Input Delay(FID)
- Cumulative Layout Shift(CLS)
- 指標の判断は各々
- Lighthouseを利用する
- npx lighthouse ...
- goal: outputを知り目標とする数値を超えていないかを検知して知らせること
- lighthouse-ciを使ったaction: treosh/lighthouse-ci-action
- 新しいworkflowを追加する
- GitHub Actionsではworkflowを物理ファイルで分けられる
- .github/workflows/lighthouse.ymlを作成
- 特定のmetricsや閾値の設定
- uploadArtifacts: true
- 結果reportをdownloadできる
- Developer_Toolからtrace可能なreportがほしいときは,lighthouseを使うのも〇
- --save-assets optionが必要
- puppeteerというChroniumをheadlessで動かすtoolとlighthouseを使って簡単にscriptの実装ができる
- Datalogという監視やmonitoringのためのSaaSで数値をplotして可視化もできる
- GitHub Actionsではworkflowを物理ファイルで分けられる
- 早い段階での画面描画のspeedが重視されている
- 強力な武器はない,人には人のperformance
- performanceは1つの指標に過ぎない
- backendでHTML documentのresponseを返すlatencyが大きい
Ch08 analysis, monitoring
- serviceの成長とともに開発する
- 保守・運用: product, serviceを成長させていくphase
- 数字として可視化して目標と比較するために,計測する仕組みとしてanalysis_toolやAB_testが導入されることが多い
- 計測のための実装やAB_testの実施もfrontend_engineerの責務
- 仮説検証,AB_testの目的
- 仮説検証
- personaを使って施策の議論や価値提供の優先度を考えることも多い
- analysis_toolの導入により,目標値に向かうためのuser actionをある程度可視化できる
- AB_test
- personaから推察される行動を考え仮説を立てて,短いiterationで立証するため
- marketingにおける調査・試験の一種
- GUIにおけるpatternや組み合わせで立証することが多い
- UIや使い勝手,操作性などclient接点における価値をすばやくuserに届け仮説検証を行うことが,analysis, AB_testの目的になる
- 仮説検証
- toolの導入: Google_analytics
- 計測のためのsnippetを導入するだけでデータの可視化や計測がいちはやく手に入れられる
- Google_marketing_platformの1 product
- analyticsの利用登録
- 計測のためのtracking code
- eventの計測,属性の追加
- ラップしたようなevent送信用の関数を作る
- service 1つに対してproperty 1つ
- 重要
- action nameやcategory, label nameなどをteamで設計し,memberが共通理解を得ること
- toolの導入: Google_optimize
- AB_test用のtool
- html code → p.211
- 振り分けの完了は,Cookieの_gaexpの値の末尾を見るとわかる
- product codeに組み合わせる
- ReactのHooks APIを利用した実装方法
- UIと振り分けを宣言的にする
- Reactが実行される段階ではtest patternは決定している
- third_party scriptとの兼ね合い
- client performanceにはいくらか影響が出ることに注意する
- AA_testで導入によって数値に影響が出ないことや実際に振り分けが行われることを確認する
- toolの導入における懸念事項の洗い出しや組み込んだ場合の結果の提供もfrontend_engineerの責務
- user_monitoring, error_event_monitoring
- 障害や問題をrealtimeで検知する仕組みが必要
- userを取り巻く環境を知る
- Developer_Tool
- network状況をemulate
- specをemulate
- analysis_toolでまずuserの環境・状況を知ることがimportant
- Developer_Tool
- browserで起きるerror_eventなどからuserを知る
- error_event_monitoringのため,Sentryを導入
- yarn add @sentry/react
- 設定できること
- error_eventへの緊急度levelの設定
- error_eventの閾値超えによるalert(各種tool連携)
- release versionやuser definitionのmeta information付与
- sourcemapを利用した影響のあったsource codeの表示
- documentが豊富
- team全体で導入する
- Sentryの動作とcodeへの組込
- global scopeにおける例外handler
- top levelに繰り上がった例外をさばいている
- 事前に用意できるものは個別に準備しておく
- global scopeにおける例外handler
- React Error Boundaryを使う
- fallback UIをuserに提供できる
- error_eventのlogも取れる
- 昨今のReactでの開発は関数としてcomponentを実装するが,Error Boundary componentはclass baseの componentである必要がある
- 収集したerror_eventを役立てる
- errorとして収集して対応したものも,情報として収集を続ける必要があることもある
- Cookieの使用状況など
- error_eventのlevelづけ
- error_eventの発生ログは,大きな判断材料になる
- この数字がteamでの対応優先度を決めるのに一番良い判断材料になる
- product_backlogに追加も〇
- errorとして収集して対応したものも,情報として収集を続ける必要があることもある
Part 3 応用編 より深く学ぶために知る
Ch09 team_developmentとWebへの貢献
- teamで働く
- Scrumという開発手法について(あらためて)
- → 学習メモ参照
- Scrumを採用したteamに入ったら
- story: sprint_planning
- story: sprintの開始
- story: sprintの終わり
- team_developmentとはtechnical skillではない
- Scrumという開発手法について(あらためて)
- communityへの貢献活動
- OSSへの貢献はcode_commitだけではない
- bug report, document修正, 簡単なpull_requestから始めてもよい
- communityをのぞいてみる,issueを立てる
- CONTRIBUTION.mdのようなdocumentに,貢献の方法や何から始めるのが良いかが書いてある
- CODE_OF_CONDUCT.mdで行動規範を掲げているものもある
- 機能報告・bug報告の方法
- まずは,OSSのrepositoryにあるissueを検索し,類似した内容の有無を確認
- bugの再現状況の追記なども〇
- templateを使う
- できることからOSSへcommitする
- 各issueにはlabelがある
- 寄付する,翻訳するといった違ったapproach
- Webというplatformに貢献する
- Webというplatform: Web site/applicationを開発するためのHTML,CSS,JavaScriptの標準化されたtechnology群
- Webは維持し続けることがimportant
- product_codeを健全に保ち周知していくことも,小さな規模だがteamへの貢献になる
- OSSへの貢献はcode_commitだけではない
- Web platformにかかわるfrontend_engineerとして
- 仕様を知るには
- lightにcatch_upする
- frontend technologyを楽しむために
- 動くproductを早いcycleで変化に対応しながらuserへ届けるために,必要な解決策を持ち実現できることがより重要
- 実現できることよりさらにproductに反映できることが重要
- Webへの興味関心を持ち続ける
- 変化が早く感じるときは,情報を見過ぎている可能性を考える
- enduserはdeveloperではない
- userの課題を解決するために,userへの価値提供のためにWeb platformを使ってdevelopmentを進めていく・課題を解決するということに,意識的であることや楽しむことがfrontend開発において大切