tomoima525's blog

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

アメリカ西海岸に移住して2年がたった

f:id:tomoima525:20170926184032j:plain:w400
アメリカのベイエリアに移住して2年がたってしまいました。タイトルはベイエリアよりもキャッチーかなと思って"西海岸"にしました。ちょっとした節目であるので、環境や心境の変化などをつらつらと書きとめておこうと思います。

続きを読む

Dagger2 + KotlinでEspressoのInstrumentation test を書く

Instrumentation Testを書く時、実際にAPIリクエストは行わせず、APIレスポンスをmockしたいですよね。方法としては2通りはあるかと思います。

  • Gradleで Test flavorを作り、APIを差し替える
  • Dagger2を使い、mockをinjectする

mockの値を変更するのが容易なので、2番目の方法がおすすめです。しかしながらDagger2でmockを依存性注入するのは結構面倒で、実際テストを書き始めるまでにいくつかステップが必要です。この記事ではDagger2とKotlinを使ってEspresso instumentation testをを書く方法を説明します。

続きを読む

React Nativeハイブリッドアプリケーション開発ことはじめ

こちらはReact Nativeアドベントカレンダー 19日目の記事になります。

ここ1、2年でReact Nativeによるアプリ開発はますます盛んになっていますが、一方でNativeと組み合わせたとハイブリッドアプリケーション開発はまだ発展途上です。 React Nativeの公式ドキュメントにもIntegrating with existing appという項目がありますが、あっさりと書かれている上に鮮度がお世辞にも高くありません。

しかしながら、FacebookAirbnbなど大企業がハイブリッドアプリケーションを積極的に導入していることや、Nativeアプリを部分的にリプレイスできる利便性から、今後も採用が増える分野と考えられます。本記事ではハイブリッドアプリを開発した自分の経験から、プロコンや実装の基本についてまとめました。

続きを読む

結婚式で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のコミュニケーションが一番良いですが、それだとチームとしてスケールしません。なので、適切なサイズを見計らってチャンネルを動的に作っていくのが大事なのかなと思いました。