2019年3月25日月曜日

無料+非広告+広告可のブログ関連サービスまとめ

たとえコーヒー代程度でもブログで広告収益が得られると嬉しいものです。 でもきちんとコーヒー代を得るためにはコストのお話も重要。まとめます。


Blogger、Tumblr

ブログサービスはたくさんあるけど、コスト的に最も優れている無料+非広告+広告可のブログサイトだけ探せば良いと私は思っています。 ただそういったサイトは予想外に少なくて、BloggerTumblrしかない。

BloggerTumblrは便利ですが、完璧という訳でもありません。 例えばBloggerはいくつでもブログを作れるけど、アカウントとロールは1つしか持てない。 これは気にしなければ大丈夫なレベルだけど、色々やろうとすると結構面倒臭い事になってしまう。 例えば色々なサイトを作り過ぎるとキャラ崩壊しかねないので注意が必要です。

Tumblrはアカウントもブログも大量に持てるけど、検索と記事管理に難があります。 以前はできなかった全文検索ができるようになって使いやすくなってきましたが、記事管理のほうはどうにもならないので、書き殴り用途以外では少しつらい。



Netlify、GitHub Pages

最近はこれらに加え、ブログサービスじゃないけどブログ化しやすいサービスとして、NetlifyGitHub Pagesの2つが加わりました。 ちなみに頑張ればHerokuFirebaseでも無料+非広告+広告可を達成しつつブログ運営はできると思いますが、今回は語りません。 NetlifyGitHub Pagesのほうが無料領域が明確化されているので、おすすめしやすい。

NetlifyGitHub Pagesの違いは、主に3つです。 (1) Netlifyはサブドメイン単位でアカウントを複数持てるけど、Github PagesはGitHubのアカウントに依存する。(2) NetlifyではCGI要素も少しならこなせる。(3) NetlifyはGitHub以外のアカウントでも使える。 若干だけどNetlifyのほうが高機能ですが、ブログ用途ではアカウントとロールの取り扱い以外はそれほど気にする必要はないと思っています。


Netlify/GitHub PagesBlogger/Tumblrと比較すると、どちらも静的ジェネレータなどで1からサイト構築しないといけないので、多少の知識が必要という違いがあります。 そしてページ内検索が特に手間なのですが、静的ジェネレータ側で自分で設定できるのでカスタマイズ性は高い。 例えば静的ジェネレータのHugoは公式でも色々と選択肢がある事を宣言しているし、hugo-site-searchというものもあって、これも便利そう。 Jekyll/Gatsbyでも上記で紹介されているLunr.jsは利用できるので、今のところおそらくこれが静的ジェネレータに全文検索を付けるベストプラクティスと思われる。

他にもAlgoliaという全文検索サービスと連携する手段もあります。 非商用利用なら無料との事でアフィリエイトサイトには使いにくいので注意が必要だけど、 JSONファイルを生成しておけばどのようなサイトにも対応できるようなので、 そういういうものもあるのだと覚えておくには良いかも知れません。


久々に無料ブログ漁りをしてみたけど、技術をきちんと扱えれば無料での提供とカスタマイズが楽になってきていますね。 プログラマに限らず、プログラミング能力はコストを抑える必須能力になってきているとも感じます。

2019年3月24日日曜日

Cloudflare Workersに見る静的サービスのトレンド

Cloudflare Workersというサービスが出ていました。面白いサービスと思ったのでメモだけしておきます。



イメージとしてはJavaScript (Service Worker) をCGIの代わりに使って、静的化してCDNしてくれるサービスと認識しました。 この分野、CDN Edge Serverとか呼ばれているらしい。 実は「こども翻訳」でもまったく同じ事をしているんだけど、まさにそのようなニーズを狙ったサービスに思う。

ちなみにService Worker単体でもそのような処理は、もともと実現可能ではありますが、様々な制約がある。 というのもCORSに関しては以下の方法で回避できるからです。 ただ回避してもopaque filtered responseになるので操作できない問題がある。
fetch("http://example.com/", { mode: 'no-cors' });
そしてUser-Agentを変更できないなどの問題もある。 なので実現はできても制約が厳しく、結局はサーバは介さないといけないというのが結論と思っていました。


こども翻訳のような翻訳サイトにおいてはこれは致命的な問題で、こども翻訳ではNetlify Functionsを使ってごにょごにょする事で回避、実現している。 Cloudflare Workersはこれと同じ処理をサービスとして用意したものだと認識しました。 CDNで動くから早いし、おそらくオンザフライ実行ではないから早いみたいだけど (60msくらい)、無料利用はCPU処理時間が5ms未満という制約があり、これはかなり厳しい。 この秒数だとCORSを回避して後はすぐにさばかないとキツイだろう。 こども翻訳は高度な処理を色々としているので20msくらい掛かっており利用はできない。残念。 実装をクライアントサイドに寄せればいける気もするけど、それはそれで課題があるので気乗りはしない。

私のコスト感覚ではCPUほぼゼロだから5$/月はちょっと高い感じもする。 現状では有料より遅くても無料のFirebase/Netlifyを採用する事に変わりはない。 ただ課題と思っていた部分を解決してくる海外事業者の速度は早いなあ。 解決されると割とアツイと思っているので、今後似たようなサービスが出てこないか、サービス動向には注目しておきたい。

2019年3月20日水曜日

こども翻訳というWebサービスを作った (対象: 小1〜中3)

こども翻訳というWebサービスを作ったので、紹介します。 漢字やカタカナに読みがなをルビで振って、ネットを見る事ができる翻訳サービスです。



このサービスをなんで作ったかというと、子供たちに調べものをしてもらう時に意外と苦労するからです。 国語辞典も漢字だらで最初のハードルは割と大きいし、といってネットも漢字が多くてファーストステップとしては使い勝手が悪い。 しかしこのサービスを使うと、ひらがなとアルファベットさえわかれば、すぐにでもネットで自由に勉強ができる。

最近はYouTubeで子供用の教育動画を見ている子供たちも増えているように思うけど、動画はネットの一部でしかなく、より実用的なのはまだまだ文章だと思っている。 何らかの翻訳サービスが必要と思いました。


ひらがなとカタカナを多くの子がきちんと習うのは6歳だけど、早い子だと2歳で読めるとも言われる。 しかしネットを閲覧できる程度の漢字をきちんと習うのは10歳くらい。 英語だとアルファベットを覚えれば2歳から無限に勉強できる訳だから、この最大8年くらいの差は、思っているより大きな才能の障壁を作っているのではないか。 ひらがなとアルファベットさえ覚えて、後はカタカナと漢字をこども翻訳を通じてネットを見ながら勉強すれば、読みの勉強は一切する必要がなくなるかも知れない。


今後は英単語の取り扱いを改善したいと思っています。 子供たちにとって一番大きな障壁であろうカタカナと漢字の読みがな処理はだいたい完成したので、すぐに使ってもらうためにも速攻で公開しました。

まずは使えるレベルのものを作った状態なので、これからはより多くの機能を追加していきたいです。 作りたいと思っている機能はこちら。 機能要望がありましたら、こちらのフォームから送信して頂けると嬉しいです。

2019年3月17日日曜日

lazygitを使い始めた

lazygitというGitコマンドを改良するCUIツールがある事を知り、かなり良い感じのツールだったので使い始めました。



Gitコマンドの改良ツールは昔から色々あって、 私が使いやすいかなと思っていたものはtigfugitive.vimです。 ただこれらのツールも最低限のCUI操作を覚えない事には若干使いにくく、 久々に起動すると「あれ?どうやって使うんだっけ?」となりがちです。

lazygitもCUIツールなので多少の操作性には慣れないといけません。 ただヘルプが内蔵されていてすぐに確認できるし、覚えるべきキーバインドはほとんどないところが違う。 私がlazygitを使うに当たって覚えたのは、上下左右キーで移動できるFilesビューで以下の操作をするという事だけです。
  • Spaceキー: git add / git reset の toggle
  • aキー: git add --all /git reset (all) の toggle
  • cキー: コミット

この3つさえ覚えておけばあとは何とかなるという設計がとても良いです。

