Google先生が考えているモバイル体験2017(Web/ネイティブ)

Googleは「モバイルWebの読み込み負荷の問題」や「ネイティブアプリのユーザー体験の冗長さ」を解消するために、昨今いろんな施策を出している。
今年に入ってからもいろいろな実装をリリース/プレビューとして入れ込んできていて、今現在の状況が追いかけづらいので何が何なのか一旦整理しようと思う。

  • AMP (Accelerated Mobile Pages)
  • PWA (Progressive Web App)
  • WebAPK
  • Instant Apps

今回取り上げるのは以上の4つである。


AMP (Accelerated Mobile Pages)

AMPは、WebサイトをGoogleのキャッシュサーバーから配信することで高速な表示を目指そう、という技術の総称である。すでに日本でも実装済み。

たまにモバイル検索結果で出てくるこの⚡マークが目印。

 
 

 
 
基本的には記事メディアでの用途になる。現行ですでに実装されており、対応サイトも多い。

Pros

高速

これに尽きる。Googleがキャッシュしているのでムッチャ速い。
データ転送量が従来の1/10にもなるという。

あくまでGoogle検索上での実装なので、もちろんiOS/Android問わずその恩恵に預かることができる。

Cons

基本的には開発コスト/広告周りがデメリットとしてよく挙げられる。
AMPに対応したHTMLファイルを別途別ページとして用意する手間はがっつりかかってしまい、それなりの構造化作業を必要とする。

タグ制限/独自タグへの置き換え

script , frame,input , labelなど禁止されているタグもいっぱいある。
このへんはChromeでデバッグが可能。
MediaElements系は<amp-image />, <amp-video />などの独自タグに置き換えなければいけないなど、制限が多い。
ソーシャル連携のための<amp-twitter /> などもあって、対応には独自の知識が何かと必要になりそう。

AMP JS以外のスクリプトの制限

jsによる実行ブロックを防ぎ、ページの高速化を図るために amp HTMLでは規定のjavascriptファイル以外の実行を許されていない。
当ブログもAMPのプラグイン入れたけど、コードブロックの表示にhighlight.jsを使っているため、特にその辺はまともに動いていないので、この辺はがっつりCSSで描画をなおす必要がありそう。

広告

js/iframeなどの実行が許されていないので、当然既存の広告プラグインもそのままでは動作しない。
このへんはGoogleが <amp-ad /> などの専用タグを使った施策を紹介している。

 
 
 


PWA (Progressive Web App)


Webアプリ(サイト)をネイティブアプリみたいに使おうぜ、というGoogle先生の施策の一つである。
プログラムやデータをバックグラウンドプロセス上でキャッシュすることで、ページの高速化やオフラインでの動作が可能になる。
また付随技術としてWebアプリでもPush通知が使えるようになる。

ここにサンプルになりそうなサイトが溜まっている。
 
PWA Rocks
 
特にAndroidだと、対応サイトは「ホーム画面に追加」してネイティブアプリの感覚で扱うことができる。

Pros

ServiceWorker/ ホーム画面アプリモードによるスタンドアローン

W3Cで策定されている、ServiceWorker API というWebページとは別に実行されるスクリプトを使う。バックグラウンドプロセスみたいなものかな?
(WebWorkerは別スレッドみたいなもんだから間違えないように。)

Android Chromeの場合、サイトのルートに規定のjsonファイルを置けば、GoogleがPWA対応アプリとして認識し、ホーム画面への登録を促すToastを出してくれる。
タップすると、すぐにホームにアイコンが追加されるはず。

Push通知

Push API(WebPush)も基本このServiceWorkerのプロセス上に乗っているはずなので、PUSH通知ができる。
対応サイトでは、通知の認可を求めてくるようになる。
使える場面は結構多いはず。

Cons

iOSとかいうやつ

iOS Safariは ServiceWorker/WebPushなどのAPIが2017.1 現在非対応である。
要するにオフラインでの プログラム/APIからのデータのキャッシュや PUSH通知機能を使うことができない。

iOSは現状でもホーム画面アプリモードとしてWebアプリを登録自体は可能である。(Safariが立ち上がらず、ヘッダーとか隠せるようになるやつ。)
できないこともないが、もちろんオフラインで操作することはできない。 (あるいはAppCacheなどで頑張る)
 
