カテゴリー: テクノロジー

「アイソモーフィックJavaScript」を読みました

はじめに

タイトルのインパクトで本を選んでしまうことが時々あります。
「バンディットアルゴリズムによる最適化手法」とか。
そんな感じでオライリーの書籍一覧の中に「アイソモーフィック」という耳慣れない言葉を見つけて以来ずっと気になっていた本を読みました。

「アイソモーフィックJavaScript」

アイソモーフィックJavaScriptとは

アイソモーフィックJavaScriptとは、サーバ側とクライアント側で同一のJavaScriptコードでウェブアプリケーションを動かそうという考え方のことです。
本書では、今どきのウェブアプリケーションに求められる以下の3つの条件を同時に満たす手法としてアイソモーフィックJavaScriptが有効であると説きます。

  • SEO対応(検索エンジンによるインデックス化が可能)
  • 最適化され高速に読み込まれる初期ページ
  • ユーザーの操作に対する迅速なレスポンス

ウェブアプリケーションの発展に見るアイソモーフィックJavaScriptの利点

古典的ウェブアプリケーション

  • リクエスト毎にページ全体を読み込む
  • 検索エンジンによるインデックス化: ○
  • 初期ページ読み込みの最適化: ○
  • ユーザー操作への応答性: ☓
    新しいページが前のものとほとんど同じでもページ全体の再読込みが必要

古典的ウェブアプリケーション+Ajax

  • ユーザー操作への応答性向上
    書き換えが必要な部分だけをサーバから取得してクライアント側で再描画
  • コードの保守性、開発の効率性に問題
    サーバ側とクライアント側で同じ処理内容を異なる言語で記述
    処理フローの見通しの悪さ
    など

SPA(Single Page Application)

  • サーバ側とクライアント側との責任分担を明確にして保守性・効率性を向上
  • サーバからクライアントに送信されるのはテンプレート(初回)とデータ
  • 描画はクライアント側
  • 検索エンジンによるインデックス化: △
    同じURLのままページが書き換えられる
  • 初期ページ読み込みの最適化: △
    テンプレートを読み込んだ後、データの読み込みが完了するまで描画できない
  • ユーザー操作への応答性: ○

アイソモーフィックJavaScript

  • 検索エンジンによるインデックス化: ○
    HTML5のHistory APIを活用して状態毎にURLを変化させる
  • 初期ページ読み込みの最適化: ○
    初回だけサーバ側で完全なページ描画、それ以降はクライアント側で書き換え。コードがサーバ・クライアントで同一なので保守の問題が生じない
  • ユーザー操作への応答性: ○
    書き換えが必要な部分だけクライアント側で再描画。場合によってはサーバ側との通信さえも発生させずに済むことも

どうやって実現するか

良いことだらけに見えるアイソモーフィックJavaScriptですが、現時点ではデファクトスタンダートと呼べるフレームワークが存在している訳ではなく、自前でフレームワークにあたる部分を実装する必要があります。(あるいは人柱覚悟でオープンソースのフレームワークを導入する)
本書はフレームワークの実装例を示す第II部がメインになっています。

サーバとクライアントと同じコードを動かすためにはかなり泥臭い仕掛けが必要になります。たとえば以下のような課題を解決しなければなりません。

  • サーバ側とクライアント側とでアプリケーションの内部状態を同期する
  • サーバ側とクライアント側とで統一されたアプリケーションルーティング
  • サーバ側とクライアント側とで異なるファイルパスの隠蔽
  • Cookie の読み書きの抽象化
  • リダイレクトの抽象化
  • JavaScriptが無いクライアント(たとえば検索エンジンのボット)のためのサーバ側での描画

これらをどのように解決しているのかについては是非本書を読んでみて下さい。

実例

第III部は Walmart, GetHuman, Bloomberg, Colony といったサイトでのアイソモーフィックJavaScriptへの取り組みの実例です。同じような問題意識を持った各社の人たちがより良い実装とベストプラクティスを求めて工夫している様子がよく分かります。

こちらを先に読んで、アイソモーフィックJavaScriptで解決しようとしている問題の大枠を頭に入れてから第II部を読んだ方が読み進めやすいかもしれません。

ちょっと残念だったところ