フリゲ紹介: ブレスオブザわてり

ブレスオブザわてりはVIPRPG2018紅白で2位だった作品。 タイトルからブレス オブ ファイアを想像した人は多そうだ。 実際にはわてりが息 (ブレス) を吐くように毒を吐くゲーらしい (笑)。 ゲーム自体はいわゆる探索ゲーで、とても面白い。



唐突にスタートする系のゲームですが、マップはほぼ一画面内に収まるくらい (左下)。 たったこれだけに見えても隠し要素は満載です。 ほこらを訪れながら (右下) わてりをレベルアップしたり、アイテムを集めて物語を進めていきます。



最初は何をするべきなかはあまり明らかになっておらず、イキったわてりを楽しみつつほこらのパズルゲームを攻略したり、ダンジョンを攻略していく事になります。 もちろんボスもたくさん居ます。



ほこらとダンジョン探索だけでも十分楽しいのですが、終盤に近付くにつれ徐々に物語の形が見えてきます。 物語を進めていくとただ単にダンジョンを攻略するゲームではない事がわかってきます。 きちんとしたクリアを目指そうとすると意外とボリュームもある。

そして何よりやりこみ要素が充実しているのがこの作品の目玉だと思います。 クリア後にはタイムアタック的な要素やコンプリート要素がでてきて、完全クリアのために何度も楽しめる仕様になっています。

わてりを見ているだけでも面白いのですが、気軽に楽しめつつ、やり込みもできてとても面白い作品だと思いました。

フリゲ紹介: ふたりの旅のきろく

ふたりの旅のきろくはVIPRPG2018紅白の優勝作品。 優勝作品だけあってとても面白い。

私も手軽に楽しめる作品が好きになっていますが、そういった人にとても良い作品だと思いました。 またVIPRPGとはどういうキャラクターが居て、どのように面白いのかというのを、歴代作品の中でも一番わかりやすく、楽しくまとめた作品じゃないかな。 VIPRPGが初めてという人に、過去の名作以外では真っ先におすすめしたい。



ストーリー的には、リナの影響を受け、冒険をしたいと言い出したライチと、それに付き合う事にしてあげたやみっちの、2人のほのぼの冒険物語です (下)。



思い出作りのためになんとなく始まった冒険でしたが、ひょんな事から願い玉 (ドラゴンボー的な何か) が見つかり、様々なクエストをこなしていきながら願い玉を探す事も冒険の1つの目標になります (左下)。 この作品はとにかく作り込みが凄くて戦闘画面も凄く凝ってる (右下)。やみっちがかっこいい。



戦闘画面以上に凄いのは、とにかくやみっちとライチの表情が豊かなところです (左下)。 やみっち&ライチ愛を感じました。 こんなに2人の表情を作り込んだVIPRPGはないんじゃないかなあ。 他にもミニゲームもたくさん用意されていてまったく飽きさせない (右下)。



結構ボリュームがあるのに一切ストレスなくプレイできて、凄いと思った作品でした。

フリゲ紹介: ガールズパーティ!

ガールズパーティ!は女の子だけでパーティを組んで世界の「歪み」を解決する探索RPG。 まだ最初の4層ほどプレイしてみた感想ですが、面白い。



登場キャラクターは7人で、4人だけ選んで潜るタイプの探索RPGです(下)。 敵キャラも全部自作みたいで意気込みが感じられる。 半分ランダムで、半分固定マップのダンジョンになっているみたい。

多キャラローグライクって結構難しいと思ってて、メンバーが固定化されてしまいがちなんですよね。 たくさん仲間が居るのに探索しているのは4人だけみたいな事になりがち。 どうなるかと思ってプレイし初めてみましたが、みんな個性を持ちつつ良い感じに成長してくれている。 スキルが偏り過ぎる事もなく、個性がかぶり過ぎる事もないので、良い感じです。 探索に同行しなかった女の子たちもほとんど同じくらい経験値が入るので、気軽にメンバーを交代できるのは良いですね。



プレイ感覚はらんだむダンジョンによく似ています。 ダンジョンの踏破進度や、自室のベッド (左下) で休憩して時間が進んだ時にイベント (右下) が起きるような仕組みになっている。 序盤から色々な伏線が張られたイベントが起きて、先が見たくなる。 ダンジョンに潜る手前で全回復できるクリスタルがあるのですが、積極的に自室で休憩したほうが良いように思う。 ダンジョンは何層か進むと急にハードルが上がるポイントがあるのですが、そういった時はイベント→クエストがあったりします。



クエストをこなしていくとバランスが良くなりますが、それでも3層はきつめです。 ただ3層は割とユニークスキルを持った武器防具が多くて、このあたりで私はこのゲームのスタンスがわかってきました。 ユニークスキルをうまく活かして、属性パズルを意識して戦うと結構楽しくて良い感じです。 序盤から属性パズルを考えていくのはらんだむダンジョンもそうですが、Nepheshelを彷彿とさせる感じもあります。 かなり練られていると感じる。 4層からはスキルも増えてきてまた違った印象で、バランスも良いように思う。

15時間〜のプレイを想定しているゲームなので、長く楽しめそうなゲームです。

2019年3月16日土曜日

Firebase/Netlifyは現時点で最高の個人開発サービスだと思う

Netlifyを使ってWebサービスを作ってみたけどなかなかに素晴らしかった。 ローカルで検証可能な、無料レンタルCGIサービスの凄い版みたいな感じ。 Firebase/NetlifyがVPSの完全な代替になる訳ではないんだけど、次のサーバビジネスの形が見えた気はする。 使ってみて感じたポイントを書いてみる。



ビルドシステムを限定した事でメモリ効率が良い

VPSはLinux→VM→ユーザ空間でサービスを提供しているけど、ユーザ空間内でゲストOSを読み込むのでマシン効率は良くない。 ただNetlifyのようにLinux→ビルドシステム→ユーザ空間で提供するとメモリ効率が非常に良い。 これNetlifyがなぜ無料枠がこれだけ大きいかにも関わってくる話だと思ってる。

ビジネスユーザだけで賄えている

Netlifyは1ユーザならAWS Lambdaを使い過ぎない限りは無料で使える。 チーム開発の課金だけでお金は賄えると言っている。 FirebaseGoogle App Engineと比較すると無料枠が大きくなっている。 海外は最近このような個人優遇の傾向が徐々に強まってきている。

動的サービスの無料提供のハードルが下がった

ビルドシステムを起点にしてユーザ空間を分割させるのは頭の良い割り切りで、有名なビルドシステムに対応すればほぼすべての静的サービスのニーズに対応できている。 しかしそこで終わらせなかったのがNetlifyの凄いところだと思う。 AWS Lambdaを登録なしに使えるようにしてハードルを下げたのは実に上手いやり方だった。 これによってログインが不要な動的サービスの大半はNetlify「だけ」で提供できるようになったのは大きい。 無料で提供するためには、このような割り切りを見極められないといけないのだろう。



使ってみて感じた展望も書いてみる。

VPSである必要性が小さくなりそう

個人ならVPSからFirebase/Netlifyに移動する人が増えそうと思った。 単純なリクエストを処理するだけならこれらで十分と思う。 逆にVPSでなければならないケースは、サーバで何らかの処理をして返却する時に、(1) メモリをたくさん利用して処理するケース、(2) サーバサイドで何らかの処理をして必ず100ms以内に応答を返したいなどの高速ニーズ、(3) 認証くらいじゃないかな。 そんなには多くなさそう。 これはDeep Learning以外ならサーバの負荷をクライアントに移譲すれば割と解決できる事が多いからだ。 これからのVPSはただ提供するだけでは駄目で、Firebase/Netlifyに価格面で何らかの対抗ができないといけない。

JavaScript/Node.jsはさらに流行りそう

またNetlifyは様々なビルドツールに対応してはいるけど、Node.jsが機能的に突出しているので、なんやかんやとNode.jsへの移民が増えそうな気がする。 他にもNetlifyAWS Lambdaのサポートが今のところNode.js/Goだけ、FirebaseのサポートはNode.jsだけな事もあって、ベンチマークが良ければ色々な言語覚えるの面倒だから、今後はサーバからクライアントまでJavaScriptで良いやともなるかも知れない。 仮にそうなれば割と多くの言語がWeb開発から脱落しそうでもある。 言語の棲み分けは考えておかないといけない。

