hamburger

主に日記

Firebase Cloud Functionsで定期実行してみる

前回

hamburger.hatenablog.jp

定期実行するためには、対象プロジェクトのプランをBlazeに変更する必要がある。 これは、functionを通知するためのGoogle Cloud Pub/Sub と定期的に通知する Cloud Scheduler API を利用するためらしい。
なお

Google アカウントごとに 3 つのジョブを無料で使用できる

とのことなので、動作確認して見るだけならば無料でできそう。プラン変更直後にアラートを設定できるので、デフォルトの$25でメールが来る様に設定はしておいた。

実装は簡単で、functions.pubsub.scheduleを利用してfunctionを実装すればデプロイ時に適切に設定してくれるらしい。

exports.scheduledFunctionEvery1Minutes = functions.pubsub.schedule('every 1 minutes').onRun((context) => {
    console.log('This will be run every 1 minutes!');
    return null;
});

デプロイ後にコンソールを確認したところ、たしかに定期実行されておりGCPのコンソール上にcronジョブに関する記載が増えていた。 なおこのジョブを削除したいときはコンソール上で消すのではなく、jsの関数を削除するようにする。そうでないとcronやpub/sub、関数に不整合が発生した際にエラーが出るとのこと。

試しに上記関数をコメントアウトして再デプロイしてみたところ、 confirmはあったもののデプロイ後は一連の設定がコンソール上から消えていた

Firebase Cloud Functionsでfirestoreに書き込む

前回はチュートリアル通りにRealtime Databaseへの書き込みを試したが、最近だとFirestoreを使うことが多いような気がする(気のせい?)。
同様のfunctionでFirestoreにも書き込むようにしてみた

hamburger.hatenablog.jp

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp()

// firestoreへの書き込みサンプル
exports.addMessageToFireStore = functions.https.onRequest(async (req, res) => {
      // パラメータを取得
      const original = req.query.text;
     // realtime databaseと違うのは、firestoreを指定してるところ
      const writeResult = await admin.firestore().collection('messages').add({original: original});
     // realtime databaseではドキュメントへのリンクにリダイレクトしたが、firestoreではやり方が分からなかった
      res.json({result: `Message with ID: ${writeResult.id} added.`});
});

参考にしたリポジトリ

github.com

Firebase Cloud FunctionsでRealtime Databaseに書き込む

前回

hamburger.hatenablog.jp

公式を見ながら進めている途中

firebase.google.com

関数を書いてみる

index.jsにhello worldのコードがコメントアウトされた状態で記載されている。 ここは無視して最初の関数を記載する。

// const functions = require('firebase-functions');

// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions

// exports.helloWorld = functions.https.onRequest((request, response) => {
//  response.send("Hello from Firebase!");
// });

Cloud Functionsの設定と、Realtime Databaseにアクセスするための宣言をする。

// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions');

// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp();

次に関数の宣言 - httpリクエスト用の関数 - 同期的にリクエストをさばくためasyncを利用 - 最後にリダイレクトさせる

// Take the text parameter passed to this HTTP endpoint and insert it into the
// Realtime Database under the path /messages/:pushId/original
exports.addMessage = functions.https.onRequest(async (req, res) => {
  // Grab the text parameter.
  const original = req.query.text;
  // Push the new message into the Realtime Database using the Firebase Admin SDK.
  const snapshot = await admin.database().ref('/messages').push({original: original});
  // Redirect with 303 SEE OTHER to the URL of the pushed object in the Firebase console.
  res.redirect(303, snapshot.ref.toString());
});

デプロイする

$ firebase deploy --only functions

実行後、関数とoverviewのURL2つが表示される。

まずは関数を実行してみる。ブラウザ上で https://{個人のurl}.cloudfunctions.net/addMessage?text=hogehoge を開くと、Realtime Databaseのページにリダイレクトされた。

f:id:burgerham:20200429114328p:plain
パラメータに設定したテキストが保存されている

ちなみに別のテキストを再度URLを叩くと、updateではなくinsertとしてmessages配下に登録された。

別の関数を書いてみる

今度はRealtimeDatabaseのcreateをトリガーとして、対象テキストを読み取り、変換して保存する関数。

