masaibarの雑記

胃腸は弱いが肉は好き

aCrew #1 スマホ決済サービスのグロース特集に参加してきた

この記事 is 何

repro.connpass.com

に(ブログ枠で)参加してきたので義務を果たすため雑にではありますがまとめたものです。

aCrewとは

サービスグロースのためのコミュニティです。

今回はReproとApp Annieの共催で、テーマは 「スマホ決済サービスのグロース」 でした。

講演

モバイル決済は求められているか?

登壇者:App Annie 武藤さん

  • いかにテクノロジーやサービスとして優れていてもユーザーニーズかなければ使われない
  • 日本での普及率は依然としてあまり高くはない
  • 海外の普及事例からニーズについて読み解く
  • インドの事例紹介
  • Paytm
    • 親会社がSBから出資を受けており、PayPayにも技術提供を行っている
    • 高額紙幣の廃止タイミングで出てきた
    • 累計2.1億DLなのでインドの人口比でいうと7人に1人はDL、DAUは2000万人
  • Google Pay for India (Tez)
    • 1年半で8倍に成長し、8000万台にインストールされておりWAUは驚異の8割
    • ユニークな機能として音声で送金が出来るAudio QRコード
      • 低価格帯のスマホが多い(マイクとスピーカーは低価格でも付いている)ので爆発的に伸びた
  • 北欧の事例紹介
    • Swish 100万DAU 人口は1000万
    • Mobile Pay 275万DAU 人口は500万後半
    • Vipps 200万DAU 人口は500万前半
  • 北欧の勝因と思われる項目
    • BankID(マイナンバーの上位互換みたいなやつ)が整っていた
    • もともとデビットカードという文化はあったので単純に置き換えになった
  • 日本で流行らせるにはただ お金を払う だけを見据えるのではなく お金を払う前後のUX を含めたあたりにヒントがありそう

金融業界がアプリに注力するべき理由とグロースのポイント

登壇者:Repro 平田さん

  • アプリに投資するべき理由
    • アプリはWebよりも継続率が高く、LTVが最も良いチャネル
  • アプリビジネスの典型的な失敗
    • サービスを改善する前にプロモーションしてしまう
      • 典型的な穴の空いたバケツ
      • サービスの継続率が閾値を超えるまではプロモーションするべきではない
  • アプリのありがちな失敗3選
    • 機能の詰め込みすぎ (ex. みずほ銀行アプリ)
      • アプリは流行るまでは単機能&シンプルにしないとグロース市内
      • ボタンは1画面に3つくらいを意識して作るべき
    • アプリである必要がない(ex. 三井住友銀行アプリ)
      • ボタンを押すと全部Webで開く、それWebでいいじゃん
    • 適切な改善がなされていない (ex. 三菱東京UFJ銀行アプリ)
      • ユーザーが求めている改善が反映されていない
  • アプリを成長させる2つのアプローチ
    • 改善アプローチ
    • マーケティングアプローチ

そもそもグロースハックの当たり前ってなんじゃいという人は、久しぶりに読み返したんですがこの本読むと大体把握できるんじゃないかなと思います。

パネルディスカッション

モデレーター:Repro 平田さん、App Annie 向井さん

パネリスト:Fintech協会 丸山さん、メルペイ 金さん、ドコモ 高須さん、Origami 古見さん

メモが中途半端なのと全部書くのしんどいので印象に残ったところだけ書きます。

  • 各社アプリの紹介の第一声
    • 金さん「メルカリのPayPayです」
    • 高須さん「ドコモのPayPayです」
  • 「今後どの程度まで決済アプリは増えていくか?」の問いに対し、各社とも一時的にもっと増える見通しのようだが、最終的にどのあたりに落ち着くのかという観点はそれぞれ違う予想

  • パネリストではないが参加者の中にいたみずほ銀行の人「銀行としても現金は(管理コストなどかかるし)なくなって欲しいと思っている」

  • 「8/1からQRの統一規格がスタートするようですが、各社やりきれますか?」に対してメルペイ 金さん「仕様を早く決めてほしい」
  • 「災害とか想定していますか?」
    • Fintech協会丸山さん「キャッシュレス協議会の今季のテーマとして上げている」
    • ドコモ 高須さん 「現状の普及数だとライフラインとしての通信を優先になるが、災害時の経験値はあるので将来的にはやっていきたい」
    • Origami古見さん、メルペイ 金さん「ネットワークありきなのでドコモさん頑張ってほしい」

感想

モバイル決済は求められているか?

インドの非可聴域の音声でペアリングして送金するやつはワクワクするし賢いなーという感想。

日本ではどうしてもアーリーアダプター以外への普及が思ったよりも進んでいなさそうだなと感じていたが、データを見てもそのとおりのようだった。

個人的には親世代の「クレカは怖い」という強迫観念を崩すのは(加齢とともに新しいことを受け容れづらくなっていることも含め)相当手強いだろうなと思っているので、その世代にも訴求できる何かを武器にするか、一旦その世代は切り捨てて若い世代に訴求しているけるかが鍵になりそうだと思っている🤔

金融業界がアプリに注力するべき理由とグロースのポイント

典型的な残念なアプリあるあると、どうやってグロースさせていくか(Reproさんのセールストーク込みで)の基本的なお話。 グロースハックの話を聞くたびに銀の弾丸はなく、当たり前の改善を粛々とやっていくしかないんだなぁという印象、あとRepro便利そう🤔

パネルディスカッション

各社の「○○のPayPayです」という大変分かりやすい自己紹介からPayPayの強さを窺い知ることが出来た。

QR規格の統一にせよデータにせよ、どこか1社が一人勝ちしようと抱え込んでしまうとうまく行かなさそうだけど各社商売としてやっている以上バランス感覚難しそうだなぁという印象です。

おわりに(宣伝)

これからももう少し増えそうな決済アプリですが、多すぎて端末内でアプリ見失う問題を解消したいという思いからこういうアプリを作っているのでAndroidで同じ悩みを抱えている人は是非お試しください。 私はコンビニのレジで狼狽えることがなくなりました(個人の感想です)。

play.google.com

メイキングの様子です、興味がありましたら併せて御覧ください🙇‍♂️ www.masaibar.com

個人開発のすゝめ 実践編

はじめに

2018年末のAdventCalendarに個人開発のすゝめという記事をQiitaに投稿したところ、多くの方にいいねしていただけました。

f:id:masaibar-dev:20190122230041p:plain

これは元々AdventCalendarで書こうと思っていた東京公共交通オープンデータチャレンジネタが自分の中で没になり1、残り時間もネタもなかったので技術書典用に温めておいた個人開発ネタを泣く泣く流用した記事をポストしたものでした。

そんなことはさておき「あそこまで書いたくせにお前はなにか作らないの…?🤔」という自責の念に駆られて年末年始休みを使って一本Androidアプリ2を作ってこっそりリリースしていたので作業の工程をまとめました。

作ったもの

play.google.com

決済アプリをまとめるためだけのアプリを作りました、出来ることは下記の二点だけです。

  • 使った順にソートされる
  • 通知領域からも起動できる

f:id:masaibar-dev:20190325215455p:plain

作業工程

前述記事内のもう少し具体的な話の内容に沿って今回のアプリの内容をまとめていきます。 画面に余裕のある方はぜひ元記事と併せながらご覧くださいませ。

アイデア出し

たまたま流れてきたこのツイートを見たときに思いつきました、それだけです。

市場調査

"Pay""決済アプリ"などの目ぼしい単語でGooglePlayストア検索をしました。 見てわかるように決済アプリが乱立しまくっていました、果たしてどこが生き残るのやら。

f:id:masaibar-dev:20190325220148p:plain f:id:masaibar-dev:20190325220122p:plain

また、競合アプリはなさそうに見えたのですが、リリースしてから競合アプリが存在していたことを知りました3

画面構成

とにかくシンプルな構成を心がけた結果下記のようになりました。

  • メイン画面(2タブ)
    • 使用履歴順
    • おすすめ順
  • 「このアプリについて」画面
  • (通知領域)

コード管理

みんな大好きBitbucketを使ってprivateリポジトリで開発していましたがGitHubのprivateリポジトリ無料が発表されたので乗り換えました、ありがとうBitbucket君のことは忘れないよ。

タスク管理

Evernoteにやることをとにかく細分化して箇条書きにして片っ端から潰していきました。

個人開発では進捗管理というよりも単純にリリースまでに何が残っているのかが分かればよく残タスク把握ができていれば充分だと思っています。

f:id:masaibar-dev:20190325220638p:plain

広告