サーバ処理のレスポンスがどこまで早くなるかが鍵

バックエンドはNetlifyにぶん投げして、WebフレームワークもNetlify Functionsで妥協して、JavaScriptで完結した世界はどうなるか。 まずスケーリングとか、障害監視とか、Linuxカーネルの設定とか、HTTPサーバの設定とか、Webフレームワークの選定とか、バッチの設定とか、セキュリティの設定とか、そういった煩雑な仕組みをまったく意識する必要がなくなる。平和だ。

肝心の速度はどうかというと、簡易的な静的ページのTTFBを測定してみるとNetlifyは80msだった。 Vultrなら20msくらいなので、平凡よりちょっと早い感じである。 ではNetlify Functionsはどうかというと、Node.js実装でほぼ何もせず返答を返すようなモデルで1.3sくらいかなあ。 ゴリゴリ使わなければ無料で返答が帰ってくるだけで画期的と思うけど、まあ遅いですね。 Firebaseは確認してないけど、キャッシュに載っていなければそこまで早くはないんじゃないかなあ。 ここが改善されるとVPSの領域はガンガン小さくなる。 プログラムの起動時間の高速化技術などがもっと進化するかも知れない。

個人開発が進みそう

海外のサービスでは個人が優遇され始めているので、個人開発は今後もどんどん増えていくんじゃないかと思っている。 チーム開発ではFirebaseのほうが有利だと思うけど、転送量が厳しいので、そういったところが色々影響が出そうだ。 個人の優遇が進む事によって日本のサーバビジネスがどうなるのかは少し気になる。

2019年3月13日水曜日

最近のWebサービス開発の最適化ポイントまとめ

久々にサービス作った際に、忘れていたり、触っていなかった事によって無駄に時間が掛かった最適化ポイントをまとめてみました。
HTML/CSS/JavaScriptの最小化や圧縮、サーバの設定などは元からできるものとして、最近変化した事や私が忘れていた事、気付いた事のまとめです。 事前に知ってると3日くらい実装時間を短縮できるかも知れない。 次回作る時のためのメモ。

faviconの作り方は変わっていない

faviconの種類は肥大化し続けている。自力での対応は面倒なのでFavicon Generatorに頼ると良い。 またfaviconの編集も割と面倒である。 画像編集ソフトを山ほどインストールしたけど、一番便利だったのはPinta。 私はいつもフリー素材で作ってるので、透過PNGをそのまま編集できて、レイヤをコピペで合成できる機能だけあれば十分なんだけど、 何年経ってもPintaが一番簡単に思う。

faviconはインライン化する必要がない

画像をインライン化するとレスポンスが良くなりますが、 最近のブラウザはfaviconを遅延ロードしてくれるのでインライン化は不要です。 最近はfaviconの種類が増え過ぎて、インライン化すると端末依存の不要なものを読み込んでしまい、むしろ遅くなります。

14KB/98KBを意識する

4Gネットワークでは50~100ミリ秒のラウンドトリップ時間が発生する。 1パケットは14KBに制限されているので、1ファイルはなるべく14KB以内に収まるようにする。 またスクロールせずに見れるATFコンテンツを98KB未満にすれば3回のラウンドトリップでページを表示できる。 PageSpeed Insightsの指針に従って最適化しましょう。

<link rel="preload"> ができていた

linkタグにCSSのレンダリングをブロックしないための属性ができていた。 ファーストビュー部分をインライン化しておいて、残りをpreloadで読み込めば、高速化が簡単にできるようになった。 現時点では対応していないブラウザが多めなので、loadCSSを併用する。
これも楽にはなったけど完璧ではないです。 CSSをpreloadでロードした後にdeferしたscriptを実行するためには、今のところライブラリが必要です。 loadCSSでは以下のように実装すると、#loadcssタグの前にCSSを読み込んだ後にスクリプトを実行してくれる。
<script id="loadcss">
  loadCSS("path/to/mystylesheet.css", document.getElementById("loadcss"));
  :  // 何らかの処理
</script>
preloadよりは、後述するファーストビューのインライン化を先にやるべき。

ファーストビューのインライン化ツールができていた

ファーストビューのインライン化はUnCSS, Criticalの2つが有名みたいです。 説明は少し長くなるのでこちらを参考ください。 ファーストビューのインライン化は起動時間短縮にかなり効果があって、今回のサービスでも100msくらい早くなりました。

PageSpeed Optimizationモジュールができていた

h2oでサーバの設定が終わってから気付いたので、これも今回は使っていない。 これを使えば面倒臭いインライン化回りを自動化できて開発が楽になる気がします。 今回はpreload回りのコードをビルドツールに組み込んでしまったのでセーフという事にしておいた。 他にもGoogleがいくつか新しい最適化ツールを推奨し始めた

headタグに書ける事が増えた

Twitter Cardとか構造化マークアップとか出たらしい。 構造化マークアップでパンくずリストを作れるのは割と便利かも知れない。 でも今回は何も使ってない。 明らかに参考になって今後も使えそうなページだけ載せておくと以下。 Googlebotの機能を見るに、実はほとんど書かなくて良いのではないかという気がしている。

iOS WebKit Debug Proxyができていた

Macを使わなくてもiPhoneのデバッグできるようになったので、Linux使いの私は捗るようになった。 なおWindowsでは動かないらしい。

iOS12以降でBasic認証の処理が色々とよくわからなくなった

よくわからないけどまともに動かなくなってデバッグつらい。これはマジでつらい。 デモで見せたい時とか超困る。 適当なtokenをキーとしたページをでっちあげて短縮URLで送るくらいしか抜け道を思い付かないが…。

iOSでWebページを最大化表示できるようになった

Androidは以前からこの機能がありましたが、iOSでも対応しました。 ホーム画面に登録するとアプリっぽく動作してくれるようになります。 iOS/Androidの両方で最大化表示できるようにするには以下のように書きます。
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">

iOSでWebアプリをホーム画面に追加するとリロードが効かなくなる

iOSでホーム画面にWebページを登録すると、独自の更新間隔でキャッシュをリロードするようになります。 HTTPサーバのキャッシュ情報が使い物にならなくなるので、検証中は content="no" にしないと検証が困難に。
<meta name="apple-mobile-web-app-capable" content="no">
日本語情報はまったく見つからなかったけど、海外ではハマっている人が結構居た。 キャッシュを消すためには、端末のデータを直接弄って消すか、iOSのキャッシュを削除した上で content="no" にするしかないのかなあ。 運用時もキャッシュが効き過ぎて割と困る。 PWAを設定するとService Workerを見てくれてその更新モードが適用されるみたいなので、PWAの利用を前提に使ったほうが良さそう。 これはPWAに対応していない古めのiOSやSafariのバージョンをどうするかという話にも繋がってくる。

PWAができていた

iOS 11.3 / Safari 11.1からiPhone/iPadでも対応し始めたらしい。 色々な使い方があるけど、コンテンツキャッシュとアドレスバーを消してアプリっぽく利用できるようにするためだけに利用している。 最近のスマホだとPWAを使えば先に述べた指定をしなくてもアプリっぽくなる。 PWAのキャッシュ更新は手動で調整できて嬉しい
PWAのおかげでかなり早く起動できるようになった。対応も簡単なので、これはどんなサイトでもやったほうが良い。 今回は使ってないけどGoogleフォントはPWAに対応しているし、結構色々なものがキャッシュできる。 適当な実感値だとスマホは200msくらい改善できる気がする。 他にもPWAは設定しているだけで簡易的なF5アタックブロッカーになるので、割と良い仕組みだと思った。

Desktop PWAができていた

Chrome 67からデスクトップでもPWAが使えるようになった。 インストールするとデスクトップにアイコンまで作ってくれる。Electronより楽かも? スマホほどの速度改善は期待できないし、まだ試験的機能でしかないけど、将来には期待が持てる。
いずれ解決される気がするけど気になる動作が色々。 DevToolsのネットワークのロード時間がService Workerのせいでおかしくなる。 遅くなっているように見えても実際には早くなってるので注意が必要。 他にも普段からキャッシュが効きまくってデバッグがしにくくなる問題もある。 毎回キャッシュを消して確認してる。

