読者です 読者をやめる 読者になる 読者になる

visible true

技術的なメモを書く

Androidアプリケーションのビルド体験を改善するリモートビルドサービス Cyborg-Build を作りました

Android

はじめに

これはAndroid Advent Calendar 2016の20日目のエントリです。

本エントリではAndroidアプリケーションのビルド体験を改善するリモートビルドサービス Cyborg Build を紹介します。

背景

以前AndroidアプリケーションをGoogle Compute Engineのインスタンスでビルドする - visible trueクラウド上にインスタンスを作ってAndroidアプリケーションのビルドを代行させる方法について書きました。エントリでは低スペックなインスタンスでの試用でしたが、その後いくつかのインスタンスを試しGCEではn1-highcpu-8(vCPU x 8、メモリ 7.2 GB)くらいのスペックがパフォーマンスとコストのバランスが良いとわかりました*1

パフォーマンスとコストのバランスが良いと言ってもn1-highcpu-8は一ヶ月フル稼働で$150ほどかかります。インスタンスの可用性の設定をプリエンプティブにすれば$44くらいまで抑えられますが、プリエンプティブインスタンスは最長で24時間の稼働という制限があるので、インスタンスの起動処理などを別途行う必要があります。さらに最長で24時間といっても5分で落ちるケースもあるので安定的な動作をさせたい場合は色々と工夫が必要になります。

gcloudなどを使ってインスタンスの状態を見て起動したり落としたりするのを自動化してもよかったのですが、この辺りで「もっと簡単に誰でも使えて安上がりな仕組みができないか」と考えてサービス化を検討し始めました。

解決したい課題

リモートビルドサービスで解決したい課題は次の通りです。

  1. ビルドを待つ間CPUを専有されてしまって他の作業ができない
  2. ビルド速度が遅い
  3. リモートビルドシステムの構築やメンテの手間がかかる
  4. 運用コストが高い

1と2はAndroidアプリケーション開発における課題で、3と4はリモートビルドシステムを自前で運用する場合の課題です。

今回作ったCyborg Buildは1,3を解決しています。2についてはリモートインスタンスのスペックアップで可能ですが、4の問題をサービス化で解決できるかどうかを先に検証しなければならないので直近のスコープには入っていません。

Cyborg-Build

1ヶ月ほどプロトタイピングしながらあれこれ試してある程度形になってきたので本日よりα版として公開します。ビルド時の体験が劇的に良くなると思うのでぜひ使ってみてください。

Cyborg Build

始め方はこちら

http://cyborg-build.com/getstarted

仕組み

サービスの仕組みは次の通りです。

Cyborg-BuildにGoogleアカウントでログインするとGoogle Cloud Storageのバケットをアカウントごとに払い出します。このバケットにソースコードをアップロードします。バケットにはログインしたアカウントとCyborg-Buildサービスのみがアクセスできます。

Cyborg-Build内でビルドコマンドを定義したプロジェクトを作成すると上図の操作をするスクリプトをダウンロードできます。ビルドスクリプトAndroidプロジェクトのルートに置いて実行するとバケットへソースコードをアップロードし、Cyborg-Buildに対してビルドリクエストを行います。Cyborg-Buildは対応するリクエストをリモートインスタンスで実行し、成果物をバケットにアップロードします。その後ビルドスクリプトはアップロードされた成果物をローカルにダウンロードします。オプションで起動アクティビティを設定すれば端末へのインストールと実行まで行えます。

機能

  • プロジェクトの作成
    • プロジェクトはパッケージ名と複数のタスクを持っています。
    • タスクは実行するgradleタスク回収する成果物のパス起動するアクティビティ名を設定できます
  • リモートビルドスクリプトのダウンロード
    • 作成したプロジェクトにもとづいてリモートビルドスクリプトを生成します
  • コマンドラインでのリモートビルドの実行

制限

α版なので最低限リモートビルドが体験できるところまでの機能となっています。次の項目はまだサポートしていませんが順次改善していきます。

  • 作成したプロジェクトの編集(かなり早期にやります)
  • イントラ内にあるmaven repositoryへのアクセス(未検討)
  • NDKの利用(おそらく動くとは思いますが...)
  • gradlewタスク以外のコマンド実行
  • テスト結果などの回収(動くかまだ試してない)
  • 各種メトリクスの表示などなど
  • IDEA Plugin化によるシームレスなリモートビルドの利用