とりあえず思考停止でAdMobのバナーを入れましたが、このアプリは通知領域からのライトな起動がウリなので期待はしていません。

リリースから約4ヶ月で1000円4にも満たない売上でした、時給換算はしないほうが精神衛生上良いです😇

分析

こちらもFirebaseAnalyticsとCrashlyticsをとりあえず導入したものの合計150DL程なのでデータは無いに等しいです、母数をくれ!!!

ASO

なるべく多くのターゲットにしたいキーワードを引っ掛けられるような言葉を選んではいるものの昨月実績値を見ると訪問者数に対するインストール率が平均値を大きく下回っており殆ど奮っていない感じです。 ここはアップデートを重ねてもう少し頑張っていきたい部分です。

アイコン

ここが今回一番の頑張りどころでした。

以前のアプリアイコンはパワポでシコシコ頑張っていたのですが

  • 表現力の幅に限界があり辛かったこと
  • ある程度まとまった時間が確保できたこと
  • デザイナーさんが使っているツールを使えるようになりたかったこと

以上3点の理由により今回はSketchを購入し、UdemyのSketch基礎講座が安かったので受講して自作しました。

学びとしては

  • 新しい道具や概念の使い方覚えるの大変だけど楽しい
  • ツールが使える <<< 越えられない壁 <<< 良いものが作れる
  • 本職のデザイナーさんはやっぱりすごい

の3点でした。

ちなみに出来上がったアイコンを知人に見せたらフロッピーディスクかなって言われました 。

問い合わせ対応

とりあえずメーラーが起動してヒアリングしたい内容が自動で入力される仕組みを使いまわしました。

今のところはユーザーが少ないため連絡来ていません、掲載しているアプリの企業から来ないか戦々恐々としております。

利用規約

記事中で紹介していたジェネレーターをポチポチしてGitHub Pagesで公開しました、所要時間5分くらいです。 https://app-privacy-policy-generator.firebaseapp.com/app-privacy-policy-generator.firebaseapp.com

時間の捻出

年末年始休暇で使える時間はふんだんにあったものの、年末にスマブラのために購入したSwitchが全ての元凶でした。

スマブラ発売まで時間があったのでそれまでのつなぎとして買ったBotWに今更ハマりました、これは確かに良ゲーです。

魅力に関して語りだすと一記事書けてしまいそうなので控えますが、肝心のスマブラはキャラクター出すのがしんどくてかなり放置してました挑戦者強くないですかね🤔

モチベーションの維持

8割くらい出来てきた時点でハイラルに執心し、正月休みも終わってしまったのですがこの記事が背中を押してくれました。

中で引用して頂いていて純粋に嬉しかったと同時に「お前は何をやっとるんだ」と尻を叩かれた気がしました。その節はどうもありがとうございました!

note.mu

おわりに

「基礎はできたんだけど、次は何したらいいんだ?」で一歩踏み出せない人は少なくなさそうだなと思っていて、自分もその一人でした。

なんで踏み出せなかったかを深掘っていったところ、自分にとっては「作るにあたって実際の工程がイメージしづらかった」のが原因の1つでした。

最近はそのあたりが見えるような記事が有料無料問わず増えてるので読んでみるとイメージしやすいかもなぁと思いつつも、「こんなクソアプリでも良いんだ、俺もやってみようかな」と思ってもらえたらこの記事を書いた甲斐があったというものです。

最後にもう一度だけリンクはっておきます、通知領域からアプリ起動できるのホント便利なのでAndroid端末内の決済アプリ増えすぎて困ってる方はぜひ入れてみて下さい!

play.google.com


  1. 各社フォーマットが微妙に不揃いな上に一部の運行業者に関してはデータを提供していないというなかなか辛い感じのものでした😇

  2. お前iOSアプリに挑戦するって言ってなかったかという点については触れないでください🙊

  3. リリース後になってしまいましたが、作者さんには謝罪連絡済みです🙇‍♂️

  4. 最低振込金額は8000円からとなっております💰

副業としての個人開発と開業のすゝめ

はじめに

こちらは個人開発 Advent Calendar 2017の24日目の記事です。

私はサラリーマンですが、勤め先の企業が副業を認めていることもあり、プライベートでも「のぞきみ」というAndroidの既読回避アプリを開発しています。
リリースから1年が経ち、累計18万DLで平均評価は4.6と個人アプリとしてはまずまずの成果を残しております。
また、勉強目的で作り始めたアプリではありますが、開発だけに留まらずASOやマネタイズの勉強にもなっています。


と、どうでもいいプロダクトの宣伝はこのあたりにして、今回は内部の技術や作り方の話には触れず敢えてお金の話をしようと思います。

ちなみに本記事の対象としているのはサラリーマン兼個人開発者でプロダクトの収益が発生している人若しくはマネタイズも含めプロダクトを作ろうとしている人がメインとなります。

自分がやったこともないフリーランスを安易にオススメする記事ではありません

専業の方は当然知っている内容かと思いますので、読み飛ばしていただくか間違いを指摘するなどしていただけると幸いです。
また、会社にバレない副業の仕方については知りませんので、取り急ぎ副業OKの会社に転職とかすればいいんじゃないでしょうか。

目次

開業して事業とするという選択肢

個人開発をしており、そこでリリースしたプロダクトの中に継続して少なからず収益が発生している(広告や有料課金など)場合や、まだ収益が上がっていないがマネタイズにも本気で取り組んで行くつもりがある場合ならば、開業を検討する余地があると思っています。

開業すると聞くと「別に会社をやめてこれで起業しようとは思っていなんですが…」と思われる方もいるかと思います。
しかし開業 ≠ 起業 であり、独立するわけではなく会社で働きながら個人事業主として開業することは可能です。
実際に私自身は今年に開業して、サラリーマン兼個人事業主として二足のわらじを履いて活動しております。

そして個人開発の方にも帰宅後や休日のかなりの時間をつぎ込んで来たこともあり、来年の確定申告では雑所得ではなく事業所得として申告を行う予定です。

これから説明していく青色申告を副業でするためには事業所得、不動産所得、山林所得のいずれかの所得があることが必要です。

www.sumoviva.jp

「副業は雑所得と事業所得のどちらと判定されるか」という基準は曖昧であり、明確な判断基準は設けられていないようですが「継続的に行われているか」や「社会通念上事業と呼べるか」等で判断されるようです。
この観点に照らし合わせた時に、アプリ開発とは継続的に行えるものであり、例えば最近「1人で6時間で作って買収された」と話題になっているPeingのように仮に短時間で作ったものだとしても出来が良ければ事業価値も認められるため、事業と呼ぶのには非常に相性が良い分野なのではないかと考えています。

もちろん「片手間で作ってノーメンテ、月々100円も儲からない」みたいなのは雑所得として扱われる可能性もありますが、時間と労力を注ぎ込んでいるなら事業として認められる可能性があると思うので、あまり収益額自体は上がっていなくても開業を目指す場合は税理士さんや税務署に確認してみて下さい。

それではここからは開業すると何が変わるのかについて少し詳しく説明していきます。

メリット

まずはメリットを紹介していきます、結構長くなっちゃいましたが何を言いたいかと言うと
本気で個人開発しているなら、開業して事業所得として申告することによって可処分所得が多少なりとも増える可能性がある
というお話です。

確定申告の控除額が増える

まずはじめに、確定申告には白色(10万控除)、青色(10万控除)、青色(65万控除)の3種類があります。
当然控除額が多いほうが税金は少なくなりその他の恩恵も受けやすいですが、その分やるべきことも多くなります。
これは開業というよりも青色申告のメリットであり、その青色申告をするためには開業が必要になるということです。
ちなみに開業しない場合でも、副業での利益が年間20万円を超えると白色申告として確定申告を行う義務があります。

白色申告 青色申告(簡易) 青色申告(複式)
控除額 10万円 10万円 65万円
帳簿 簡易簿記 簡易簿記 複式簿記
届出 不要 必要 必要
一括で買える消耗品の上限額 10万 30万 30万
損益通算 出来ない 出来る 出来る

こうしてみると分かりますが、白色の場合でも記帳の義務があり青色申告の簡易簿記と殆ど手間が変わりません。 それでいながら享受できるメリットは青色の簡易簿記の方が多いので、そもそも申告が必要なくらい稼げている場合や逆に赤字の場合は青色にする旨味のほうが多いように思えます。

この辺はうめのんさん*1のブログに分かりやすくまとまっていました。

umenon.com

技術書や端末の購入が楽になる

技術書、検証用端末、セミナーの参加費用など、払おうとすると「うっ…」となってしまうくらいの金額のものでも、事業に必要なものであると言い切れるならば何もやましいことはなく経費計上して購入できます。
また私は借りていませんが、アプリのためにサーバーをレンタルしている場合などは当然それも経費ですね。

