Go Conference 2018 Springに参加してきた感動をなんとか言葉にしたい

gocon.connpass.com

1週間経ってしまいましたが、Go Conference2018 Springに参加してきました。やっていくぞという気持ちの昂ぶりが止まらないためちょっと書き残しておきます。
資料やセッション等はconnpassのページをどうぞ。

gocon.connpass.com

 この1週間、会社で「GoCon行ってきた!スライド見て!ほら!」と騒いでおりました。「GoCon良かったなぁ」といい思い出で終わらせないうちに、特に面白かったものをまとめておきます。

Testing with microservices in merpay

speakerdeck.com

概要

  • merpayで使っているgRPCとGoの話
  • 決済システムを扱う上でのテストについて
  • マイクロサービスアーキテクチャを使用する上で、一貫性をどう保っていくか

感想

Go Conferenceでスカラーシップを提供してくれたmercari, merpayのスポンサー枠セッションです。

tech.mercari.com

 今業務でマイクロサービス(的なもの)のTransactionalな処理についてちょうど考えていたところだったので、いいタイミングで発表を聞けました!実際、コンポーネントとその接点が増えれば増えるほどテスト項目は増えるので、そこを完璧にテストするのって難しいよなぁ……などと思っていいたのですが、やらなきゃ駄目ですよねごめんなさい。
 特に、gRPCに関するテストの話題ということで、主題とは外れますが「ああ、gRPCってもうこんなレベルで動いているんだ」などと今更ながら感慨にふけっていました。学習コストも踏まえると、すぐにチームで導入!というのは正直難しい点もあります。だからといって知らないでいい、というのは問題外ですが、一方業務で必要に駆られる環境に身を置くことって大事だなぁと改めて感じました。業務でGo触りたいなぁ……。

How to write Go code

speakerdeck.com

概要

www.youtube.com

感想

 あるものを学ぶ際、公式のドキュメントを読んで勉強しようというのはどの言語、ライブラリでも変わらないことですよね。ただ、頭では分かっていてもGoogle検索で初心者向けの記事を探ってしまう……というのが恥ずかしながら現状でした。アーキテクチャや書き方の好みなども相まって、「公式にはこうあるけどほんとは……」みたいな情報ばかり出回ってしまったりするとなかなかつらいところです。
 Goの場合、書き方がある程度統一されている点もあり、ドキュメントがある程度Godとなりえます。もちろん、発表者のkaneshinさんもコメントされていましたが、開発していく中の応用的な書き方として、個人のブログを参照することも価値があります。一方、バージョンや有用性を判断する基準を持ち合わせていない時期に急に応用面に触れてしまうと、という点もあり。
 こういう勉強の仕方の部分をクローズアップしてくれる発表はめちゃくちゃ有難かったです……!「Goの命名ってどうすればいいんだっけ」とか聞かれた際にポンってURLを投げられるような場所として、覚えるくらい読み込んでおきたいです。

所感

 資料も上がるのに勉強会わざわざ何で行くの、と聞かれることがあります。同じ問題を考えている人と実際に会って話せる、というのがその時の答えでした。加えて、一つ大きな理由として、自分が興味のあるテーマの中で知らなかったことの存在を知り、それについてある程度時間を取って考えられる、というものがあるなぁと思うわけです。

 改めてスケジュールを全体的に眺めてみると、本当に被りのないテーマばかりだったなと思います。これだけ様々なレイヤー、領域が何か1つのテーマを持って集まれる場ってそんなに無いんじゃないかなと。
 大げさに言えばGo言語の共通言語的な側面が好きです。これってコンピュータサイエンスの基礎が無い僕のような人間にとってすごく有難くて、例えばOS関連のシステムプログラミングを勉強したい、といった際、じゃあそのためにC言語を勉強しようとなると、それだけでまた一つハードルが上がってしまいます。一つの言語でアプリケーションからOSのAPIを直で触るような開発まで実際に使われているとなると、また1つ知れることが増えてきます。(文句を言わずCやれ、という話もありますが……)
 次はこの本に真面目に取り組んで行きたいです。

Goならわかるシステムプログラミング