URL遷移をやろうと思ったら、普通に遷移するとネイティブのSafariが立ち上がってしまうので、シングルページアプリケーション的なルーティングが必要になってくる。  
また、Webアプリの実行状態から抜けるたびにレンダリングやルーティングの状態がリセットされるので、状態を再度復元しておこうと思ったら、
localStorageなどを駆使して、がっつりアプリケーションの状態を保存するアーキテクチャを用意しないといけない。
ネイティブアプリ/SPA的な知識がかなり要求されてくる。
 
 
個人的には面白そうな分野なのでiOS SafariにはぜひServiceWorker,WebPUSH等の技術に対応してもらいたい。
だけど、Appleが考える(Appleが胴元の)ユーザーエクスペリエンスのあり方と微妙に違う気もするので、ホーム画面アプリとしてのPWAには及び腰になりそうな感じもする。

バックグラウンド動作でのバッテリー消費とかメモリ食いとか

PCのChromeアプリが裏で連れてくる、元気に跳ね回るプロセスのみなさんを彷彿とさせて若干不安になる。
Facebookアプリのバッテリー消費プロセスと同様のことがWebサイト開発者側の実装次第で起きるとしたら、携帯端末の状態が結構カオスになりそうな気もする。
このへんは技術要件をがっつり調べたわけではないので、確認しておきたい。
 
 
 


WebAPK(Android)


ここから先はAndroid独自の話となる。

WebAPK というのは先日実装が開始された機能である。   
Google、Android用ChromeにWEBサイトをアプリとして利用可能にする「WebAPK」を実装開始 -ガジェット通信-
 
 
これによると、先のPWAをパッケージングして、ネイティブアプリと同じようなchromium上で動作させる仕組みらしい。要するにWebView上のアプリである。
WebサイトをAndroidアプリのパッケージ形式であるAPKに変換して端末にインストールさせる。  
具体的にPWAのホーム画面登録時とユーザー体験としてどのように違うのかは、資料が足りないのでよくわかっていない。  

(規定のWebView上で動作させるようになるとすれば、Webアプリケーション側から専用のAPIとか叩けるようになったりするのかな?)
ただ、この方式のアプリの配布はどうやらGooglePlay側からできるようになるそうで、そこは面白いかな、と思う。 
(WebAPKの配布は既にGooglePlay側で機能しているそうである。QRコードからもインストールできるようになるとか。)
 
 
 


Instant Apps (Android)

Chrome Nightly Buildから実験的に実装が始まった機能。
これに関してはHTML5のWebアプリを動かそう!という文脈ではなく、コンパイル済みのAndroidのネイティブアプリをChrome上で一時的に呼び出して動作させようという施策のようである。

公式の先のVideoや、下のgifを見ると使用感がわかりやすい。
 
 
公式
事前のインストールなしでアプリを実行できる「Android Instant Apps」の実地試験が開始される -Gigazine
Android Instant Apps starts initial live testing
 
 

 
 

既存のAndroidネイティブのコードがそのまま利用可能で、Android4.2から対応できるようになるそうだ。(やめろ)
呼び出しの重さや対応できるAPIが気になるところ。SDKが提供されたら触ってみたい。
 
 
 


まとめ

AMPのようなGoogle独自の高速化施策を打つ一方、Webアプリとネイティブの垣根を取り払っていくようなアプローチが続々出てきて、大変だと思いつつものによっては面白いこともできそう。
全部の実装が果たして軌道に乗るのか、どれに乗っかるべきなのかは注視していきたい。

Read More

DynamoDB使ったり調べたまとめ (2017Early)

書くこと

サ〜バ〜レスな構成にお安く気軽なデータストアが欲しかったのでちょっと調べた。
世間的にはDynamoDBを割と併用してるっぽいので。


1.小規模用途で安いデータストアが欲しいだけ

初期コスト以外の要素をあまり気にしない方向で考える場合。

基本

  • 最小は1読みキャパ/1書きキャパで約0.6$ / 月
  • でもアカウントごとに無料枠は25ユニット無料
  • この確保量が月額かかるので別に使用量従属課金というわけでは全然ない

読み込み