私個人としては副業で上がった収益はお小遣いではなく、更にプロダクトを伸ばしていくための資金として捉えています。

これに関しては、最近流れてきた記事がすごく良かったので貼っておきます。
記事のタイトルで誤解を生むかもしれませんがここでいう投資とは「設備投資」や「自己投資」です。

blog.craftz.dog

私自身も作業環境への投資としてMac mini (Late 2012)からiMac 2017 Retina 5Kに乗り換えましたが、控えめに言って最高でした。
AndroidStudioやGoogleChromeがメモリを食い荒らす事によるストレスが大幅に下がり、逆に作業効率が上がったことを実感しています。

ちなみに購入時点ではそこまで収益も上がっておらずギリギリどころか普通に赤字でしたが、作業効率の向上と「せっかく買ったのだから頑張ろう」という心理的な働きによりなんとか年内中にペイできたので良しとします。

開業しない場合でも、経費として物品を購入することが可能ですが消耗品として購入できる上限は10万とされており、それを超える場合は償却年数に応じた額を毎年計上することになります。
それに対して、青色申告の場合は少額減価償却資産特例として、30万以内までの資産を一括で経費計上することが出来るため上述のiMacはその制度を利用して一括で計上しています。

家事按分も出来る

経費として計上できるものは購入したものだけに限らず、水道光熱費や家賃、通信費も適切な割合であれば経費として認められます。
勿論プライベートでも使うものだと思いますので全額と言うわけにはいきませんが、実際に事業のために使っていると証明可能な分に関しては経費として計上できます。

損益通算も出来る(?)

これは専業の事業所得の場合はその年が仮に赤字だった場合に翌年に繰り越せるという制度です。
副業の事業所得の場合はどうなるかというと、本業のお給料ももらっているのでトータルで赤字になるということはほぼ起こり得ません。
そうなると、本業のお給料から副業で発生した赤字分を相殺し「年末調整で税金を払いすぎた」として還付金を受けられる可能性があります。

しかし、数年前に「(架空の)副業でわざと赤字を出し、給与との損益通算で還付金を受ける」という税ハックが逮捕者が出るレベルで横行した結果、現在は税務署も目を光らせているそうなので軽い気持ちでやるべきではありません。
ですので、もしも本気でやった事業としての副業が赤字になった結果としてこの制度を利用したい場合は念のため税理士さんに相談するのが無難だと思います。

デメリット

開業のメリットだけを並べた記事は枚挙に暇がないですが、当然デメリットもあるので思いつくものを紹介していきます。

純粋なプロダクトを作る以外の作業の増加

実際手間は増えるので、純粋に勉強目的でプロダクト作りを始めてコードだけを書いていたときよりもやらなければいけないことは増えました。
なので「俺は金のこととか考えず、とにかくコードを多く書きたいんじゃ!」というエンジニアの方には割と苦痛だと思います。

確定申告の義務が発生する

権利には義務もつきものということで、青色申告の恩恵を受けるためには確定申告が必要になってきます。

開業しない場合であっても、少なくとも収益が20万を超えた場合には確定申告が必要になります。
どうせ控除額が同じで手間も同じくらいの確定申告をするのであれば、白色でするよりも青色の方がお得感はあります。

保管義務がある

確定申告の義務に付随するのですが、申告で利用した帳簿書類や決算書類、証憑書類には7年の保管義務があります。
後日税務調査があった場合に保管されていないと申告の正当性を疑われ申告を全面的にやり直しになる可能性があるので、領収書などは100均のクリアファイルでも買ってきて月ごとに分けるなどして保管しておきましょう。

失業保険が貰えないかも

失業した場合でも「あなたは事業やってますから無職ではないですよね」という話になる場合があるそうです、確かに筋は通っている。
その場合失業保険を受け取ってしまうと不正受給扱いになる可能性もあるとかないとかなので注意が必要です。

但し会社を辞める前に閉業届を出していれば大丈夫という話もあるので、どうしても気になる人は開業前にお役所に確認して下さい。
ちなみに私の場合は開業後にこの事実を知ったのですが今のところは特に何も影響なくやっております。

開業の方法

ここまで具体的な開業手続きの説明をしていなかったので軽く説明しますと、主な工程としては

  1. 管轄の税務署を調べてそこに行く。
  2. 開業届と青色申告承認申請書を書いて提出する。

以上の2点になります。

拍子抜けしたかもしれませんが、本当にこれだけでした。
強いていうならば税務署は平日の8:30〜17:00しかやっていないため有給休暇を取る必要があったことと、書類記載時に利用するため印鑑とマイナンバーカードを持っていくことを忘れないようにするくらいでしょうか。

開業届の作成には開業freeeを利用すると、必要事項を入力するだけで簡単に作成することが出来ました。
その後の勧誘がちょっと鬱陶しいくらいに来たので開業届だけ出して解約しましたが開業freeeで開業届を作って出したらそのままfreeeで帳簿をつけるという選択肢もありだと思います。

屋号はいい名前が思いつかず空欄で出しました。
なくても開業できますが、あったほうが多分カッコイイです。

一点注意しなければならないのは、提出日についてです。

開業年度から青色申告を希望する場合は3月15日まで、もしくは事業開始より2ヶ月以内とされています。
つまり今から開業届けを出しても2017年分の収益を2018年の確定申告で申告することは出来ませんが、2018年分の収益を申告をしたい場合は2018年の3月15日までに届け出をすることによって2019年の確定申告時に対象とすることが出来ます。

開業に際しては、最寄りの市役所で税理士による無料相談会なども行われている場合があるので、興味のある方は一度「自分のアプリ開発の内容で開業できるか否か」を聞きに行くのが良いかもしれません。

でもお高いんでしょ?

個人事業主の開業届けの提出に関しては会社設立と異なり資本金などを用意する必要はなく1円も払っていません。
当日払ったお金といえば書類を提出しに行った税務署への往復の電車賃くらいです。

帳簿の記帳に関しては 、一番安いクラウド会計ソフトを使うと想定すると月々1000円くらいかかる認識でいたほうが良いと思います。

記帳・確定申告の方法

具体的な方法についてはネット上に詳しい記事が多くあるので割愛します、というよりも私も来年の確定申告が初めてになるので未体験です。

ちなみに私は縁あって税理士さんとお会いすることが出来たので、お願いして顧問税理士として契約していただいています。
日々の記帳などはfreeeMFクラウドを使うという方法もあるようです。
最初はこのどちらかを使いながら自分でも複式簿記を覚えようとも思ったのですが勉強を始めたところ流石に辛さを感じ、餅は餅屋ということでお願いすることにしました。

自分でやるよりも多少高くはなりますが、お金周りについて疑問に思った事はなんでも聞くことができ、万が一申告後に税務署に突っ込まれた場合は代理で答弁をしてくださるそうなので適正か、逆に安いくらいの出費だと思っています。

最近は顧問税理士にLINEで相談できるサービスなんてのもあるみたいですので、もし税理士さんと出会っていなければ会計ソフトとこのサービスの合わせ技を使っていた気がします。

もちろんこれらの契約料や月額利用料は必要経費として計上できます。

で、結局どうしたらいいの?

身も蓋もないですが、最終的には好きにすればいいと思います。

ただ私個人の考えとしては、開発だけに留まらずプロダクトの収益化やマネタイズも本気で考えているのなら開業について一考の価値はあると思っています。
最寄りの市役所などで定期的に税理士の無料相談会をやっている場合もあるので、私のような素人の書いた記事を読むよりも実際にお話を聞きに行ったほうが早いです。 収益額にもよりますが、面倒さが勝るなら開業せずに白色申告で出すのも選択肢の一つではあります。

ちなみに、申告が必要なレベルの収益が上がっていながら「収益も少額だし税務署も忙しいからこんなところなんか来ないよ〜」と言いつつ申告をしていない人もいるかと思います。

所謂脱税というやつです、追加徴税は最大で7年まで遡って行われるそうですのでお忘れなきよう。

当然指摘が入らなければ丸儲けであり、結果的にここまできちんとやっているほうが馬鹿を見ることになるのかもしれませんが、あくまでもサラリーマンの副業という立ち位置なので、少額の税金をケチった結果会社から解雇され職と社会的信用を失うリスクを潰す意味でもちゃんと申告をするべきだと思っています。

おわりに