本書ではアイソモーフィックJavaScriptの概念をざっくり説明した後はおもむろにフレームワークの実装に掛かります。Hellow Worldだけを表示する簡単なアプリケーションルーターとテンプレートだけからスタートして徐々に機能を追加・更新しつつ説明を加えるというスタイルです。
コードを入力しつつ読むと実装を追体験できるしボトムアップの説明を好む方には良いと思うのですが、私は通勤中に字面だけでコードを追っかけつつ読んだのでなかなか辛いものがありました。

  • 途中段階ではアイソモーフィックJavaScriptになっていないので、「この節で説明しているこの実装をすると何が嬉しいのか」を見失いがち
  • 同じファイルをちょこちょこ変更しつつ説明が進むが、以前のものとの差分が分かりづらくてどこをどのように変更したのか捉えづらい
  • 利用しているライブラリやAPIの位置付けが説明不足なところがある。
    たとえば、Node.jsやBabelやnumjucksなどインストールから説明しているものも有る中で唐突にHistory APIというものが導入されて少々混乱しました。調べてみたらHTML5に含まれるAPIということでなーんだとなりましたが。

個人的には全体像を最初にばーんと示してからブレイクダウンしていく説明の方が分かりやすかったと思いますが、この辺りは人それぞれでしょう。

まとめ

技術的に枯れるまでにはまだしばらくかかりそうですが、アイソモーフィックJavaScriptという考え方の魅力はとてもよく理解できる本でした。
興味のある方は是非。

Laravel 5.1でQueueを使って困ったこと

 

技術系のメモ書き程度のことですが、メール送信処理や時間のかかる処理等をLaravelのQueueを初めて使って困ったところを書いておきます。

結論を先に書くと
1. listenよりworkを使う
2. ドライバーにdatabaseを使う場合は複数立ち上げない

1. listenよりworkを使う

処理の優先順や別々の機能等があり何個かQueue処理を作ってそれぞれlistenで立ち上げていたのですが、複数立ち上げていくとCPU使用率がどんどん上昇してしまい最終的にはちょっと実用に耐えられないぐらい上がってしまいました。

もともとlistenで立ち上げるとCPUを食うことは知っていましたが、listen1つでここまでCPUを使うとは・・・

こちらはlistenからworkに変更することで問題は解決しました。
全然CPUにかかる負担が違う。

2. ドライバーにdatabaseを使う場合は複数立ち上げない

基本的にはSQS等を使えば問題ないとは思いますが、当面は処理量も少なくまたローカル開発環境で手軽に使える為、ドライバーにdatabaseを使用していました。

特に処理も滞りなさそうに動いていたのですが、複数のqueueを立ち上げているとログに不穏なものが・・・

 

Deadlock found when trying to get lock; try restarting transaction

 

調べてみると、どうやらドライバーにdatabaseを使用して複数立ち上げると発生するっぽい。
とりあえず基本的に量が少ないうちだけdatabaseを使用して、処理量が多くなったらSQS等にドライバーを切り替える予定なので、当面は同じQueueについては1つのみ立ち上げる形で運用しています。

 

以上、LaravelでQueueを使って困ったことでした!

 

あとがき
次のLTS出たのでそろそろバージョンを上げたい。
・・・でもそんな時間がまだ取れないorz
いつになるかわかりませんが、5.1から5.5に上げた時に困ったことを記事に書く予定です。

 

簡単!DockerでPHP環境構築

先日美容院にいったら小学校以来の短さになったノリフミです。

Dockerについてシリーズ物で記事を書こうとおもっていたのですが、まずは元になる記事をかかねば…
ということで、今回は簡単にPHP環境を構築していきます。

目次

今回の妄想


ア○パ○マ○みたいになってしまいました、、、

今回の妄想は、サーバーやローカルなどでDockerを使い、各プロセスを独立して構築し稼働させることです。
これはDockerの思想?理念?である「1コンテナ1プロセス」に乗っ取った構築図になります。「1コンテナ1プロセス」については色々と論争が絶えないようですが、見なかったことにして進めます。

「簡単」が目標のため、Dockerfileを弄って云々はしません!
コマンドのみで公式debian imageを使って進めますので悪しからず。

Dockerでブリッジネットワークを構築

Dockerで独立して構築したコンテナを相互接続できるようにブリッジネットワークを構築していきます。

既にインストール時に、3種類のネットワークが構築されていますが、分かり易いように独自ネットワークを使いたいと思います。

# dockerブリッジネットワーク構築
docker network create -d bridge --subnet 192.168.99.0/16 --gateway 192.168.99.1 example_nw

「example_nw」は構築するブリッジネットワークの名前になります。
任意で設定してください。

作成が終われば、作成したネットワークを確認しておきます。

# ネットワーク詳細確認
docker network inspect example_nw
[
  {
    "Name": "example_nw",
    "Id": "hashhogehoge",
    "Created": "2017-11-06T00:15:36.163888222Z",
    "Scope": "local",
    "Driver": "bridge",
    "EnableIPv6": false,
    "IPAM": {
      "Driver": "default",
      "Options": {},
      "Config": [
        {
          "Subnet": "192.168.99.0/16",
          "Gateway": "192.168.99.1"
        }
      ]
    },
    "Internal": false,
    "Attachable": false,
    "Ingress": false,
    "ConfigFrom": {
      "Network": ""
    },
    "ConfigOnly": false,
    "Containers": {},
    "Options": {},
    "Labels": {}
  }
]