// Listens for new messages added to /messages/:pushId/original and creates an
// uppercase version of the message to /messages/:pushId/uppercase
exports.makeUppercase = functions.database.ref('/messages/{pushId}/original')
    .onCreate((snapshot, context) => {
      // Grab the current value of what was written to the Realtime Database.
      const original = snapshot.val();
      console.log('Uppercasing', context.params.pushId, original);
      const uppercase = original.toUpperCase();
      // You must return a Promise when performing asynchronous tasks inside a Functions such as
      // writing to the Firebase Realtime Database.
      // Setting an "uppercase" sibling in the Realtime Database returns a Promise.
      return snapshot.ref.parent.child('uppercase').set(uppercase);
    });

先ほどと同様にデプロイし、再度addMessageのURLを実行してみる。すると、messages配下にoriginalとは別に、uppercaseも登録された

f:id:burgerham:20200429115606p:plain
`thisisapen`と入力した結果

そのほか

cloud functions for firebaseの実態はGCPのcloud functionsらしく、overviewのページからGCPの管理ページに移動できる。関数の登録や更新もできそうなので、ローカルでやりたくない場合はこっちで編集するのもはありかもしれない

Firebase Cloud Functionsのローカル環境設定

環境整備

cliツールをインストールする。 日本語のget startedでは npm install -g firebase-tools を紹介されるが、初心者は curl -sL firebase.tools | bashを使ったほうがよいかもしれない。

firebase.google.com

なぜかというと、 npm: command not foundとなりそのメッセージを検索して色々やった結果、以前私用PCのnodeバージョンがめちゃくちゃになって挫折したから

ログイン

$ firebase login
Allow Firebase to collect CLI usage and error reporting information? # Yes
# ブラウザが開いてログインする

プロジェクトの設定

$ firebase init functions 
# webコンソール上で作成したプロジェクトを選択して言語はJS、それ以降は全てYesにした

functions/index.jshello worldらしき関数が見える

続きは次回

プログラマの数学 第5章 順列・組み合わせ

植木算

  • 算出する対象を正確に把握することが重要。
    • 長さ10メートルの道に1メートル間隔で木を植えたとき、必要な木の本数は? という問に対し、10という数字は木と木の間の数であり、木の本数ではない
  • 少ないデータ量で一般化した後に、大きい値の計算をするのが良い

和の法則

  • 和の法則が成立するのは、ダブリがない場合のみ
  • ダブリを見抜けるか

積の法則

  • それぞれに対して といえるか

置換

  • 階乗

順列

  • n - k + 1 の項の理解

組み合わせ

  • 順序で考えて、その後重複度で割る

プログラマの数学第2版

プログラマの数学第2版

  • 作者:結城 浩
  • 発売日: 2018/01/17
  • メディア: 単行本

ブログタイトル

メッチャどうでもいいことだが、 タイトルを 404 not found に変更したときは自分メッチャセンス良いじゃんとか思ってたのに、既にもっとちゃんとした人がもっとセンス有るブログで使っているタイトルだった。

かなc

blog.livedoor.jp

FirebaseAnalyticsのログデータを分解して扱いやすい形に変換する

FIrebaseAnalyticsのデータはコンソールのダッシュボード上確認できる。
ただし見れるデータは限られるため、詳細なデータを活用したい場合はBigQueryに保存されている生データを確認する必要がある。

2020/04/09現在、データは最新の日付のものが events_intraday_yyyyMMdd 、過去の日付のものが events_yyyyMMdd の形式で保存される仕様となっている(※いつからか日付ごとにパーテーションがきられるようになった)。

このテーブルの中に格納されているデータの形式が特殊で、1カラム内に配列で複数の値が入っているものもある(BigQueryで提供されている配列型)。

おそらくこういう形で格納されているはず。これで1レコード

event_date event_timestamp event_name event_params.key event_params.value.string_value event_params.value.int_value
20200408 1586311773017025 screen_view firebase_previous_id null 99999999
firebase_previous_class SampleActivity null
firebase_screen_class Sample2Activity null

これを以下のようにすれば通常の正規化されたテーブルの様に扱えるので、集計しやすくなる。

