tomoima525's blog

Androidとか技術とかその他気になったことを書いているブログ。世界の秘密はカレーの中にある!サンフランシスコから発信中。

結婚式でLINE Message APIを使った写真共有サービスを作った話

f:id:tomoima525:20171016191718j:plain:w400

先日結婚式を挙げました。式中ご参列いただいた方と簡単に写真を共有したいなと思い、そういうマイクロサービスを作ってみました。ここではどのように実装していったのかを記憶が薄れぬうちに書いていこうと思います。

着想と仕様

自分が結婚式に参列する時、写真を撮るものの、主賓に送りそびれることがよくあって、だったらそのままさくさく送れたら楽じゃんねーと思っていました。で送りっぱなしだとグルーブ感がないので、出来たらその場でシェア出来たらよいかもと考えていました。それを踏まえて仕様としては、

  • その場でサクサク送れる
  • 送った写真をリアルタイムに共有できる

ことを目指しました。

全体構成

全体構成は以下のようになっています。

f:id:tomoima525:20171016191745p:plain

LINE Message APIを使ってLINEのチャンネルを参列者に登録してもらい、そこから写真を投稿してもらいます。webhookを介して画像データをサーバーに渡し、CDNに保存したのち、WebSocketでスクリーン側(ブラウザの全画面表示)に更新通知を投げて画面を更新しています。

クライアントサイド

当初、写真を送る部分はReactNativeでiOSAndroidアプリを作る想定でした。しかしiOSでのアプリ公開のハードルは非常に高いです。テスト用に公開するにしても審査を通らなくてはならず、個人の結婚式用アプリだと到底通らないですし、デプロイゲート等の配信サービスを使う場合でも端末単位でプロファイルIDが必要だったりします。そこでどうしようかと模索していたところ、皆がまず間違いなくインストールしているLINEを利用することを思いつきました。

LINE Message API
サンプルやドキュメントが充実しており、とても簡単に扱えました。チャネルはTrial,Free,Proがありましたが、100人以内のログイン&チャネルからポストしないであればFreeが良いです。

サーバーサイド

リアルタイムに共有する部分については、スーパーハッカー夫婦の@hatoneさんと@kyoroさんが以前ご自分達の結婚式でやはり写真を共有するサービスを作っていらっしゃったので、実際に相談に行きました。画像のCDNとしてCloudinaryを使う点やWebsocketで更新を通知しビューを更新する点などはめちゃくちゃ参考にさせていただきました。足を向けて寝られません。

Framework
ミニマルな機能でマイクロサービスを作るのにうってつけなサービスであるFlaskを利用しました。ドキュメントは若干散らばっていてわかりにくい部分もありますが、シンプルなサービスを作るのには適していると思います。ORMとしてはSQLArchemyを利用しています。ただ途中から導入したので部分的に生SQLを叩いている所もあります。

Pythonプロフェッショナルプログラミング 第2版

Pythonプロフェッショナルプログラミング 第2版


Flask Web Development: Developing Web Applications with Python

Flask Web Development: Developing Web Applications with Python

CDN
Cloudinaryは画像に特化したCDNです。Cloudinaryの優れた点として画像の加工が容易な点が挙げられます。例えば300px,300pxサイズで画像を作り隙間部分は黒色としたい場合、

https://res.cloudinary.com/xxx/image/upload/c_pad,b_black,h_300,w_300/%s.jpg'

というようなリクエストを投げるとよしなに画像を生成してくれます。
またフリープランがとても充実している点もおすすめです。月間20000枚の画像加工と300000枚の画像と動画を扱えるので、結婚式サービスくらいなら十分カバーしてくれます。

Server
リージョンが日本にもあるGAEとも迷ったのですが、Herokuを利用しました。理由としてはHeroku CLIが使い勝手が良かったということがあります。サポートしているDBもPostgreSQLで、FlaskのローカルDBがSqliteなので親和性が高いです。

FrontEnd
jQuery部分は知識がほぼ皆無だったのですが、Kyoroさんから教えていただいたコードを参考になんとか実装しました。ライブラリ群はWebpackでまとめました。Webpack便利ですね。

実装期間

結婚式約3週間前にサービスを作ることを思い立ち、週末や飛行機内でぽちぽち書きました。

残ってしまったバグ

画像が欠けてしまう問題

LINE Message APIの不具合なのかサーバー側の問題が切り分けができなかったのですが、受け取った画像の下部が途中で切れてしまうという不具合がありました。結局解決できなかった。

WebSocketの動きが怪しい