AMPができていた

CSS/HTML/JavaScriptに様々な制限を加えてキャッシュする事で高速な表示を可能にする技術。 こちらは対応が面倒臭い。 制限がキツ過ぎて、正直いくら早くなると言ってもJavaScriptバリバリのサイトへの適用は困難を極める。 そもそもファーストビューのインライン化では !important を使ったほうが楽だけど、使ってしまうとAMP化できなくなる。これはキツイ。 今回作ったサイトでは使えそうもないので使ってない。

jQueryがボトルネックになった

様々な最適化ツールの進化によって、今回のサービスで一番のボトルネックは外部サービスの遅さとjQueryのロードの遅さになりました。 ネットワークとDBの細かなボトルネックをきちんと処理して負荷が大きく掛かってない状態なら、確かにjQueryはキャッシュが効いていなければ100ms近く掛かってしまうので、現状一番重いです。 jQueryより前に色々処理するのが最初の対策ですが、残りの部分はやはりjQueryを使う事になるのでどうしても遅くなる。 うまくネイティブ化して50ms以下にしたい気持ちはあるけど未着手です。

BootstrapVueが出ていた

先に述べたようにロード時間のほうが問題なので、ほとんど使ってないjQueryでも良いかなと思ってるんだけど、今も採用の候補にはある。仮想DOMを自前で処理してると別にフレームワーク自体の機能はそんなに関係ないんだよなあ。 一番気になるのはPWAの進化に対してVue Nativeなどのネイティブ化技術がどれくらい強さを維持できるかどうか。
ところでBootstrap v5ではjQueryへの依存がなくなるらしい。 私はアニメーションとBootstrapの依存ライブラリのためにしか使ってないので、そこを提供してくれれば移行は困りません。 ただ意外とそこが面倒。 前者はVelocity.jsが出てきたけど別にサイズが軽い訳ではないし、ライブラリのjQuery離れもどれくらいの速度で進むかな。 Native JavaScript for Bootstrapやv5が安定してから採用するほうがVueを使うより楽だし軽いと思うので待ちですかね。 v5が出るまでは基盤ライブラリに何を使うかは迷い所かも。

Parcelができていた

煩雑なHTML/CSS/JavaScritptを何も設定せず最小化してくれるParcelという素敵なツールが出ていた。 便利なのは理解したけど、最小化やキャッシュ周りで最も注意が必要なのはService Workerで、ここをミスするとバグに気付けなくなるので、ここを自動化するためにもビルドツールは完全に自作した。
ただこれはworkbox-webpack-pluginを知らなかったからであり、このプラグインは上記で述べた事を良い感じにやってくれるので、今だったらこちらを使うかも。 workbox-webpack-pluginがかなり便利なので、次回作る時はWebpackでも良いかなとも思っている。 Parcelはそのへんが安定してきたら候補に上がる。

レイアウトのリフロー対策はよくわからない

とりあえず完成したサイトはPageSpeed Insightsでパソコン版は99点だった。 その後モバイル最適化のためにあえて点数を少し落としたけど、1つ気になったのは過大な DOM サイズの回避というもの。 リッチサイトじゃどうしようもないような。 もしかしてレイアウトのリフローを避けるためには、iframeを使うべきなのだろうか。

ChromeのDevToolsから色々なSEOのチェックができるようになった

DevTools -> Auditから確認してもらえる。 PageSpeed InsightsのようなレスポンスのチェックだけでなくSEO周りもチェックできるようになって嬉しい。 jQueryでWarningが出るという。 その問題を無視すれば、Performanceを以外を100点にするのは今のところ簡単。

WebPが良い感じになってきた

WebPは以前からたいていのブラウザでHTML経由の表示はできていたと思うのですが、2018/01/29でリリースされたFirefox65の正式採用によって、ついに実用的な利用が視野に入ってきたように思います。確認テストもしてみた感じでは、画像の多いサイトでは通信量を1/10以下にできる可能性もありそうですね。

CGIはSSHが使えないとつらい

もしくはリバースプロキシがいかに天国であるか。 もしくはレンタルサーバとVPSの選び方。 結構長い話になるので詳しくはこちらをどうぞ
さらにEC2やGCP、S3なども含めて運用基盤全般も軽く調査し直したけど、 今回は検討の結果、Vultrを利用した。 価格のバランスが良くてネットワーク速度が早かったので選んでみたけど、適宜増設していくつもりです。

マイクロWebフレームワークが増えて選択肢が広がった

昔はRuby on RailsDjangoなどの巨大なフレームワークしかなかったけど、マイクロWebフレームワークの種類が凄く増えた。 Ruby/Pythonでも早いものが増えたので、気軽に実装できるようになった。

静的ファイルを作り過ぎてinodeが枯渇した

静的ファイルのほうが早いものはひたすら静的化していたのですが、容量の小さなVPSで小さなファイルをたくさん作ると、容量より先にinodeが枯渇する事を知りました。 ちなみにext4でinodeが枯渇するとファイルシステムを作り直さないといけない。これはあかん。 ファイルに書き出しまくるとこういう問題もあるんだなあ。 レンタルサーバはVPSよりクリティカルな問題にならないかなこれ。
仕方がないのでKVS実装にサクっと書き直した。 ほぼファイルシステムとしてしか使ってないけど、ファイルシステムより効率は良いのでファイルサイズが1/3になったし、リクエスト数も減らせて高速化した。 レンタルサーバにこだわらなければハマる事はなかった問題だったけど、勉強になった。

init.dスクリプトのテンプレートができていた

いつも超迷う /etc/init.d/service でサービス登録するテンプレートができていて、凄く簡単にサービス登録できた。

決済周りが一番時間が掛かった

コア実装は満足のいくレベルの1万行〜くらいを3週間でパパっと書けたので、速攻でリリースしようと思ったものの、実際にはかなり時間が掛かっている。 調査に1週間、少額決済の実装に1週間、申請に5週間、利用可能までに2週間掛かった。
調査の時間が長いのは久々にWebサービス作ったせい。 決済の実装が思ったより闇が深くて検証に時間が掛かって、審査にも凄く時間が掛かった。 やっぱ申請って疲れるなあ。 最初からすべてOKをもらってから運用開始しようとするのは凄い時間掛かるのでやめたほうが良い。 申請中にまったり機能改善をするのが良さそう。

今回は割と学びの多い開発になった。

2019年3月12日火曜日

iframeを良い感じに表示するCSSテクニックまとめ

高さのわからないiframeを指定した余白いっぱいに、良い感じに表示するのは割と難しい。 いつも物凄くハマるので、何が駄目で、どう書くと良いかという事例ベースでテクニックをまとめておく。

html,body { margin:0; height:100%; overflow-y:hidden; }
iframe { width:100%; height:100%;  }
ネットでよく見かける書き方だけど、これはスマホでスクロールできなくなる。 html,bodyに height:100% を指定するのは基本的に危険。 もちろんあえてスクロールさせたくない場合には付けても良い。

html,body { margin:0; width:100%; overflow-x:hidden; }
iframe { width:100%; height:100vh; }
overflow-x:hidden; を入れても良さそうに見えるけど、これはPCサイトでhtml,bodyのスクロールの余白が残ってしまう。

html,body { margin:0; width:100vw; }
iframe { width:100%; height:100vh; }
overflow-yを指定しない路線でいくならこれが一番まともだと思う。 html,bodyのスクロールバーを100vwであえて表示しないようにして、iframeのスクロールバーと重複した位置に配置する。 見た目上は普通のスクロールバーに見えるので、ぱっと見では違和感がない。 ただページの最上部と最下部でスクロールバーが本当は2つある事によって若干不自然なスクロールになるのが欠点。 これがあるので overflow-y:hidden; が良い。