event_date event_timestamp event_name firebase_previous_id firebase_previous_class firebase_screen_class
20200408 1586311773017025 screen_view 99999999 SampleActivity Sample2Activity

配列型は unnest句を使えばよいという情報は多くヒットするのだが、ほとんどがfrom句でunnestせよという内容でその方法では別レコードに分かれてしまう。個別に利用するのならそれでも問題ないのかもしれないが、例えば複数のSQLから参照するための前処理として加工しようとしている場合はレコードが一緒の方が別カラムを組み合わせて検索条件を設定しやすく都合が良い。

前置きが長くなってしまったが、以下のようなクエリを書くことでフラットなレコードに変換できる。ちょっと冗長な気もするので別の良い方法が見つかったら再度記事を書きたい。

SELECT
  event_date,
  event_timestamp,
  event_name,
  (
  SELECT
    unnest_event_params.value.int_value
  FROM
    UNNEST(event_params) unnest_event_params
  WHERE
    unnest_event_params.key = "firebase_previous_id") AS firebase_previous_id,
  (
  SELECT
    unnest_event_params.value.string_value
  FROM
    UNNEST(event_params) unnest_event_params
  WHERE
    unnest_event_params.key = "firebase_previous_class") AS firebase_previous_class,
  (
  SELECT
    unnest_event_params.value.string_value
  FROM
    UNNEST(event_params) unnest_event_params
  WHERE
    unnest_event_params.key = "firebase_screen_class") AS firebase_screen_class,
FROM
  `テーブル名`;

ビッグデータ分析・活用のためのSQLレシピ

ビッグデータ分析・活用のためのSQLレシピ

Swiftのアクセサについて

微妙に覚えきれていないので調べた。swift実践入門から検討したほうが良い順にしてみる。スコープが小さい順で良いはず

private

対象の要素が属しているスコープ内のアクセスのみ許可する

fileprivate

同一ソースファイル内のアクセスのみを許可する

同一ファイル内で複数のクラスを記載しているときに使うもの?

internal

同一モジュール内からのみアクセスを許可する

普通の(単純なという意味)アプリならこれで十分そう

public

モジュール内外のすべてのアクセスを許可する。ただしモジュール外で継承したりオーバーライドしたりはできない

publicとopenは外部モジュールからの利用を想定するときに使うものとして考えていれば良さそう

open

モジュール内外のすべてのアクセスを許可する

継承やオーバーライドしたいときに使うイメージ

引用:

カラダファクトリーに3ヶ月通ってみた

きっかけ

ある日突然首の付根が痛くなった。原因は不明。上下左右に顔を回すと非常に痛い。

元々体の歪みからくる慢性的な肩こりなどは抱えていたが、仕事に支障をきたすのでマッサージを受けてみることにした。

家の近くにカラダファクトリーがあることを知っていて、営業時間が長くて融通が通いやすそうなのでそこに行くことにした。

初回の施術

ホットペッパーのクーポンを使い60分の全身コースをお願いした。 前半は事前に伝えた症状が出ている首周辺をマッサージしてもらい、後半は全身の調整をしてくれた。首は筋肉をほぐすだけでなく背骨の位置調整をふまえたストレッチもしてくれて、動きによっては骨のパキパキ音が聞こえて気持ちよかった。

終了後、施術結果を定着させるために定期的に通うことを勧められ、キャンペーン期間を利用してクーポンを購入して次回予約をしてきた。その後、最初の2ヶ月は週に一度、次の1ヶ月は二週間に一度のペースで通った。

施術後の変化

初回の施術直後は軽い揉み返しがあった。ただ、それ自体は元々そういうものだと理解していたのであまり気にならなかった。

最初は施術後2〜3日すると体の調子は元に戻っていたが、4回目くらいから1週間程効果が持続しているのを実感できた。全身マッサージの効果もあったのか、ここ数年で一番コンディションが良かった。首だけでなく腰の痛みも解消し、日常生活がかなり楽になった。

不満

通ううちに気になる点も出てきて、最初に購入したチケットがなくなったタイミングで通うのを止めた。

店舗の雰囲気

