Webを支える技術を読んだ
会社の本棚にあったものを読むことにした。
普段の生活や業務の中で息をするようにHTTPに触れているが、HTTPのことちゃんと理解してないのでは?と思い読み始めた。
RESTやHTTPの成り立ちや基本的なところのおさらい、特にヘッダーまわりについてはちゃんと意識することが無かったので新しい発見があった。一方で、流石に内容の陳腐化も進んでしまっていた。ATOMまわりはぼんやりしか知らなかったのでそれはそれで面白かったが。
以下読書メモ。
REST Webのアーキテクチャスタイル
- アーキテクチャとアーキテクチャスタイルは異なる
- デザインとデザインパターンが異なるのと同様
- RESTはネットワークシステムのアーキテクチャスタイル
- クライアント/サーバーに特に有効
- まさにWeb
- クライアント/サーバーに特に有効
- リソースの名前 = URI
- リソース = Web上の情報
- RESTは、複数のアーキテクチャスタイルを組み合わせて成り立っている
- クライアント/サーバー
- ステートレスサーバー
- クッキーでのセッション管理はこれに反する
- キャッシュ
- 統一インターフェース
- ここでのインターフェースは、GETやPOSTを指している @
- 階層化システム
- コードオンデマンド: プログラムをクライアントにダウンロードして実行する
URI
HTTP
- TCP/IPとは
- インターネットのプロトコルは階層型プロトコル
- ネットワークインターフェース層
- ケーブルとか
- インターネット層
- ネットワークで実際にデータをやり取りする部分
- IPとは、インターネット層のプロトコルのこと
- IPでは、送り出したデータが相手に届くかまでは保証しない
- トランスポート層
- アプリケーション層
- メールやDNS、HTTPSを実現する層
- ソケットとは、TCPでプログラムを用いるときに使うライブラリ
- ネットワークでのやり取りを抽象化したAPI
- 接続、送信、受信、切断など。。。
- WebSocketとの関連はどうなんだろう
- websocketとは: https://qiita.com/south37/items/6f92d4268fe676347160
- リクエスト/レスポンス
HTTPメソッド
- POSTでPUT/DELETEを代用する
- _methodパラメータ
- formの中にtype=hiddenなinput要素を配置し、idを_methodとする
- valueに書いたメソッドが使える
- application/x-www-form-urlencodedの場合にのみ使える
- X-HTTP-Method-Override
- _methodパラメータ
- 条件付きリクエスト
- HTTPメソッドと更新日時などのヘッダを組み合わせて、メソッドの実行可否をキメられる
- If-Modified-Sinceヘッダなど
- 冪等性と安全性
- 冪等性: ある操作を何回行っても結果が同じこと
- 安全: 捜査対象のリソースの状態を変化させないこと
- 変化を与える: 副作用
ステータスコード
- 仕様で定められたステータスコードを正しく使いたい
- 分類
- 1xx: 処理中
- 2xx: 成功
- 3xx: リダイレクト
- 4xx: クライアントエラー
- 5xx: サーバーエラー
HTTPヘッダ
- メタデータ
- 認証やキャッシュなどHTTPの機能はヘッダで実現する
- ヘッダの機能
- 日時
- Date
- Expires
- MIMEメディアタイプ
- Content-Type
- charset(文字エンコーディング)
- 言語タグ
- Content-Langugage: ja-JP
- コンテントネゴシエーション
- Accept
- クライアントが処理できるメディアタイプをサーバーに伝える
- Accept-Charset
- Accept-Language
- Accept
- Contente-Length
- 認証
- Authorization
- キャッシュ
- Pragma
- キャッシュ禁止
- Expires
- Cache-Control
- 詳細なキャッシュ方法の指定
- 前述の指定はここでもできる
- max-ageとか
- 条件付きGET
- If-Modified-Since
- Pragma
- 日時
microformats
- classやrel属性でメタデータを表す
- wordpressでは採用されてる
- microformats は競合する他のメタデータのフォーマットと比較して、古くから存在し、Wordpress などでも採用されていることから、 検索エンジンも採用したのだと考えられます。(他に Yahoo が一部取り入れているようです。)ただし、Google は schema.org の提唱するメタデータを採用するように推奨しています。 schema.org は、Google, Yahoo, Bing(Microsoft) などが共同で管理する団体です。 また schema.org が提唱するメタデータの記述形式、microdata や RDFa フォーマットは、W3C で制定されるフォーマットです。検索エンジンを提供する各社が microformats のサポートを直ぐに止めることは考えられませんが、 今後は schema.org のメタデータを microdata フォーマットでマークアップ(記述)することがスタンダードになっていくと思われます。
- SEOに寄与するかも微妙、標準化競争に負けたように見える
Atom
Web開発者のための大規模サービス技術入門を読んだ
会社の本棚にあったものを読むことにした。
業務ではWebフロントに注力していて、触るとしてもnginxやCDNまわりなのでサービス負荷について考える基準が欲しかったことがモチベーション。
少し古い本なので多少内容が陳腐化している箇所もあったものの、今でも使える基本的な知識や考え方について解説されている。(やむを得ないが)書籍中に出てくるコードはほぼPerlなので読んでなんとなく内容を察する程度で精一杯だった。
OSキャッシュやスケーリングの考え方はあまり詳しく知らなかったところなので良かった。業務外でサーバーを立てる時もスペックは割と適当だったりするので、この辺りの考え方を体得できると業務にも役立てることが出来そう。OSキャッシュの辺りは特に、言われてみれば当たり前だが今までさほど気にしたこともなかった。普段はブラウザ全体のメモリ消費量をなんとなく気にする程度なのだが、アプリケーションのパフォーマンスの観点でもメモリ消費量を気にする癖をつけたい。モニタリングが手軽に出来れば良いのだろうか。
DBまわりも通り一遍というかクエリの書き方を知っている程度なので、サービスに落とし込む際にどういったことを考えるかを知れてよかった。マスタースレーブ構成のクラスタにおいて、マスター間の遅延について考えたこともなかったので新鮮だった。また、これも初歩的な話だがストレージエンジンについて今までほぼシカトしてきていたので知ることができてよかった。
また、アルゴリズムにも興味があった。学生時代に講義で触った記憶はあるものの、ほぼ忘れ去っているからだ。せめてクイックソートくらいは諳んじて書けるようにしたい。結果、書籍中では具体的なアルゴリズムに踏み込んではいなかったが、きっかけにはなった。実践するには競技プログラミングあたりに踏み込むことになるのだろうか。
領域外の知識を吸収する足がかりに出来そうなので、定期的に読み返しておきたい。
以下読書メモ。
オリエンテーション
- スケールアウト時の課題
- ロードバランシング
- データの同期
- ネットワークレイテンシ
- 大規模データ量への対処
- ディスク、メモリ、キャッシュメモリ、CPUの順で速度差がある
- データが小さいうちは処理をメモリで行えるが、大規模になるとそうはいかない
- いかにデータを小さく持つか、複数サーバーに分散させるか、必要なデータを最小限の回数で読み取るか
大規模データ処理入門
- 大規模データとは何か
- 大規模すぎてメモリで処理できない
- メモリはディスクの105 ~ 106倍早い
- SSDは高速だが、バスの性能差故にメモリほどではない
- 負荷の種類
- CPU負荷
- I/O負荷
- ボトルネックを調べるには
- CPU負荷のスケーリングはサーバー台数を増やす
- DBなどI/Oの場合は、データ同期の観点から分散が難しい
OSのキャッシュと分散
- ページ: OSが物理メモリを確保/管理する単位、仮想メモリの最小単位
- プロセスは仮想メモリにしかアクセスできず、ディスクに直接アクセス出来ない
- そのプロセスがアクセス済みになったデータもメモリに残しておく、これがページキャッシュ
- 一度ディスクにアクセスすると、その後のアクセスが早くなる
- LRU: Least Recently Used、一番古いものを破棄して新しいものを残す
- Linuxはメモリがあいていればディスクをキャッシュし続ける
- メモリを増やす = I/O負荷軽減
- キャッシュがI/O対策の基本
- 小さければメモリに載せきれる
- データをキャッシュしきれない規模になったら、複数サーバーでのスケールを考える
- CPUリソース(APIサーバー)が必要な場合は単純に増やせる
- DBの場合は局所性が絡んでくる
- メモリの増設ポイント
- キャッシュ容量と、アプリケーションが扱う有効なデータ量を比較する
- 局所性対策
- アクセスパターンを考慮して分散させて、キャッシュできない領域をなくす
- パーティショニングで実現することが多い
- 負荷分散の学習のためには、OSの動作原理を知ると良い
DBのスケールアウト戦略
- インデックスを正しく運用する
- カラムの型が何で、どれくらいのバイト数で、全体通すとどれくらいのサイズになるのか計算する
- B+木
- O(n) to O(log n)
- MySQLでは、where, order by , group byに指定されたカラムに対してインデックスが使われる
- 明示的に作用したインデックス、プライマリーキー、UNIQUE制約がインデックスとして作用する
- MySQLにおいては、複数カラムがインデックス利用の対象になった場合には、複合インデックスを使う必要がある
- 単一のインデックスの場合は、どちらかのインデックスのみが使われる
- explainコマンドで、インデックスが効いているかどうか確認できる
- レプリケーション
- マスタースレーブ
- マスターが更新系、スレーブが参照系
- 参照系はスケールするが、更新系はスケールさせない
- どうしても更新系をスケールさせる際は、テーブル分割でテーブルサイズを小さくする
- もしくはKVSを使う、RDBMSではなくする
- ポーリング
- マスタースレーブ
- MySQLでは、異なるサーバーにあるテーブルをJOINできない
- クエリを分割して対応する方が良い
- テーブル同士が密結合であれば、同じサーバーにおいてしまう方が良い
- パーティショニングのデメリット
- 運用が複雑になる
- 故障率が上がる
- 冗長化を考えるとマスター1スレーブ3の4台1セットにすると良い
- 故障時のデータコピーのことを考える
- パーティショニングはあくまで切り札として扱う方が良い
大規模データ処理[実践]入門
アルゴリズムの実用化
- 広義のアルゴリズム
- 実装の仕組みなど
- 狭義のアルゴリズム
- 定義された計算問題に対して、定義された計算を行うもの
- 対数的な計算量のアルゴリズムを選びたい
- アルゴリズムとデータ構造はセット
- (私見)アルゴリズムを知っているかどうか、が重要な気がする
- アルゴリズムを用いる場合は、テストファーストで開発を進めると良い
大規模データ処理を支えるサーバー/インフラ入門
- エンタープライズでは信頼性が最重要視され、またトランザクションが多用される傾向にある
- webとエンタープライズではインフラにおける重要ポイントが異なる
- クラウドのメリデメ
- スケーラビリティ
- 各クラウドサービスの独自仕様に対応
- オンプレ
- サーバー/インフラ構成の自由度が高い
スケーラビリティの確保に必要な考え方
- 多くのサービスはサーバー一台で動く
- 4core CPU 8GB: 100万PV/月
- 4core CPU 32GB: 200万PV/月
- 負荷を測るための項目
- ロードアベレージ
- それらのプロセスがいつでも動ける状態なのにCPUが未割り当てで、待ち状態にあるプロセスの平均値
- メモリの割当状態
- ロードアベレージ
- 用途ごとのチューニング
- レスポンスタイム、処理数など何に注力するのか
- 用途が増え、細分化すると管理や異常検知が大変
- だからkubeが人気になったんだよなあ
冗長性の確保、システムの安定化
- 単一故障点の除去
- APサーバーは、台数を並べるのが基本
- ロードバランサのフェイルオーバー、フェイルオーバー
- ロードバランサによるAPサーバーのヘルスチェック
- 落ちたら外して、復帰したら戻す
- ロードバランサのフェイルオーバー、フェイルオーバー
- サーバーが止まる理由は様々
- 人為的な理由
- 物理的な故障
- メモリ異常
- DBサーバー
- マスタースレーブ方式で、一台二台落ちても大丈夫にする
- マスターの冗長化にはマルチマスタ方式を用いる
- 双方が双方のスレーブである
- 片方への更新が、もう片方にも伝搬する
- ミリ秒単位の遅延は避けられない(割り切るか、どうか
- マルチマスタ
- ストレージサーバー
- MogileFS: 分散ストレージサーバー
- システムの安定化
Webサービスとネットワーク
- サービスの成長とネットワークの分岐点
いまどきのWebサービス構築に求められる実践技術
- ジョブキューシステム
- リクエストを非同期にしたい
- 構成要素
- クライアント
- ジョブを投入するもの
- ジョブキュー
- ジョブを蓄えるキュー
- ワーカー
- ジョブキューから未実行のジョブを取り出して実行
- クライアント
- よさそう
- ストレージの選択
- 適切なストレージを選択することは難しい
- アプリケーションからストレージを参照する際のアクセスパターン
- 平均サイズ
- 最大サイズ
- 新規追加頻度
- 更新頻度
- 削除頻度
- 参照頻度
- ストレージの種類
- RDBMS
- 分散key-valueストア
- memcached
- メモリ上で動作
- キャッシュとして使う
- redisと比べて、パフォーマンスに大きく差があるわけではない
- redisに出来て、memcachedに出来ないこと
- データの永続化(ただし永続化設定するとその精密さに応じてパフォーマンスは下がる)
- master/slave構成
- 暗号化
- ソート
- https://qiita.com/robitan/items/2e7f599c4cb1d65f3286
- memcached
- キャッシュシステム
- フォワードプロキシ
- クライアントが外部のサーバー・ネットワークに接続する際に挟むプロキシ
- リバースプロキシ
- 外部のクライアントが内部のサーバー・ネットワークに接続する際に挟むプロキシ
- これらのプロキシでは、リクエストをキャッシュしておくことが出来る
- キャッシュサーバーのメリット
- 平常時に、APサーバーへのリクエストを軽減することが出来る
- サーバーの台数削減に繋がる
- アクセス増加時には、負荷増大によるシステム全体のダウンを予防することが出来る
- アクセスが集中しているコンテンツをキャッシュして返す
- 平常時に、APサーバーへのリクエストを軽減することが出来る
- 分散、冗長化も効果的
- 容量が大きいファイルなどをキャッシュする場合は、キャッシュサーバーを二重化すると良い
- サーバー起動時にはキャッシュが全然ないから注意
- activeにする前に、ウォームアップをしてキャッシュを溜めておこう
- Squid
- リバースプロキシキャッシュサーバー
- 結構歴史がある
- 代替にはnginx, varnishなど。。。
- Varnish
- フォワードプロキシ
- 計算クラスタ
- Hadoop
- Redshift
- 最近のトレンドは。。。?
- BiqQuery?
アプリケーションアーキテクチャ設計パターン読書メモ
一連の読書シリーズはこれで最後。アプリケーションアーキテクチャ設計パターンを読んだ。
本書はアプリケーション全体、システム全体の設計について具体例を添えて書かれている。Javaを中心に様々なパターンについて触れられており、全部に触れていくとキリが無い。気になったワードや解釈を中心に触れていく。
気になる
- アプリケーションの構造と処理方式を決めるのがアプリケーション設計の目的。
- アプリケーションサーバーの中身の内訳についてはあまり意識したことが無かった。
- プレゼンテーション層
- ビジネス層
- インテグレーション層
- セッション管理や認証系についても詳細な解説があるのは、サーバー側の実装や知識がない僕にとっては嬉しい
- バッチ処理やデータアクセス層の解説はもう何度か読み直したい
- クライアントの実装、SPA等についても触れられている
まとめ
内容が多岐にわたることもあって簡単なワードやらを羅列する形でまとめているが、サーバー側の知識を中心に増やすことができた。これまでWebクライアント一本で進んできたので、繰り返し読み返して身につけたい。もう少し個人でもサーバーサイドのコードを書こうかなー。
CleanArchitecture読書メモ
僕がプログラムを一番最初に書いたのは17歳の時だったが、これまでに自分が書いたソースコードを全て見直しても、おおよそ設計と呼べるものが無かった。
設計思想、設計とは何かを学ぶためにCleanArchitectureを読んだのでメモを書く。
例の図
いつも見る例のアレ。既にネットにある種々の解説を読んでみてもピンとこなかったが、本を読むとそれなりにしっくりきた気がする。自分なりにまとめてみる。
内容物
- Entities: 企業全体の最重要ビジネスルールを司る。ビジネスルールとは、例えばローンの計算など、コンピューターで行うかどうかを問わないビジネス上の重要なルールのことを指す。このビジネスルールには、例えば利子のレートや支払いスケジュールなどのデータが紐づく。このデータを最重要ビジネスデータとよぶ。この図で表現されているEntitiesは、この最重要ビジネスデータそのものと、それらにアクセス、操作する関数群で成り立っている。このEntitiesは、システムの他の要素に依存せず独立しているようにしておく必要がある。
- UseCases: 自動化されたシステムを使用する方法を記述したものであり、アプリケーション固有のビジネスルールを記述したオブジェクトである。例えばユーザーの入力やそれに対するインタラクション、入力後の処理などが相当する。ユースケースでは、エンティティに含まれる最重要ビジネスルールをいつ、どのように呼び出して使用するかを規定したルールが含まれている。ここで、ユースケースにはUIに関する記述は無いことに注意する。インターフェースを問わず、インターフェースが使用する処理が書かれている。ユースケースはアプリケーション固有である一方、エンティティはたとえアプリケーションが違ってもそのまま使用できる。そのため、ユースケースはエンティティに依存し、下位に位置する。
- Interface Adapters: この層は、エンティティやユースケースと外部を繋ぐ部分となる。図に示されているように、ControllerやGatewayがこの部分に相当する。DBやWebへの接続はこの層から行う。Interface層やUseCases層を中心に、それぞれの層をまたいだデータのやり取りが発生することになる。その場合は、常に内側の層に対して便利な構造にしておくと良い。
- Frameworks and Drivers: この層が、アプリケーションにとって最も外側の層となる。DBやUIが相当する。肝要なのは、これらは円の内側に依存するが、円の内側であるEntitiesやUseCasesはこれらに依存しないことだ。
依存方向のコントロールとコンポーネント粒度
この本では、依存方向のコントロールと適切なコンポーネント粒度の重要性について語り口を変えて幾度も説かれている。アプリケーションやソースコードに依存が発生するのは避けられないが、依存の方向はコントロールすることが出来る。それが出来れば、依存先に重大な変更が加わった場合でも、依存している側への影響は最小限で済む。そのために、例えば必ずインターフェースを定義、用意しておくことでコントロールが容易になるなどの例が繰り返し紹介されている。
また、依存方向をコントロールするためには、適切なコンポーネント粒度である必要がある。コンポーネントが密結合すぎると、アーキテクチャの変更等アプリケーションにとって大きな変更が加わった場合に対応できなくなる。コンポーネントの分割粒度や可変/普遍など詳しくは書籍の中で触れられているが、それぞれのコンポーネントがどういう位置づけで、他のコンポーネントとどのように関わるのかは常に意識したい。
個人的には、こういったことを意識することでテスタブルなコードを書けることも嬉しい。
まとめ
本書を読むまで、上記の図すら理解出来なかったがまずはそこをクリア出来てよかった。クリアするためにはその前提である依存方向のコントロールやコンポーネント粒度を理解しておかねばならず、その理解が無かった僕にとっては多くの収穫があった。本の中でも触れられているが、あくまで円の図は一例であるので、実際のアーキテクチャを考えるにあたっては完成はなく常に見直し続けることが大事らしい。そういった考えに至れたり、少しずつ自分の書くコードがまともになっている気がするのはほんの少し進歩したと思う。思いたい。
超速本読書メモ
僕がWebフロントエンドの世界に飛び込んでから数年経った。しかし、恥ずかしながらこれまでアプリケーションのパフォーマンスについてあまり深く考えたことがなかった。僕がWebに飛び込む前から、そして飛び込んだ後もWebページの高速化は日に日にその重要性を増してきており、最低限の知識や考え方を持っていないと成果を出すどころか同僚との議論にすら全くついていけなくなる有様だ。
パフォーマンスの世界への入り口として 超速本 を読了したので自分なりにまとめてみることにした。
基本戦略
とにかく計測から入る
推測するな、計測せよ
は様々な領域で言われていることだが、改めてこの言葉を噛みしめることになった。
考え方としては、
- ボトルネックを探して対応することが成果への近道
- 手段から入るのは間違い
の2つが特に重要そう。
高速化のためのポイント
高速化と言っても、ボトルネックの正体やそれに合わせた対応を考えると様々である。
しかし、主に軽量化(取り扱うデータ量を削減する)や最適化(実行の順番やデータ経路などのチューニング)を意識することになる。
具体的には、下記のようなことを考えることになる。
- ネットワーク処理
- データの転送量をなるべく小さくすること
- データの転送回数をなるべく少なくすること
- データの転送距離をなるべく短くすること
- レンダリング処理
- UIの応答速度
- 100ms以内を目指す
- FPS
- テレビ: 30fps, アニメ・映画: 24fps
- Webでは60fpsを目標とする
- UIの応答速度
- スクリプト処理
計測手段
計測に用いるツールについて
ここまでで、Webのパフォーマンスアップに対する考え方や着目点を知ることが出来たが、重要なのは計測することである。計測手段はいくつかあるので、それぞれ見ていく。
Chrome DevTool
おそらく最も多くのWebフロントエンジニアに馴染み深いツール。DevToolの各タブで出来ることを見ていく。
Networkタブ
個人的には、DevToolの中でも使用頻度が高いタブ。ページ内の関連リソースの通信状況を確認できる。
Yahoo!JAPAN でnetworkタブを開いてみるとこんな感じ。
ページ上部
ページ上部にはページ読み込み完了までのリソース読み込み状態が表示されている。
ここで、青と赤の赤線に注目したい。
- 青い縦線がDOMContentLoadedが完了したタイミング
- 赤い縦線がLoadが完了したタイミング
上記のリソース読み込み状態の下には、Waterfallが表示されている。ここでは、リソースがダウンロードされる順番や、各リソースをダウンロードするのにかかった時間がわかる。それぞれのリソースの詳細も見られる。
Perfomanceタブ
Webサイトのパフォーマンスを計測できる。これまであまり使ったことがなかった。
AbemaTVのもの
-
この値が小さいほど、より速く画面が更新され動くことを示す。
CPU
このグラフが示すのはCPUの負荷の大きさで、色によってそれぞれ意味が異なる。
- 青/Loading: HTTPリクエスト、パース
- 黄/Scripting: JavaScriptでの処理
- 紫/Rendering: スタイル評価、レイアウト算出
- 緑/Painting: ペイント処理、画像のラスタライズ
- 灰色/Other: その他
NET
ネットワーク通信状態を示す。優先度の髙い/低いリソースへのアクセスを表す。
PageSpeed Insights
Googleが提供しているツール。URLを入力することで、そのWebページのPC/SPでの表示速度を計測できる。
久しぶりに自分のWebページに対してチェックをかけてみたら一見良さそうな値が出てきた。一見早く見えるが、単純にコンテンツが無いだけ。
複雑なWebページであればあるほどスコアは落ちてくるが、改善項目をサジェストしてくれるのでその項目を精査、改善するだけでも結構違う。
WebPagetest
合成モニタリングを行うサービス。実際に特定のリージョンからアクセスを実行し、ChromeDeveloperToolsのNetworkタブに相当するデータを取得できる。
こちらに詳しい。
自分のWebページに対して実行してみた結果。有料の合成モニタリングサービスとしては、 SpeedCurve
が有名。
表示速度の指標
上記のツールを用いてパフォーマンスの改善を図る場合に、どのタイミング/段階の数値を改善するのかを追いかける方がより良い改善ができる。表示速度においては、ナビゲーションからのパフォーマンスを示す複数の指標がある。
具体的な指標の数々
- First Paint
- ナビゲーション後に、ページ内の何かが表示され始めたタイミングのこと
- クリティカルレンダリングパスの改善が有効
- First Contentful Paint
- ナビゲーション後に、ページ内のコンテンツが表示され始めたタイミングのこと
- これら2つの指標は、サブリソースのロード状況やクリティカルレンダリングパスの状態などを示す
- パフォーマンスの指標となりうる
- ユーザー体験に直接影響する数値ではない
- Paint Timingで取得可能
- First Meaningful Paint
- ユーザーにとって意味のある表示になったタイミング
- あいまいな指標
- 標準化が難しい
- User Timingを利用して計測もしくは計測ツールでスクリーンキャプチャを撮って画像比較で判定
- Time to Interactive
- ロードが完了し、ユーザー操作に確実に応答できるようになったとき
- RAILモデルのIdleを満たす状態
- SPAのようにJSの初期化やAPIとのやり取りに時間がかかるアプリケーションなどで有効な指標
- こちらも、標準化には至っていない
- Speed Index
- ATF(Above the fold)
- スクロールせずに閲覧可能な画面領域
- ATFでの表示性能を数値化
- ファーストビューにおける描画量のスコア
- ATF(Above the fold)
こういった指標が挙げられ、それぞれに効果的な改善を模索、実行していくことになる。ここで意識しておきたいのは、 最も重要視するべき指標はプロダクトによって変わってくる
ことである。プロダクトでの各指標がどうなっているかを継続的に計測すること、改善するために何が出来るかをチームで議論して実践することが何より大事っぽい。
その他、取り組みたいキーワード
- Resource Hints
- https://www.w3.org/TR/resource-hints/
- link要素を利用したリソースの先読み
- TCPの事前接続/リソースの事前ダウンロードなど…
- 対応ブラウザはまだ多くない
- 通信内容の軽量化
- キャッシュ戦略
- ServiceWorkerを用いたキャッシュ戦略
- 優先度の髙いリソースをキャッシュしたりする
- 画像の圧縮
- メタデータの削除
- 減色、圧縮
- フォントのサブセット化
- Unicodeのコードポイントで分割
- ブラウザが必要なフォントファイルのみロードすることを補助する
まとめ
いろいろ考えることがあって混乱してしまうのが正直なところだが、まずは計測する仕組みする仕組みを整えること、それぞれの指標/フェーズにおいて何が出来るのかを一つずつ明らかにしていくのが良さそう。
計測による可視化がなければ闇雲かつ場当たり的な対策しか出来ず、パフォーマンスを改善したとは言えない。特にWebは多種多様な環境でのアクセスが当然のように起こる世界なので、チーム/プロダクトで協力して様々な環境を用意し、定期的なモニタリングと評価、改善が肝要なのだと知ることが出来た。
参考
セッション認証付きAPIサーバーをnode.js(express)で作る
プライベートプロジェクトのサーバー実装を一新するべく,セッション認証とパスワードハッシュ化を付けたのでメモ.
本当はユーザー情報をDBに持たないと意味が無いけど,ユーザーは僕しか居ないからまあいいやと妥協した.
実際のコード
const express = require('express') const oauth = require('oauth') const http = require('http') const path = require('path') const crypto = require('crypto') // 暗号化 const bodyParser = require('body-parser') const session = require('express-session') const app = express(); app.use(express.static(__dirname)); app.set('port', process.env.PORT || 3000); [f:id:heimusu:20180518115114j:plain] // Cross Originを有効化 app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS'); next(); }); // Optionsも app.options('*', (req, res) => { res.sendStatus(200); }); // urlencodeとjsonの初期化 app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); // セッションの生存時間(分で指定) const maxage = 1; // セッション管理設定 app.use(session({ secret: 'keyboard cat', cookie: { maxAge: maxage * 60000 }})) // セッション管理関数 const sessionCheck = (req, res, next) => { if (req.session.email) { next(); } else { res.status(440).json({message: 'セッション切れです'}) } } const email = 'email@email.com' const password = 'hogehoge' // sha-512で暗号化 const hashed = password => { let hash = crypto.createHmac('sha512', password) hash.update(password) const value = hash.digest('hex') return value; } // ログイン処理 app.post('/login', (req, res, next) => { const reqEmail = req.body.email const reqPass = req.body.password try { if(email === reqEmail && hashed(password) === hashed(reqPass)) { req.session.email = {name: req.body.email}; res.send(200) } else { res.status(401).json({message: 'メールアドレス/パスワードが一致しません'}) } } catch (error){ res.status(500).json({message: 'error'}) } }); app.get('/', (req, res, next) => { sessionCheck(req, res, next) res.sendStatus(200) }) app.listen(3000, function(){ console.log('working'); });
リポジトリ
React.jsのsetStateが遅い問題
散々言われ続けてきたことだが,自分の備忘録として残しておく.
this.stateを参照してDOMを書き換える
失敗する例
例えば下記のような場合
constructor(props) { super(props); this.state = { isOpen: false } } componentDidMount() { this.setState({ isOpen: true }) } click(flg) { alert(flg) } render() { return({ <div onClick={()=>this.click(this.state.isOpen)}> }) }
DOMをクリックした場合に,1回目のクリックではfalse,2回目以降でtrueが表示される. 本当は1回目のクリックでtrueが表示されてほしいが…
成功する例
正しい対処法なのかどうかはさておいて,上記のコードを次のように変更すると良い.
constructor(props) { super(props); this.state = { isOpen: false } } componentDidMount() { this.setState({ isOpen: true }) } click(flg) { alert(flg) } render() { const isOpen = this.state.isOpen return({ <div onClick={()=>this.click(isOpen)}> }) }
render()内でthis.state.isOpenを変数に外出しにして,その変数をDOMに渡す. こうすることで一回目のクリックでもtrueが表示されるはずだ.
私見
業務でReact.jsを扱う中でハマったので試行錯誤した結果この形になったが,原因や良い対処法についてはっきりしていない…
stateの変更タイミングが意図的に制御されているのだと思うが, そもそもreduxを使っていれば心配いらないのかもしれない.
原因やよりよい方法についてご存知であれば是非コメントにて.