※ ブリッジネットワーク内のコンテナは設定しているコンテナ名やIPアドレスでアクセスすることが可能です。

Dockerでmysqlを動かす

コンテナを再構築時にもデータを保持できるように、mysqlデータ用のディレクトリをホストに作成しておきます。

mkdir ~/example/mysql

Docker imageはDocker Hubより適当に拝借します。

# docker mysql構築
docker run -d --name mysql \
-v ~/example/mysql:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=root_user_pass \
-e MYSQL_DATABASE=example_db \
-e MYSQL_USER=example_user \
-e MYSQL_PASSWORD=example_user_pass \
--net=example_nw \
--ip=192.168.99.100 \
mysql:latest
Unable to find image 'mysql:latest' locally
latest: Pulling from library/mysql
85b1f47fba49: Pull complete
5671503d4f93: Pull complete
3b43b3b913cb: Pull complete
4fbb803665d0: Pull complete
05808866e6f9: Pull complete
1d8c65d48cfa: Pull complete
e189e187b2b5: Pull complete
02d3e6011ee8: Pull complete
d43b32d5ce04: Pull complete
2a809168ab45: Pull complete
Digest: sha256:hashhogehoge
Status: Downloaded newer image for mysql:latest
hashhogehoge

※ 使用するimageがホストにない場合は初期構築に時間を要します。

mysqlデータ永続化確認

# mysql接続
docker exec -it mysql mysql -u example_user -p example_db
Enter password: 
# テーブル生成 
create table example_tb (id int); 
Query OK, 0 rows affected (0.04 sec) exit; 

# docker-mysql再構築 
docker stop mysql && docker rm mysql 
docker run -d --name mysql \ 
-v ~/example/mysql:/var/lib/mysql \ 
-e MYSQL_ROOT_PASSWORD=root_user_pass \ 
-e MYSQL_DATABASE=example_db \ 
-e MYSQL_USER=example_user \ 
-e MYSQL_PASSWORD=example_user_pass \ 
--net=example_nw \ 
--ip=192.168.99.100 \ 
mysql:latest

再度mysqlに接続し、テーブル確認。

docker exec -it mysql mysql -u example_user -p example_db
Enter password: 
show tables; 
+----------------------+
| Tables_in_example_db |
+----------------------+
| example_tb           |
+----------------------+
1 row in set (0.00 sec)  exit;

Dockerでphp-fpmを動かす

nginxもありますが、先にfpmを構築していきます。

プロジェクト用のディレクトリと簡単なindexファイルを作成しておきます。

mkdir ~/example/src
vi ~/example/src/index.php
<?php
// pdoインスタンス生成
$pdo = new PDO('mysql:host=mysql;dbname=example_db;charset=utf8', 'example_user', 'example_user_pass');
// テーブルリスト取得
$result = $pdo->query('SHOW TABLES')->fetch(PDO::FETCH_ASSOC);
// テーブルリスト表示
echo "example_db table list<br>";
foreach ($result as $row) { echo "{$row}<br>"; }

Docker imageはDocker Hubより適当に拝借します。

# docker php-fpm構築
docker run -d --name php-fpm \
-v ~/example/src:/var/www/html \
--net=example_nw \
--ip=192.168.99.111 \
php:fpm
Unable to find image 'php:fpm' locally
fpm: Pulling from library/php
85b1f47fba49: Already exists
d8204bc92725: Pull complete
92fc16bb18e4: Pull complete
9859644f2c58: Pull complete
eed3518188ca: Pull complete
33c8f7623948: Pull complete
3211acc287de: Pull complete
83bc6e66e57e: Pull complete
c15398ec94ed: Pull complete
Digest: sha256:hashhogehoge
Status: Downloaded newer image for php:fpm
hashhogehoge

※ 使用するimageがホストにない場合は初期構築に時間を要します。

公式imageにデフォルトでmysqlと連携可能なimageが見つからなかったため、手動でインストールしておきます。

# pdo pdo_mysqlインストール、再起動
docker exec php-fpm docker-php-ext-install pdo pdo_mysql
docker restart php-fpm

Dockerでnginxを動かす

nginxの設定ファイルを作成しておきます。

# 設定ファイル用ディレクトリ生成
mkdir ~/example/conf
# nginx設定ファイルを生成
# ドメインは適宜設定しなおしてください
vi ~/example/conf/nginx.conf
server {
 listen 80;
 root /var/www/html;
 server_name example.com;
 index index.php;
 location / {
  try_files $uri $uri/ /index.php?$query_string;
 }
 location ~ \.php$ {
  fastcgi_pass php-fpm:9000;
  fastcgi_index index.php;
  fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
  fastcgi_read_timeout 300;
  include fastcgi_params;
 }
 sendfile off;
}