html,body { margin:0; width:100vh; overflow-y:hidden; }
iframe { width:100vw; height:100vh; }
vw, vhもよく見かけるけど注意が必要。上記はスマホではスクロールバーぶんシフトされた表示になってしまう。 あといかにもページが固定されそうだけど固定されない。
PCでも色々問題が起きる。 例えばページ全体が固定される、フッター部分に余白がないと見切れる、横スクロールぶんシフトされる問題などが発生する。

html,body { margin:0; width:100%; overflow-y:hidden; }
iframe { width:100vw; height:100vh; }
上記の問題に対処するため、html,bodyは%で設定してスクロールバーを考慮する。 iframeのheightは100vhにしてあるけど可視領域に応じて調整する。 たぶんこれが正解の書き方だと思う。



他にも以下のような書き方があります。 iframe-wrapperでiframeを囲んでその領域全体にiframeを記述する方法です。 これもたまに見かける書き方で、これでも動きます。
<style>
  html,body { margin:0; width:100%; height:100%; overflow:hidden; }
  #iframe-wrapper {
    position:absolute; top:50px; left:0px; bottom:0px; width:100%;
  }
  #iframe { width:100%; height:100%; position:absolute; top:0px; bottom:0px; }
</style>
<div id="iframe-wrapper">
  <iframe id="iframe" src="/example.html"></iframe>
</div>


ここまで書いてきた2つの書き方ならたいていのケースでうまく表示できるのですが、厳密にはまだ駄目です。 たいていのケースでは確かにうまくいくんですが、preのように折り返しのないオブジェクトがあった時、どうやってもiOSで表示が崩れてしまう。 これ私はどうやってもCSSで対処できなかったのでGoogleがどうやってるか見てみたのですが、 Googleはiframeを使う事を諦めて、外部サイトをサーバで読み込んだものをDOMに直接書き込んでレンダリングしていました。

iframe駄目じゃん。闇は深い。


そもそもどうしてpreがあると表示が壊れるかですが、これは推測しかできませんが、 おそらくiOSではiframe内の画面サイズが設定されていないんじゃないかなあと思います。 だからpreが可能な限り横方向を伸ばそうとして表示が崩れてしまう。

iframeを使わないというのも1つの手ですが、他にもonload後に固定幅を指定し直す方法が考えられます。 例えば以下のような感じ。
const iDoc = docuemnt.getElementById('iframe').contentWindow.document;
iDoc.body.style = document.body.clientWidth + 'px';
これはDOMを直接書き込むような実装変更よりずっと簡単に対処できるので割とおすすめですが、弱点もあります。 iframeのonload後にしか指定できないので若干レンダリングが遅くなるかも知れません。 実装量と速度のどちらを取るかは開発者次第。


何にしてもこういったものを初見で書ける気がしないんだよなあ。 何年書いていてもCSSは全然慣れないしわからない。

2019年3月7日木曜日

本気で使い倒す人のためのプリンタ選びまとめ

急場しのぎで適当に購入したプリンタが色々残念で本気でプリンタ選びをしたので、まとめてみます。 ちなみに「本気で使い倒す」の意味は、年間5000枚以上は印刷するガチな人にも対応できるという事です。 普通の人にも参考になるとは思いますけど。


1. 印刷コストを正しく予測しよう

まず最近の家庭用プリンタは、ここ数年で割とインクのコスト感覚が変わりました。 A4印刷で効率の良い順に方式を並べると、だいたい以下のようになる。 これは印刷率5%のモノクロを想定して補正を加えています。 時代と共にコスト感覚は変わるので参考値ですが…。

種類モノクロ印刷コスト (円/枚)
エコタンク (互換)0.15-0.7
エコタンク (純正)0.3-0.7
レーザー (リース)0.7-1.2
インクジェット (互換)1.0-3.0
インクジェット (純正)3.0-10.0
レーザー (互換)2.1-3.2
レーザー (純正)2.5-4.0

ちなみにこの図表、そのまま比較しては駄目です。 まずリースは印刷枚数に応じて契約価格が変わってきて、1.0円/枚が標準と思います。 月に何万枚も印刷するようなら0.7円くらいで契約できるのかも知れませんが、そんなに印刷するのは出版社くらいでしょう。 平凡な事業者は1.0円/枚以上での契約しかできないはずです。

また家庭用プリンタの印刷コストですが、公表価格はメーカーごとに想定がバラバラという事には注意が必要です (なので先程の表で補正が必要だった)。 モノクロは5%の印刷を想定したメーカーが多いように思うけど、カラーの印刷想定はバラバラに感じます。 カラー/モノクロの印刷コストは印刷率が一緒なら実はたいして変わらないので、私は想定にブレが生じにくいモノクロで比較しています。 また比較が面倒なのでメーカーごとの想定を以下にまとめます。想定の記載がないメーカーも結構ある。 モノクロも印刷率が5%の想定で正しいかは上記の想定ページを見て確認しておくと良いでしょう。 おそらく最大でも公表値の2倍を見積もっておけば十分とは思います。


2. モデルから利用シーンに合わせて選ぼう

製品を選ぶ時には、コスパや印刷速度が良いものを利用シーンに合わせて選びましょう。 例えば私は、以下のような想定でコスパを測定してみました。
基本利用はモノクロのみ、印刷は常に互換インクを利用
印刷コスト (1枚/円)=モノクロ印刷コスト (紙面の5%印刷) 
買い替えサイクル (年)=耐用枚数 / 年間印刷枚数 (12000枚)
年間コスト (円)=(プリンタ価格+印刷コスト×耐用枚数) / 買い替えサイクル
びっしり埋まっている資料などを印刷する場合は、印刷コストはもう少し高くても良いかも知れません。 年間印刷枚数は職種に合わせて調整してください。

このような割とガチめな印刷スタイルでは印刷コストが馬鹿になりませんから、エコタンク対応モデルを念頭に製品を選ぶ必要があります。


3. コスパで製品を比較しよう

上記のコスパ方程式を用いて、執筆時点のエコタンク対応モデルをすべてまとめました。 エコタンクはまだそんなに商品が多くないのですべて比較する事ができる。 またインクジェットとレーザーのコスト感を知りたい人も多いと思うので、価格.comで一番の売れ筋だった商品を比較してみました。 見るのが面倒な人は右端の年間コスト (円/年) を見るとすぐにコスト比較ができます。

メーカー型番印刷コスト価格.comAndroid
Linux
印刷速度
(ipm)
耐用枚数年間コスト
EPSONEW-M770T0.5/253782o/o135万枚15908
EPSONEW-M630T0.4/238644o/o155万枚12475
EPSONEW-M571T0.4/231723o/o10.53万枚15089
EPSONPX-S160T0.3/217879o/o155万枚6091
EPSONPX-M160T0.3/227210o/o155万枚8330
EPSONEP-M570T販売なしo/o5万枚
EPSONEW-M660FT0.4/246440o/o13.75万枚13546
EPSONEW-M770T0.5/251548o/o135万枚15371
CanonG33100.3/0.926599o?/o?8.8記載なし19199
CanonG13100.3/0.917025o?/x8.8記載なし13455
BROTHERDCP-J988N0.7/128793x/x12記載なし25676
BROTHERMFC-J1500N0.7/133801x/x12記載なし28681
BROTHERMFC-J6999CDW0.7/177940x/x22記載なし55164
BROTHERMFC-J6997CDW0.7/166670x/x22記載なし48402
ここまでがエコタンク対応モデル
EPSONPX-049A9.9/3/45139o/o?記載なし12983
CanonTS81309.9/3/414980o/o?記載なし18888
RICOHC260L2.516980x/x209万枚32264

検証条件の補足: BROTHERは大容量インクとは言えカートリッジなので、これをエコタンクと言うのかは若干の疑問があるけど、念のため入れておきました。 印刷コストの /x の記述はAmazonで測定した互換インク/純正インクの割引係数です。 耐用枚数に記載がない場合は2万枚 (よく聞く数値) で計算したので、あまり当てにはしないでください。 ちなみにHP、富士ゼロックス、RICOHなどにはエコタンク対応モデルが今のところありません。 色違いで値段が異なるものがあった場合は最高値を採用しています。 価格に絡む話はすべて2019/02/28時点のものなので、多少変動があると思います。

