heihei blog

Blog icon by Unsplash https://unsplash.com/@virussinside

Notes - droidcon NYC 2017: Upgrading to Moshi

※Notes記事では、英語のセッション動画やポッドキャストの内容を(雑に)英語でメモに書き残すことを行っています。本記事は、あくまで動画を見ながら、参考程度に読んでいただくことを想定しています。Notes記事には雑メモ程度のものだったり、書き起こしのようなものもあります。これから実際の動画を見る際には、本記事の内容が少しでもお役に立てば幸いです。(内容において不備、誤字脱字等ありましたら気軽にご連絡いただけると嬉しいです。)

本記事は、droidcon NYC 2017 - Upgrading to Moshi - YouTubeの記事です。

今現在、AndroidにおけるJsonシリアライズ・デシリアライズを行なうライブラリの中では、Gsonが一番人気であると個人的には感じているのですが、 本セッション動画では、Moshiとは何なのか、MoshiがGsonよりも優れている点(またはGsonが提供していてMoshiが現状提供していないAPIについて)、そしてGson→Moshiへの置き換えのメリットや方法などについて紹介されています。(※本セッション動画にはmoshi-kotlinについての説明はほとんどありません。Kotlinに関する話というよりは、MoshiというJsonパーサーライブラリについての説明に重きをおいた発表となっているようです。)

f:id:shaunkawano:20180109131119p:plain

Upgrading to Moshi

What is Moshi?

JSON serialization library for Java with a streaming and object-mapping API.

  • Moshi is kind of "Gson 3"; it is kind of Gson 2 but kind of like "Gson Lite"
  • It takes great things from Gson API and removes extra part of Gson API that not many people are using

Why update from Gson?

  • Gson often contains breaking API changes
  • Application using Gson does not often update Gson dependnecy
  • If the code already works with Gson then not necessarily need to upgrade; you are not going to obtain amazing performance optimization by switching from Gson to Moshi

Why update from Gson: Gson

  • In Inactive development
    • Breaking changes
    • Not many people update to use the latest version
  • Too lenient
    • "Platform type issue"
      • "Date" type adapter
      • Implementation change in the platform affects your adapter that has relied upon the previous version of the platform implementation
  • Large API
  • Inconsistent exceptions(e.g. IOException may occur when it actually should be data exception).
  • ~188KB, 1345 methods (Moshi: 112KB, 759 methods)

Why update from Gson: Moshi optimizations

  • Share buffer segments with other Okio users.
    • If you use OkHttp or Retrofit or any other libraries that rely on Okio
  • Avoid allocating strings while deserializing.
    • JsonReader.selectName(Options) allows you to pre-allocate memories.

How to upgrade?

FieldNamingPolicy

=> Defining model classes as actual JSON response may be clearer. (Even using sneak_cases as wrigin sneak_cases for layout_ids in Android)

Reflective field naming policy

  • @SerializedName("the_name") => @Json(name="the_name")

Streaming API

  • It's the same!
  • com.google.gson.stream.JsonReader => com.squareup.moshi.JsonReader
  • com.google.gson.stream.JsonWriter => com.squareup.moshi.JsonWriter
  • Moshi bonus
    • JsonReader.Options
    • JsonReader.setFailOnUnknown

JsonReader.Options

Prepare strings ahead of time:

Options.of("key1", "key2")

Read out directly from the input source:

JsonReader.selectName(options), JsonReader.selectString(options)

returns index of string in Options.

setFailOnUnknown

  • JsonReader.setFailOnUnknown(true)
  • Useful for debugging, not for production app
  • Fail when JsonReader.skipValue() is called to ensure you are not missing any JSON data while debugging

Object Mapping

  • TypeAdapter => JsonAdapter
  • No document-level API like Gson.fromJson()
  • Gson.getAdapter(Type) => Moshi.adapter(Type)
  • Cache your adapters!
    • Object Mapping without bad leniency
      • Platform types require explicitly registered JsonAdapters.
      • moshi.adapter(java.util.Date.class)
      • moshi.adapter(java.util.ArrayList.class)
      • moshi.adapter(android.graphics.Point.class)
    • JsonAdapter wrappers:
      • serializeNulls(), nullSafe(), lenient(), indent(String), failOnUnknown()
    • TypeToken => com.squareup.moshi.Types factory methods

Moshi preferes plain Java's java.lang.reflect.Type. => TypeToken.getParameterized(List.class, String.class) => Types.newParameterizedType(List.class, String.class)

Unknown Enums

enum Exercise { RUN, JUMP, WALK }

Gson: exerciseTypeAdapter.fromJson("jog") => returns null Moshi: exerciseJsonAdapter.fromJson("jog") => throws JsonDataException