ざっくりいうと体育会系の雰囲気で、自分には合わなかった。リラックスしている横で大きな声の挨拶が繰り広げられると緊張する。他の不満はある意味、この雰囲気から引き起こされているのかもしれない。

言葉遣い

一般企業だと社外の人に対して社内の人を呼び捨てにすると思っているので、他の施術師のことを"〇〇先生"と言っているのが気になった。まぁこれは自分が気にし過ぎかも。

雑談内容

仕切りがないベッドが並んだ空間で施術するため、基本的に会話は他の客に筒抜け。なのに担当が「女ってめんどくさいですよねーーーw」みたいなことを平気で言ってしまうタイプで、聞かされている自分がヒヤヒヤすることがあった。

そもそもイキった大学生と会話している感じなので、「〇〇なんすよ〜w」「マジウザイっすよね〜w」みたいなノリに合わせるのが精神的に疲れた。

他の客とのコミュニケーション

自分の施術中に、担当が隣のベッドの女性客と整体師の会話に混ざろうとして明らかにマッサージが雑になっていることがあった。別に会話してもいいし僕と話してほしいわけではないが、そういうことがあると集中してくれと思ってしまう

指名と全身マッサージ

自分は知らない人と会話するのがそれほど得意ではないので、美容院などと同様に担当を指名していた。この指名は有料。カラダファクトリーでは施術師を指名しても担当してくれるのは前半だけで、後半は別の人に変わるシステムとなっている。特に説明がなかったが、「ここからは〇〇先生に変わりますね~」と言って勝手にチェンジされる。

別にそれだけなら良かったが、この後半の担当者がかなりの頻度で話しかけてくるタイプで、自分が興味のないアイドルオタク活動の話を延々と繰り広げる人だった。自分がよく行く時間帯の全身マッサージ担当なのか、かなりの確率でその人が担当。別に悪意があるわけでは無いだろうから愛想笑いと相槌を返していたが、施術後顔の筋肉だけ疲れていることが多く、この時間がかなり苦痛だった。

通わなくなった一番の理由は多分これ。

まとめ

休日も営業しているので、平日勤務の社会人は通いやすいかもしれない。施術のスキルも、チェーン店である程度保証されてそう。多分。

ただ、上に書いたとおり担当が指名した人とは限らないので、そのガチャが外れた時につらそう。当たりだったら自分も通い続けたかもしれない

Slackで思考ログを残すようにしてみた

きっかけ

僕は結構集中力がない。なので、目の前のタスクに集中できるように余計なタスクや懸念点はなるべく先に片付けてからまとまった作業時間を確保するようにしている。が、役割が増えてくるとそれをさばいている間に別のタスクが発生するようになってきた。最近だと対応中の新機能の仕様に関することの他にも、チームマネジメント関連や追加のバグ報告、作業中に気になった技術課題からプライベートな悩みまで、次から次へと情報がやってくる。そうすると問題を解決する欲求と、忘れる前にメモしておきたい欲求がぶつかり合って同時に違うことを考えて結局思考が堂々巡りになる、というケースが出てきた。更に、それによって思考が乱れて余裕がなくなってくると精神的にネガティブになりがちなので悪循環になりやすい。最近は自覚が出てきたので思考が乱れていると思ったらとにかく紙にメモをするようにしていたが、勢いで書いているのであとから読めないことが多く、最近の悩みだった。

急なひらめき

ところが最近ふと思考ログという単語を思いつき、それをどこかに常に残すようにすれば少なくとも自分の脳のメモリ不足は解決するのではと思うようになった。

googleで検索してみると、ちらほら思考ログで記事が見つかる。大体はブログかtwitterなのだが、思考ログというだけあって思いついた情報を人に見せない前提で書きたいし、各ハードルは極力下げていきたいのでそれらの手段はうーーんという感じだった。

twitter

アカウント切り替えをミスって誤爆する未来が見える。そもそもそんなにツイートしてないので、余計目立ちそう。会社の内部情報だと致命的なのでちょっと怖い

ブログ

ブログはある程度情報をまとめて発信するプラットフォームなので、短い文章を大量に送信するのは向かなそう。