終身雇用があってないようなこの時代ならばフリーランスという働き方もあるのでしょうが、大して優秀でもなく生来冒険心のの薄い私にそこまでのリスクを取る覚悟はありませんでした。
しかし急にそこまで冒険せずとも、本業でお給料をいただきつつ個人でもプロダクトを開発して少しずつ収益を増やしていくことのできる副業サラリーマンという攻守のバランスが取れた働き方の選択肢もあって、少なくとも私にはそれが合っていると感じています。

この辺りの話題に関しては、ヨッピーさんの本を最近読んだのですが、副業や独立に関して自分が何となく考えていたことがスッキリまとまっていました。小難しい話は抜きにしても普通に読み物としても面白いのでオススメです。

お金のことばかり書いてきましたが、エンジニアの皆様におかれましては勿論お金の面だけでなく副業で得た技術や経験を本業に還元できますし(あわよくばそれで成果を挙げて昇給を狙う*2)、逆に本業で得た知見を副業にも活かすことができるという好循環が形成されやすいという点においても個人開発はオススメです!

何が悲しくて12月24日の夜にこんな色気のない長文を書いているのか分かりませんが、文字数を数えてみたら9000文字近くなっていました。

来年はアプリを作るのもいいですが彼女も作りたい所存です。

お後がよろしいようで。

免責事項

本稿は私個人の意見であり、所属企業・部門見解を代表するものではありません。
掲載している情報の正確性については気をつけておりますが、本記事に含まれる情報または内容を利用することで、直接および間接的に生じた損失に関し、一切責任を負わないものとします。

本記事に嘘を書いているつもりはありませんが、私は税理士資格を持っているわけでなく副業エンジニアとして調べたことや税理士さんに聞いた話をまとめた内容となっております。
また、税法もコロコロ変わるようなので鵜呑みにせず、開業や確定申告をする際には税理士さんや最寄りの税務署などで専門家に確認していただければと思います。

そしてもし記述が間違っていた場合にはご指摘頂けると幸いです🙏

*1:Taxnoteにはお世話になりました。

*2:結局お金の話じゃないか!

Play Billing LibraryのCodeLabをなぞってみた

はじめに

開発しているアプリに課金要素を入れたいと思い、そのために新しいPlayBillingLibraryを覚えたかったのでチュートリアルとしてCodeLabをなぞってみた覚書。

ちなみにCodeLabだけ全部やっても本番投入するには不充分であるというのが結論。

Buy and Subscribe: Monetize your app on Google Play

目次

手順

セットアップ

まずはチェックアウトしてくる。

$ git clone https://github.com/googlecodelabs/play-billing-codelab

このままAndroidStudioで開くのではなくworkのフォルダを開くことに注意。

開くと、サンプルコードが一部古いようなのでupdateしてやる。 f:id:masaibar-dev:20171112123704p:plain

ベースとなるアプリの確認

完成図としてはこんな感じになるらしい。 f:id:masaibar-dev:20171112124754p:plain

とりあえず何も考えずビルドしてみるとこんな画面が出てくる。 f:id:masaibar-dev:20171112125103p:plain

画面に表示されているのは下記の要素。

  • 車と燃料の残量を表示
  • 燃料を消費して運転ゲームをプレイできるボタン
  • 空の購入画面(これから実装していく)を開くための購入ボタン

ここから下記のようにアプリ機能を拡張していく。

  • Googleデベロッパーコンソールに定義した商品詳細を表示
  • GooglePlay料金確認ダイアログ経由での購入

Play Billing Libraryとの統合

build.gradleファイルにBillingライブラリを追加

app/build.gradleにBillingライブラリの定義を追加してSyncする。

compile 'com.android.billingclient:billing:1.0'

BillingClientの作成

既存のBillingManagerのコードを編集していく。 PurchasesUpdatedListenerをimplementsするのを忘れないように。

public class BillingManager implements PurchasesUpdatedListener {

    private static final String TAG = "BillingManager";

    private final BillingClient mBillingClient;
    private final Activity mActivity;

    public BillingManager(Activity activity) {
        mActivity = activity;
        mBillingClient = BillingClient.newBuilder(mActivity).setListener(this).build();
        mBillingClient.startConnection(new BillingClientStateListener() {
            @Override
            public void onBillingSetupFinished(int responseCode) {
                if (responseCode == BillingClient.BillingResponse.OK) {
                    Log.i(TAG, "onBillingSetupFinished() response: " + responseCode);
                } else {
                    Log.i(TAG, "onBillingSetupFinished() error code: " + responseCode);
                }
            }

            @Override
            public void onBillingServiceDisconnected() {
                Log.w(TAG, "onBillingServiceDisconnected()");
            }
        });
    }

    public void startPurchaseFlow(String skuId, String billingType) {
        // TODO: Implement launch billing flow here
    }

    @Override
    public void onPurchasesUpdated(int responseCode, @Nullable List<Purchase> purchases) {
        Log.d(TAG, "onPurchaseUpdated() response: " + responseCode);
    }
}

テスト

書き換えが完了した状態で、Runボタンを押すとGamePlayActivityのonCreateの中でBillingManagerの初期化が行われ、logcatに以下のログが出力される。

onBillingSetupFinished() response: 0

SKU詳細の取得

SKUとは在庫管理を行う場合の単位。アイテムは商品の種類を指すが、SKUは同じ商品でもパッケージの違いや値段の違いなど、アイテムより小さい単位で分類される。http://www.e-logit.com/words/sku.php

クエリの開始

一度onBillingSetupFinishedが呼ばれると、BillingClinetが使用できるようになる。

まず、SKU詳細を問い合わせてみる。

CodeLabのアプリには既に2つのアプリ内アイテム

  • gas
  • premium

と、2つの定期購読アイテム

  • gold_monthly
  • gold_yearly

が用意されている*1ので、それらの詳細を問い合わせるためにクエリを実行する。

まずはGooglePlayデベロッパーコンソールから特定SKUタイプの全てのSKU IDリストを取得するためのデータ構造を定義する。

static {
    SKUS = new HashMap<>();
    SKUS.put(BillingClient.SkuType.INAPP, Arrays.asList("gas", "premium"));
    SKUS.put(BillingClient.SkuType.SUBS, Arrays.asList("gold_monthly", "gold_yearly"));
}

public List<String> getSkus(@BillingClient.SkuType String type) {
    return SKUS.get(type);
}

次に、BillingManagerに新しいメソッドを追加し、GooglePlayデベロッパーコンソール上で定義された商品(SKU)に関する全ての詳細情報を取得出来るようにする。 このメソッドは情報を取得するための、SKUタイプとSKUのリストであるSkuDetailsParamsを受け取る。

    public void querySkuDetailsAsync(@BillingClient.SkuType final String type,
                                     final List<String> stringList,
                                     final SkuDetailsResponseListener listener) {

        SkuDetailsParams skuDetailsParams = SkuDetailsParams.newBuilder()
                        .setSkusList(stringList)
                        .setType(type)
                        .build();

        mBillingClient.querySkuDetailsAsync(skuDetailsParams, new SkuDetailsResponseListener() {
            @Override
            public void onSkuDetailsResponse(int responseCode, List<SkuDetails> skuDetailsList) {
                listener.onSkuDetailsResponse(responseCode, skuDetailsList);
            }
        });
    }

次にデータをUI上に表示する。

AcquireFragmentにhandleManagerAndReadyメソッドが予め定義されており、フラグメントを表示しBillingManagerがアクセス可能になった際に一度だけ呼ばれる。その為、アプリ内アイテムのSKU詳細を取得するためにこのメソッドをqueryで拡張する。

private void handleManagerAndUiReady() {
    // Start querying for SKUs
    List<String> inAppSkus = mBillingProvider.getBillingManager()
            .getSkus(BillingClient.SkuType.INAPP);
    mBillingProvider.getBillingManager().querySkuDetailsAsync(BillingClient.SkuType.INAPP,
            inAppSkus,
            new SkuDetailsResponseListener() {
                @Override
                public void onSkuDetailsResponse(int responseCode, List<SkuDetails> skuDetailsList) {
                    if (responseCode == BillingClient.BillingResponse.OK &&
                            skuDetailsList != null) {
                        for (SkuDetails details : skuDetailsList) {
                            Log.w(TAG, "Got a SKU: " + details);
                        }
                    }
                }
            });

    displayAnErrorIfNeeded();
}

テスト

アプリを起動し、Purchaseボタンを一度押すとAcquireFragmentが表示され、handleManagerAndUiReady()が呼び出される。 logcatには以下のログが出力される。

