Webサイトのパフォーマンス改善

社内の勉強会でHTTP/2とかパフォーマンスについて話したのでまとめた。

見た情報

www.amazon.co.jp

HTTPの仕組みからパフォーマンス改善の取り組みまで詳細に説明している。基本的にはこの本を一冊読めばそれで十分なんじゃないかと思った。

英語版はWebで見れる。High Performance Browser Networking

designingforperformance.com

Lara Callender Hoganさんのサイト。なぜパフォーマンスを改善しないといけないかについて調査結果がまとまっている。

パフォーマンスを測定できるサイト

PageSpeed Insights

PageSpeed Insights コンテンツを解析し、どこを改善すべきか教えてくれる。

www.webpagetest.org

DNSルックアップやTCPの3ウェイハンドシェイクなど、どこでどれぐらい時間が掛かっているかを可視化してくれる。 TCPのコネクション単位での表示もしてくれるので、それでボトルネックがわかることもあると思う。

Magit入れたEmacsでgit rebase -iしたら便利だった

masterから生やしたトピックブランチで下のコマンドを打ち込むとブランチの分岐点からのコミットを対象にしたrebase -iを実行できる。

git rebase -i --keep-empty --autosquash $(git show-branch --merge-base master HEAD)

f:id:saito400:20151212201602p:plain

squashしたい行の先頭でfを入力するとfixupに書き換えてくれる。

f:id:saito400:20151212201606p:plain

同僚5人ぐらいに説明したけど誰も共感してくれなかった。

Emacsにyasnippet入れた

設定

設定ファイルに以下を追加。