ドライバの対応状況は私にとって割と重要なので入れました。 EPSONのLinux対応はここから確認しAndroid対応はここから確認しました。 Linux/Androidは機能が制限されている事もあるので対応状況はよく見たほうが良いです。 印刷速度はモノクロを基準にしています。 エコタンク対応モデル以外は価格.comで人気の高いものを適当に選んでいますが、モノクロの印刷コストが載ってない場合、A4カラー印刷の数値/3で計算しています。 レーザーは耐用年数が載っているものに限定し、印刷コストが載っていないので2.5円としました。


考察: リースの値段は色々ですが安くても8,000円/月〜くらいはするので、速度面で問題が生じない限りは家庭用でも良いかも知れません。 EPSONのように純正インクが高いメーカーは、互換インクを使うとかなり運用コストを下げられるので、思っている以上にコストが下がります。 安価なインクジェットも本体は安いんですが、印刷速度、耐用枚数/耐用年数には注意が必要です。 耐用枚数にコスパがほぼ依存するので、使い倒すつもりで利用する場合、一瞬で壊れる可能性を考慮すると少し怖い。

エコタンクのモデルが良いところは、印刷速度と耐用枚数が明記されてる型番が多いのが良い点です。 ロングランを想定していない家庭用インクジェット、例えばPX-049Aなどは本気で使うとたぶんすぐ壊れると思いますし、壊れても「使用上限を超えてるから仕方ないよね」と言われればそれで終わり。 なので耐用枚数が明記されてるほうがずっと安心して買えます。耐用枚数以下で故障すれば不良品ですから。 エコタンクはロングランしないと効果が出てこない性質上、耐用枚数のないモデルの購入はしたくない。


ちなみに私は何を購入したかというと、PX-M160T を買いました。


PX-M160TPX-S160T はモノクロしか印刷できないという漢仕様ですが、その割り切りが良いですね。 PX-M160Tはスキャナも連続コピーもでき、Android/Linuxでも使えて、意外と高速な印刷ができ、ポイント高い。 こういう尖った製品を出してくれると、消費者としては嬉しいです。


モノクロしか印刷できないのは困るという人には、EW-M630Tが良さそうです。


ちなみに実際に使ってみてどうかですが、PX-M160Tは常用していてもかなり使い勝手が良いです。 公表値で印刷速度が1/2の安物プリンタを持っているのですが、体感速度では5倍くらい違います。 あと標準設定だと濃過ぎるくらいに印刷されるので、常に濃度を50%以下にして使っています。 これ印刷コスト0.08円くらいだよなあ。思ってるよりずっと安くなると思います。 なかなか良い買い物だった。

2019年3月2日土曜日

Google Pay API + Payment Request APIの実装方法

Google Pay APIには2つのUIがあります。 (1) Google Payだけを使う方法と、(2) Google Pay APIPayment Request API経由で使う方法です。 今回は後者 (2) のお話。



少額決済は変化の激しい分野のせいもあって、記事もよく間違ってる。 最も信用できるのは以下のリファレンスである。 本来ならGoogle Pay APIに限らずすべてに言える事だと思うけど、少額決済は特に注意が必要。 この記事は現時点では可能な限り間違いがないよう書いたつもりだけど、いずれ陳腐化すると思います。 動かなくなっていたらリファレンスを参照して変更点を修正しましょう。 これが今回一番言いたかった事。

リファレンスを見よ、といっても紹介記事をベースにとりあえず動かして作ってみるのは、初心者には良い方法です。 今のところこの記事 (最終更新日: 2018-10-11) が最もハマりにくく、ベースになる記事だと思う。 ただこれも動かないので、この記事を良い感じに動かすための、現時点の方法を書いておきます。

このサンプルで間違ってるのは、今のところ以下の決済メソッドの定義だけです。
var supportedInstruments = [{
  supportedMethods: [
    'visa', 'mastercard', 'amex', 'discover', 'maestro',
    'diners', 'jcb', 'unionpay', 'bitcoin'
  ]
}];
まずbitcoinにはまだ対応していない。 dinersやonionpayも対応していないように見えるのだがどうなのだろうか。 とりあえず残しておくとAPIに怒られるので除去する。 指定の仕方も、以前は小文字でも動いたのですが、今は大文字じゃないと動きません。 対応していないカードを入力するとAPIに怒られて一定時間利用を止められる。つらい。

Google Payが日本でサポートしているカードは、店舗での購入時のサポートカードのページを見れば良さそうな気はしている。 あと海外のGoogle Payが対応しているか、Chromeが対応しているか、為替が対応しているか、決済プロセッサーが対応しているか (ex: Stripeのサポート状況) が関わってくるので、それらのANDを取るようにする。 リファレンスやGoogle以外のドキュメント、W3CのPayment Request APIの記述を見ると以下のような指定が良さそうである。 ちなみにJCBは日本だけ、DISCOVERは米国だけの対応となる。
var supportedInstruments = [{
    supportedMethods: ['basic-card'],
    data: {
      supportedNetworks: [
        'VISA', 'MASTERCARD', 'AMEX', 'DISCOVER', 'JCB'
      ]
    }
}];


他にもチュートリアルを参考にすると、支払い方法にGoogle Payを指定する事ができる。 これはGoogle Payに記憶したカードで決済する方法である。
var supportedInstruments = [{
  supportedMethods: 'https://google.com/pay',
  data: {  // 長いので省略
  }
}];
data内の書き方を補足すると、Google Payのゲートウェイを通じて決済するという事になるので、PAYMENT_GATEWAYの指定が必要になってきます

そしてこの指定の仕方も、やってみる系の記事では色々な方法が書かれていて、どれが正しいのか凄くわかりにくい。 仕様変更後に書かれたGoogleの中の人の記事でさえ間違ってるし、記事通りに間違えるとAPIを短時間だけど止められる。つらい。 何度も言うようですが正しいのはリファレンス。 とりあえず執筆時点で動いていたのは以下です。
const supportedInstruments = [{
  supportedMethods: 'https://google.com/pay',
  data: {
    environment: 'TEST', apiVersion: 2, apiVersionMinor: 0,
    merchantInfo: { merchantName: 'Example Merchant' },
    allowedPaymentMethods: [{
      type: 'CARD',
      parameters: {
        allowedAuthMethods: allowedCardAuthMethods,
        allowedCardNetworks: allowedCardNetworks
      },
      tokenizationSpecification: {
        type: 'PAYMENT_GATEWAY', parameters: gatewayParameters
      },
    }],
  }
}];
const request = new PaymentRequest(supportedInstruments, details, options);
記載を省略している部分についてはここを参考にして欲しい。 ここまでの内容で一応は決済ができる直前のところまでは動くようになったはずです。 あとはPaymentRequestの実際の処理を書いていく必要があるのですが、ここは依存性が強いので省略します。 私はそこに到達するまでのほうがハマりまくったので、このようなメモを残しておく事にしました。



あとこれは自分用のメモなんですが、私はURL指定はプラットフォーマーがかなり有利な仕組みと思っていたのですが、W3CにおけるGithubでの議論を見ていて代替案に気が付きました。 basic-cardではなくtokenized-cardというプロパティが使えるらしい。 これはどうやらtokenを発行している業者を経由して決済するためのプロパティのようです。 ただ現時点では使える業者がよくわからない。

Webサービスにおける少額決済の実装面での現実

前稿Google Pay, Google Pay + Payment Request API, Microsoft Payに対応する事を決めたのですが、実際に実装をしてみると課題がたくさんわかりました。

1. すべてのプラットフォームで動かせるOAuth決済基盤は少ない

OS/ブラウザサポート状況を掴むのは意外と面倒なので、まずはそこをまとめました。 上記の対応状態を見るとGoogle Payにさえ対応しておけばあらゆる環境に対応できる。 Apple Payも気楽に使えるかと思っていたのですが、MacだとTouch IDが必要だったり、細かな条件が色々あって割とハマりやすい気がする。 特にiPhoneではカードごとの専用アプリでクレジットカードを認証しないと使えないのには驚きました。 Web認証用のIDを持ってる人って少ないと思うんですよね。 少なくとも私は持ってなかったので面食らいましたし、少し面倒だなと思いました。