WebSocketがたまにうまく動かず、更新の通知を受け取れない問題がありました。リロードするとうまくつながったりするのですが、この辺の知識が浅いこともあり、いまいち原因がわかりませんでした。

そしてあやうく炎上案件に

当日実際に式場で動かしてみると、ソケット通信がうまく動かないという事案が発生しました。元々結構不安定だったので、その場で何度かサーバーをやブラウザをリロードして対応しました。

実際どれくらい使われたの?

約7割の参列者がLineチャネルを登録し、160枚近くの写真が投稿されました。実はQRコードを一部のテーブルにしかシェアできていなかったので、皆が登録できることを知らなかった可能性があります。事前にQRコードを積極的にシェアしておくのがよいです。

f:id:tomoima525:20171016191927p:plain:w400

全然関係ない写真なんかもポストされていて微笑ましかったです

参列からの反応

  • LINEで送れるので楽!面白い!という反応もらいました
  • まじでこの場でデバッグしてるんですね?(そうなんです)
  • 有料で売れるんじゃないですか?と色んな人から言われました。結婚式で動かなかったら責任重大やで...。

その他気づいたこ

  • 可能な限り式の事前にwifiが使えること、プロジェクタのサイズを把握しておくべき
  • QRコードはわかりやすいところに置いておくこと
  • いつでもデバッグできるようにひな壇のテーブルにはパソコンを置くスペースを確保

他のイベントでも使えるかも

ということでちょこちょこメンテしつつ、普通のパーティなんかでも使ってみようと思います。ソースコードは以下で公開しております。もし何かのイベント等でつかいたいという場合はもちろん大丈夫ですが、上記で述べたバグがあるので、うまく動かなくても責任はもてませんことをご承知ください。また、一言連絡いただける(&どんな風に使われたか等をシェアいただける)と大変うれしいです。

github.com

Flow導入して数ヶ月がたった所感

f:id:tomoima525:20171003132858p:plain
ReactNativeプロジェクトで、型がないことによるつらいシーンが多くなり(特に変数の解釈に起因するバグ)、Facebook製の静的型解析ツールであるFlowを数ヶ月前に導入しました。導入時の学びと、しばらく運用して感じていることについて個人的な感想を書きました。

Flow選定理由

Javascriptで静的な型付けをするといえばTypeScript(正確にはJavascriptのスーパーセット)がありますが、プロジェクト途中からの導入しやすさの観点からFlowにしました。Flowはお作法(行頭に @flow つける等)さえ押さえれば誰でも使えることから導入障壁はだいぶ低いといえます。導入のメリットについては以下のスライドがとてもわかりやすいです。

speakerdeck.com

flow status でプロジェクトに対して静的型解析を走らせることもできますが、 コーディング時にワーニングを出す方が便利です。Atomを使っている場合、Nuclideを導入し、Flowの設定をするだけです。

導入時の学び

Flowのドキュメントに従うと手こずる

素直にFlowのinstallationドキュメントを参考にすると、node_module配下のflowアノテーションが付いたファイルも解析されてしまい大量のエラーが出ました。実はそもそもReactNativeは標準でFlowに対応しているため、Flowのドキュメントを参考にする必要がありません(むしろうまくいきません)。完全に罠ですね。

ReactNatveでFlowを導入する場合は、以下のようにします。

  • rootディレクトリにある.flowconfigの中身をみてflowのversionを確認する
[ignore]
; We fork some components by platform
.*/*[.]android.js
...
[version]
^0.38.0
  • yarnやnpmでflowを追加します
npm i flow-bin@0.38.0 --save-dev

これだけです。

参考:
medium.com

なお、もし無理やりFlowのinstallation手順で行く場合は、 .flowconfig にいくつかの設定を行いnode_module/配下を解析対象から外すように出来ます。

[ignore]
; Ignore templates for 'react-native init'
.*/local-cli/templates/.*

; Ignore "BUCK" generated dirs
  <PROJECT_ROOT>/\.buckd/
            
.*/Libraries/react-native/React.js
.*/Libraries/react-native/ReactNative.js   
; Ignore react related flow in node module
.*/node_modules/react-native.*/.*
.*/node_modules/fbjs/.*

上記の場合、Moduleが認識されなくなるのでreact-nativeのModuleについてStubを作る必要もあります。

declare module 'react-native' {
  declare var exports: any
}

参考:
github.com github.com

一部のモジュールが認識されなかった

例えばフォーマット関数を持つIntlクラスはオブジェクトとして認識されず、エラーが出ます。

const mmyy = new Intl.DateTimeFormat(ENV.LOCALE,...)
                 ^^^^ identifier `Intl`. Could not resolve name