Goならわかるシステムプログラミング

 また、このカンファレンスを通してもう一つ。会社で社内勉強会を運営したりしているのですが、気になっている問題がありました。それはテーマ設定の部分で、オンプレで動いてるシステムがあるような会社だと、なかなか全員を巻き込むような大きなものって開催がしづらいと感じています。ちゃんとテーマを絞った方が面白いものになるというのも理解はしているのですが、横断的な会も一回やってみたいなぁなんて思ってみたりしています。Goを社内でどれだけ導入しているところがあるかは分かりませんが……ちょっと調べてみます。

 長々としたポエムになってしまいましたが、締めくくります。3倍近い倍率にもなったカンファレンスに参加できたのはめちゃくちゃ幸運でした。ブログだけではなく、コードのアウトプットもしなくては……!

おまけ

keynoteで発表してくれたdaveから、突然AirdropでみんなにGopherの画像が飛んでくるサプライズが。

とのことでした。素敵。

Android App Linksを試してみた

 会社で資料を眺めていたら、今更ながらAndroid App Linksのことを知ったのでまとめてみます。
 みなさんも、バックエンドチームが作ったシステム構成図に知らないAndroidの機能が書いてあって震えることありますよね

Android App Links

 「外部のリンクを踏んだら特定のアプリを立ち上げたい」、なんてのはよくあることだと思います。入門書などでもActivity連携などで取り上げられてるテーマですし、そこで大体Intent(特に暗黙的Intent)の話につながっていく流れですよね。それを別の方向から実現するのが今回のAndroid App Linksです。
 Android6.0で登場した機能なので、全世界で見るとちょっとまだ導入には厳しそうですが……。
f:id:t-miliya612:20180418233137p:plain

何が出来るの

  • deeplinkよりも起動するアプリを指定できます
  • 立ち上げるアプリを事前に認証できます
  • これ全部をAndroidStudioのウィザードで片付けることができます

詳しく見ていきましょう

deeplinkよりも細かく起動するアプリを指定できます

 外部アプリを起動するとき、custom url schemeを使ってintent filterを設置するのがよくやる方法です。例えば、地図アプリを起動するときはgeo:など、Androidデフォルトのアプリが提供しているものもあります。
 Androidのユーザー側が自分で使用するアプリを決められるのがメリットですが、正直そんなに……という気持ちになります。それよりも、複数アプリが同じschemeを待ち受けている際に出てくるchooserのストレスの方が大きいような。
f:id:t-miliya612:20180418233025p:plain
 ここで「ALWAYS」を選んだばっかりに「アプリが立ち上がらない!」と問合せを受けるのは誰もが通る道だと思います。

f:id:t-miliya612:20180418233055p:plain
いらすとやにはなかった

 そこで他と被らない独自のcustom url schemeを作り始めるのですが、httpスキーマじゃないとリンクとして認識してくれないメールやSMSクライアントがあったりしてちょっとつらいのが現状です。仕方ないのでこれまではWebサーバーにリダイレクトを設置して頑張っていたのですが、どう見てもコレジャナイ感があります。

 一方、Android App Linksではhttpスキーマを使いつつ、パスまでしっかり使って起動するアプリを細かく指定できます。これで、chooserに悩まされるユーザーを減らすことができます。

立ち上げるアプリを事前に認証できます

 Android App Linksとして指定するURLは、個人で所有するドメインを使う必要があります。正確に言うと個人で契約していなくてもいいのですが、事前にドメインに紐付いているサーバーにアプリ情報を含むjsonを上げておき、認証するというプロセスが必須です。これによって、得体の知れないアプリがlinkを侵食してくる問題を予防ことができます。
 例えば、悪意あるアプリが決済系アプリと同じURLで待ち受けていた場合、ユーザーの選択によってはきれいに情報を引っこ抜かれてしまう恐れがあります。これを事前に防げるわけですね。

これ全部をAndroidStudioのウィザードで片付けることができます

 (実は一部出来ていないようなところがあるのですが…)App Linksを設定するには、AndroidStudioのウィザードに沿って作業を進めるだけでOKです。公式ページ動画にもやり方は載っているのですが、以下で簡単にまとめておきます。

どうやるの

 動画を参考に進めていきます。

 まずは適当にprojectを生成しましょう。注意点は、minSdkVersionを23以上にすることくらいです。今回はkotlinを選択しました。

f:id:t-miliya612:20180418233427p:plain
f:id:t-miliya612:20180418233446p:plain

 次に、AndroidStudioのTools->App Links Assistantを選択します。