α版で検証すること

色々とやりたい事はあるのですがα版では次の点に絞って取り組もうと思ってます。

  1. そもそもリモートビルドに価値があるのかを検証する
  2. 自己運用より安価にリモートビルドを提供ができるか
  3. 十分なマーケットサイズがあるか

資金周りが最初からクライマックスなので2については早期に検討して課金を開始したいところです。

フィードバックをください

個人的にはリモートビルドほんとに最高なのでぜひ皆さんに使っていただきたいです。そして色々とフィードバックを頂けると嬉しいです。

  • Twitter: @sys1yagi
    • おそらく一番反応が良いです。
  • Slack: invite link
    • 一応常駐しています。
  • ご意見フォーム(Cyborg Build)
    • トップの右下に設置しています。投稿は必ず読みます

サイトは英語ですがわりと適当なのでtypoや文法違うぞといったフィードバックももらえると嬉しいです。この構成だと動かない!みたいなケースもslackなどで相談して頂けると応対できると思います。

おわりに

個人のアプリはすでにCyborg-Buildを使って開発しています。会社ではリモートビルドシステムが構築済なのでそちらを使ってますが、コスト面でCyborg-Buildのほうが安いよねって感じにして移行できたらな〜とか思っています。とりあえず世界中のAndroidエンジニアのビルド体験を最高にできたらいいなと思っています。

*1:AWSではc3.2xlarge辺りを使っています

Kotlin 1.1 async/awaitの仕組みと使い方の概要 for Android

Kotlin Advent Calendar Android

これはKotlin Advent Calendar2016の19日目のエントリです。

本エントリではKotlinの次期バージョン(1.1)で導入されるコルーチンと、その実装のひとつであるasync/awaitについて解説します。

今回書いているコードはGitHub - sys1yagi/kotlin-async-await-sample: yey!に置いています。

Kotlin 1.1の様子

Kotin 1.1は2016年7月にFirst glimpse of Kotlin 1.1: Coroutines, Type aliases and moreで変更の概要とEAPが公開されました。コルーチンのほかにタイプエイリアスやメソッド参照、ラムダ式での引数の分解宣言などなど様々な便利な機能の追加が予定されています。2016年12月の時点で1.1-M03が公開されています。

Kotlin 1.1の仕様はKEEPで検討が進められていて、最近では1.1以降のものについても検討が走っているようです。Github ProjectsのKEEP Kotlin 1.1 では1.1に絞ったissueの進捗を確認できます。

コルーチンとはなにか

コルーチンは任意の箇所で一時停止ができる計算と考えることができます。一般的な関数は処理の開始からリターンまででひとつの処理を表しますが、コルーチンは処理の途中に中断するポイントを明示できます。中断するごとに値を返せるほか、中断したときの状態を保ったまま任意のタイミングで再開ができるので、非同期処理や遅延リストの作成(ジェネレータ)を簡潔に書けるようになります。

次のコードはasync/awaitを用いた非同期処理の待ち合わせの例です。

asyncAndroid {
  val user = userApiClient.get(id).await() // ここで中断して非同期処理
  val articles = articleApiClient.getArticles(user).await() // ここで中断して非同期処理
  // 取得完了
  showArticles(articles)
}

一般的な非同期処理はコールバックを用いてネストが深くなりますが、コルーチンを用いるとフラットに記述できるようになります。

Kotlin 1.1のコルーチンのアプローチ

Kotlin 1.1ではコルーチンの処理全体を「状態」の集まりとしてステートマシンに変換することで、JVM上での動作を実現しています。

コルーチンのコードをステートマシンとして解釈するために、コルーチンの処理を表すcoroutineキーワードと、中断点を示すためのsuspendキーワードが追加されています。これらのキーワードによって「コルーチンの実装」を言語機能としてサポートします。

Kotlin 1.1で提供されるasync/awaitやジェネレータは、コルーチンの実装としてライブラリの形式で提供されます。

Kotlin 1.1におけるコルーチンの実現方法の詳細についてはTechBoosterがC91で頒布する「なないろAndroid」に詳細な解説を書いていますのでぜひ読んでみてください。

Kotlin 1.1を導入する