こういったオブジェクトは型を明示的に定義して上げる必要があります。

type IntlType = any;
const intl: IntlType = window.Intl;

const mmyy = new intl.DateTimeFormat(ENV.LOCALE,...)

参考: github.com

数ヶ月運用した所感

Flowを使い始めてしばらくたった個人的な感想をつらつらと書きます。

良かった点

スピーディな型チェック

コーディング中に型チェックが行われるのでまずい実装をしているとすぐわかります。また↓のように定数の打ち間違いなども適宜指摘してくれます。いくつかの潜在的なバグが洗い出されたのは良かったです。

f:id:tomoima525:20171003132624p:plain
PhoneVerificationTypeにreset_to_initial_stateというPropertyが定義されてないと教えてくれている

ラーニングコストの低さ

導入も含め、ラーニングコストが低いです。型の作り方も初歩的なものであれば容易に理解できますし、TutorialもReactやReduxで導入する方法など充実してます。なおTypeScriptはDocumentをちょろっと読んだ程度なので、比較はできてないです。

課題点

誰かが率先していかないと導入は進まない/効果は低い

Flowはあくまでもコーディング中にWarningを出すだけなので、強制力はありません。@flowアノテーションをつけないとWarningもそもそも出ません。なので、チームがメリットをよく理解した上で率先して導入していかないと、導入率は上がらないです。その点で言うと型を強制するTypeScriptの方が良いかもしれません。

バニラなJavascriptではなくなり、コード量が増える

当たり前な話なのですが。FlowはJavascriptに型を与えるものなので、正確にはJavascriptとは呼べなくなります。例えば、React ComponentにFlowを適用すると、propTypes等の型定義が必要になります。これにはFlowの特有の記法が求められます。またpropsの型定義を追加すると当然ながら若干コード量が増えます。いざFlowを辞める場合(ないとは思いますが)、このような変化はチーム内で合意を得ておく必要があると思います。

結局全てに導入しないと本当の恩恵は受けられない

例えばあるクラスにFlowを導入した場合、呼び元のクラスがFlowに対応していない場合は当然警告が出ないです。なので導入が進まないと目に見えた効果が出てこないな~と思いました。途中から導入する場合でもガガっと全てにFlowを適用する方がよいのかもしれません。

まとめ

三行でFlowについて思う所を述べるとこんな感じです。

  • 導入は非常に簡単、ラーニングコストは低い
  • 型付けの恩恵を十分に得たいのであれば最初から導入したほうがよい
  • 型を強制するものではないので、チーム全体が意識を持って利用しなければ効果は薄い

中規模チームスプリントでSlack上のコミュニケーションが抜群に取りやすくなったひとつの方法

チーム規模が大きくなってくると、メンバーでコミュニケーションを取る際のストレスがだんだん上がってきます。特にSlack上でのやりとりは関係者が増えると複雑になりがちです。この点に関してここ最近、明らかにコミュニケーションの質が向上したチームの取り組みがあったのでシェアします。

中規模チームにおけるSlackコミュニケーション課題

プロダクトチームはPM、デザイナー、エンジニア、データサイエンティスト含めて30人弱。同じスプリントを回すチームとしては少々大きいサイズです。結果としてチームとしては1単位ですが、あらゆるその中でタスクが並行して走っており、それぞれが色々な粒度のタスクを掛け持つような形になっています。
チームで使っているSlackのチャンネルは以下のような感じで分かれています。

  • product-channel: プロダクト全般の仕様
  • dev-channel: 開発レベルの仕様
  • design-channel: デザイン系
  • dev-*-channel: 各プラットホーム(Android, iOS, サーバーサイド)の技術検討

f:id:tomoima525:20170924150517p:plain:w400

その他リリースやアラート専用のチャンネルもありますが大体上記が全てです。
ここで発生していたコミュニケーション問題が、複数のタスクの内容が並行する問題です。

  • AさんとBさんがXの仕様を話していて、一方でCさんとDさんがYの仕様を話すと混線する。スレッドを使うと、議論が埋もれてしまう(Xに関係しているEさんが気付かない)
  • 一つのタスクに関しての議論が飛び飛びになる。例えばSlack上だと
(Aの内容の議論1)
(Bの内容の議論)
(Cの内容の議論)
(Aの内容の議論2)

と言ったように話し合いがとぎれとぎれになるので、あとでもう一度確認したい時にとてもストレスフルになる。

小タスク単位でチャンネルを個別に作る