f:id:t-miliya612:20180418234040p:plain

 すると、こんな感じのメニューが出てきます。

f:id:t-miliya612:20180418234215p:plain

 この4ステップでやっていきましょう。

①Add URL intent filters

f:id:t-miliya612:20180418234336p:plain

 Host, Path, 起動したいActivityを設定します。  Hostにはリンクに使用したいwebサイトのURLのhost部分のみを入力してください。今回はgithub.ioを使用します。理由は後述します。
 また、PATHのプルダウンメニューでは、今回とりあえずpathPrefixを選んでおきましょう。pathの末尾の値を取得するために必要です。

f:id:t-miliya612:20180418234355p:plain

 Check URL Mappingに試しにURLを入力してみましょう。うまく設定できていれば、先程指定したActivityが出てくるはずです。
 また、この時点で自動的にAndroidManifest.xmlにintent filterが設定されています。Previewを参考にしてください。

②Add logic to handle the intent

 次にIntentを受け取って処理するロジックを、選択したActivityに自動で記述してくれる……はずなのですが、

f:id:t-miliya612:20180418234409p:plain

 駄目でした。。。Javaだと通ったのですが、Kotlinはまだ未対応のようです。
 仕方ないので手で書いていきます。

MainActivity.kt

package tech.miliya.applinkssample

import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        handleIntent()
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        setIntent(intent)
        handleIntent()
    }

    private fun handleIntent() {
        val appLinkAction = intent.action
        val appLinkData = intent.data
        if (Intent.ACTION_VIEW == appLinkAction && appLinkData != null) {
            val comment = appLinkData.lastPathSegment
            tv_comment.text = comment
        }
    }

}

 ついでに、xmlも少し弄っておきます。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tv_comment" <!-- この行を追加 -->
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

 一旦ここで、アプリを起動できるかテストしておきましょう。④Test on device or emulatorを選択します。

f:id:t-miliya612:20180419000511p:plain

 先程入力した、{HOST}/{PATH}/適当なコメントを入力し、テストを実行します。

f:id:t-miliya612:20180418234416p:plain

 無事、準備したアプリが起動候補に出てきました。
 いよいよここからアプリをドメインと紐付けていきます。

③Associate website

f:id:t-miliya612:20180418234423p:plain

 Site Domain(リンクとしたいURLのホスト)とApplication ID(アプリのパッケージ)を入力し、Generate Digital Asset Links Fileを選択します。
 すると、Previewjsonファイルが表示されます。これを指定されたURLに配置していきましょう。

 ここだけはHTTPSが必須です。準備するのが面倒なので、ここは動画の通りにgithub.ioを使ってホストしていきます。

github.com

 Github{USERNAME}.github.ioの名前でリポジトリを作成し、指定された階層の通りに/.well-known/assetlinks.jsonを作成します。
 作業が完了したら、下の方にあるLink and Verifyをクリックしましょう。

note

 github.ioでは、そのままだと.well-known以下が見えないので、下記のファイルをリポジトリのルートに配置します。

  • .nojekyll(空ファイル)
  • _config.yml
include: [".well-known"]

④Test on device or emulator

 最終動作確認です。

f:id:t-miliya612:20180418234427p:plain

 無事設定できていれば、先程のようにchooserが出てくることなく、いきなりアプリが起動します。
 テキストが反映されていることも確認しておきましょう。お疲れ様でした。

まとめ

 AndroidStudioにあるアシスタントを使いながら、Android App Linksを使ってアプリの外部起動のフローを実装してみました。
 起動用URLの使い勝手の良さ、セキュリティ面ももちろんですが、chooserが出ないことをひたすら祈らなくてよくなるのは有り難いです。
 しかもアシスタントが優秀で素晴らしい……!
 Android6.0がもうちょっと広まれば、もっと積極的に使っていきたいです。

参考

developer.android.com developer.android.com www.youtube.com stackoverflow.com github.com

Googleの電話番号を扱うライブラリlibphonenumberを使ってみたのでメモ

Androidアプリの開発で電話番号を扱いたくて、googleのlibphonenumberを使ってみたのでまとめます。

電話番号について