Kotlin 1.1はまだEAPの段階なので導入のためにいくつか設定が必要です。次のようにEAPmaven urlを追加した上で1.1-M03などのバージョンを指定してください。差分のみ記載しているので適宜必要なものを設定してください。

// build.gradle
buildscript {
  ext.kotlin_version = '1.1-M03'
  repositories {
    maven { url = 'https://dl.bintray.com/kotlin/kotlin-eap-1.1' }
  }
  dependencies {
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
  }
}
repositories {
  maven { url = "https://dl.bintray.com/kotlin/kotlin-eap-1.1" }
}

// module/build.gradle
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'

dependencies {
  compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}

Koltin PluginをEAP 1.1にする

Android Studio向けのKotlin PluginもEAP版が提供されています。[Tools]-[Kotlin]-[Configure Kotlin Plugin Updates]でUpdate channelを'Early Access Preview 1.1'に変更し、プラグインをアップデートしてください。

async/awaitライブラリを導入する

Kotlin 1.1向けのコルーチン実装はkotlinx.coroutinesで開発されています。現時点では次の3つがbintrayで配布されています。

  • kotlinx-coroutines-generate : ジェネレータ
  • kotlinx-coroutines-async : async/await
  • kotlinx-coroutines-rx : RxJavaを用いたasync/await

kotlinx-coroutines-asyncはasync/awaitのインタフェースとしてCompletableFutureを用いています。CompletableFutureはJava 8のクラスなので、Androidで利用しようとするとminSdkVersion 24が必要となります。そのためAndroidでasync/awaitを使う場合はkotlinx-coroutines-rxを選択することになります。

kotlinx-coroutines-rxを導入する設定は次の通りです。スレッド操作のためにrxbinding-kotlinも入れておきます。

buildscript {
  ext.kotlin_coroutines_version = '0.1-alpha-2'
}
repositories {
  maven { url = "https://dl.bintray.com/kotlin/kotlinx.coroutines" }
}
dependencies {
  compile "org.jetbrains.kotlinx:kotlinx-coroutines-rx:$kotlin_coroutines_version"
  compile('com.jakewharton.rxbinding:rxbinding-kotlin:1.0.0') {
    exclude group: 'io.reactivex', module: 'rxjava'
    exclude group: 'com.android.support', 'module': 'support-annotations'
    exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib'
  }
}

Androidでasync/awaitを使う

kotlinx-coroutines-rxはasyncRx関数を提供します。asyncRx関数は引数のブロック内で呼び出した中断関数を直列に連結し、最後の処理の値を戻り値としてObservableで包みます。

val observable = asyncRx<List<Article>> {
    val user = userApiClient.get(1L).awaitSingle() // ここで中断と再開をする
    articleApiClient.getArticles(user).awaitSingle() // ここで中断し、戻り値を返す
}
observable.subscribe { articles ->
    // do something.
  }

上記の例ではawaitSingle()が中断関数です。この関数はObservableの拡張関数として定義されています。このほかにawaitFirstawaitLastがあります。中断関数の種類や名前はコルーチンの実装に依存します。

asyncRx関数の機能は、Observableの中断関数の呼び出しにもとづいて直列に処理を連結することのみで、実行スレッドの管理等は行ってくれません。非同期処理をするために次のように書く必要があります。

val observable = asyncRx<List<Article>> {
  val user = userApiClient.get(1L)
    .subscribeOn(Schedulers.io())
    .awaitSingle()
  articleApiClient.getArticles(user).awaitSingle()
}
observable
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe { articles ->
      // do something.
  }

かなり不格好ですね。このまま実用するのはちょっと冗長に思えます。というか普通にRxJavaを使えばいいような気がしますね。

asyncAndroidを実装する

asyncRxをそのまま使ってもあまり便利ではないので、次の要件を満たす独自のコルーチンとしてasyncAndroid関数を実装してみましょう。

  • Observableは常にsubscribeOn(Schedulers.io())observeOn(AndroidSchedulers.mainThread())で実行する
  • コルーチンの中で非同期、同期処理のすべてを記述できる

実装内容が次です。

package kotlinx.coroutines.android

import rx.Observable
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import rx.subscriptions.CompositeSubscription

fun asyncAndroid(
  coroutine c: RxAndroidController.() -> Continuation<Unit>
): CompositeSubscription {
  val subscriptions = CompositeSubscription()
  val controller = RxAndroidController(subscriptions)
  c(controller).resume(Unit)
  return subscriptions
}