Got a SKU: SkuDetails: {"productId":"gas","type":"inapp","price":"¥113","price_amount_micros":113484176,"price_currency_code":"JPY","title":"Gas (Play Billing Codelab)","description":"Buy gasoline to ride!"}
Got a SKU: SkuDetails: {"productId":"premium","type":"inapp","price":"¥170","price_amount_micros":170226264,"price_currency_code":"JPY","title":"Upgrade your car (Play Billing Codelab)","description":"Buy a premium outfit for your car!"}

SKU情報の描画

アプリ内アイテムの表示

このサンプルでは、描画のためのUIが予め用意されているためクエリの結果をadapterに繋ぐだけで良い。 最初に、AcquireFragment#handleManagerAndUiReady()でローカルのSkuRowDataの配列に入れ直すため、onSkuDetailsResponseを次のようにする。

if (responseCode == BillingClient.BillingResponse.OK &&
        skuDetailsList != null) {
    List<SkuRowData> inList = new ArrayList<>();
    for (SkuDetails details : skuDetailsList) {
        inList.add(new SkuRowData(
                details.getSku(), details.getTitle(), details.getPrice(),
                details.getDescription(), details.getType()));
    }
    if (inList.size() < 1) {
        displayAnErrorIfNeeded();
    } else {
        mAdapter.updateData(inList);
        setWaitScreen(false);
    }
}

apkをビルドして実機に入れ、Purchaseボタン押下後に表示されるAcquireFragmentが次のように表示されていることを確認する。

f:id:masaibar-dev:20171112204959p:plain

ちなみにCodeLabのサンプル画像だと値段が円表記ではなく$表記になっている。 恐らく端末の言語設定によって表示が違うのではないかと思われる。

f:id:masaibar-dev:20171112205102p:plain

定期購読アイテムの表示

CodeLabでGoogleデベロッパーコンソール上に用意されているのは定期購読アイテムもあるので、それらも同様に表示できるようにする。

このタスクはアプリ内アイテム追加とよく似ているため、コードのコピペを避けるためにAcquireFragment.handleManagerAndUiReady()内のgetSkuDetailsメソッドで利用する、再利用可能なリスナーを定義する。

final List<SkuRowData> inList = new ArrayList<>();
SkuDetailsResponseListener responseListener = new SkuDetailsResponseListener() {
    @Override
    public void onSkuDetailsResponse(int responseCode, List<SkuDetails> skuDetailsList) {
        if (responseCode == BillingClient.BillingResponse.OK && skuDetailsList != null) {
            for (SkuDetails details : skuDetailsList) {
                Log.i(TAG, "Found sku: " + details);
                inList.add(new SkuRowData(details.getSku(), details.getTitle(),
                        details.getPrice(), details.getDescription(),
                        details.getType()));
            }

            if (inList.size() == 0) {
                displayAnErrorIfNeeded();
            } else {
                mAdapter.updateData(inList);
                setWaitScreen(false);
            }
        }
    }
};

この再利用可能なリスナーと拡張可能なリストを準備したら、アダプター内にアプリ内アイテムと定期購入アイテムを簡単に入れることが出来る。 どちらのタイプのSKUに対しても、同じSkuDetailsResponseListenerでクエリを投げることが出来る。

// Start querying for in-app SKUs
List<String> skus = mBillingProvider.getBillingManager().getSkus(SkuType.INAPP);
mBillingProvider.getBillingManager().querySkuDetailsAsync(SkuType.INAPP, skus, responseListener);
// Start querying for subscriptions SKUs
skus = mBillingProvider.getBillingManager().getSkus(SkuType.SUBS);
mBillingProvider.getBillingManager().querySkuDetailsAsync(SkuType.SUBS, skus, responseListener);

これらの変更後、handleManagerAndUiReadyは次のようになる。

private void handleManagerAndUiReady() {
    final List<SkuRowData> inList = new ArrayList<>();
    SkuDetailsResponseListener responseListener = new SkuDetailsResponseListener() {
        @Override
        public void onSkuDetailsResponse(int responseCode, List<SkuDetails> skuDetailsList) {
            if (responseCode == BillingClient.BillingResponse.OK && skuDetailsList != null) {
                for (SkuDetails details : skuDetailsList) {
                    Log.i(TAG, "Found sku: " + details);
                    inList.add(new SkuRowData(details.getSku(), details.getTitle(),
                            details.getPrice(), details.getDescription(),
                            details.getType()));
                }

                if (inList.size() == 0) {
                    displayAnErrorIfNeeded();
                } else {
                    mAdapter.updateData(inList);
                    setWaitScreen(false);
                }
            }
        }
    };

    //// Start querying for in-app SKUs
    List<String> skus = mBillingProvider.getBillingManager().getSkus(BillingClient.SkuType.INAPP);
    mBillingProvider.getBillingManager().querySkuDetailsAsync(BillingClient.SkuType.INAPP, skus, responseListener);

    // Start querying for subscriptions SKUs
    skus = mBillingProvider.getBillingManager().getSkus(BillingClient.SkuType.SUBS);
    mBillingProvider.getBillingManager().querySkuDetailsAsync(BillingClient.SkuType.SUBS, skus, responseListener);
}

テスト

ビルドしてPurchaseボタンを押すと次のように表示されるはずである。 f:id:masaibar-dev:20171112211905p:plain

購入フローの開始

GooglePlayの料金設定ダイアログを表示

下記のコードをBillingManager#startPurchaseFlow()に実装すると、AcquireFragmentのボタンを押された時に呼び出される。 また商品のSKUと、ボタンを押された商品の請求タイプも知っている。

※デモンストレーションなのでクレジットカードを追加しないこと。

BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
        .setType(billingType).setSku(skuId).build();
mBillingClient.launchBillingFlow(mActivity, billingFlowParams);

テスト

デバイスにインストールして、1番上のGasのカードのBUYボタンを押すと次のような画面が表示される。 f:id:masaibar-dev:20171112212153p:plain

最後の仕上げ

基本的な再試行のポリシーを実装

例えばPlayStoreアプリがバックグラウンドでアップデート中だった場合など、何らかの理由でPlayStoreサービスが切断された場合は再接続しようとするのが道理である。

切断後にBillingClient#startConnection()を一度だけ実行するような基本的なリトライ機構をBillingManagerに実装する。

これを実現するために、BillingClient#isReady()メソッドを利用する。

そして、BillingClinetの接続開始処理を再利用可能にするために、BillingManagerのコンストラクタから別メソッドに移動する。

また、クライアントが接続されていなかった場合か、接続成功時に一度だけ呼ばれるようなRunnableな引数を追加する。

private void startServiceConnectionIfNeeded(final Runnable executeOnSuccess) {
   if (mBillingClient.isReady()) {
       if (executeOnSuccess != null) {
           executeOnSuccess.run();
       }
   } else {
       mBillingClient.startConnection(new BillingClientStateListener() {
           @Override
           public void onBillingSetupFinished(@BillingResponse int billingResponse) {
               if (billingResponse == BillingResponse.OK) {
                   Log.i(TAG, "onBillingSetupFinished() response: " + billingResponse);
                   if (executeOnSuccess != null) {
                       executeOnSuccess.run();
                   }
               } else {
                   Log.w(TAG, "onBillingSetupFinished() error code: " + billingResponse);
               }
           }
           @Override
           public void onBillingServiceDisconnected() {
               Log.w(TAG, "onBillingServiceDisconnected()");
           }
       });
   }
}

何らかの理由でクライアントが切断された場合、このメソッドが再接続を一度試みる。 例えば、上記再試行ポリシーを使用してSKUの詳細クエリを実装するなら次のようにする。

public void querySkuDetailsAsync(@BillingClient.SkuType final String itemType,
            final List<String> skuList, final SkuDetailsResponseListener listener) {
        // Specify a runnable to start when connection to Billing client is established
        Runnable executeOnConnectedService = new Runnable() {
            @Override
            public void run() {
                SkuDetailsParams skuDetailsParams = SkuDetailsParams.newBuilder()
                        .setSkusList(skuList).setType(itemType).build();
                mBillingClient.querySkuDetailsAsync(skuDetailsParams,
                        new SkuDetailsResponseListener() {
                            @Override
                            public void onSkuDetailsResponse(int responseCode,
                                    List<SkuDetails> skuDetailsList) {
                                listener.onSkuDetailsResponse(responseCode, skuDetailsList);
                            }
                        });
            }
        };

        // If Billing client was disconnected, we retry 1 time
        // and if success, execute the query
        startServiceConnectionIfNeeded(executeOnConnectedService);
}

startPurchaseFlow()メソッドはこのようになる。