まずは、電話番号そのものについてちょっと調べてみました。
例えば、080-1234-5678なんていう番号があったとします。海外からこの電話番号にかけようとすると、+81-80-1234-5678となります。
これは、ITU-T(International Telecommunication Union Telecommunication Standardization Sector)が勧告するE.164に沿っていて、調べてみると意外と奥が深かったりします。

ドキュメントはここに落ちているので、気合いの入った方は是非読んでみてください。
(E.164 : The international public telecommunication numbering plan)
https://www.itu.int/rec/T-REC-E.164-201011-I/en

とりあえずパースしたい僕としては、ドキュメントのこの図だけ分かっておけば十分そうです。

f:id:t-miliya612:20180414190859p:plain
Figure 1 – International ITU-T E.164-number structure for geographic areas - ITU-T Rec. E.164 (11/2010) The international public telecommunication numbering plan

総務省の資料もありました。これだけで十分でしたね。
(電気通信番号制度概要) http://www.soumu.go.jp/main_sosiki/joho_tsusin/policyreports/joho_tsusin/bango/pdf/061012_4_s8.pdf

結局、必要そうな情報は以下の三点です。

  • 電話番号には世界共通の勧告がある
  • 先頭には1〜3桁のCC(国番号)が必要
    • 国際番号を除けば海外と電話番号が被る可能性がある?
  • 電話番号は最大で15桁

libphonenumber

github.com

ようやく本題です。Google Internationalizationが提供するライブラリで、電話番号をパースするのに必要なことをよしなにやってくれます。
Android限定というわけではなく、JavaC++、JS向けのライブラリのようです。

何ができるの

電話番号のパースをしたい

# パース
fun libphonenumberTest_parse() {
    var msn = "08012345678"
    println(phoneNumberUtil.parse(msn, "JP"))
    msn = "818012345678"
    println(phoneNumberUtil.parse(msn, "JP"))
    msn = "+818012345678"
    println(phoneNumberUtil.parse(msn, "JP"))
    msn = "+81 80 1234 5678"
    println(phoneNumberUtil.parse(msn, "JP"))
    msn = "+81-80-1234-5678"
    println(phoneNumberUtil.parse(msn, "JP"))
    msn = "080(1234)5678"
    println(phoneNumberUtil.parse(msn, "JP"))
    msn = "080.1234.5678"
    println(phoneNumberUtil.parse(msn, "JP"))
}
# => Country Code: 81 National Number: 8012345678
# => Country Code: 81 National Number: 8012345678
# => Country Code: 81 National Number: 8012345678
# => Country Code: 81 National Number: 8012345678
# => Country Code: 81 National Number: 8012345678
# => Country Code: 81 National Number: 8012345678
# => Country Code: 81 National Number: 8012345678

fun libphonenumberTest_parse_withInvalidRegion() {
    val msn = "+818012345678"
    println(phoneNumberUtil.parse(msn, "US"))
}
# => Country Code: 1 National Number: 818012345678 

電話番号のフォーマットをしたい

# フォーマット
fun libphonenumberTest_format() {
    /*
      public enum PhoneNumberFormat {
        E164,
        INTERNATIONAL,
        NATIONAL,
        RFC3966
      }
      */
    val msn = phoneNumberUtil.parse("08012345678", "JP")
    println("E164: " + phoneNumberUtil.format(msn, PhoneNumberUtil.PhoneNumberFormat.E164))
    println("INTERNATIONAL: " + phoneNumberUtil.format(msn, PhoneNumberUtil.PhoneNumberFormat.INTERNATIONAL))
    println("NATIONAL: " + phoneNumberUtil.format(msn, PhoneNumberUtil.PhoneNumberFormat.NATIONAL))
    println("RFC3966: " + phoneNumberUtil.format(msn, PhoneNumberUtil.PhoneNumberFormat.RFC3966))
}
# => E164: +818012345678
# => INTERNATIONAL: +81 80-1234-5678
# => NATIONAL: 080-1234-5678
# => RFC3966: tel:+81-80-1234-5678

電話番号のタイプを知りたい: getNumberType

固定電話、携帯電話、フリーダイヤル、、、など、電話番号のタイプ判別ができます