EnumWithDefaultValueJsonAdapter => API in Moshi to have fallback enums?

JsonQualifier

Special-case type qualifiers:

class Data { @JsonAdapter(WrappedStringTypeAdapter.class) String string; }

=>

@Retention(RUNTIME) @JsonQualifier @interface WrappedString {}
class Data { @WrappedString String string }

WrappedStringTypeAdapter.java

class WrappedStringTypeAdapter extends TypeAdapter<String> {
  String read(JsonReader reader) throws IOException {
    reader.beginObject();
    String string = reader.nextString();
    reader.endObject();
    return string;
  }
}

Easier JsonAdapters

Traditional JsonAdapter.Factory code implementation looks like this:

class PointJsonAdapterFactory implements JsonAdapter.Factory {
  JsonAdapter<?> create(Type typem Set<? extends Annotation> annotations, Moshi moshi) {
    if (Types.getRawType(types) != Point.class) return null;
    return new JsonAdapter<Point> {
      Point fromJson(JsonReader reader) { ... }
      void toJson(JsonWriter writer) { ... }
    }
  }
}
  • A lot of boilerplates
  • The code tends to be error-prone codes
    • Often the code is not tested

Blow is the easier version:

class PointJsonAdapter {
  @FromJson Point fromJson(JsonReader reader) { ... } 
  @ToJson void toJson(JsonWriter writer, Point value) { ... }
}

It uses reflection API; when you add this object to Moshi.Builder then Moshi will create the factory for you

Here is the even easier ones:

@FromJson Foo fromJson(JsonReader reader)
@FromJson Foo fromJson(JsonReader reader, JsonAdapter<any> delegate, <any more delegates>)
@FromJson Foo fromJson(Bar value) // Bar is already a type that can be deserialized

@ToJson void toJson(JsonWriter writer, Foo value)
@ToJson void toJson(JsonWriter writer, JsonAdapter<any> delegate, <any more delegates>)
@ToJson Bar toJson(Foo value) // Foo is already a type that can be serialized

Advanced: Polymorphic types

class Animal { String type; }
List<Animal> animals = animalAdapter.fromJson(source)