public void startPurchaseFlow(final String skuId, final String billingType) {
        // Specify a runnable to start when connection to Billing client is established
        Runnable executeOnConnectedService = new Runnable() {
            @Override
            public void run() {
                BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
                        .setType(billingType)
                        .setSku(skuId)
                        .build();
                mBillingClient.launchBillingFlow(mActivity, billingFlowParams);
            }
        };

        // If Billing client was disconnected, we retry 1 time
        // and if success, execute the query
        startServiceConnectionIfNeeded(executeOnConnectedService);
}

リソースの掃除

Javaではリソースを綺麗にし、メモリリークを避けることが大切なので、この部分も抜かりなく。

全てのリソースを消去し、Observerを登録解除するのはBillingClient#endConnection()を呼び出すだけである。 BillingManagerの内部に下記メソッドを実装し、GamePlayActivity#onDestroy()から呼び出す。

public void destroy() {
   mBillingClient.endConnection();
}

終わりに

一連の実装を体験することによって、大体の概念と流れは把握できたように思う。

しかし、試しにGasを買ってみたはずが燃料に反映されていなかったり、再度GasのBUYボタンを押しても反応しない状態になっている。

複数購入できるようなアイテムであればローカルで消費したことにして、再度購入が出来るようにするべきだと思うし、買い切りのアイテムであれば購入された時点でそれを検知してボタンをdisableにするなどCodeLabの内容だけでは実用に耐えうるクオリティではなさそうだ。

Play Billing Library | Android Developers

公式のドキュメントを読んで更に理解を深める必要があるが、予め必要な部品などは用意されており入門としてやる分にはCodeLabは良い物だと思う。

*1:通常、GooglePlayデベロッパーコンソールからSKUを設定する。 変更が反映されるまでに数時間かかるため、ここでは予め用意されたSKUを利用する。

CAMPFIRE Growth Hack #2 に参加してきたのでまとめ

CAMPFIRE Growth Hackとは

ヤフーが「グロースハック」にフォーカスした情報共有を定期的に行う、勉強会/交流会イベントです。

「勉強会は数多くあれどグロースハックを主題にしたものはあまり無い、コミュニティを盛り上げていきたい」との一言で始まりました。

yj-meetup.connpass.com

発表

スポーツナビアプリ スモールチームでのアプリ強化の進め方

登壇者:今田 仁美さん(ワイズ・スポーツ株式会社)

  • スポーツナビアプリとは

    • Web版が元々あってそのアプリ版、リリースから2年弱で累計200万DL突破
    • コアバリューは「スポーツの「今」をどんなサイト・アプリよりも快適に、ストレスなく知ることができる」
  • 現場の課題

    • 人が少ない(常時4人ほどで回している)ので、大きな機能追加アップデートは難しい
    • ユーザー獲得のためのプロモーション施策の同時並行も難しい
    • 上から求められるアプリの成長は大きい
    • リリースから一定期間立つとユーザー数が伸び悩む
    • 「どうしたら少人数で効率よく高品質なアプリを提供し続けられるのか」が課題
    • 一旦立ち返って「チームのこと」を考えた
    • これまでのチームは一方通行気味のチーム。安全にリリースしたら終わり、で次のリリースへ
  • どんなチームになったか
    • 「ワクワクするチーム」とあるメンバー談
    • 週1回の定例を開き、重要なところは必ず全員で決め、全員が納得した状態で開発に入れるように。
    • 「案件ベースから長期的にアプリを考えられるチーム」
    • 納得感を得た状態でものづくりのフェーズに入ると一歩先が見えるようになり+αの提案が出来るように
    • 結果的にアプリの質の向上に繋がった
    • 最後に振り返りの場で褒め合う、労り合う
  • チームが同じゴールを目指すために「コアバリュー」を強く意識、ユーザーに何を届けたいか
    • 活発になった分議論がブレても方向修正
    • 纏める役割として、アイデアを肥大化させずに優先度付けして絞っていく(人数は増えなかった…)
  • 優先度の基準
    • スポーツアプリだと伸びるシーズンがある程度決まっている(五輪、シーズン開幕…etc)のでそこをゴールに定めた
    • DAUなど重要KPIに効くか
    • これを何のためにやっているのか
    • コアバリューに沿っているか
  • まとめ
    • アプリの前にチームを成長させる
    • その上で優先度決定をしっかり
    • 今田さん的には「褒め合う」ことが成長の秘訣なのではないかとのこと

発表資料

Android: スポーツナビ‐野球/サッカー/ゴルフなど速報、ニュースが満載 - Google Play の Android アプリ

iOS: スポーツナビを App Store で

サービスに新しい価値を作る方法