fun libphonenumberTest_getNumberType() {
    val mobile = phoneNumberUtil.parse("08012345678", "JP")
    val fixed = phoneNumberUtil.parse("81312345678", "JP")
    val free = phoneNumberUtil.parse("0120123456", "JP")
    println("mobile: " + phoneNumberUtil.getNumberType(mobile))
    println("fixed: " + phoneNumberUtil.getNumberType(fixed))
    println("free: " + phoneNumberUtil.getNumberType(free))
}
# => mobile: MOBILE
# => fixed: FIXED_LINE
# => free: TOLL_FREE

電話番号の一致をチェックしたいisNumberMatch

2つの番号が同一かどうか、その信頼性を判断します。どのスケールでなら一致しているかを判断してくれるみたいですね。

fun libphonenumberTest_isNumberMatch() {
    println(phoneNumberUtil.isNumberMatch("+81334311234", "+81334311234"))
    println(phoneNumberUtil.isNumberMatch("+81334311234", "0334311234"))
    println(phoneNumberUtil.isNumberMatch("+81334311234", "34311234"))
    println(phoneNumberUtil.isNumberMatch("+81334311234", "+818012345678"))
    println(phoneNumberUtil.isNumberMatch("+81334311234", "0"))
}
# => EXACT_MATCH
# => NSN_MATCH
# => SHORT_NSN_MATCH
# => NO_MATCH
# => NOT_A_NUMBER

電話番号のバリデーションをしたい: isPossibleNumber, isValidNumber

電話番号の長さだけを見て、電話番号として成立しているかどうかを判断します。
isPossibleNumberは電話番号の長さを、isValidNumberは加えてprefixまで見ているらしく、前者の方が速いみたいです。

fun libphonenumberTest_isPossibleNumber() {
    val msn = phoneNumberUtil.parse("08012345678", "JP")
    val justNumber = phoneNumberUtil.parse("00000", "JP")
    val just15Numbers = phoneNumberUtil.parse("000000000000000", "JP")
    println(phoneNumberUtil.isPossibleNumber(msn))
    println(phoneNumberUtil.isPossibleNumber(justNumber))
    println(phoneNumberUtil.isPossibleNumber(just15Numbers))
}
# => true
# => false
# => true

fun libphonenumberTest_isValidNumber() {
    val msn = phoneNumberUtil.parse("08012345678", "JP")
    val justNumber = phoneNumberUtil.parse("00000", "JP")
    val just15Numbers = phoneNumberUtil.parse("000000000000000", "JP")
    println(phoneNumberUtil.isValidNumber(msn))
    println(phoneNumberUtil.isValidNumber(justNumber))
    println(phoneNumberUtil.isValidNumber(just15Numbers))
}
# => true
# => false
# => false

終わりに

今回紹介したものはほんの一部で、他にもダミーの電話番号を生成してくれたり、文章中から電話番号を抽出してくれたり、など至れり尽くせりなライブラリになっています。
電話番号というと、個人情報の中でもなかなか扱いづらく収集しづらいものに分類されてしまいがちなので、なかなかさわる機会ってないのがちょっと残念です。
ついでに、先日、キャリアがRCS準拠のサービスを始めるとのニュースがありました。

www.nttdocomo.co.jp

news.kddi.com

www.softbank.jp

これ使って遊べたら面白そうだなぁ。

おまけ

電話番号がどの企業に割り当てられているか、が一覧になっています。携帯の電話番号だとMNPのために判断が難しくなっていますが。。。 (電気通信番号指定状況) http://www.soumu.go.jp/main_sosiki/joho_tsusin/top/tel_number/number_shitei.html

雰囲気でカンバンやってませんか - 『カンバン仕事術』を読んだ

 結構長い間、『カンバン仕事術』という本を読んでいます。

カンバン仕事術

カンバン仕事術

 数ヶ月前、業務でカンバンツールを取り入れる機会を得ました。近くの部署の方々に話を聞いたりパブリックになっているカンバンを眺めながらなんとなーく運用をしてきたのですが、今のところあまりうまくいっていません……。
 正直カンバンツールを入れれば自然と上手くいくじゃろ、と思っていた節もあり、なんとかしようと思っていた所この本と出会いました。まだ読み終わってはいないのですが、途中までのまとめと現時点での感想・反省を書き残しておきたいと思います。続編として書くかはまだ決めていませんが、この溢れ出る思いをなんとか今のうちに書き残しておきたい……と待ちきれなくなり書き始めてしまいました。