Get

  • まあKVSなので、基本はユニークなHashKeyのみでアクセスできるようにする
  • プライマリキーはHashKey(順不同),かHashKey + RangeKey(範囲指定、Sort可)から成る
  • ユーザーごとに独立してるデータとか。
  • indexは グローバルセカンダリインデックスと HashKeyに従属するローカルセカンダリインデックスがある。
  • 安く済ませたいならグローバルセカンダリインデックス(ユニークキーを含まないindex)は諦めろ

Scan、Query

  • 小規模ってわかってるなら理性捨ててScan(index全件取得)するのもあり
  • 読み込み時に強い読み込み整合性モードを使えば、直前の書き込み全て反映されたレコードとして取得できる、(ただしRCU消費2倍)
  • 範囲指定やソートができるのはRange Keyのみ。
  • 基本検索はそこまで強くないと思っておく

書き込み

  • 普通に update column += 1 とか使える (これと先の”強い整合性”があるだけでもS3にJSON突っ込んでデータストア代わりにするのと話は違ってそれなりに意味はある気がする。)
  • 条件付きアップデートも可能
  • レコード間でのトランザクションはもちろん保証されない
  • 特に複数テーブル書き込みに関してはオレオレトランザクション化要るので基本諦めろ

2.大規模用途での可用性や整合性の担保についてメモ

読み込み

Get

  • 基本はこっちでもユニークなキーのみでのget,シンプルなKVSとしての利用にすることを心がける
  • HASH KEY(の頭文字)は散らす。データサイズがでかくなるとHASH KEYをもとに自動でパーティションが切られるから。
  • グローバルセカンダリインデックス多用しそう。この場合インデックスごとにキャパシティユニット設定する。
  • データサイズは小さくしよう。

Scan , Queryについて

重要

  • Scanはセカンダリインデックス全件取得、QueryはRangeKeyやIndexの内容に従って走査する
  • 1度のレコード取得クエリに対してデータが1MB上限あるので、テーブルがでかくなると一度にScanできない可能性はある
  • LIMITやフィルタ機能はRCU消費を何ら抑えることはできない,あくまでSQLのWHERE文的にクエリ書きやすくなるだけっぽい
  • Queryはともかく特に大規模用途だとScanは使わないに越したことがない。

クエリキャッシュ

  • 同じテーブルが参照されまくるとRCU消費するのでElastiCacheとか前に置いてるケースを散見。結局そうなるんか。

書き込み

DynamoDB ベストプラクティス 参考にした
DynamoDBでのポイントまとめ

複数テーブル同時更新

  • テーブル分割時、複数テーブル書き込み必要な時は自前でACID整備することとなる。NoSQL…
  • 更新依頼書テーブル的な実装/タスクキュー的な実装の上でupdateという形をとる(辛そう)
  • スループット確保のためどうしてもテーブル分けたり非正規化しなければ場面も出てくるので、全く触れなくて済むというわけでもないかも????
  • DynamoDB Stream も使えるそう。

同じレコード(というよりテーブル)に対する大量のupdate

  • 同じレコードに同時に大量にincrement指定がくるような場合、そのパーティションのスループットが非常に下がる。
  • ここでも更新リクエストをタスクキュー的に実装しておいて、読み込み時にそれらをSUMするか、1つのレコードにまとめる実装をする必要がある。

感想

  • 単なるKVS以上の何かを求め始めた場合、結構留意することありそう。(うまい話はない)
  • トランザクションって素敵だね…
  • 他のNoSQLとしてAWS SimpleDBってのもあったけど死んでしまったの?
  • GCP周りのサービスも調べたい

Read More

TypeScriptのテストをパッと書く / 特に何も入れずにスクレイプのテストをパッと書く

TypeScriptのテストをパッと書く

typescriptのユニットテストしたいんじゃー的な時。余計なビルド結果を出力したくないのでプリプロセッサ機能必須。
ts-jest で書いていたが なんかコレジャナイ感あったので 一周回って mocha + power-assert + espower-typescript の王道構成に戻ってきたらメンテされて使いやすくなってた。

 

モジュールインストール

yarn add mocha power-assert espower-typescript --dev

型定義インストール

yarn add @types/power-assert @types/mocha --dev

実行

./node_modules/.bin/mocha --compilers ts:espower-typescript/guess test/spec/**/*-test.(ts|tsx)

とかでプロジェクトのtsconfig.jsonの設定を読んでいい感じにやってくれる。

