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

Webブラウザの呼び声(自動音声)

Web Speech APIを使うことでWebブラウザを喋らせることができます。
ブラウザを利用したWebアプリケーションであれば簡単にユーザーに通知する手段を増やすことが可能です。

例えば、

  • Webサイト上に書かれたテキストを読んでもらう。
  • 特定の座標に到着したことを知らせる。
  • 音声認識機能も併用してGoogle Homeの再発明。

などなど、組み合わせ次第でいろいろ遊べそうです。
 
自動音声ですが全くの機械声という訳でもなく、割と自然な感じに読み上げてくれます。
環境依存とはいえ、これがブラウザさえあればいつでも利用できるなんて素晴らしい。
 
さっそく時報でもやってもらおうと思います。
 
環境
Android 7.1.1
Chrome 63

上のコードをブラウザで表示したスクリーンショットがこちら

 
startを押すと、時刻を5秒ごとに喋ってくれます。
音量調整しかありませんが、音程や速度の調整もできます。
 
注意しなければいけないのは、speechSynthesis.speak を呼んだ回数だけ読み上げてくれるところ。(どんどんスタックする)
連続で呼び出すような処理が入ってしまうと延々同じ文章を読み上げられ軽くホラーな体験になります。
 
また、例にもあげましたが、Web Speech APIの主要機能の一つに音声認識があります。
それも組み合わせてとてもとても頑張ればAIブログ、AI進捗管理システムも作れるかもしれません。
 
APIのより詳細な情報はこちら。
Web Speech API – Web API インターフェイス | MDN
https://developer.mozilla.org/ja/docs/Web/API/Web_Speech_API

 
ちなみにですが、時報自体は別の方法でも実装可能です。
Web Speech APIは調整できる幅が狭いのですが、必要なものは揃っていて細かいことを考えなくても形になるという点で非常にお手軽です。
 
まだドラフトなのが残念ですが、実用性の高い機能だと思うので今後の更なる発展と可及的速やかな本採用をお祈り申し上げます。


Cordovaを使ってみました!

こんにちは。開発担当のマットです。

最近、AndroidとiOSのアプリ開発をしています。
作っているアプリがiOS端末(iPhoneやiPad)とAndroidのネイティブ機能を使うので、iOS版とAndroid版を別々に作成しました。

もちろん、アプリを2つのプラットフォームで作ることは手間が掛かりますが、iOSとAndroidの力を完全に引き出すには必要です。

しかし、単純でウェブサイトのようなアプリケーションを作ろうと思ったら、二つのネイティブなアプリを作るより、簡単な方法が沢山あります。私はその簡単な方法を一つ試してみましたので、ご紹介したいと思います。

開発環境

この記事にて、iOSとAndroidのアプリをビルドします。

・iOSのアプリをビルドするには、XcodeがインストールされているMacが必要です。
・Androidのアプリをビルドするには、Android Studioをインストールする必要があります。Android StudioはWindows、Mac、Linux、全てにインストールすることができます。

Cordova

Wikipediaによりますと、Cordovaは「オープンソース(Apache 2.0 License)のモバイルアプリケーション開発フレームワーク。」

Cordovaの特徴ですが、

モバイルデバイスのカメラ、GPS、加速度センサーなどにアクセスするためのAPIを追加することにより、JavaScript、HTML、CSSといったウェブアプリケーション開発の技術でモバイルアプリケーションを開発することができるのが特徴である。

簡単に言いますと、ウェブサイトのようなものをHTML、Javascript、CSSで作れば、Cordovaはそのウェブサイトをモバイルアプリケーションに変換してくれる。
なお、Javascriptで特別のファンクションを呼び出すと、ネイティブアプリケーションのネイティブ機能(カメラ、GPS、加速度センサー、など)を利用することができます。

 

使ってみよう

まずは、Cordovaをダウンロードしました。
詳細は https://cordova.apache.org/ でも書いてありますが、コマンド実行でインストールします。

なお、Cordova自体をインストールする前に、node.jsをインストールする必要があります。まだインストールされていない場合、https://nodejs.org/ja/からダウンロードして、インストールしてください。


では、コマンドプロンプトから以下のコマンドを実行してください。
npm install -g cordova

インストールが完了されたら、Cordovaのアプリケーションを作成するコマンドを実行しましょう。例として「MyCordovaApp」というアプリケーションを作成する。
なお、アプリケーションの bundle ID (アプリを特定するID)もこの時点で設定しましょう〜。
cordova create MyCordovaApp com.example.myCordovaApp MyCordovaApp
                                  (ディレクトリー名 Bundle ID アプリ名

次は、作ったディレクトリーに移動する(MyCordovaApp)。
今回、iOS版、Android版、ブラウザー版を作ってみます。
cordova platform add browser
cordova platform add ios
cordova platform add android

なお、以下のコマンドを実行すると、対応されているプラットフォームの一覧が表示されます。今回の記事の範囲外となりますが、BlackberryやOSXやWindowsのアプリも作れるようです。
cordova platform

ところで、Cordovaの準備ができました。
さて、簡単に何かを作ってしまおう。

初めてのCordova

アプリケーションディレクトリーの中にwww/index.htmlというファイルがあります。
これがアプリケーションの最初に表示されるページとなります。
空白のページではなく、既に内容が入っています。ちょっと変更してみましょう!

bodyの部分に以下のHTMLが入っている。

以下に変更してみました。

なお、非ASCII文字も入れちゃっているので、headに以下のmetaタグも追加しました。

<meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″ />

そして、ファイルを保存!

各プラットフォームにビルド!

コマンドプロンプトに戻って、以下のコマンドを実行すると、追加されているプラットフォームのファイルが更新されます。
cordova build

XCodeでMyCordovaApp/platforms/ios/を開くとiOSアプリケーションをビルドできます。
Android Studios で MyCordovaApp/platforms/android/を開くとAndroidのアプリケーションをビルドすることができます。
なお、cordova run browser だけでウェブページを確認することができます。

今回、作ってみたものをスクリーンショットで撮ってみました。

まとめ

Cordovaで簡単に多くのプラットフォームに対応できることはとても便利だと思います。
特に、HTML,CSS,Javascriptに経験が深いウェブ系の開発者の場合、Cordovaの利用により、複数のプラットフォームに対応しているアプリを迅速に開発できると思います。

しかし・・・
個人的意見にすぎませんが、Cordovaやこのようなマルチプラットフォームサービスは、開発オプションの中間に位置していると思います。

完全にウェブサイトのようなモバイルアプリを作成したい場合、iOSやAndroidが提供するWebViewを利用する方がいいかもしれません。
その反面、多くのネイティブ機能を使いたい場合、手間は掛かりますが、ネイティブのアプリケーションを作ると、そのプラットフォームにより適している製品を作れると思います。

でも、「あまり手間を掛けずに、ウェブサイトに近くて、カメラやGPSのようなネイティブ機能を利用するが、依存しない複数のプラットフォームに対応したアプリケーション」を作りたいと思う場合は、ぜひ使ってみてください。


「アイソモーフィック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、複数プロセス対応など記事にしたいと思います。

それでは。