チームについて

  • 開発者3人(自分含む)、マネジメント層数人
  • 運用作業はまだない
  • カンバンツール導入まではGithub issueベースのタスク管理をしていた
  • カンバンツールとしてTrelloを導入

本について

 大きく3章で構成されています。

  • 第I部 カンバンの学習
    • 開発プロセスに悩むチームが、カンバンを実際に導入する(したくなる?)までの流れが物語形式で書かれています。
    • カンバンの紹介です
    • チームメンバーのうち何人かには、本書を回してとりあえずこの章だけは読んでもらいました。
  • 第II部 カンバンの理解
    • カンバンの生まれてきた背景や概念について説明しています。
    • 第I部で出てきた用語が詳しく紹介されていきます。
  • 第III部 カンバンの応用
    • まだ読んでません!

学び

カンバン導入のメリットは「改善の機会」を洗い出すこと

 冒頭で、カンバンツール導入があまりうまくいっていないと書きました。具体的には、途中からみんながカンバンに状況を反映しなくなったり、手元のお気に入りのツールにメモしてしまったりで、カンバンに情報が集まらなくなってしまったんです。
 そもそも、本来カンバンツールって何?ってところから考える必要がありました。
 導入時には「タスク管理ツール」として、以下のようなメリットを想定していました。

  • タスクの進捗が見えやすくなる
  • Excelを達成し、キレイなUIでモチベが上がる
  • Githubのコードとの連携が楽

 要は、Excelで作った職人技ガントチャートを脱して、少しでもナウい開発現場を作ろうとしていました。ガントチャート作成の手間やら管理の手間やらを減らし、少しでも長くコーディングの時間を確保したかったんです。
 ところが、結果は先程書いたとおりです。各自お気に入りのタスク管理方法があったため、なかなか情報がカンバン上に集まってきませんでした。

 この本では、カンバン導入の効果はチームの「改善の機会」(問題のこと。本書の中ではこのような表現を意図的に用いているようでした)を可視化することだとありました。つまり、ただタスク全体を見やすくして期限までに全ての作業を完了させるだけではありません。
ただタスクを全部終わらせて満足ではなく、常にその時その時の状況に応じて最適化へ向けて変化し続けるチームを作る/になること。配属以来なかなか意識できていませんでした……。

レーンの決定は真似すればいいものじゃない

 何となく導入したカンバンを見ると、大抵は「Backlog」「Ready」「OnGoing」...などのレーンが並んでいるはずです。僕のいる部署のことです。出処は色々あると思いますが、とりあえず始めてみようかーといってざっくりレーンを作ると大抵こんな感じになるのではないでしょうか。
 結論から言うと、この時点で使われないカンバン作りは完成です。使われないどころか、何も業務を見せてくれないカンバンが出来上がります。業務の流れを勝手に想像で決めてしまうと、見えるはずのものも見えなくなってしまいます。業務と業務の間にある隠れタスクを洗い出すこともカンバンの大きな役割でした。
 カンバンを使って業務を流れとして明確にすること。これって、Rx系のStreamの定義と近いところがあるように思えます。データ(タスク)の流れを定義する。どこかで処理が失敗したり、バッファから溢れそうなときはちゃんとエラー処理をする。コードやシステム上であれば想定しやすいし、完全にはできなくても考える意識は持てるはずです。何より、開発メンバーにはこっちの方が響くような気がしています!(明日伝えてみよう)

イケてるツールがカンバンツールの全てではない

 カンバンツールと聞くと、TrelloやらZenhubやら、最近だとGithub projectが上がってくると思います。カンバンを導入した際も、これらの中から検討して現在はTrelloを使っています(最低限の機能はありながら、あまり縛りがない点が気に入っています)。
 ですが、これらって結局カンバンの電子ツールの側面でしかないんですよね。立派なツールでなくても、ホワイトボードと付箋さえあればカンバンは始められます。今いる会社は業務上の都合上、電子ツールを選択するしかありませんでした。結果的にセーフでしたが、ツールの使用許可が下りず断念するくらいなら、カッコつけておしゃれなツールを使う必要はないということは覚えておきたいです。

反省

  • カンバンでタスク管理だけをやろうとしない。チーム全体の隠れ作業を暴き出そう。
  • カンバンのカラムはチーム全員で決めよう。その辺のボードを真似して終わりではない!
  • PCやスマホ、ネット環境がなくてもカンバンは始められる!