上記のような状況に対して、小さなタスク単位でSlackチャンネルを作ってみました。具体的にチャンネルを作る基準としては、1スプリント単位で完了するタスク(機能)レベル以上にしています。現チームのスプリントは2週間なので、その期間で完了する見込みなタスクがスタートするとチャンネルを作ります。

pj-A-channel
pj-B-channel
...

f:id:tomoima525:20170924150555p:plain:w400

チャンネルに招待されるのはそのタスクのステークホルダーです。うちの場合ですと、エンジニア(クライアント、サーバー)、PM、QA、デザイナーで平均6人程のチャンネルになります。チャンネルのトピックにはConfluenceの仕様リンクを貼っています。ここで行われる議論はどう機能を作っていくかにフォーカスします。

  • 進捗共有
  • 仕様の詳細な認識合わせ
  • リリーススケジュールの共有

毎日のスタンドアップは全体で行い、小チーム単位では行いません。その他、直接会話した方が早いような話ではもちろん対面で話したり、メンバーがリモートにいればハングアウトなどを行います。その内容もSlackのチャンネルに議事録的に貼ったりします。↓

f:id:tomoima525:20170924154205p:plain:w400

チャンネルは機能のリリース完了後には閉じます。

このSlack運用に変えた結果以下のような効果がありました。

  • 議論がスレッド上でクリアになるのでコミュニケーションの負荷が下がる
    議論はそのチャンネルに集約されるので、どこで話しあったっけ、という問題はなくなります。
  • 自分のタスクに関する集中力があがる
    今までは自分と関係ないタスクに関するポストも全て dev-channelproduct-channelに投稿されていたので、通知に煩わされたり、あるいは重要なポストを見過ごすということがしばしばありました。一方で今はタスクチャンネルはアサインされたメンバーしかいないので、何かコメントがあれば必ず自分に関係する内容になります。結果として必要な時に必要な情報が得られるので、タスクに対する集中力が上がりました。

チャンネル増えすぎる問題

一方で発生する問題として、Slackでありがちなチャンネル増えすぎ問題があります。コレに関してはトレードオフな部分もあるのですが、なるべく関係ない人は招待しないことで少しは緩和できるのかなと考えています。例えばトラッキング等メンバーとちょっと会話できれば済むようなことはpj-チャンネルに呼ぶことはせず、devで済ますようにするなどの配慮をするようにしています。

まとめ

結局のところ、Slackにおけるコミュニケーションの問題はいかに粒度を小さく出来るかが重要なのかなという感じです。もちろん1to1のコミュニケーションが一番良いですが、それだとチームとしてスケールしません。なので、適切なサイズを見計らってチャンネルを動的に作っていくのが大事なのかなと思いました。

皆既日食 in アメリカ 2017

8/21/2017の皆既日食を見てきました。興奮冷めやらぬうちに旅行録を写真とともに残しておきます。

日食を見るまで

皆既日食アイダホ州のWeiserという地域の近くにあるMann Creekというところで観測しました。ここは奥さんの知人の天文ファン(本人曰く”めちゃくちゃ天文マニア”)の方が一年前から天候、日食経路、周辺環境を踏まえて選定した場所です。

f:id:tomoima525:20170823161415p:plain:w400

アメリカで皆既日食が見られるのは38年ぶりで非常な混雑が予想されるということもあり、日食の前々日に現地最寄り(と言っても100km離れている)のボイジというところに入りました。

どこに行っても「日食見に来たの?」と言われ、日食グッズもそこかしこで売られていました。

f:id:tomoima525:20170819181241j:plain:w400

前日はやはり混雑を懸念し、早朝にはボイジを出てMann Creekに向かったのですが、思った以上に空いていました。多くの人がより気軽に鑑賞できる場所に向かったようです。場所の選定大事ですね。

現地に朝9時半頃に到着しテントを立てた後は、合流した方たちとBBQをしたり本を読んだり過ごしました。気温は36度前後あり、乾燥していてとにかく暑い。テント場なので周りにもいくつもテントやキャンピングカーがあり、目の前の池で泳いだりしてのんびり過ごしていました。

キャンプ場
f:id:tomoima525:20170821103711j:plain:w400

テントだけだと蒸し風呂なのでタープを貼って日よけ
f:id:tomoima525:20170820102459j:plain:w400

$5の使い捨てグリルでBBQ
f:id:tomoima525:20170820162709j:plain:w400

観測器具セットアップ
f:id:tomoima525:20170820102505j:plain:w400

日が暮れにはとても美しい夕焼け空と夜には綺麗な天の川が空にかかっているのが見えました。
f:id:tomoima525:20170821115824j:plain:w400
f:id:tomoima525:20170821154351j:plain:w400