登壇者:外崎 匠さん(Retty株式会社 アプリプロジェクトリーダー)

  • すでにあるサービスに付加価値をつけるには?
    • すでにサービスのベースはある
    • サービスがある程度ユーザーに認められている
    • 今の世界観は壊せない
  • Rettyについての紹介 日本最大級の実名型グルメサービス
    • ある日CEOから「新しいお店探しの体験を作って欲しい」
    • まずはサービスの置かれた現状を把握しよう
    • 強み弱みを自分で考えて、自分事化することが大切
  • 強み
    • 「実名」であるがゆえに、口コミの信頼感があってポジティブなものが多い
  • 弱み
    • 他のユーザーがグルメ的にどんな人なのか分からないので、どの人のオススメがいいのか分からない
  • 戦略を立てよう
    • 現状の強みを活かして、弱みを解決する戦略を考える
    • 現状の世界観はなるべく壊したくない = 実名制を損ねず、出て来る人がグルメ的にどんな人かわかるように
    • グルメ度 × 専門性 = TOP USER
    • ある程度方向性が決まったら超高速でプロトタイピングを繰り返す
      • 考えた戦略が正しい方向か確認
      • 方向性が間違っていなかったら、よりユーザーに刺さるものを見つける
      • (間違っていたら止める勇気も大事
  • プロジェクトでのプロトタイピングでの事例
    • 大まかな方向性を確認
    • もう少しブラッシュアップする
    • 全体を俯瞰してみる
  • TOP USERの体験
    • ヘビーユーザーがなりたいと思えるインセンティブを設計
    • TOP USERでも取れないような会員制のお店を使ってのオフ会、Rettyへの愛着も形成
    • TOP USERの口コミを雑誌にして、グッズ化する
    • サービス外でTOP USER制度の認知やブランド力の向上
      • 投稿やプレスリリースを打つなど
      • TOP USERのメディア出演を積極的にサポート
  • まとめ
    • まずは現状把握(強み・弱み)
    • 強みと弱みを踏まえた戦略を立てる
    • 戦略を高速プロトタイピングで確認&ブラッシュアップ
    • 全体を俯瞰

発表資料

retty.me

FiNCアプリ流 チャットオンボーディングのグロースハック

登壇者:近藤 慶水さん(株式会社FiNC データ分析エンジニア)、百瀬 恵さん(株式会社FiNC アプリディレクター)

  • FiNCの紹介、3月頭にリリース ヘルスケアコンテンツ、歩数などのライフログ管理、チャットAiサポート
  • Retention Rate 継続率を重要指標にしている
  • 約3ヶ月改善の結果 1dayRR / 7dayRR /30dayRR 150~300%改善
  • RRの要因となるKPIとしてプッシュ通知許可率歩数データ取得率が存在
    • プッシュ通知 × 歩数データ = コア体験
    • 歩数データが記録されると、チャットAiが反応、プッシュ通知が届く 簡単、達成感、お得
    • プッシュ通知許可率が8,9割、歩数データ取得率も9割以上 プッシュ通知許可率に関しては驚異的な数値!
  • チャット形式のオンボーディング(≒チュートリアル)
    • プロフィール情報
    • 健康に関する悩みなどを聞く
    • プッシュ通知の許可などを求める
    • アカウント登録処理
    • 離脱を少なくするは当たり前だけど良い初期体験をしてもらうことが需要
    • 極端な話多少離脱率が上がっても、最終的ににKPI(継続率)が上がれば良い
    • なんの脈略もなくアプリを使い始めたときにpush通知許可 40%台(一般的なアプリと同数値)
    • オンボーディングに入れ、許可した際のメリットを提示 許可率70%台
    • (数十回のチューニングを経て)画像や文言やエフェクト等でわかりやすく伝える 許可率90%弱
  • 改善する現場で奮闘したこと
    • 「とりあえずbotでいいから、とスタートしたAiちゃん」=> 「なんでこいつ豆知識しか喋らないんだよ!」
    • 今後の構想を見越して汎用的なチャットマスタ作成を一ヶ月くらいの間行い、今のAiの基盤が出来上がる
    • いろんな会話を入れたいのに更新にひたすら時間がかかった => 今はエラー検知のためのテストが行えるようになりエラー文言も出るように、会話マスタ管理コンソール開発中
    • たったひとつの絵文字、されど絵文字 文言や絵文字・画像の使い方・Aiの表情等のディティールの改善を繰り返した
  • グロース出来る前提基盤とは
    • 絶対的な評価軸があった ユーザー継続率
    • 機能の役割が明確だった 連携率を上げる
    • リリース体制が整った 汎用設計/マスタ体制
    • 可視化環境が整った KPIダッシュボード

発表資料

finc.com

データで説明できないカスタマーの課題を解消するために。

登壇者:竹信 瑞基さん(株式会社リクルートジョブズ アプリプロダクトオーナー)

  • タウンワークについての紹介 バイトだけではなく正社員、派遣社員、業務委託など様々な雇用形態に対応
  • データで説明できない事象をどう解くか
    • カスタマーの声 データで説明できないことがある
    • スマホでのバイト検索=めんどくさい
    • 「おしゃれで楽そうなバイトってどう探すの?」
    • UU単位で生ログ見ても「検索条件が変わっていっている」傾向しか見えない…
    • 「なにが課題?」 わかっていることを、コトバにして整理
      • イメージを具体化出来ていない
      • スマホでの検索が面倒くさい
    • 構成要素を足すことで言語化出来た
    • 「前提」「課題仮設」「結果」に分解できた
  • 限られたスコープでどう打ち手を導くか
    • 現状理想状態に分けて整理
    • 前提状態から理想的な状態にするための打ち手は?
    • 働きたい仕事が見つかることが理想状態、そのための手段は問わない
  • オンボーディングで情報取得し求人レコメンド
    • しかし、求職者/求人者の利益を守るため、様々な法令を遵守という制約があり、意図的、恣意的に歪めるのは良くない
    • 何かしらの検索で目的を果たさねばならなくなった。
    • 能動的で複雑な検索が課題 => 受動的にシンプルな検索ならいいのでは?
    • 受動的な検索に寄り添うシンプルなUIをコンセプトにパターン出し
    • ジョブーブの相談部屋 質問に答えるだけで検索できる
    • しかし、質問について質問文言と検索条件との紐付けに制約条件は?
    • 法令を読み込み、法務・コンプラ部署に相談
    • 法令遵守を前提にレギュレーションを定義・合意形成
  • ROIが測れない企画をどう進めるか
    • 開発の優先順位≒ROIの大きい順 リターン最大化、コスト最小化
    • 主機能の検索に課題はありそう
    • リターンは検証でしかない、コストが問題ならコスト最小でやってみるしかない
    • 質問をランダム表示、位置を主要導線外で試す
      • 二週間の実装リリースでCVRが1.6倍以上
      • オンボーディングにペライチ追加、利用UUが3倍以上に
  • まとめ
    • 課題状態を構造化し、カスタマーの課題解決とプロダクト成長を図っていこう

townwork.net

前途多難でも関係ない!基本の型でハッピーグロースハッキング

登壇者:松下 三四郎さん(ヤフー株式会社 第6代 アプリグロースハック黒帯)

  • Yahoo! MAPについて 目的地が決まっていてナビゲーションをするアプリだった。
  • ミッションは「地域と人々の毎日をより便利に、豊かに」
  • リニューアルのタイミングで松下さんがjoin
  • レビュー大荒れ 日時平均2以下
    • 旧アプリとかなり違うコンセプトなのに、上書きでアップデート => *旧ユーザーにとって改悪アップデート:
    • 組織の課題
      • リニューアル後の進め方が決まっていない
      • ステークホルダーが多すぎる100人以上
      • 東京大阪名古屋の3拠点
  • 課題解決のために大切な3つのこと
    • コアバリュー お出かけに関するいい情報に出会えて探せて迷わず行ける
    • KPIツリー ビジネス観点ではなくサービス改善につながるものでないと意味がない
    • ロードマップ KGI, KPI, プロダクトの状態, ユーザー価値、メリット, やること ゴールを定める、そこに至るまで月ごとの戦略を定める
      • 新しい月に入ったら前月の振り返りを必ず行う
    • 全職種のキーマンを強引に巻き込んで決める
    • データからユーザの声を集める
  • 新ユーザと旧ユーザの2種類のユーザーがいる
  • 行動ログと声を集めて定量化する
  • 新ユーザーには初回体験を見直し、継続利用の仕組みを作る
    • コア機能の理解度を行動ログから定量的に分析
      • ある機能のあるステップまで踏んだユーザは翌日継続率が高いのでそれをより多くのユーザーにしてもらうために
  • ネガティブな意見を減らす
    • ネガティブとポジティブ両意見を引き出し定性的な意見を冷静に定量化する
    • 分析したユーザーの声/データをKPIツリーにプロット
    • 新規ユーザー 初回体験を見直し、継続利用の仕組みを作る
    • 旧ユーザー ネガティブな意見を減らし、新ユーザで成功した体験を旧ユーザーにも
  • まとめ
    • どんな状況でもゴールコアバリューを決める
    • ゴールを達成するためにロードマップを作る
    • 現状起きていることを把握し、戦略をアップデートしていく

発表資料

Yahoo! MAP - 【無料】ヤフーのナビ、地図アプリ - Google Play の Android アプリ

Yahoo! MAP - 地図、ナビ、お出かけ情報アプリを App Store で

まとめ

どの発表を聞いていても、まずは「コアバリュー」有りき。

当たり前だが、そのサービスは何を解決したいのかがブレているとユーザーにうまく届かないし、しかしそのようなサービスは少なくない。

次に現状を言語化、数値化し課題を解決するための指標を明確化させることが必要。

これも当たり前だが、何をどうすれば良いのかがぼんやりした状態では改善のアクションは起こせない。

後は明確化された指標を上げるためにそれぞれのサービスに合った手法があるといった感じだったが、特に今回の幾つかの発表で触れられていたオンボーディング(初回チュートリアル)を工夫して初回のユーザーをうまく導いてあげるのはとても効果が高そうだ。

余談ですがCAMPFIREでは懇親会のケータリングでお寿司が出ます、今回も美味しかったです。

f:id:masaibar-dev:20170717144138p:plain

朝起きたら玄関が開かなくなっていた件

今朝の出来事

朝から有明に行く用事があったため、前日は早めに就寝し5時半に起床した。

身支度も終わり、駅に向かうため玄関を開けようとしたところ何故かドアが開かない

我が家は賃貸だが玄関前に宅配ボックス1を置いており、何か荷物が届いていたのかなとも思ったがそもそも夜中に何かが届いているはずもない。

一体何が起こっているのか分からないが、扉を強く押してみると若干だが隙間ができた。

隙間を覗くとそこには



















おっさんの後頭部











おっさんが寝ていた

http://2.bp.blogspot.com/-l-r0zT7iUWg/Ufj1EmLDOWI/AAAAAAAAWlY/1G4qhRPHJdE/s400/gorogoro_ojisan.png

(画像はイメージです)











?!?!?!?!?!?!?!?!?!?!?!?!?!?!



理解不能な事態に心臓は早鐘を打っていたが、大声で「大丈夫ですか?」と呼びかけると朦朧とした感じで応答があった。

一瞬ホームがレスな方かとも思ったけど、身なり的にはそうも見えない。

昨晩から降り続いていた雨をしのぐため、酔っ払ったおっさんがうちの玄関前の屋根を頼りに寝てしまったのだろう。

人んちの玄関前で何やっているんだという怒りよりも電車を逃すと遅刻してしまうという焦りが勝ったため、とにかく扉の前から退いてもらい駅へ。

玄関を振り返るともう一度そこに横たわるおっさんの姿が見えたので、駅についてから最寄りの警察署へ通報。

後に報告の電話を貰ったがお巡りさんが見に来た頃にはおっさんの姿はなかったとのこと。

その後

無事に有明に着いたものの肝心の用事は雨のため流れてしまい、家に帰るとそこにはファミリーマートのレジ袋に入った未開封の金麦の缶が残されていた。

f:id:masaibar-dev:20170625220620j:plain

吐瀉物とかなくてホント良かった。

そのままにしておくわけにも行かず、かと言って飲む気にもなれず、朝のお礼も言いたかったので最寄りの交番に拾得物として届けることにした。

朝の方はおらず、また「財布や鍵ならともかく飲食物は原則拾得物として扱えないのだ」とのこと。

「気持ち悪いでしょうし、この場で処分しましょう」とご提案頂いたので近くのゴミ箱行きへ。

急いでたしおっさんの顔は全然覚えていないのだけど、こちらは自宅が割れているからちょっと不安だ。

万が一おっさんが家に「酒を返せ」と来たら警察立ち会いで処分した旨を伝えて、ゴネるようなら通報してくれと言ってもらえた。

交番にいる人は高圧的な態度の人が多い印象だったが、今日は親切なお巡りさんで良かった。

まとめ

お酒は節度を守って、楽しく飲みましょうね。

仮に酔っ払っても人の家の玄関前で寝るのはやめましょう。


  1. こんな感じの簡素なやつ。買ってからメチャクチャ捗ってるのでいつかちゃんと紹介したい。

    by カエレバ

アプリの評価を高くするために実践しているたった3つの事

はじめに

私は昨年末に個人でAndroidアプリをリリースしました。

のぞきみ ~既読回避をサポート~ - Google Play の Android アプリ

もうそろそろ出してから半年経つのですが、現時点で累計7万ダウンロードと初めての個人アプリとしては悪くない数字だと思っています。

また、評価も2017/06/19現在で平均4.6(合計460件)と客観的に見ても割と高い数字がついていると思います。 f:id:masaibar-dev:20170619233236p:plain

今回は、なるべく高い評価をつけてもらうために普段から実践している3つのポイントについてご説明していきます。

安心してください。「人を雇って大量に★5をつけます」みたいな手法じゃないです。

目次

悪くないものをリリースする

「良いものじゃないのかよ」と思われるかもしれませんが、ユーザーレビューは5点満点の減点方式です。

つまり、悪いものやバグを出すと一部のユーザーはこれ幸いと言わんばかりに噛み付いてきます。

消極的表現ではありますが「悪くないもの ≒ 最低限の期待値はクリアしているもの」のようなイメージです。

それではもう少し詳しく、最低限の期待値について掘り下げていきます。

クラッシュは少なく

まず、一番の前提条件としてはクラッシュが少ないことです。

ユーザーのそれまでの操作、場合によっては時間をかけた入力などが一瞬にして無に帰したときの怒りは計り知れません。

それが頻発するようであれば、良くてその場でアンインストール、悪ければレビューに罵詈雑言を書いてからアンインストールでしょう。

バグも少なく

バクも少ないに越したことはありませんが、特にアプリの根幹を揺るがすような致命的なバグは早めに潰したいところです。

致命的なバグは上記のクラッシュ同様ユーザーへ悪い印象と攻撃材料を与えてしまうため、レビュー等で指摘されたもので「これはヤバイ」というレベルのバグは一刻も早く修正するべきだと思います。

アップデート時にはいきなり100%公開するのではなく、段階的なリリースを選択することで様子を見ながら公開範囲を広げ、本当にヤバそうだったら途中で公開をストップすることも出来るのでオススメです。

しかし、軽微なバグ(判断は難しいですが)に関してはそこまで焦らなくてもいいのではないかなという認識です。 緊急度は高くないものの、優先度は高めにして次回のリリースのついで等で対応することによってユーザーに改善の意思があることを示すことが出来るのではないかと考えています。

自分の納得できるものを

仕事としての開発だと厳しいかもしれませんが、少なくとも気兼ねなくリリースを先延ばしに出来る個人アプリであるならば 自分の中でも納得の出来ていないような中途半端なものはリリースはするべきではないと考えています。

中途半端な状態でのリリースはバグの温床にもなりやすく、後から仕様を変える際にもユーザーからの反発を生む場合があります。

自分が納得できたものがユーザーに受け入れられない可能性ももちろんありますが、自分ひとり納得させられない機能に対しユーザーが魅力を感じることはないと考えます。

いい評価をしてくれそうな人を探す

個人的には、使っていると頻繁に評価を求めるダイアログが表示されるアプリは大嫌いです。

肝心なアプリの出来がイマイチなアプリなんかは、それだけで悪い評価をつけたくなる衝動に駆られることすらあります。

そのアプリに悪い印象を持っているユーザーに向けてそんなものを出すのは火に油を注ぐ行為に他なりません。 そのため私のアプリでは評価をお願いするユーザーをある程度選んでからお願いしています。

誰が高いレビューをつけてくれるのかということを考えると自ずといい印象を持っているユーザーだと分かります。

そのユーザーをどうやって見分けるのかの基準は難しいですが、少なくとも起動直後のユーザーや普段あまり使っていないユーザーは該当しないと考えます。

また、インストールしても満足できなかった場合にはすぐアンインストールすると考え、私のアプリでは起動回数やインストールからの経過日数等を判断材料にしてレビューへの導線を表示しています。

いい印象をもっているユーザーを更に絞る

ヘビーユーザーをある程度絞ったところで、更に良い印象を持ってくれているユーザーに絞り込むにはどうしたら良いのか。

単純な話です、ただユーザーに聞いてみればいいのです。

私のアプリでは、ダイアログを表示する頭からレビューをお願いするのではなく

「このアプリを気に入っていただけましたか? はい / いいえ / 今度答える」

というワンクッションを挟み、いい印象を持ってくれているユーザーを更に絞り込んでいます。 ここで「いいえ」を選択したユーザーに対しては別の導線を用意します(後述)。

上記の関門をすべて通り抜けたユーザーに対して初めて「良かったら応援をお願いします」という意図のダイアログを表示し、ストアの評価画面への誘導をしています。

また、これは余談ですが以前ネット上で少し話題になっていたファイアーエンブレムのスマホゲーが有りました。

あまりに露骨すぎるのもちょっとアレですがいい印象を抱いている人に褒めてもらうという観点ではこの手法自体はそこまで大きく間違っているとは思いません。 blog.esuteru.com

はけ口も用意しておく

前述のワンクッション部分で、「気に入っていない」と答えたユーザーに対しても真摯に向き合うべきだと考えます。

不満がありながらも数日間は使ってくれていたというのはありがたいことであり、その不満が何であるのかを知るために私のアプリではお問い合わせフォームへ遷移するような導線を作っています。

問い合わせフォームも別に凝ったものは作っておらず、GoogleフォームとGoogleスプレッドシートの合わせ技を使うことによってものの10分で投稿フォームと一覧管理画面が用意できます。

agn.jp

ときには心無い言葉が投稿されて気持ちが濁ることもありますが、ユーザーが何を期待しているのか、どういう機能が欲されているのかという生の声を一部分ではありますが知ることが出来るのは重要です。

もちろんユーザーの声に振り回されるのは本末転倒ですが、それでも数人から同じ要望が上がってくるようであれば次回以降のアップデート内容の一案として検討の余地があると思います。

バグや改善要望レビューは直したら返信する

ここまで悪い評価をつけそうなユーザーは極力排除しようとしても、アプリに対して強い不満を持つユーザーはこちらが誘導せずとも自分から悪いレビューを書きに来ます。

内容としては言いがかりに近いものもあれば、バグや仕様などこちら側に改善の余地があるものも存在しています。

言いがかりは華麗にスルーするとして、バグ修正や要望された機能を実装した後にはレビューへの返答という形でユーザーに一報入れるようにしています。

GooglePlayはレビューへ返信をするとそのレビューを書いたユーザーに対して通知が飛ぶので、改善を期待していたユーザーとしては「不満が解消された」、「自分のことを気にかけてくれている」という二点を感じることができ、低い確率ではありますが★1のレビューが★5に化けたりする場合があります、これはデカイです。

まとめ

至極当たり前の内容かもしれませんが私のアプリでは下記の3点を実践し、それなりの平均評価をもらっております。

  • 悪くないものをリリースする
  • いい評価をしてくれそうな人を探す
  • バグや改善要望レビューは直したら返信する

平均評価によってダウンロード数も大きく左右されるらしい1ので、ASO対策などと併せて実施していくと自然流入のユーザーが増えやすくなるのではないでしょうか。

また、ストアを見ていると日本国内ユーザーは残酷なまでに簡単に★1をつけていきますが海外ユーザーはその辺りが寛容で、評価平均は世界中から付いた合算で算出されるため海外でも公開しているようなアプリだと平均評価が高くなりやすいように見えます。だからちょっと怪しげで日本国内のレビューは寧ろボロボロあのアプリの評価4.7になってるのね

レビュー依頼ダイアログの出し方などはこの記事がとても参考になりました。 appmarketinglabo.net

PR

最後に宣伝にはなりますが、良かったら「のぞきみ」をよろしくお願いします。

play.google.com


  1. 私のアプリは最初から条件を全て満たすように作っており5.0から4.9、4.8とじわじわ落ちてきて安定してきたのが4.6なので今ひとつ実感できていない。「3.0から4.5に上がったらこの位伸びましたよ」ってのが示せないのは残念なのでどなたか実データをお持ちでしたら教えてください。