おわりに

 本当はカンバンの原則を紹介したり、WIP制限などの具体的なカンバン運用の話をしたほうがいいのかもしれません。が、憧れだとか前の現場で使ってたからだとかで導入する際に躓いたこと、といった観点でまとめてみました。カンバン運用などについてはその先にある話だと思います。
 試行錯誤をしながら作り変えていくものなので、なかなかみんなが気持ちいい形に落ち着くことはできなさそうですが……。早めに数字として結果を計測できるようにしていくことが大事ですね。今後も本書は手元に置きつつ、定期的に見直していきたいと思います。

 また、本書ではカンバン運用のみならず、TDDやBDDなどの開発手法、さらには上手な付箋の剥がし方(!)まで触れられています。普段技術書しか買わない、といった方も、意外な発見があるかもしれません。

今だから読みたい -「Androidアプリ開発の教科書 なんちゃって開発者にならないための実践ハンズオン」を読んだ

 Androidの開発に携わるようになって半年ほど経過しました。RxJavaやDaggerなどのライブラリ、ナウい設計のフレームワークなど、様々な技術要素に揉まれながら何とかやってきましたが、いまいちAndroidと仲良く慣れたような気がしません……。
 一度基礎からやり直そうかと思っていたところ、今年発売の新しい入門書が出ていたので読んでみました。『基礎&応用力をしっかり育成! Androidアプリ開発の教科書 なんちゃって開発者にならないための実践ハンズオン』です。
 2月に発売されたばかりで、もちろんAndroidStudio3対応です。

基礎&応用力をしっかり育成!  Androidアプリ開発の教科書 なんちゃって開発者にならないための実践ハンズオン (CodeZine BOOKS)

基礎&応用力をしっかり育成! Androidアプリ開発の教科書 なんちゃって開発者にならないための実践ハンズオン (CodeZine BOOKS)

目次と学べること

  1. Androidアプリ開発環境の作成
  2. はじめてのAndroidアプリ作成
    • Androidプロジェクトの作成方法について
  3. ビューとアクティビティ
    • ViewのそれぞれのXMLタグの意味、使用方法
    • ViewのXMLでよく使う属性
  4. イベントとリスナ
  5. リストビューとダイアログ
    • リストビューの生成と描画(ArrayAdapter)
    • リストへのクリックイベントの設定
    • Toastの生成と表示
    • Dialogの生成と表示
    • Contextについて
  6. ConstraintLayout
    • ConstraintLayoutの概要、使い方
  7. 画面遷移とIntentクラス
    • リストビューの生成と描画(SimpleListAdapter)
    • Activityの追加方法
    • インテントを使った画面(Activity)遷移
    • Activity間のデータの受け渡し
    • Activityのライフサイクル
    • AndroidのLogについて
  8. オプションメニューとコンテキストメニュー
    • オプションメニューの生成と描画
    • コンテクストメニューの生成と描画
  9. フラグメント
    • Fragmentの生成
    • Fragmentのライフサイクル
    • Activityへのアタッチ
    • Fragmentの遷移とデータの受け渡し
    • Fragmentを使った複数サイズの画面対応
  10. データベースアクセス
    • SQLiteデータベースを使ったデータ永続化
  11. 非同期処理とWeb API連携
    • AsyncTaskを使った非同期処理とスレッド
    • AndroidでのHTTP通信(外部ライブラリの使用は無し)
  12. メディア再生
    • 音楽ファイルの再生、停止
    • 音楽ファイルのループ再生
    • 音楽ファイルの巻き戻しと早送り
    • 素敵なフリー素材サイト(!)
  13. バックグラウンド処理と通知機能
    • サービスを用いたバックグラウンド処理
    • 通知の生成とActivityの外部起動
  14. 地図アプリとの連携とGPS機能の利用
    • 暗黙的インテントの使い方
    • 位置情報の取得方法
    • Permissionの確認と取得時のハンドリング
  15. カメラアプリとの連携
  16. マテリアルデザイン
    • マテリアルデザインの概要
    • ScrollViewの使い方
    • ToolBarの使い方
    • スクロールに応じて動的に変化するToolBar
  17. リサイクラービュー
    • ScrollViewとRecyclerViewの違い
    • RecyclerViewの使い方

いざ洗い出してみるとすごい量です。。。