package.jsonにシェル書いとけば npm test とか yarn test で動く

"scripts": {
    "test": "./node_modules/.bin/mocha --compilers ts:espower-typescript/guess test/spec/ --timeout 30000",
}

test.ts

tsconfigの設定によってはES7 async や デコレータも使えて調子いいっすね

import "mocha";
import assert = require("power-assert");

const sleep = (time : number)=> new Promise(r => setTimeout(r , time))

describe("section", ()=>{

    it("非同期テスト", async ()=>{
        await sleep(2000)
        assert.equal(3 ,3)
    });

    it("高階関数テスト" , ()=>{

        function decorate(clazz) {
            return class extends clazz {
                constructor() {
                    super();
                }
                prop : number = 100;
            }
        }

        @decorate
        class BaseClass {
            prop : number = 0;
        }

        const base = new BaseClass()
            assert.equal(base.prop , 100)
        });
    });
});

特に何も入れずにスクレイプのテストをパッと書く

スクレイプ / WebサイトE2Eテストの構成がほしい時。

TypeScript勢は上記の構成に好きにヘッドレスブラウザなりを入れて自由にしたらいいと思うが、それ以外の方。

結論から言うとこちらのボイラープレートを参考にするのが一番早い
nightmare-ava-example

 

ava はmochaみたいなテストフレームワークで、デフォルトでasyncをサポートしていたりとシンプル。
Nightmareはヘッドブラウザphantomjsのラッパー。(casperjsみたいなもん)…だったが、最近はElectron(chromium)が裏で立ち上がるようになってる。

こんな感じ

import test from 'ava';
import Nightmare from 'nightmare';

const nightmare = Nightmare({ show: true });

test.serial('Async/Await!', async (t) => {
    const result = await nightmare
       .goto('http://yahoo.com')
       .screenshot('output/png/hoge.jpg')
       .type('form[action*="/search"] [name=p]', 'github nightmare');

    const result2 = await nightmare.click('form[action*="/search"] [type=submit]')
       .wait('#main')
       .evaluate(function () {
           return document.querySelector('#main .searchCenterMiddle li a').href;
       });
    t.true(result2.includes('images.search.yahoo.com'));
});

実行

./node_modules/.bin/ava --verbose spec/

すぐに書き始められていいかと思う。

Read More

CompileDaemon を使ってオートリロード

auto-reload は色々あるのですが、たまたま見つけた、CompileDaemon を使ってみました。

上から5番目(2017年01月13日時点)ということで、まぁまぁいいんではないでしょうか。

% go get github.com/githubnemo/CompileDaemon
% go install github.com/githubnemo/CompileDaemon

で、インストールすると、CompileDaemon というプログラムが出来上がります。

オートリロードさせたいプログラムがある場所へ移動して、以下のように使います。

% CompileDaemon -command="./app_name" -include="*.go"

“./app_name” のところは、build したときに出来上がるファイル名を指定します。

“-include=” を指定することで、*.go 以外のファイルが更新されても無視します。

なかなか簡単に使えて良い感じです。

Read More

serverless frameworkでのLambdaファンクション縮小/デプロイ速度向上

serverless framework (v1.4)使用。

include/exclude

普通にデプロイすると、node_modules以下が全てパッケージングされ、各Functionのサイズが大きくなってしまったり、デプロイに時間がかかったりする。
結論としては、パッケージングの設定をきちんとすること。
 
公式ドキュメント参照のこと。
 
この設定はもちろん各Functionごとに独立させることもできるみたい。
 
開発時にwebpackを使っている方なら、(作り方にもよるが)そもそも初めから各エンドポイントに必要なものだけrequireしてbundleする構成にはなってるかと思うので、
一括でnode_modules以下をexcludeしても構わないかもしれない。

serverless.yml

service: hogehoge

package:
  exclude:
    - node_modules/**

...

serverless-webpack排除

2016年末段階ではserverless-webpackプラグインを常用していたが、

serverless deploy function -f <functionName>

に対応していない?ため、全functionの一括デプロイしか手段がなかった。
普通に自前のwebpackでjsを吐いた方が個別にアップロードできるため何かと融通がきくかもしれない。

このプラグインは、

serverless webpack serve

でローカルのテストが簡単にできる利点があったが、serverless-offlineに移行すること。

Read More