そんなこんなで一週間くらい悩んでいたら、slackの自分の個人チャンネルが良いのでは?と思い試してみることにした。結果としてはかなり満足で、精神安定に寄与している気がする。

効果

f:id:burgerham:20200321222423p:plain
思ったことは書き捨てるようにしている。書いたら一度一区切りできるので必要以上にリソース取られることもなくなる

f:id:burgerham:20200321222532p:plain
プログラミング中考えたことはその時しか覚えていないことが多いが、少し書いただけでその処理の意図を思い出しやすくなる

メリットとデメリットを上げておく。

メリット

  • 業務で使用しているアプリなので、追加で色々設定する必要が無い
  • slack内で⌘ + kme で開けるので、ある程度短いアクションで投稿できる
  • slackのやり取りの結果何かを考えることが多いので、それのリンクを貼ったりしやすい
  • (ある程度)検索しやすい
  • 他の人からは普通に仕事をしているように見える(twitterとかは遊んでいるように見えかねない)

デメリット

  • 仕事に集中するためにslackを1時間に一度だけ開くように習慣づけようとしていたのだが、アプリを落とすわけには行かなくなったので別の手段を検討しなくてはならない
    • 特定時間以外は別チャンネルを開かないという鉄の意志を持つことで、回避している

意外とデメリットなかった。。。しばらくしてから見直すことで、振り返りとかに活かせないかなぁと思って運用中。

「はじめてのUIデザイン」を読んだ

peaks.cc

以前pdf版を購入していたのだが、会社に物理本があったのでようやく読むことができた。
モバイルアプリのデザインは基礎的なところをうっすら知っていたが、体系的に学びたかったのとこれを機にwebのことも知りたかったというのが主な動機。

前半はコンポーネントやプラットフォームごとの用語説明・歴史背景が書かれており、普段マテリアルデザインの範囲内でしかデザインを考えない自分にとってはiosやwebの考え方が参考になった。特にwebデザインは流行り廃りが早いイメージがあってそれほど真剣に学んでいなかったのが、ベースの部分がちゃんとできた気がする。

後半は要件の中から画面フローやサービス全体をどのようにデザインしていくか?にフォーカスされていた。デザイナ向けとして書かれていたが、結局UIデザインも課題抽出と要件定義が一番大事ということが書かれていた。エンジニアも同じようなことをやっているので、UIに対する興味の有無関係なく協力できそうだった。

総じて、はじめてのとついているだけあって内容がわかりやすく、デザイナ以外でもデザインを考えるはじめの一歩になり得る書籍だなと感じた

「テセウスの船」を一気読みした

きっかけ

www.tbs.co.jp

元々BackspaceFMで紹介されていたので興味はあって、今季のドラマを妻が見ていたので一緒に見ていた。タイムリープものと聞いていたので、僕のいない街のパクリのような先入観があったのだが全然違って面白かった。
ただ、一話目に若干の違和感を感じていたのが2話、3話と見続けるうちにそれが気になり始めて仕方がなくなり、結局ドラマを見るのが辛くなってしまった。

ドラマで辛かったこと

まずはじめに気になったのは映像の使い回しが多いという点。家族愛を表現したかったのだろうが、食卓を囲んで猪木のモノマネして笑っているシーンやマスコミに頭を下げているシーンは何回見せられたか分からない。重要シーンで出てくるならわかるけど、何か決断しようとするたびに出てくるので、途中から感情移入できなくなってしまった。
また、演技での表現が少なくて考えていることや感情をセリフで話しているシーンが多すぎた。「いや、ここでこんなことを言ったら・・・」「でもこの人は・・・」みたいな漫画だと四角く右上に出てくるようなやつ。
最後にこれは僕が見逃していただけかもしれないが、細かいポイントで情報が落とされている感じがして理解できないシーンが残ったまま進んでいたのが気になった。第一話で退場した三島千夏と佐野文吾が一緒に雪山行ったのなんでスルーしてんねんとか、そのお姉ちゃんを探しているシーンで翼くんがキョドってた理由とか。

漫画を一気読みした