2. 巨大プラットフォーマーのOAuth決済は結構お金が掛かる

ではGoogle Payが最強なのかというとそうでもない。 最初に調べた時は記載されていないので気付けなかったけど、いざ中の人とやり取りすると実は、みたいなところが色々ありました。 実際掛かる手数料をGoogle Pay以外も含めて、確認が取れているものだけまとめると、こんな感じになります。
  • Amazon Pay: カード決済基盤に月額3,000円、決済手数料4〜4.5%
  • Google Pay: 決済手数料なし、ただしGoogle Playのmerchant IDを通じて販売
  • Apple Pay: Developer Programに登録が必要なので年間99ドル
    • iOSアプリでなければ決済手数料30%は取られない
なんか意外と高いなあ。 Google Payが実装時点では一番安く見えたのですが、使い方によっては一番高くなるのが意外でした。 いざ中の人に申請をしている時にGoogle Playのアカウント必要だし、手数料はそこに依存するよと言われ、おんぎゃーとなりました。 Payは無料でもPlayで取られるのかあ。甘く見ていた。
Google PayにはStripeでそのような記載がなかったので、掛からないのかと思ってしまいました。 merchant IDがどのように結び付くのかで調べるべきだったようですね。やり取りの結果、手数料が掛かるとわかりました。 Microsoft Payのmerchant IDももしかしてMicrosoft Store (収益分配率95%) に依存するのかなあと思ったけど、こちらはStripeのドキュメントには追加手数料は掛からないと書いてある。む、難しい…。

3. 自社にカード情報を送信しないで済むOAuth/ログインID決済が良いかも

Google Payは手軽にあらゆる環境をサポートできるので便利ですが、他の決済基盤より高いし、少しレスポンスが悪い問題があります。 またGoogle Payに頼り過ぎになってしまう問題も出てくるでしょう。 無料でもう少し頑張る方法がないかという事になるのですが、実はいくつかの選択肢がある。 Stripe CheckoutPAY.JP Checkoutです。

Stripe CheckoutはログインID決済なのでメールアドレスとクレジットカード番号を収集しないといけないのですが、 それらをStripeが管理してくれる仕組みを用意してくれている。 ログインIDの決済を利用すると基本的に自社サーバ内にデータを保持する必要がありますが、そこをStripeが担保してくれるので手軽に信頼性が高まる。これは嬉しい。 自社に機密情報を持たないで済むぶんだけ若干セキュアなのかなあ。

PAY.JP CheckoutはOAuthなのでカード番号の送信も不要になります。 その場でOAuthでログインしてカード番号を受信して補完し、そして決済するという仕組み。面白い。 たぶんこちらのほうがよりセキュアな仕組みになっていると思います。

これらのサービスは手数料も安いし、APIもオープン、申請も自動化されており、どのような環境でも動くUIを提供してくれており、なおかつ決済が非常にスムーズという、非常に素晴らしい機能を提供してくれています。 私は強大なプラットフォーマーのOAuthのほうが強いかもと最初は思ったけど、こちらのほうが良いかも知れない。 このレベルでサービスを提供してくれれば是非とも使いたくなります。

4. Payment Request APIの実装は全然楽じゃなかった

Payment Request APIを使った決済処理の実装は、実装が一緒で済むから楽そうだと思ったのですが、そんな事はなかった。 実際に実装してみてわかったのは、確かにPayment Request APIの仕様に準拠する部分は実装が楽なのですが、ブラウザに依存する部分の実装はバラバラで、全然楽じゃありません。 コードでは new PaymentRequest() あたりですかね。 どうせ各ブラウザでしか表示できないUIをサポートするために、仕様が微妙に異なる実装をブラウザ毎に書くのはかなりストレスです。

この問題、またしてもStripeは解決策を用意してくれていて、 Payment Request APIを使う決済処理基盤に対して、Stripe Request Buttonという統一的な仕様とUIを用意してくれている。 基本的には素晴らしいものなのですが、完璧なものという訳でもないんですよねえ。 第一の理由は、そのものの問題ではなく、ストアのロイヤリティがバラバラなせいで利益を圧迫する可能性がある事です。 統一的なUIで表示すると当然ながら価格は同一にしないといけないけど、〜30%のロイヤリティを適当に取られるのは割と面倒だし、勝手に利益率が下がる可能性を抱えるのもちょっとなあ。 といってストアごとに実装するかと言われると面倒過ぎ、Payment Request APIは現状があるべき姿なのかよくわからない。

第二の理由は動かない事があるため。 これはたぶんChrome 70の挙動がめちゃくちゃ変わったのが原因で、Chrome 70以降からブラウザをインストールした人にはボタンが表示されないバグが出てしまっている気がする。 ちょっと正確なバグはよくわからないので、私は偉い人が解決してくれるのを待っている。 他にも例えばMac+Chrome (70-?) でたぶん動かないしiOSのChromeでもたぶん動かないような問題を認識している。 このようにPayment Request APIは理想は素晴らしいものの、現実では意外とうまく動かない事がわかってきました。つらい。 正直とても対応する気にはなれないし、すべての環境で動くものを使って、時代の流れに身を任せようと思ってます。

このような理由から、私はPayment Request APIには力を入れてません。 デスクトップのPayment Request APIは最初触った時にはなかなかイケていただけに、残念な感じです。 あとちょっと気になるのが、Chromeの chrome://flags です。 これを見るとPayment Request APIではなく、PWA+少額決済に関する本気度を感じられると思うので、一度見てみると良いと思います。 逆にマイクロソフトは自社モバイルOSからiOSやAndroidに乗り換えを推奨しており、Payment Request APIに依存するMicrosoft Payの扱いも少し不安ではある。

5. ブラウザにクレジットカード情報を入れられなくなるかも?

クレジットカードの入力をなくす方法は、OAuthによる決済や、ログインIDによる決済以外にも、ブラウザにカード情報を保存する方法も、選択肢として一応は考えられます。 私はこれも結構便利かなと思っていたのですが、Chrome 70からクレジットカード情報はブラウザ内に記憶しなくなくなりました。 おまけにGoogle Payに登録しているクレジットカードは使えなくなったので、basic-cardの指定は想像以上に使いにくいものに変わってしまった。

セキュリティ的には良い改善と思うけど、basic-cardを毎回入力するのはさすがにちょっとね。 今は他のブラウザでは使えるものもあると思いますが、将来的にはもしかすると、ブラウザに記憶はできなくなる事も想定しておく必要がありそうです。



このような実装上の様々な問題はあったものの無事、決済処理の実装は完了し、サービスもリリースする事ができました。 今後もユーザを増やすために、なるべく無料で、より多くの決済基盤に対応していきたいと思っています。 Stripe CheckoutPAY.JP Checkout的なものをどこかの会社が作ってくれればすぐに採用する予定です。

今のところはAlipayが次の候補に上がりそうだけど、ブラウザのサポート状況を見てという感じである。どこに書いてあるんだろう。 あとAlipayは手数料無料を謳ってるけど、Stripe経由だと手数料は掛かるはず。 手数料を無料にはできないのかな。この辺はきちんと調査していないので、いずれ調査したい。


以上で少額決済全体を俯瞰するお話は終わりですが、Google Pay API + Payment Request APIの実装方法はこちらにまとめておきました。 よろしければこちらもどうぞ。

Webサービスの少額決済について少しまとめた

少額決済サービスを作ってリリースしたのだけど、最近界隈が流行ったせいでサービスが乱立していた。 つい最近参入が決まったものだけでこんなにあるらしい
  • 最近参入 LINE Pay、楽天ペイ、PayPay、Origami Pay、pring、d払い、Amazon Pay、Pay ID、pixiv PAY、Sma-sh Pay、EPOS Pay、&Pay、atone、銀行Pay
  • 参入予定: メルペイ、ゆうちょPay、7pay、Bank Pay、au PAY、ファミペイ、Payどん
数が多過ぎて比較する気も起きないのですが、私は「Webサービスで」どれを使うかだけは興味がある。 今回Webサービスで少額決済を実現するに当たってどのようなサービスを使えば良いかを選定したので、その思考の過程をメモとして残しておきます。