今回はホストの80ポートをポートフォワードさせて、ホストに飛んできたアクセスをdocker nginxに向くように構築します。

# docker nginx構築コマンド
docker run -d --name nginx \
-p 80:80 \
-v ~/example/src:/var/www/html \
-v ~/example/conf/nginx.conf:/etc/nginx/conf.d/example.conf \
--net=example_nw \
--ip=192.168.99.110 \
nginx:stable
Unable to find image 'nginx:stable' locally
stable: Pulling from library/nginx
bc95e04b23c0: Pull complete
f473e7d72364: Pull complete
82cca2490d0d: Pull complete
Digest: hashhogehoge
Status: Downloaded newer image for nginx:stable
hashhogehoge

接続確認

設定したドメインにアクセス可能か、mysql接続が問題ないかを確認します。

ブラウザからアクセス確認した画像
成功!

まとめ

1コンテナ1プロセス…
ローカルmysqlをrdsに変更する場合など、参照先を変更して対象コンテナを削除するだけで、なかったことになるので便利は便利です。

ただ、公開サービスで「リソース監視したい!」と思うだけで
→ munin導入する…?
 → 1コンテナ複数プロセスになる…
  → 実行管理がデフォルトで出来ない…?
   → …etcetc
壁がすごい…

マイクロサービスの運用などには非常に有用ですが、適切に管理するためにはそれなりに知識が必要です。
また機会があればdockerfileやcompose、複数プロセス対応など記事にしたいと思います。

それでは。
 

Go言語をさわってみた

にゃんこスターから目が離せないマエダです。
 
全然にゃんこスターと関係ないんですけど、重い腰をあげてGo言語をさわってみました。
https://golang.org/
 

 
Macでは
brew install go
※ brew updateをするといいかも。
 
まずはHello Worldですよね。
 
vi hello.go
 

go build hello.go
./hello
 

Hello World!!

 
 
はい。
 
 
そう。
 
 
ほんとにさわってみただけです。
 
 
シンプルなシンタックスでとっつきやすいのにGoルーチンを利用してかんたんに並列プログラミングできちゃうそうです。
 
go f()
 
Go使えるようになるとモテそうなので頑張りたいと思います。爆

そろそろVisual Studio Codeに乗り換えたい

使い慣れたエディタを変えるには(個人的に)かなり決心が必要なのですが、この度、話題のMicrosoft製Visual Studio Code(以下VS Code)をお迎えしました。

Visual Studio Code – Wikipedia

https://ja.wikipedia.org/wiki/Visual_Studio_Code

Visual Studio Code はソースコードエディタである。マイクロソフトにより開発され、Windows, Linux, macOS 上で動作する[5]。デバッグ、Gitクライアントの統合、シンタックスハイライト、インテリセンス、スニペット、リファクタリングなどの機能を持つ。カスタマイズもでき、利用者はエディタのテーマやキーボードショートカット等を変更できる

実際に使いだしてみたら想像以上に便利だったので、今更感はありますが個人的にVS Codeの良かったと思う点を書いてみようと思います。

因みに主に想定する言語はPHPです。

Visual Studioっぽい


当然ですが、名前にVisual Studioと付いているだけあってVisual Studioに似たアトモスフィアを放っています。
Visual Studioを使ったことがあれば割と抵抗なく導入できるような気がしました。
個人的には大事なポイントです。

検索がつよい


Ctrl+Pを押したときに「ファイルを検索して開く」ボックスが開くのですが、他にも色々なことができます。
最初に”#”を入力すると「ワークスペース内のシンボルを検索して移動」、”>”を入力するとVS Codeの「コマンドの検索と実行」になります。
“?”で機能の一覧が表示されるので「なんだっけ?」ってこともありません。
それぞれの検索機能は別途専用のショートカットで開くこともできます。

IntelliSenseが使える


イマドキっぽい。
定義の参照は、参照箇所が別ファイルでも問題なく認識・動作してくれます。
ただ、Pluginで導入できるPHP IntelliSenseはphp-language-serverを利用しているため、PHP7を参照できるようにしないと動作しません。

Emmetが使える


イマドキっぽい。
デフォルトで入ってます。

Xdebug使える

イマドキっぽい。

印象まとめ

とにかく検索が便利。
エディタ自体も多機能かつ使いやすいです。
まだまだ進化途中(のはず)なので、謎の仕様や不思議なことが起きたりもしますが、しばらくはVS Codeのお世話になっていこうと思います。