そんなこんなでまとめ買いしてイッキ見した。
ドラマで辛かったことがすべて解消されて、どのシーンもドラマとの違いを比較したり答え合わせしたりしながら読めた。買ってよかった。事件に関する細かい考察やちょっと物足りない感じはしたけど、事件の全容が語られていないという設定だと思えば納得できた。
個人的には漫画のほうがテンポよくて変なテレビの演出が無いから良いと思っているが、妻は全く逆の意見だったので好みが分かれるかもしれない(ドラマのような感情表現が漫画にはなくて不満、絵が苦手など)。でも全10巻で起承転結しっかりしているので、色んな人に見てほしいなぁと思った。

「リファクタリング 既存のコードを安全に改善する」を読んだ

目的

リーダブルコードなどを通じてきれいなコードを書く方法は学んだことがあったが、既存のコードをどう改善していくか?について体系的に学んだことがなかった。(転職直後ということもあるが)新規実装よりも既存処理の改善や、機能追加が業務的に多いため、適切に改善する方法を学びたかった。
まえがきにもあるように、前半がリファクタリングに取り組むにあたって身につけておくべき考え方について、後半は系統別にリファレンス的な内容だったので、前半を一気に読み、後半は必要に応じて読みながら業務で活かしていきたい。YAGNI的な感じ

感想

  • 一般論の他に作者の主観も書かれていたのが良かった。
    • 例えば、関数の返却する戻り値はresultにして、返却するという意味を明確にするためらしい。Carクラスのインスタンスを返却する関数の戻り値のを carmyCar のようにしていたが、たしかにこれだと string int命名しているのと変わりないので、自分も真似しようと思う
  • (特に第一章は)タイトルやトピックの説明をするのではなく、実際の作者のストーリーを追いながらその課題に対して取るべきアクションを紹介されているので、自分の理解フローにあっていた
    • 説明的な本はリファレンス的には役立つけど、なぜ必要なのか?が気になってしまい個人的に苦手
  • 小さく変更し、小さく確定(commit)し、小さく確認する という明確な基準に沿っている。ほぼすべてのトピックはこれに集約されるので、とにかくこれを意識して業務に取り組む
  • 実装とリファクタリング、パフォーマンスチューニングは分けて取り組む。ただし、コンテキストの把握を容易にするためにコミット(masterへのマージのこと?)は分割する必要はない。
    • 一緒にやってしまうと局所最適になりがち
    • きれいに整理されたコードが準備されたときに全体を計測し、ボトルネックになっているホットスポットに対処したほうが良い成果を得やすい
      • 個人的には↑は特に意識してやりたい

Bonfire Android #6 参加メモ

Yahoo Japanさんが主催しているBonfire Androidに参加してきました。

yj-meetup.connpass.com

目的

  • キャッシュレス × Android のトピックのテーマってなかなか見かけないなと思ったので
  • この辺は流石ヤフーって感じ

内容

新 Kyash Card を支える技術

  • Kyashは人数が少ないので標準に寄せて学習コストを抑えてる
  • カードの描画でConstraintLayoutを使用していて、GuideLineで位置を調整している
    • SpaceやRatioを駆使すれば大概のViewは実現できる
    • ただし、Previewで一見して分からないView( = 可読性が低くて保守できない)は避ける
  • 自前ViewModelからandroidxのviewModelに統一した
    • 複数の画面で共有したいデータはSharedViewModelを活用
  • 以前から導入要望があったNavigatonも利用している
  • SharedVIewModelはデータアクセスを制限するために、interfaceを作成して、それをFragmentごとにInjectしている
  • SharedViewModelの注意点
    • ロジックを持つと複雑になるので、責務は制限すべき
    • まずは使わなくても良いようにすべき
  • SpringAnimation
    • viewにバネのような動きを与えるもの
    • SpringAnimationのほうがバウンスより簡単に自然なアニメーションを作れる
  • UIテストではKakaoを利用
    • EspressoのDSL
    • UIテストを書きやすくなり、時間も短縮できる
    • Espressoから書き換えたときにタイミングやDelayは調整する必要があるかもしれない

Q viewmodel、プロセスkillは?

A savedState使ってる

Q kakaoの他に選定した?