いざ皆既日食

皆既日食にはサロスと呼ばれるいくつかの周期があるそうです。今回のサロスは比較的短いもので、最長約2分40秒の皆既日食です。なお日食は英語で Solar Eclipse ですが、皆既日食は特にTotal Solar Eclipseあるいは Totality と言います。Totalityって響きがカッコイイですね。

最初の部分日食は現地時間AM10時15分ごろからスタートしました。この段階ではまだ実感はほとんどわかず、観測している人たちもワイワイしています。

f:id:tomoima525:20170821112343j:plain:w400

部分食は日食グラス越しでないと欠けている様子はわかりません。しかし11時頃になるといよいよ太陽が欠けてきて、空は青みが増し、気温が明らかに下がってきます。さっきまで飛んでいた鳥がいなくなり、静かになったのが印象的でした。 ピンホール越しに光を映すと、月形に影が変形しているのがわかります。

f:id:tomoima525:20170821110759j:plain:w400
f:id:tomoima525:20170821111536j:plain:w400

そして11時33分。いよいよ皆既日食の瞬間がやってきました。

あっという間に周囲が暗くなり、太陽は周辺部のみゆらゆらと輝きを放ちます。一方地平線は赤みを増し、まるで夕焼けのよう。

とにかく不可思議な風景に「ヤバイ」しか言葉が出てきませんでした。カメラを準備していたのですが、とてもちゃんと撮影する余裕などなかったです。息を呑むことしかできないほどあっという間の美しい自然現象でした。

観終わった後

日食を堪能した後は再び気温も上がってきたので、早々にテントを畳んでボイジへ向かいました。同じような帰り道をたどるキャンパーたちのためか通常より1.5時間くらい長くかかりましたが、他の観測地では通常2時間の道が7時間になったそうです。比較的空いている場所でよかった。そのままボイジに一泊して、次の日サンフランシスコへの帰路につきました。

ところでアイダホ州は白人が84%もいるらしく、レストランやお店に入っても自分たち以外全員白人ということが何度もありました。会う人会う人とても親切でフレンドリーだったのが印象的でした。

f:id:tomoima525:20170822094542j:plain:w400
The Potato Capital of the U.S.

旅費

以下に忘備録的に経費を残しておきます。奥さんの分のキャンプ道具を揃えたりテントを買ったりしたこともあり、$500程使いましたが旅行自体は二人で$1200程度でした。飛行機を5ヶ月前に予約していたので、値段が高騰する前に買えたのが良かったのかもしれません。

飛行機 * 2人分 $434 レンタカー $280 ガス $20 (約200km分) Airbnb $80 Hotel $180 外食 $100 キャンプ場での雑費(BBQセットその他) $70 キャンプ道具(テントその他) $500 雑費(お茶等) $50

合計 $1714

Kotlinの標準ライブラリ(let, apply, with etc)を何となく使うから卒業する

f:id:tomoima525:20170804154058p:plain:w400

Kotlinの標準ライブラリ便利ですよね。Kotlinを書き始めて T.?let{ } の便利さには感動しました。標準ライブラリ色々ありますが、どんなものがあり、どういう挙動をするのかよく把握していなかったので、自分の勉強のために*1まとめてみました。

*1:多分Qiitaにはまとめてあるのだろうけど

続きを読む

React Native Meetup Portlandでハイブリットアプリ開発について話しました

先日React Native Meetup Portlandという勉強会でReactNativeとNativeのハイブリットアプリ開発について発表をしてきました。アメリカの自社開催以外のの勉強会で発表することは初めてだったので、知見と反省をメモしておこうと思います。

続きを読む

Project Fi 2ヶ月使ってみた所感

f:id:tomoima525:20170604235902j:plain:w400
通信キャリアをT-mobileから Googleが提供するモバイル通信サービスであるProject Fiに乗り換えて2ヶ月ほど使ってみたので、その感想です。

Project Fiとは

いわゆる格安SIMのグローバル版のようなものです。特徴としては

  • 複数のキャリアの中から接続が良好なものを自動的に切替え、品質の高いモバイル通信が可能
  • 世界135カ国で利用可能な電話番号、モバイル通信が提供される
  • モバイル通信料は一律 $10/1GBで、利用した分だけ課金される(例 0.65GB = $ 6.5)

少々古いのですが、Gigazineで紹介された記事があります。

gigazine.net

複数のキャリアから良好なものを選べるという点はGoogleならではな特徴だと思います。

続きを読む