Gson: JsonElement(JsonObject, JsonArray,

Gson: RuntimeTypeAdapterFactory Moshi: ???

Updating piecemeal

Retrofit

retrofit/AnnotatedConverters.java at e6a7cd01657670807bed24f6f4ed56eb59c9c9ab · square/retrofit · GitHub

@Moshi for new code

Retrofit retrofit = new Retrofit.Builder().baseUrl(server.url("/"))
  .addConverterFactory(new AnnotatedConverterFactory.Builder()
    .add(com.example.Moshi.class, moshiConverterFactory)
    .add(com.example.Gson.class, gsonConverterFactory)
    .build())
  .addConverterFactory(gsonConverterFactory) // Fallback
  .build();

interface Service {
  @GET("/new_endpoint") @com.example.Moshi Call<Foo> newEndpoint();
  @GET("/old_endpoint") @Gson Call<Foo> oldEndpoint();
  @GET("/old_endpoint") Call<Foo> oldEndpointDefault(); // Will use Fallback converter
}

AutoValue with Moshi

github.com

2017年を振り返る

個人的に大きかった出来事3つを振り返ることで、今年をざっくり振り返ります。

  • 仮想通貨に手を出しました
  • 仕事でアプリをリリースしました
  • DroidKaigiのプロポーザルを出して初めて採択されました

下記にて個別に振り返ります。

1. 仮想通貨に手を出しました

入社してからよく飲んでいる同期に勧められたことがきっかけです。「なくなってもしょうがないや」と思える程度のお金を入れて、放ったらかしにしています。ビットコインではなく、アルトコインのほうに手を出しています(基本Ripple)。1000円くらいになってBitcoinの次に流通し始めたあたりでお金として利用したいなーという思いで始めました。Ripple頼んだ!(どうなるかは誰にも分からない)

2. 仕事でアプリをリリースしました

個人ではリリースしたことはあったのですが、仕事で自分ひとりで書いてリリースしたのは初めてでした。2017年はこれに一番時間も努力も費やしました。まだまだやりたいこと、やらなきゃいけないことたくさんありますが間違いなく2017年一番感慨深い出来事でした。

また、アプリをリリースするにあたって社内の先輩方、後輩方にはたくさんご相談させていただきました。 お世話になっている先輩方、後輩方、いつも本当にありがとうございます。 来年も、何卒宜しくお願い致します!m(__)m

3. DroidKaigiのプロポーザルを出して初めて採択されました

プロポーザルは3つほど出し、1つ採択されました。Fluxについての発表をします。Fluxについての発表や資料などはすでにたくさんあるので、概要などはざっくりと説明して(まだ確定ではないですが)、残りは

  • 実際にFluxで実装するとこういう良いことが(改めて)あった
  • こういうところに悩んだ・迷った
  • AACと組み合わせるとこんな感じになりそうかも?
  • こういうプロジェクトには向いているかも・向いていないかも

などについて話そうと思っています。

もし「Fluxのこういうところについて聞きたい!」という方いましたらなるべく早くTwitterやリアル等でご連絡いただければと思います。(発表内容に含めるという保証はできませんが出来る限り努力します)

振り返りは以上です!

来年も何卒宜しくお願い致します!

Notes - droidcon NYC 2017: App Development - Pragmatic Best Practices

※Notes記事では、英語のセッション動画やポッドキャストの内容を(雑に)英語でメモに書き残すことを行っています。本記事は、あくまで動画を見ながら、参考程度に読んでいただくことを想定しています。Notes記事には雑メモ程度のものだったり、書き起こしのようなものもあります。これから実際の動画を見る際には、本記事の内容が少しでもお役に立てば幸いです。(内容において不備、誤字脱字等ありましたら気軽にご連絡いただけると嬉しいです。)

本記事は、droidcon NYC 2017 - App Development - Pragmatic Best Practices - YouTubeの記事です。

このセッションの内容は、事前アンケートの回答をもとに、Androidアプリケーションの設計について重きをいたセッションでした。YigitさんとIsraelさんのお勧めの設計や開発の仕方などを幅広く(かつところどころジョークも交えて)説明されています。

f:id:shaunkawano:20171218204622p:plain

Since the talk is about very broad topic, they decided to take survey and they got 150 answers!

Survey

Q: Most difficult part of building an app?

  • 1st - Architecture
  • 2nd - Android specifics

Q: What is a recurring problem in your codebase?

  • 1st. Testing, Code bloat
  • 2nd. Architecture

Q: What design patterns that you want to replace in your codebase?

60% of them: - God classes - God activities - MVP - MVC - Mwhatever - Lack of architecture - Singletons

etc.

Talking about architecture, but why Now?

Architecture was always there, but just popular now because..

  • Ecosystem gets mature now:

    • networking code => retrofit
    • image loading => glide, picasso
    • view fragments => fragments, conductor
    • APK needs to be small => split APKs etc
  • As Android platform becomes better, people's expectations and apps become bigger as well:

    • 60fps
    • lots of functionality, complex features
    • lots of integrations
    • works fully offline
    • (Gmail example) HTML everywhere, rich text editor
  • ART >>>> Dalvik

Yigit's architecture recommendations

Separation of Concerns

Before building architecture, have separation of concerns first.

  • Have it in day one, stick to it
  • Make sure things deal with one thing
  • Build architecture over time, as needed
  • Be careful to write application in modularized way so that you can flex it to better suit your needs in the future.

Do Not Over-Engineer

  • Libraries, guides are tools, not goals
  • The goal is to ship and maintain
  • Don't use something just because X does
  • The problem is not yours , neither their solution

Israel's architecture recommendation

MVWW => Model View Whatever Works

Dependency Injection

  • Allows to declare dependencies of an object upfront

Single Responsibility

  • Similar to "separation of concerns"
  • A class has only one reason to exist
  • Have layered architecture
    • View layer: View manipulation
    • Logic layer: Screen behavior
    • Data layer: Network, DB, Memory cache, Repository Interface
    • In Complex screens,
      • Multiple logic layer components each with a single responsibility.
      • Logic layer components can subscribe to events tied to their logic ( Rx, EventBus)

Shared Logic

-> Have "Use Cases" to decouple logic and make it possible to reuse it within the app

"You don't do this in day One; trying to solve a problem before it exists is a bad idea"

Goal

  • Each layer has a reason to exist
  • Consistency in codebase
  • Testable logic layer
  • Reusable of logic layer

Android Specifics

Lifecycles

  • Embrace lifecycles, you cannot ignore
  • It is a solved problem, if you follow guides(but too many solutions you can apply out there)
  • If you have a proper separation lifecycle issue can be very tiny.

4 Options

  • Manual Lifecycle Handling

Not recommended

  • Data Binding

Data Binding already knows how not to leak your Activity or observers, so you do not to need to think about lifecycle at all for normal cases

  • Live Data

If you are comfortable using RxJava already then maybe no need

  • AutoDispose

If you use RxJava you may want to use this

.autoDisposeWith(this).subscribe(adapter:setList)

Configuration changes

  • Config Change != App Restrat
Config Change
  • Decouple UI and data
  • You may be able to use ViewModel
  • Views restore their states automatically
  • If UI is data drive, no extra work necessary
App Restart
  • Derive UI from disk
  • Use savedInstanceState
    • e.g. getIntent… setArguments .. etc.
  • Nothing in memory survives :(
  • NBU was one of the top problems in the survey

Saved State

  • View's information(e.g. RecyclerView position)
  • UI's arguments

Disk

  • Application data

Fragmentation - how to deal with it

Hardware
  • Generate a class that defines hardware profile - low, medium, high depending on RAM and CPU cores and frequency
  • year-class lib foundation to classify hardware profiles https://github.com/facebook/device-year-class
  • Based on the hardware profile apply animations e.g. rich, medium or none animations
Dependencies
  • RxJava

    • "With great power comes great responsibility"
    • You need to be careful what kind of operators you are using; you need to understand what you are using otherwise you break your application
  • Dagger 2

    • You need to build dependency graph
    • many annotations to remember
Warnings
  • Rx and Dagger help to scale your app
  • It comes at a cost. Learning their DSL, idioms.
  • The team needs to learn it and grow criteria for code reviews.
  • Moreover, many new hires will need to learn Android and these new idioms all at once.
Testing

If you want to refactor you need to have test.

  • Testing is a must!
  • If there are tests, make sure they pass
  • If there are no tests, at first, write them
  • Unit test logic layer (at least)

Best answers

Q: What is a recurring problem in your codebase?

  1. Keyboard

Q: Patterns you dislike and will like to replace in your code base?

  1. Hungarian notation

Q: What is the best part of your codebase?

  1. None

以上です!

Notes - Kotlin Types: Exposed by Svetlana Isakova (KotlinConf 2017)

※Notes記事では、英語のセッション動画やポッドキャストの内容を(雑に)英語でメモに書き残すことを行っています。 本記事は、あくまで動画を見ながら、参考程度に読んでいただくことを想定しています。これから動画を見る方にとって本記事の内容が少しでもお役に立てば幸いです。(内容において不備、誤字脱字等ありましたらご連絡いただければと思います。)

本記事はKotlin Types: Exposed by Svetlana Isakova (KotlinConf 2017)の記事です。

f:id:shaunkawano:20181216215219p:plain

Agenda

  • Basic Types
  • Nullable types
  • Collection types

How those types interact with Java and what happens when we mix types of Kotlin and Java

fun foo(): Int = 1

fun bar(): Int? = 1
public static final int foo() {
  return 1;
}

public static final Integer bar() {
  return Integer.of(1);
}

If you want to know what is going on under the food, you can "show kotlin bytecode" (and also decompile the byte code) in Android Studio

Correspondence between Kotlin and Java types

  • Int in Kotlin => int in Java
  • Int? in Kotlin => java.lang.Integer in Java

Kotlin does not have Primitive types in the language, yet Kotlin still has Primitive types in the byte code level by making use of wrapper types and nullable types

Generic arguments

  • List<Int> in Kotlin => List<Integer> in Java
  • Array<Int> in Kotlin => Integer[] in Java
Arrays of primiteve types

If you want to use primitive types of array, then use IntArray in Kotlin: - IntArray in Kotlin => int[] in Java

String

kotlin.String in Kotlin => java.lang.String in Java

kotlin.String hides some confusing methods:

e.g. replaceAll method

In Java:

"one.two.".replaceAll(".", "*") => *******

In Kotlin:

"one.two.".replace(".", "*") => one*two

"one.two.".replace(".".toRegex(), "*") => one*two

Any

  • Any in Kotlin => java.lang.Object in Java
  • Any type is the super type for ALL types, including Int or anything
Boxing under the hood
log(2017) // the value is autoboxed

fun log(any: Any) {
  println("Value: $any")
}

fun log(i: Int) {
  println("Value: $i")
}

Unit (Kotlin) vs Nothing (Kotlin) vs void (Java)?

The concept comes from functional programming; from the Type system

  • Unit: "a type that allows only one value and thus can hold no information" => The function completes
  • Nothing: "a type that has no values" => The function never completes
Unit instead of void

Whenever you use void in Java, you use Unit in Kotlin

Unit

  • No meaningful value is returned
  • No explicit returned type implies you return Unit by default
  • Two equivalent syntactic forms:
fun f() { /*…*/ }

fun f(): Unit { /*…*/ }

Under the hood, Unit is still void in the byte code

Nothing is different to Unit/void

Unit and Nothing are two very different types even though in the byte code level both mean void type

  • Nothing means "this function never returns"
Any & Nothing types
  • Any is a super type for all the other types
  • Nothing is a subtype for all the other types

e.g. fail function below returns Unit

val answer = if (timeHasPassed()) {
  42 
} else {
  fail("Not ready")
}

fun fail(message: String) {
  throw IllegalStateException(message)
}
  • If 42 is returned then the returned type of the expression function is Int
  • If fail function is called then the returned type of the expression function is Unit

=> Kotlin compiler thinks that the expression function returns Any type because the super type of both Int and Unit is Any

Returning Any means the variable answer will be initialized even if it fails, which is not what we expect; we expect it not to be initialized when it fails. => We can use Nothing in this case

Nothing is a subtype for all the other types, so that means the returned type of the expression function is now Int, which is what we expect

Type of null

var user = null // => var user: Nothing? = null
user = User("svtk") // Error: Type mismatch

val users = mutableListOf(null) // => var users: List<Nothing?> = mutableListOf(null)
users.add(User("svtk")) // Error: Type mismatch

Nullable types & Java

Nullable Types Under the Hood => Just annotations

If your returned type is annotated with @Nullable in Java, then in Kotlin, the type will become nullable

How to still prevent NPEs?

  • Annotate your Java types
    • @Nullable type
    • @NotNull type

Non-null by default (JSR-305):

@javax.annotation.Nonnull
@TypeQualifierDefault(ElementType.PARAMETER, …)
annotation class MyNonnullByDefault

package-info.java:

  @MyNonnullByDefault
  package mypackage;

Then, Kotlin will give you warning when assigning null to values:

@MyNonnullByDefault
public class Session {
  public void setDescription(String description) {
    this.description = description;
  }
}

Calling Java code from Kotlin:

val session = Session()
session.setDescription(null) // => Warning: Expected type doesn't accept nulls in Java …

If you prefer errors in compile time rather than warnings:

build.gradle

compileKotlin {
  kotlinOptions {
    freeCompilerArgs += "-Xjsr305=strict"
  }
}

Then, Kotlin will give you errors when assigning null to values:

@MyNonnullByDefault
public class Session {
  public void setDescription(String description) {
    this.description = description;
  }
}

Calling Java code from Kotlin:

val session = Session()
session.setDescription(null) // => Error: Null can not be a value of a non-null type …

build.gradle

  • Specify types explicitly
public class Session {
  public void setDescription(String description) {
    this.description = description;
  }
}
val session = Session()
val description: String? = session.description ✅

Or, the code below gives you IllegalStateException in runtime which notifies you very early what is wrong with your code:

val session = Session()
val description: String = session.description // IllegalStateException: session.description must not be null

How it works? - Intrinsic checks

The code below will be generated by compiler:

Intrinsics.checkExpressionValueisNotNull()

Collections

Read-only interfaces improve API

  • How read-only collections and mutable collections work in Kotlin

List & MutableList

  • Two interfaces declared in kotlin package
  • MutableList extends List

Read-only DOES NOT mean immutable - Read-only interface just lacks mutating methods

The actual list can be changed by another reference:

val mutableList = mutableListOf(1, 2, 3)
val list: List<Int> = mutableList

println(list) // [1, 2, 3]

mutableList.add(4)
println(list) // [1, 2, 3, 4]

In Kotlin, there is a plan to provide the immutable data structure in the standard library, but it is not ready yet

  • String! = notation, not syntax; platform type, which is a type that comes from Java

Platform types: summary

Good compromise between safety and convenience

Summary

  • primitives under the hood, and boxing is possible
  • Use Nothing whenever possible
  • Preventing NPE for Java interop: annotations, explicit types
  • Read-only does not mean immutable

以上です!

Notes - Fragmented Podcast: 105: Jake Wharton on the Android Kotlin Guides

※Notes記事では、英語のセッション動画やポッドキャストの内容を(雑に)英語でメモに書き残すことを行っています。本記事は、あくまで動画を見ながら、参考程度に読んでいただくことを想定しています。Notes記事には雑メモ程度のものだったり、書き起こしのようなものもあります。これから実際の動画を見る際には、本記事の内容が少しでもお役に立てば幸いです。(内容において不備、誤字脱字等ありましたら気軽にご連絡いただけると嬉しいです。)

本記事は、Fragmented Podcast: 105: Jake Wharton on the Android Kotlin Guidesの記事です。

f:id:shaunkawano:20171210142608p:plain

TL;DR

  • Jake Wharton working on android/kotlin-guides on github
    • Influenced by Google Java style guide
    • Hosting on GitHub makes it easy for people to not only access but also contribute
    • Different from JetBrains' style guide; following this style guide has no conflict with following JetBrains' style guide, but may not be vice-versa
  • Style guide to provide a set of rules to follow, and Interop guide to provide practices and things to care for those developers who ..
    • Introduce Kotlin into existing Java project
    • Consume Kotlin code from Java
    • Provide APIs in Kotlin that may be consumed from Java

105: Jake Wharton on the Android Kotlin Guides http://fragmentedpodcast.com/episodes/105/

About android/kotlin-guides

Q. Is this the defacto style guide for Kotlin? What was the reason for it?

There are two guides: Style guide and Interop guide

  1. Style guide for regular Android app developers to style..
    • code structure, and
    • new Kotlin files
  2. Interop guide for developers to easily co-exist both Kotlin and Java code without feeling awkward especially when calling codes from one language to the other.

Reasons:

  • Android has never had a style guide for non-Google developers
  • There was AOSP style guide but it was only for developers of ASOP. And, Android has been around for 10 years; Most apps have Java code so there needs to be something that people can follow to feel natural when introducing Kotlin code into existing Java code base or consuming APIs of Kotlin language from Java code base.

Q. Why NOT Google Kotlin Guide, and Android specific?

  • Currently Google makes use of Kotlin language for Android platform, so we want something tailored for it, fairly quickly, rather than something very general.
  • It is influenced by Google Java style guide

Q. What about current JetBrains' style guide?

android/kotlin-guides is consciously made not to have conflict with the guide from JetBrains. However, following JetBrains' Kotlin style guide does not mean it is 100% valid for android/kotlin-guides because JetBrains' kotlin-guide is more focused on Kotlin language itself and its future, but android/kotlin-guides cares about natural, comfortable interaction between Java and Kotlin languages as well.

IntelliJ platform does not support code formatting exactly as style guide recommends. (Information from KotlinConf)

Q. How did you start making android/kotlin-gudes?

Goal: - Easy to access - Easy to contribute

Docs on android.developer.com are difficult to contribute for developers.

  • Started with Google doc -> internal review -> API counsel ..etc.. Eventually to github.com with Jekyll

Q. How did you decide what to put in kotlin-guides, especially controversial ones as personal preference or something with non-logical reasons?

  • Looking up
  • Feedback from people from JetBrains who are making their guide in parallel

Q. One of the difficult choices? - for example, 2 spaces -> 1 tab(4 spaces)

  • Google Java style guide specify 2 spaces
  • JetBrains' kotlin guide specifies 1 tab
  • The almost all codebase at Square was also 2 spaces when Jake joined
  • "It seems everything is so far a part"

Q. Why "Style Guide" and "Interop Guide"?

Style Guide

Style guide aims to have rules that are unambiguous and can potentially be enforced or even formatted by an automated tool. - Meant to be 'Hard rules' - Everything should be deterministic, unambiguous just single way of doing something

Interop Guide

  • 'Rules but a bit of interpretation'
  • Something you need to think a bit
  • For people to have mixed (Java & Kotlin) sources

Eventually adding something more subjective.. - Design patterns - Best practices or patterns - Something people can decide whether or not they apply

Highlights of the guides

Style guide: Use-Site Targets

Style guide: Logical Ordering

Q. What is a good logical ordering?

  • The most important part of the guide is there is no "One true order"
  • The rule here is that "there is no rule"
  • Too strict ordering may harm the ability to understand what is going on.

Q. Why is the column limit 100 characters?

  • It is already being used
  • It is what Google Java style guide is using too
  • It is not considered as something that needs to be changed

Q. About "Higher syntactic level"

  • Stolen from Java style guide
  • When performing line breaking, you do not want to break
  • If you perform line breaking, you want to keep the inner function calls and their arguments together

Q. Expression Functions

  • Sometimes it is easier to have normal function body that have multiple expression bodies
  • By having expression functions it is tempting to delcare all functions as expression functions but sometimes it makes harder to read or understand the body of the function.

For contribution

The reason the guide is on GitHub is because we want people to contribute If there is ambiguity, wording miss, incorrect or not conveying the right thing please please contribute. - Already bunch of fixes and so on - Contents from KotlinConf - Thinking to release once every 2 or 3 weeks until the guide stabilizes - Do not want to overwhelm people with changes - Going to provide change logs to easily figure out what is changes

Use of annotations recommended by the style guide

  • You don't have to follow the every single rules but if you start writing codes from the scratch

Q. Do we / should we use Hungarian notations?

  • The language itself actively discourages you from using any kind of prefix.

e.g. Kotlin property delcaration which is consumed from Java

val mName: String = ...
pubic String getMName() { // Super weird!
    return ...;
}

Q. Interop Guide

Java (for Kotlin consumption)

The motivating factor here is that every new API that is added to Android Framework itself or support libraries are consumed from both languages by developers, so there is a strong need to have a set of rules that you can follow or interpret when you are writing these APIs to make sure that they actually feels nice from both languages.

Kotlin (for Java consumption)

We assume that in the near future, more libraries will be written in Kotlin first and those APIs may be consumed from people using Java, so the API Kotlin code needs to be feel idiomatic for them as well. That is the rason why there is a separation.

About "No hard keyword"

  • Kotlin has a notion of both "hard" and "soft" keyword
    • class
    • if
    • else
    • try
    • class
    • when

For example, You can't name a class 'name' or 'if'.

  • Keywords for Kotlin uses are different from keywords for Java uses.
  • If you were to write a new API the style guide strongly recommends not to use those keywords.

Q. Defensive copies

  • Kotlin does have a notion of 'read only' property
  • 2 parts of this: val(= read only), two versions of Collections

Whenever you return a list in a public API where you are sure or there is a possibility that the value will be refenced from Java then it should wrap it or make a defensive copy from Java

  • Guava has it's own version of immutable list
  • JetBrains is also working on Kotlinx.collection.immutable.

Links

Firebaseのサポート(CS)について

この記事は、FirebaseのようなBaaSを利用している方で、欲しい機能がサポートされていない場合に「欲しい機能サポートされていないらしい...orz」と途方に暮れてしまっているだけの方がもしかしたらいるかもしれないと思ったので、そういう人向けに、「ダメ元でもサポートに連絡することをお勧めします!」という記事です。

TL;DR

  • サービスを利用していて困ったことや欲しい機能があったらサポートに連絡してみましょう。
  • Firebaseのサポートは返信が丁寧です。(返信スピードが早い・更新情報があればその都度連絡してくれるので返信頻度が良い意味で多いです。)
  • (Firebaseに限っては)Firebaseサポートからフィードバックや機能リクエストを送ることができます。

アプリケーションを開発する上で、Firebaseを利用しているエンジニアは多いと思います。

Firebaseとは、ゲームを含めたモバイルアプリケーションや、Webアプリケーション開発の手助けや、既存アプリのビジネス拡大を行なうための機能群を提供するツールです。

f:id:shaunkawano:20171203193623p:plain

元々FirebaseはFirebase, Inc.が独自に開発していたツールだったのですが、2014年の10月にGoogleが買収しました。(Google I/O 2015や2016, 2017年では多くのFirebaseに関するセッションがありました。)また、2017年1月にはTwitterがGoogleにFabricを売却したことも発表され、その後FabricからFirebase Crash Reportingへの移行も推奨されています。(自分はまだできていません..)

Firebaseのサポートについて

そんなFirebaseですが、コンソールを使っている時や機能開発をしている際に、「こんな機能は提供されていないのかな、サポートされていないのかな?」と思う場面が何度かありました。そのうち二回ほど、ググってみたりFAQをあさってみたが見つからない、というような場合に出くわし、サポートにメールを送ってみたりしていました。ニュアンスとしては、「もしかしてxxのような機能を提供する予定ですか?」「xxすることができると嬉しいのですが、、」というようなものです。

担当者の方から、「連絡ありがとうございます!エンジニアリングチームに確認して改めて返信するので、ちょっとまってね」というような旨のメールです。

返信メールがその日のうちに返信メールが返ってきてとにかくフィードバックが早いなという印象でした。 自分の場合は、今後サポート予定ですでにスケジュールに組まれているのか、サポート予定だけど実装スケジュールは未定なのか、今のところサポート予定ではない、等を教えていただくことができました。必ずしも自分がリクエストした機能がサポートされるとは限りませんが、上記のようなスケジュール感を共有してもらえるのは開発者としてもありがたいです。

ということで、(Firebaseに限った話ではないですが、)Firebase等のBaaSを利用していてモヤモヤしていること等あれば気軽にまずはサポートに連絡してみることをお勧めします。

以上です!

firebase.google.com

最後に

Firebaseに関する説明や発表の動画は、FirebaseのYoutubeチャンネルにたくさんアップロードされています。

www.youtube.com

プラットフォーム毎にSDKが提供されており、このSDKを利用することで0から開発するにはかなり時間やお金といったコストのかかってしまうような機能を簡単にアプリケーションに導入することができます。

提供されている機能の一覧や詳細については下記ドキュメントを御覧ください:

firebase.google.com

業務で開発・運用しているアプリケーションでは、Realtime Database, Authentication, Cloud Messagingを利用しています。

※すごくFirebase推しですがFirebaseの回し者ではありません。

"XXX is a boxed field but needs to be un-boxed to execute YYY. This may cause NPE so Data Binding will safely unbox it. You can change the expression and explicitly wrap XXX with safeUnbox() to prevent the warning."の警告を見て、Data Binding周りを調べたことについ

TL;DR

  • Data Bindingライブラリで<data>タグと<variable>タグを利用してXML上に変数定義をする際には、プリミティブ型で定義できる際には積極的にプリミティブ型を使っていこう
  • 参照型の変数を定義した際には、Data Bindingライブラリが内部でunboxingする
  • safeUnbox()を利用することもできる

詳細

本記事執筆時点のライブラリバージョンは下記です:

  • com.android.support:appcompat-v7: 27.0.1
  • com.android.databinding:compiler: 3.0.0

Data Bindingライブラリを使ってXML上に変数を定義してViewの見た目を変えるとします。下記は、isLoadingであればProgressBarを表示、そうでなければProgressBarを非表示(View.GONE指定)にする簡単なXMLの例です:

<data>
  <import type="android.view.View"/>
  <variable
    name="isLoading"
    type="Boolean"
  />
</data>
...
  <ProgressBar
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      app:layout_constraintTop_toTopOf="parent"
      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintRight_toRightOf="parent"
      app:layout_constraintBottom_toBottomOf="parent"
      android:visibility="@{isLoading ? View.VISIBLE : View.GONE}"
      />
...

一見なにも問題ないように見えますが、この状態でプロジェクトをビルドすると、タイトルのような警告が表示されます。

safeUnbox()

Booleanは参照型なので、値にnullが代入される可能性があります。nullが代入される可能性があるということは、NullPointerExceptionが発生する可能性が生まれるということです。

今回のコードを改善しようとするなら、2つ改善策がありそうです。

1つ目は、変数定義の際のtypeに、unboxする必要のない型を指定することです。ここではBoolean型(=参照型)の代わりにboolean型(=プリミティブ型)を指定すれば良さそうです。

<data>
  <import 
    type="android.view.View" />
  <variable
    name="isLoading"
    type="boolean"
  />
</data>
...

二つ目は、これはタイトルの警告文言にも記載されているのですが、

w: 警告: XXX is a boxed field but needs to be un-boxed to execute YYY. This may cause NPE so Data Binding will safely unbox it. You can change the expression and explicitly wrap XXX with safeUnbox() to prevent the warning.

safeUnbox()というData Bindingライブラリが用意してくれているstaticメソッドを利用することもできるようです。

<ProgressBar
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:visibility="@{safeUnbox(isLoading) ? View.VISIBLE : View.GONE}"
      app:layout_constraintTop_toTopOf="parent"
      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintRight_toRightOf="parent"
      app:layout_constraintBottom_toBottomOf="parent"
      />

このsafeUnbox()というメソッドはandroid.databindingパッケージに内包されているDynamicUtilクラスのstaticメソッドでした。

package android.databinding;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.databinding.BindingConversion;
@javax.annotation.Generated("Android Data Binding")
public class DynamicUtil {
    public static int safeUnbox(java.lang.Integer boxed) {
        return boxed == null ? 0 : (int)boxed;
    }
    public static long safeUnbox(java.lang.Long boxed) {
        return boxed == null ? 0L : (long)boxed;
    }
    public static short safeUnbox(java.lang.Short boxed) {
        return boxed == null ? 0 : (short)boxed;
    }
    public static byte safeUnbox(java.lang.Byte boxed) {
        return boxed == null ? 0 : (byte)boxed;
    }
    public static char safeUnbox(java.lang.Character boxed) {
        return boxed == null ? '\u0000' : (char)boxed;
    }
    public static double safeUnbox(java.lang.Double boxed) {
        return boxed == null ? 0.0 : (double)boxed;
    }
    public static float safeUnbox(java.lang.Float boxed) {
        return boxed == null ? 0f : (float)boxed;
    }
    public static boolean safeUnbox(java.lang.Boolean boxed) {
        return boxed == null ? false : (boolean)boxed;
    }
}

ただ、実際にはこのメソッド呼び出しをXML上で明示的に行わなくても、Data Bindingライブラリが生成するJavaソースコード(下記)内でこのメソッドを呼び出して安全にunboxしてくれているようなので、これに関しては書いても書かなくてもどちらでも良さそうです。(詳しいことはしっかりとは調べれていませんので、言い切る自信はないですが)

// read android.databinding.DynamicUtil.safeUnbox(isLoading)
androidDatabindingDynamicUtilSafeUnboxIsLoading = android.databinding.DynamicUtil.safeUnbox(isLoading);

DynamicUtilsafeUnbox()について今回初めて知ったのでメモとして記載した次第です!以上です!

参考リンク

https://stackoverflow.com/questions/42872201/data-binding-safeunbox-warning