(unless (package-installed-p 'yasnippet)
  (package-refresh-contents) (package-install 'yasnippet))

(add-to-list 'load-path "~/.emacs.d/yasnippet")
(require 'yasnippet)
(yas-global-mode 1)

AndreaCrotti/yasnippet-snippets · GitHub

上記から必要なsnippetをダウンロードし、~/.emacs.d/yasnippet以下に保存。

これでyasnippetが有効になる。

今回はscala-modeだけを入れてみた。

使い方

scala-modeが有効になっている時にsnipetで設定されているキーワードを入力し、TABキーを押すと残りの部分が補完される。

バッファでfor と入力しTABキーを押す

補完の選択肢がミニバッファに表示される

f:id:saito400:20150815084831p:plain

選択するとバッファに挿入される

f:id:saito400:20150815084908p:plain

FluxxorとReact RouterでFluxのサンプル作った

作ったプロジェクト

github.com

構成

Fluxxor

React Router

React.js

Scala

Play 2.4

Slick 3.0

Fluxとは

Fluxとはアーキテクチャの名前。React.jsはFluxアーキテクチャのViewの実装にあたる。

以下geta6さんのスライドがわかりやすかった。各コンポーネントの説明もされている。

facebookによるfluxの説明。

facebook.github.io

Fluxxor版の全体像。

http://fluxxor.com/images/flux-simple.png

今回は上記に加えてReact Routerを使った。

ルーターの設定

https://github.com/saito400/play2.4-flux-demo/blob/master/app/views/routes.jsx

var React = require("react"),
    Router = require("react-router"),
    Route = Router.Route,
    DefaultRoute = Router.DefaultRoute;

var Navi = require("./common/components/navi_view.jsx"),
    TodoType = require("./todo/components/todo_type.jsx"),
    Todo = require("./todo/components/todo.jsx");

var routes = (
  <Route handler={Navi} name="home" path="/">
    <Route handler={Todo} name="todo" path="/todo" />
    <Route handler={TodoType} name="todo-type" path="/todo-type" />
  </Route>
);

module.exports = routes;

ビルド

JSXファイルはそのままブラウザで実行できない為、JavaScriptに変換する必要がある。

React.jsのブログでアナウンスされている通り、react-tools と JSTransformが廃止され、今後はJSXはBabelでコンパイルする形になる。なので今回はBabelを利用した。

またCommonJS方式のモジュール管理の解決の為、Browserifyを利用し、タスクランナーにgulpを使った。

facebook.github.io

https://github.com/saito400/play2.4-flux-demo/blob/master/gulpfile.js

var browserify = require('browserify');
var babelify = require('babelify');
var gulp = require('gulp');
var source = require('vinyl-source-stream');
var buffer     = require('vinyl-buffer');
var sourcemaps = require('gulp-sourcemaps');
//var uglify = require('gulp-uglify') // comment out for now because it takes too much time
var watchify   = require('watchify');
var handleErrors = require('./handleErrors');

gulp.task('build', function() {
    return watchify(browserify({ entries: './app/views/app.jsx', debug: true }, watchify.args))
        .transform(babelify)
        .bundle()
        .on('error', handleErrors)
        .pipe(source('bundle.js'))
          .pipe(buffer())
          .pipe(sourcemaps.init({ loadMaps: true  }))
//          .pipe(uglify())
          .pipe(sourcemaps.write('./'))
        .pipe(gulp.dest('./public/javascripts/'));
});

gulp.task('watch', function(){
  gulp.watch('./app/**/*.jsx', ['build']);
});

https://github.com/saito400/play2.4-flux-demo/blob/master/package.json

{
  "name": "play2.4demo",
  "version": "1.0.0",
  "description": "Demo application of play 2.4 and slick 3",
  "main": "index.js",
  "directories": {
    "test": "test"
  },
  "scripts": {
    "build": "$(npm bin)/browserify --debug app/views/app.jsx -t babelify -o public/javascripts/bundle.js",
    "watch": "gulp watch"
  },
  "author": "",
  "license": "",
  "devDependencies": {
    "babelify": "^6.1.2",
    "browserify": "^10.2.4",
    "fluxxor": "^1.6.0",
    "gulp": "^3.9.0",
    "gulp-notify": "^2.2.0",
    "gulp-sourcemaps": "^1.5.2",
    "gulp-uglify": "^1.2.0",
    "gulp-util": "^3.0.6",
    "lodash": "^3.10.0",
    "react": "^0.13.3",
    "react-router": "^0.13.3",
    "tcomb-form": "^0.4.8",
    "vinyl-buffer": "^1.0.0",
    "vinyl-source-stream": "^1.1.0",
    "watchify": "^3.2.3"
  }
}

開発中は rpm run watch を実行し、jsxファイルに変更があったら自動でコンパイルされるようにした。

BabelがES6のトランスパイラなので、ついでにES6のアロー関数を使った。

ES6のアロー関数

mapはこんな感じで書ける。

var options = this.state.todoTypes.map(x => <option value={x.id}>{x.title}</option>);

filterはこんな感じ

this.todoTypes = this.todoTypes.filter(x => x.id != id);

感想

コードの記述量は結構多い。ただ以下twadaさんのツイートにあるように、複雑な設計でも対応できるように感じた。

あと以下naoyaさんのスライドにある通り、記述量は多くなるけどブラックボックス化しにくいと思うので保守は比較的楽だと思う。

TODO

サーバサイド

Play 2.4とSlick 3.0を使った。

あとで何か書く。

Testing

後で調べる。

validation

以下のようにするのが良いらしいだけどまだ試してない。後で試す。

qiita.com

間違ってる所とかあったら教えてください。

Emacsの設定 2015年5月版

設定ファイル全体は以下

github.com

インストールしている主なパッケージ

helm

helm-miniは以下の通り設定した。これでhelm-miniのリストに現在のバッファ、最近開いたファイル、カレントディレクトリのファイル、gitの同一リポジトリのファイルが表示される。

;; helm-mini
(progn
  (require 'helm-ls-git)
  (custom-set-variables
   '(helm-truncate-lines t)
   '(helm-delete-minibuffer-contents-from-point t)
   '(helm-mini-default-sources '(helm-source-buffers-list
                                 helm-source-recentf
                                 helm-source-files-in-current-dir
                                 helm-source-ls-git
                                 ))))

helm-ls-git

↑のhelm-miniのリストにgitのファイルを表示する為にインストールした。Emacs起動後に一度手動で起動しないとhelm-miniのリストに出てこない気がするけど今の所大きな問題ではないのでそのままにしてる。

Ensime

Scala用。補完や定義へのジャンプなどができるようになる。

web-mode

htmlとかjavascript書く時に利用。

auto-complete

補完用。便利。

ScalaからElasticsearchにアクセスするサンプル

VagrantVM上にElasticsearch環境を構築し、そこに対してScalaでアクセスするサンプルを作った。

作ったファイル

github.com

環境

Vagrant 1.7.2

VirtualBox 4.3.26

Mac OSX yosemite 10.10.3

環境構築

Elasticsearchは以下のリポジトリ内のelasticsearchを使った。設定済みなので楽

github.com

vagrant upしたら/sbin/mount.vboxsf: mounting failed with the error: No such deviceというエラーが出たので以下の対応を実施

ホスト側 $ vagrant plugin install vagrant-vbguest

ゲスト側 $ sudo yum -y install kernel kernel-devel

ホスト側 $ vagrant reload

これでlocalhost:9200でElasticsearchにアクセスできる。

Elasticsearchにインデックスとドキュメントタイプを作成

インデックスとドキュメントタイプを作成しドキュメントを登録

curl -XPOST 'http://localhost:9200/twitter/tweet/' -d '{ "user" : "John Doe", "message" : "trying out Elasticsearch" }'

インデックスを確認

curl 'localhost:9200/_cat/indices?v'

検索

curl -XGET 'localhost:9200/_search'

Scala側の実装

ScalaでElasticsearchにアクセスする部分は以下のライブラリを使った。

github.com

READMEが詳細なので説明は割愛。

Emacs+EnsimeでScala開発環境を作った

動機

最初はIntelliJを使ってましたが、以下の理由でEmacs+Ensimeを使いはじめました。

IntelliJが重く感じた

・マウスを使いたくなかった

環境

・Mac OSX Yosemite

Emacs 24.5

構築

Scala+sbt

brew install scala

brew install sbt

Emacs

brew install emacs

scala-mode2+Ensime

~/.emacs/init.elに以下の記述を追加しEmacsを再起動

(require 'package)
(add-to-list 'package-archives '("melpa" . "http://melpa.milkbox.net/packages/") t)
(add-to-list 'package-archives '("marmalade" . "http://marmalade-repo.org/packages/"))
(package-initialize)

(unless (package-installed-p 'scala-mode2)
(package-refresh-contents) (package-install 'scala-mode2))
(unless (package-installed-p 'ensime)
(package-refresh-contents) (package-install 'ensime))


(setenv "PATH" (concat "PATH_TO_SBT:" (getenv "PATH")))
(setenv "PATH" (concat "PATH_TO_SCALA:" (getenv "PATH")))


(require 'scala-mode2)
(require 'ensime)
(add-hook 'scala-mode-hook 'ensime-scala-mode-hook)

sbt pluginの設定

~/.sbt/0.13/plugins/plugins.sbtに以下を追加

resolvers += Resolver.sonatypeRepo("snapshots")

addSbtPlugin("org.ensime" % "ensime-sbt" % "0.1.5")

// project/plugins.sbt
dependencyOverrides += "org.scala-sbt" % "sbt" % "0.13.8"

プロジェクト毎のEnsime用設定ファイル生成

プロジェクトのディレクトリに移動し以下コマンドを実行

sbt gen-ensime

Ensimeを起動

Emacs起動後に以下を実行

M-x ensime

Emacs+Ensimeの感想

・キーボードだけで大体コーディングできるから楽

デバッグIntelliJの方がかなり高機能

・補完もIntelliJのが良いと思うけどあんま気にならない

・作ってるのが小さいシステムなので今の所問題無いが、大規模になったらどうなるか不明

参照したページ

github.com

github.com