class RxAndroidController internal
                        constructor(val subscriptions: CompositeSubscription) {
  suspend fun <T> Observable<T>.awaitSingle(x: Continuation<T>) {
    this.single()
      .subscribeOn(Schedulers.io())
      .observeOn(AndroidSchedulers.mainThread())
      .subscribeWithContinuation(x)
  }

  private fun <T> Observable<T>.subscribeWithContinuation(x: Continuation<T>) {
    val subscription = subscribe(x::resume, x::resumeWithException)
    subscriptions.add(subscription)
  }
}

このコードの説明は省略します。内容を読み解くにはTechBoosterがC91で頒布する「なないろAndroid」をぜひ参照してください。あるいはkotlin-coroutines-informal.mdを読むのもいいかもしれません。

asyncAndroid関数を使うと次のような記述ができるようになります。便利ですね。

asyncAndroid {
  val user = userApiClient.get(1L).awaitSingle() // 中断して非同期実行
  // UIスレッドで再開
  binding.textArea.text = "asyncAndroid loading articles..." 
  val articles = articleApiClient.getArticles(user).awaitSingle() // 中断して非同期実行
  // UIスレッドで再開
  binding.textArea.text = "asyncAndroid finish loading. size=${articles.size}"
}

おわりに

筆者はすでに個人のプロダクトでEAPのKotlin 1.1を導入しています。特にasync/awaitとタイプエイリアスとメソッド参照が便利です。正式版が楽しみですね。Kotlinサイコ-なのでぜひ皆さんも使ってください。

あわせて読みたい:コミックマーケット91 新刊情報と予約開始 | TechBooster

Vue.jsでvue-routerを使ってルーティングする時にGoogle AnalyticsでPage Viewを取る

Vue.js Javascript

ググってもパッとでてこなかったので。

前提条件

  • index.htmlなどにGoogle Analyticsを初期化するコードが埋め込まれていて、グローバルにga関数にアクセスできる
  • vue-routerを使っている

コード

main.jsとする。VueRouterのafterEachにコールバックをセットしてga関数を呼び出せばよい。

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const router = new VueRouter({/*省略*/})

// これ
router.afterEach(function (to, from) {
  ga('send', 'pageview', to.path)
})

// 省略

おわりに

vue-reportingというのもあるらしい。

AndroidアプリケーションをGoogle Compute Engineのインスタンスでビルドする

Android

AndroidのBuildを別マシンで行うスクリプト書いたった - Qiitaがとても興味深かったので、Google Compute Engineのインスタンスでビルドする環境の構築を試してみました。体験としては最高だったので、環境構築の手順を簡単にまとめます。

解決したいこと

前述の記事で語られている通り、Androidアプリケーションのビルドはとても時間がかかります。しかもCPUをフルで持っていくのでビルドしているあいだは他の事ができません。そこでビルドの処理を別のマシンに委譲することで、待っている時間を有効に使えるようにします。

Google Compute Engineのインスタンスを作る

まずGoogle Compute Engineのインスタンスを作ります。環境としては次を選択しました。

- ゾーン: asia-east1-a
- CPU: vCPUx2 (n1-standard-2)
- OS: Ubuntu 16.4 LTS
- ディスク: 20GB

f:id:sys1yagi:20161113153138p:plain

ゾーンはおそらくasia-northeast1とかの方がいいんでしょうが、転送の速度よりはビルド速度の方が大きい影響を受けると思うので、安いゾーンでCPU積んだ方が体験としてはよさそうです。

静的IPを追加する

rsyncを使うのでインスタンスのIPを固定します。静的IPはインスタンスの編集画面で追加できます。

f:id:sys1yagi:20161113154544p:plain

ssh keyの登録

インスタンスAndroid開発環境を整えるため、sshでアクセスします。ドキュメントの手順に沿ってキーを作成して登録します。

Connecting to Linux Instances  |  Compute Engine Documentation  |  Google Cloud Platform

javaのインストール

インスタンスsshでログインし、必要なソフトウェアをインストールします。まずはjavaの環境を整えます。

sudo apt-get update
sudo apt-get install openjdk-8-jdk-headless

Android SDKのインストール

次にAndroid SDKをインストールします。場所はどこでも構いません。今回は~/に置いてます。