A kaspresso。機能が大きすぎるので依存しそうで避けた

UIテストに関する取り組み

  • 複数の画面サイズ・複数OSバージョン・ライブラリのアップデートの影響調査・minsdkversionの更新の影響調査などを対応したかった
  • アプリサイズが大きくなるに連れ、QAの手動テストが長くなっていった。
    • QAの手動テストを少なくする(なくすのではない)のが目的で導入した -小さく始めてall greenを優先する
  • firebase test labを活用するので、appiumではなくespresso
  • スクリーンショットテスト
    • 画面確認のためにやるので、通信部分はmock化
    • pros 画面開いてスクショ取るだけなので、メンテナンスコストが低い
    • cons そのままだとダイアログが映らない・結局目視が必要
  • ダイアログの問題は自分でダイアログのviewを明示的に取得しに行くか、Falconというライブラリを使う
  • スクショ目視確認問題
    • Facebookは期待値/実際のスクショの比較ライブラリを出している
    • wasabeefさんがブログを出していた
  • インスタルメンテーションテスト
    • 通信部分をmock化しないでテスト。とりあえずハッピーパスを通す
    • 複数端末の確認、初回起動時のみ発生するパターンの確認とかで助かっている ー UIテストはビジネスロジックをそれほど書かないので、慣れると時間がかからなくなる

API通信の状態をsealed classを使って表現する

  • アプリで管理すべき通信状況は主に以下の4種類
    • 初期状態
    • 通信中
    • 通信完了
    • 通信エラー
  • メルカリでは RemoteDataK というライブラリを使用している
    • 内部用のライブラリをOSS化したもの
  • 以下のようなよくある通信状態と意味を変数に持つデータクラスは状態を更新するために必要なロジックが多い
  • いっぽうRemoteDataKだと・・・
    • 拡張関数を使うことで更新ロジックを減らせる
    • そのままだとあまり変わらない
    • 状態をseald classで表現し、値だけ管理することで管理対象を減らせる
  • ただし、Errorは原因に応じたクラスを作成したほうが良いかもしれない

PayPay Androidアプリについて

  • 開発スピードが早いから色々大変
    • 週1のスプリント
    • 月から開発し、水〜金でQA
    • 2019年はios/android合わせて120回のリリース
  • SingleActivityかつFragmentは未使用
    • Fragmentはライフサイクルが複雑
  • lyft/Scoopというライブラリを使っている
    • viewベースに画面遷移を実現する。ライフサイクルがシンプルでわかりやすい
    • ただし、バックグラウンド時などの制御は注意
    • 現在はDeprecated

QA

Androidアプリ開発者の人数は?

  • PayPayが一番多い(2桁)
    • 書いていいのかわからないので具体的な人数は伏せておきます

PayPayはScoopはこれからも使い続けるのか?

  • 剥がすコストが大きいのと今の状態で困っていないのでこのままの予定
  • 新しいメンバーは皆驚くのが悩み
  • scoop利用後に、fragmentTransaction.commitNow()ができたので、Fragmentの辛みが減っているのは理解している。

感想・あとから調査したいこと

  • 全体的に、PayPayの戦略は人数が少なくて学習コストを抑えたいKyashさんと間逆だなぁと感じた
    • 登壇者の方もYahoo本体からの出向らしいので、採用が難しい状況でリソースの融通がきくのは強そう
  • GuideLine はすごく便利そうだと感じた。今まではLinerLayoutのほうが読みやすそうだと思っていたが、複雑なUIになればなるほどメリットが大きそう
    • ちょうどDroidKaigiのアプリで見かけて自分の中のホットトピックだったので、急に興味が湧いてきた
    • ConstraintLayoutを日頃使っている人の中では常識かもしれないが・・・
  • 会社では現在ユニットテストの対応段階なので、UIテストのイメージが少し湧いてきてやる気も出てきた
  • あまり〇〇Payならではの内容はなかったけど、競争が激しいからこそ開発スピードと品質をいかに上げるかを各社頑張っているような印象だった
    • みな自動テストは常識のような顔をしていたのにびっくり
  • 今日一番のパワーワードシュレディンガーのFragment