経歴

  • 2017年新卒
  • Android開発歴は半年
  • 学生時代はお手伝いとしてSpringとRailsでバックエンド開発を2年ほど

所要時間

 けっこう時間をかけてゆっくり読み込んだのですが、コードを写経しながらでも3日ほどで終わりました。
 ただ、多くの題材を扱うのであまり急いでやっても仕方がないかも……?

感想

 Android開発を始めるとき、この本があればかなりスタートダッシュを決められたのでは……?と思うほど、僕にはぴったりでした。
 Android開発の入門書というと、初めにViewの説明があったりなかったりした直後にActivity, そのライフサイクルの話がいきなりくるパターンが多いイメージです。
 この本では、作るアプリのイメージ→写経用のコード→解説の順番に章が立てられています。中でも、コード→解説をかなり細かい単位で繰り返しているのが印象的でした。頭ではなく体で覚えるタイプの僕には大変ありがたかったです。
 ちなみに、本のコードには省略されている箇所があるので、全部をこなそうとするとサンプルソースは必須です。
 また、上を読んでもらえればわかりますが、目次以上の内容が盛りだくさんです。個人的にはここがかなり有難くて、例えばContextなんてなかなか理解に手間取るポイントだと思います。このあたりのきめ細やかさもよかったです。

よかった章

 本を通して読んでみて、個人的に結構抜け漏れがあったのがリスト操作の章でした。リスト操作周りの処理を何回も一気に書く機会って実際の開発フェーズだとそんなに無いような気がするので、まとめて理解して手になじませるにはいい機会だったなと!
 また、マテリアルデザインの章も今この時期にはかなり貴重な学習材料だと思います。Android開発の中で、View周りのpropertyとかThemeの継承関係とかって何となくやりがちな分野ではないでしょうか?(そんなことないのだろうか) 短いサイクルでプラットフォームであるAndroidOSが新しくなっていく中で、最新版のOSの話題が本で手に入る今だからこそより一層価値がある章のはずです!

気になったこと

褒めてばかりでもステマっぽくなってしまうので、2点指摘しておきます。

誤字

初版ということもあるかと思いますが、ちらほら誤字脱字が見受けられました。ただ、理解を妨げるようなものは無かったはず。

カメラの章について

 かなり限られた用途かもしれませんが、業務上ここでのカメラの用途だと不十分でした……。
 本の中では、Intentを使ってAndroid標準のカメラアプリを使って写真を撮影する方法が推奨されています。(Googleもこの方法を薦めているようですね)
 一方、カメラ機能としてQRコードやバーコードを読み込みたい、といった要望って少なからずあるような気がしています。GoogleからBarcodeAPI(https://developers.google.com/vision/android/barcodes-overview)として提供されていますが、これのハンズオンとは言わずとも、紹介はあってもよかったのかな、と!

推奨読者層

 始めてプログラミングを始める人にはちょっと厳しいと思います。本の帯にも、対象はJava言語の学習者、とあります。Javaの解説は無く、基本的に関心はAndroidです。
 一方、ある程度プログラミング言語を触ったことがあるけどAndroid開発は初めて!という人には是非オススメしたいです。特に、プログラミング経験がほとんど無いなかで会社の研修を終えた方なんかには最適だと思います。「会社の研修」っていうのがミソです。特にそれを感じたのが、DBの章。SQLの知識はもちろんですが、JavaのDB周りを触ったことがないと調べることになりそうな箇所がいくつかありました。

 僕はそれだけでなく、数ヶ月ほどAndroidを開発したことがある人にもこの本を読んで写経してほしいです。皆さん、上の学べること、全部説明(とは言わずとも、イメージ)できますか?
 最近のAndroidでホットな話題だと、冒頭で書いたような設計やライブラリなどのものが多いように感じます。その中で、体系的にしっかり腰を据えてAndroidの学習を進める機会ってなかなか得られるものではないように思えます。この本のタイトルにもある通り、「なんちゃって開発者にならないため」には、Android StudioのNew Projectをした数がものを言うこともあるはずです。機能追加とリファクタリングだけでは経験が偏る、っていうのは僕がここ最近ひしひしと感じていることです。。。

合わせて読みたい記事、本など

まとめ

  • Android8.0が最新の今だからこそ読んで欲しい!
  • 手を動かしながら学びたい人におすすめ