wget https://dl.google.com/android/android-sdk_r24.4.1-linux.tgz
tar xvf android-sdk_r24.4.1-linux.tgz

ANDROID_HOMEの設定

.bashrcANDROID_HOMEと、androidコマンドのパスを設定します。

vim ~/.bashrc

export ANDROID_HOME=~/android-sdk-linux
PATH=$PATH:$ANDROID_HOME/tools

android update

androidコマンドを使ってビルドツールなどをインストールします。大体次でよさそうです。不足したものがあれば適宜入れてください。

android update sdk -u -t 1,2,3,4

license fileの作成

アプリケーションのビルド時にライセンス同意のファイルが必要です。ローカル環境の$ANDROID_HOME/licenses/android-sdk-licenseの内容をリモートインスタンス側にコピーします。

mkdir $ANDROID_HOME/licenses
vim $ANDROID_HOME/licenses/android-sdk-license

# localの`$ANDROID_HOME/licenses/android-sdk-license`の内容をコピーする

/tmp/buildディレクトリの作成

※追記 2016/11/14: インスタンスを再起動するとtmp/buildが毎回消えてしまってめんどくさいので、~/でやるようにgistのコードを更新しました。なのでこの節は省いて大丈夫です

次の項目のfabfile.pyでワーキングディレクトリとして/tmp/buildを使っています。最初は存在しないので、予め作っておく必要があります。

mkdir -p /tmp/build

fabfile.pyの準備

AndroidのBuildを別マシンで行うスクリプト書いたった - Qiitaで掲載されているgistのコードをforkし、少しだけ変更しました。

https://gist.github.com/sys1yagi/1f395190061a8d48db5e30ae160b4b99

設定項目は次のとおりです。

  • env.user = sshのユーザ名
  • env.hosts = VMインスタンスのIP
  • env.key_filename = VMインスタンスに登録したSSHキーファイル
  • module = ビルドするモジュール名
  • flavor = ビルドするフレーバー名
  • package = アプリケーションのパッケージ名
  • launch_activity = 起動するアクティビティのFQCN

これでfab buildでビルドできるはずです。

おわりに

vCPUx2 (n1-standard-2)のインスタンスの場合、手元でのビルドの3倍程度時間がかかるようでした。この辺はプロジェクトやローカルマシンのスペックなどによって様々と思いますが、インスタンスのスペックを積めばローカルより速いビルドも実現できるでしょう。

リモートでのビルドは、ローカルマシンのCPUを専有しないように出来るというだけでもかなり価値がありそうです。コストについてはまだ環境を作って間もないのでなんとも言えないですが、インスタンスを使う時だけ起動すればよいのでかなり低コストに抑えられるのではないかと思います。

「解剖 Kotlin ~バイトコードを読み解く~」をGitBookで公開しました。

Kotlin

テクブの夏コミ(C90)のアンドロイドアカデミアに書いた解剖 Kotlin ~バイトコードを読み解く~をGitBookにて公開しました。

GitBook

こちらから読めます

解剖 Kotlin ~バイトコードを読み解く~

概要

解剖 Kotlin ~バイトコードを読み解く~はKotlinで書いたプログラムを逆アセンブルすることで、Kotlinが提供している特徴的な機能がJavaでどのように表現されているかを読み解いていきます。Kotlinの特徴的な機能たちもJavaになってしまえばこっちのもの。なーんだKotlinもJavaなんだね。

目次

  • Introduction
  • KotlinとJava
  • 本書のアプローチ
  • 1. null許容型の正体
  • 2. 関数型とラムダ式の正体
  • 3. インライン関数の正体
  • 4. 拡張関数の正体
  • 5. プロパティの正体
  • 6. デリゲートプロパティの正体
  • 7. 末尾再帰最適化の正体
  • おわりに

Circle CIでAndroid SDK周りのライセンス許諾をローカル環境に合わせる

Android Circle CI

Circle CIの公式ドキュメントのTest Android Applications - CircleCIにある通りAndroid SDKをCircle CIでダウンロードするには次のようにcircle.ymlに記述する必要がある。

dependencies:
  pre:
    - echo y | android update sdk --no-ui --all --filter "package-name"

この記述の場合package-nameが可変なため、新しいSDKが出た時に変わることがありCIがコケる。 新しい名前をパッと調べる方法がよくわからないので大体はまる。つらい。