大前提としては、少額決済は少額になればなるほど、気軽に払えるかどうかが鍵と思っている。 決済手数料、月額利用料は低ければ低いほど良いし、固定手数料は0が基本だろう。 実はこの条件の時点で大半のサービスが脱落する。

他にも覚えるのが大変なクレジットカードを毎回入力するより、 覚えるのが簡単なログインIDによる決済や、QRコード決済のほうが優れるだろう。 手数料は日々変動するのでまとめるのが大変だから、今回は主にこのユーザビリティの部分についてまとめておく。


1. ログインIDによる決済

良い言葉がなかったので適当に名付けたのですが、ここではクレジットカードを事業者に記憶してもらい、ログインIDだけで決済する方法を指している。 ログインして即支払いが完了すれば、毎回入力するより遥かに楽です。 一般的にはメールアドレスとパスワードを使ってログインIDと紐付けるため、 新規事業者がそのような仕組みを提供しようとする場合、メールアドレス、パスワード、クレジットカード番号を保存する必要が出てくる。 ただどこの誰かもわからない適当サイトにクレジットカード番号を教えるのは、不正利用や情報漏えいのリスクが伴う。 そのへんがログインIDによる決済の弱点だと思う。 いずれその辺で選別がなされていくと私は思っていて、そこをクリアしている決済サービスだけが生き残っていくのではないでしょうか。 私はPAY.JP Checkoutは良い仕組みだなと思いました。

ログインIDによる決済サービスは山のようにあってまとめるのはギブアップ気味だし、本ページの趣旨とは外れるので、参考になったまとめサイトだけ載せておきます。

2. OAuthによる決済

先に述べたクレジットカード番号の入力の手間やトラブルを解決する方法はあります。 信頼のおける大企業のログインIDにOAuthなどの仕組みを使ってログインし、決済すれば良い。 信頼のおける大企業がクレジットカード番号を管理する事で、情報流出もクレジットカード被害も最小限に抑えられる。 ちなみにログインIDによる決済を行っているサービスでも、メールアドレスやIDとトークンと結び付けて管理すれば十分実現可能なのですが、わざわざメールアドレスを登録するのは面倒なのではないかとも思いますし、運用側にとってもそのような手間を省きたいと考えるのは自然だと思います。

OAuthによるトークン決済を採用したサービスは徐々に増えてきていて、例えば今なら米国企業のStripe, Google Pay, Microsoft Pay, Apple Pay, Amazon Pay, Facebook Pay、中国企業のAlipay, WeChat Payなどの巨大プラットフォーマーのOAuth決済が日本でも利用できる。 上記に書いた企業と比較するとややマイナーですが、日本企業でもPAY.JP Checkoutというものがあります。

米国大企業のほぼすべてが自社ログインIDを採用しているのは印象的で、実にわかりやすいプラットフォーム戦略だと思う。 その中でGoogle Pay, Microsoft Pay, Apple Payは決済の外側だけを用意しているだけで、実際にはStripeSquare、クレジットカード会社などのプロセッサーが必要になっていて、そこで決済手数料が掛かるようになっている。このへんの料金の話も、最初は安いかもと思ったものが実は高かかったりと割とハマったので、実際に実装してみて気付いた話も参考にしてみてください。

中国のAlipay, WeChat Payも手数料無料です。 この理由は、消費者金融機能からの収益、公的機関から手数料を取る仕組み、支払い履歴のビッグデータ活用などと言われている。 現金化時に0.1%の手数料を取られはするが、ほぼ手数料を取られないというのは、なかなか強い仕組みだと思う。

3. Payment Request APIによる決済

Microsoft PayApple Payは、W3Cによって標準化されたPayment Request APIを用いた決済サービスです。 Google Payは利用しても動作するし、利用しなくても動作する。 それ以外のサービスとしては、Samsung PayPayment Request APIを利用しているみたい。

Payment Request APIはブラウザに対応するプラットフォーマーのネイティブな決済基盤が立ち上がる仕組みになっている。 ネイティブ実装なので起動が早いのが特徴だと思う。 ChromeでAPIを呼び出すとGoogle Pay、Edgeで呼び出すとMicrosoft Pay、Safariで呼び出すとApple Payが起動するような要領である。 おのずとプラットフォーマーがネイティブの実装をしていなければ機能しない仕組みになるような気がするのだが、そのせいもあってかFirefoxはAPIの実装はされているものの、Payment Request APIでの決済はできない。

Payment Request APIに関する部分だけはほぼ同一のコードで様々なプラットフォームでの決済に対応できるようになるのが良い点です。ただこれも実際に実装してみるとそんなに簡単なものじゃないですけどね…。

4. QRコード決済

では最近流行りのQRコード決済はどうか。QRコードはメールアドレスを入力するより楽なのは確かです。 ただ事業者、特にWebサービスやアプリの開発者からすると簡単な話じゃなくて、セッションの問題が出てくる。 QRコードで決済する場合、QRコードで商品を選び、決済アプリからトークンを取得し、そのトークンに基づいて決済を行う。 しかしサービス側と決済を行った端末にはセッション上の繋がりがないので、 ユーザは支払いをサービス側に何らかの手段で通知する必要がある。 この手段としてはログインIDやトークンが必要になるのだけど、トークンの入力は煩雑で現実的ではない。 ようするにやっぱりログインIDを管理しなきゃ簡略化できないじゃんという事になってしまう。

QRコード決済は信頼のおける基盤を持たない事業者や、非IT業者には良さげに見えるかも知れないけど、 そうではない場合、現状では大手のログインIDに委託する決済よりコストが高く付いてしまう。 既にセッションに対応しているのもあるかもだけど、多過ぎてもうよくわからんし…。 いくつかのAPIを眺めている限りではそのような事を感じました。 コストが高く付く実例としては、PayPayでクレジットカードの不正利用の話が少し前にホットになりました。 QRコード決済のセッションが分断されて、そこに人の手が入ってしまう事もあって、中間者攻撃が成立しやすかったせいもあった事件かなと思ったりします。 実際にサービスを運用する上ではそういった事も注意しないといけないです。 なんちゃら祭りというのはハッキングの格好の標的になりやすいですしね。 中国では既にハッキングが結構大きな問題になっているようで、この記事を読むと様々な手口がわかります。 非常に参考になる記事なので一度読んでみると良いかも知れません。

リスクのあるセッション回りは自動化したほうが絶対良いと私は思うし、実装自体は簡単だと思うので、そこを一括処理してくれる機構はいずれどこかが実装してくるのではないかと考えています。 仮にそのようなサービスが出てきたら、QRコードでWebサービスのログインができるようになるはずで、その時が一番面白い瞬間かも知れません。 Webサービスでの利用は、そのようなサービスが出てくるまでは待ちです。

QRコード決済サービスも、ログインIDによる決済と同様の理由で、よくまとまってると思ったまとめページだけ記載しておきます。

5. その他様々な個人間決済

最近は色々な個人間決済アプリが出てきています。 米国ではVenmoが有名ですが、Square Cashとかも出てきました。 日本ではPaypalが個人間決済に対応した事は記憶に新しいですが、Kyash, paymo (終了予定), polcaなど、形を変えて様々なサービスがあります。他にも何かあるかな? これらもQRコード決済と同様で、セッションの問題が発生しない取引なら良いのですが、セッションの問題が生じるWebサービスでは使いにくい。 というかおそらくQRコードより実現可能性は低い状態だと思います。 ただこういったアプリがたくさん出てきているのを見ると、個人間決済は世界的にも流行なのかなあ。


このような現状を踏まえた結果、私は自前でログインIDを管理しなければいけない少額決済サービスへの対応と、QRコード決済への対応は後回しにし、まずはStripe, Google Pay, Google Pay + Payment Request API, Microsoft Pay, Apple Payに対応してみようと思いました。 その後実装を進めるとやっぱ対応しなくても良いかなというものもあったり、やっぱこっちのほうが良いじゃんという事もたくさんあったりしました。 なので実際に実装をしてみて気付いた事をまとめたこちらのページも参考にして頂けると幸いです。