CI環境でAndroid SDKのダウンロードを自動化する2016 - Qiitaにローカル環境で行ったライセンス許諾のライセンスファイルを使う方法が書かれていて、最高だったのでCircle CIにも適用した。

ライセンスファイルの中身をコピーする

ライセンスファイルの中身はハッシュ値になっている。ファイルは次の場所にある。

$ANDROID_HOME/licenses/android-sdk-license

circle.ymlに設定

ライセンスファイルから取り出した値をcircle.ymlに設定する。 ディレクトリを作ってechoでライセンスファイルを作ればOK。

dependencies:
  pre:
    # 省略
    - mkdir $ANDROID_HOME/licenses
    - echo "ここにライセンスファイルの値" >> $ANDROID_HOME/licenses/android-sdk-license

これでローカル環境で許諾したものと同様のSDKを自動的にインストールできるようになる。

WEB+DB PRESS vol.94で特集「はじめてのKotlin」を書きました

Kotlin Android 執筆

2016年8月24日発売のWEB+DB PRESS vol.94(¥1,598)で特集「はじめてのKotlin」を書きました。

特集「はじめてのKotlin」について

「はじめてのKotlin」の目次は技術評論社WEB+DB PRESS Vol.94のページで見られます。以下に抜粋しつつ補足の解説をします。

  • 第1章:Kotlinとは何か
    • Kotlinの概要と特徴、近年のAndroidの開発言語を取り巻く環境に言及し、なぜAndroidの開発言語として注目されているのかについて、具体的な理由を解説します。Jack and Jillを含めたJava8環境とKotlinのどちらを選択するべきかについても言及しています。
  • 第2章:Try Kotlinで基本文法を学ぼう
    • null許容型,スマートキャスト,制御構文,クラスなどKotlinを使う上で必要な基礎を解説します。最低限の知識は身につくはずです。
  • 第3章:ラムダ式と関数を使いこなそう
  • 第4章:Android開発に導入しよう
    • KotlinをAndroidプロジェクトへ導入する方法と,つまずきやすいポイントの解説とその解決方法を説明します。
  • 第5章:Kotlinを活用しよう
    • 拡張関数を使ったAndroid APIの改善や、スコープ関数の解説、kaptの使い方、Kotlin Bytecodeによるコンパイル結果の確認などについて解説します。
  • 第6章:Kotlinの将来
    • 公式採用の可能性について言及しています。またKoltin 1.1で追加される予定の機能などについて解説します。

全体的にAndroidエンジニアを対象として書いていますが、2章、3章はKotlinにだけ言及するので、Androidエンジニアでない方にも価値がある内容になっているのではないかと思います。

執筆の感想

4月か5月頃に技術評論社 編集長の稲尾さんに声をかけていただき、一度ランチしながらKotlin特集のプランニングをして、その後Goが出て書き始めたといった感じでした。ランチの時に「バリバリ書いて前倒しっすよ〜」とか言っていたんですが案の定ギリギリとなってしまいました。ちょうど仕事の方も修羅場になっていて全体的に修羅場でした。

稲尾さんは流石に何人もの技術者を相手してきているだけあって、サクーッと進める所は進め、シュッと用意するところは用意し、バシバシッと尻を叩く所は叩くというメリハリある編集の進行で、執筆者として大変安心して取り組めました。原稿はGithub上で管理していて、稲尾さんもissueをバンバン立てたりPRをバンバン出すのでめっちゃやりやすいです。

原稿書いてる時はマジで「ああなんでやるって言ってしまったんだろう?」と辛い思いになる事が沢山あるんですが、終わってみると「あれとかこれとかも書きたいな」とか思っちゃうので危険ドラッグでは〜?って気がします。技術書典夏コミ(C90)の原稿も重なって「死ぬのかな...?」って思いました。

最後に

特集のページ数が31Pなのでかなり盛々で濃い内容になってると思います。一方で言語の解説としては網羅性は足らないので、特集を読んでKotlinを気に入った方はぜひKotlinスタートブックも読んでください。

また、夏コミ(C90)で頒布したアンドロイドアカデミアに、Kotlinのnull許容型やラムダ式、関数型、インライン関数、拡張関数などがJavaバイトコード上ではどのように表現されているのかを読み解く「解剖 Kotlin ~バイトコードを読み解く~」という章を書いたので、こちらも合わせてぜひお読みください。