Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Code Generating Your Way to Happiness

Avatar for Zac Sweers Zac Sweers
October 27, 2017

Code Generating Your Way to Happiness

This talk explores how code gen can be used to eliminate a class of issues and sources of developer boilerplate, as well as walking through some popular libraries and uber-specific use cases.

Avatar for Zac Sweers

Zac Sweers

October 27, 2017
Tweet

More Decks by Zac Sweers

Other Decks in Programming

Transcript

  1. conferences .flatMap { it.presentations } .onEach { (presentationName, comment, author)

    -> FileSpec.builder("", presentationName)a .addComment(comment) .addAnnotation(AnnotationSpec.builder(Author::class) .addMember("name", "%S", author) .useSiteTarget(FILE) .build()) .build()b } Boilerplate
  2. class Person(val firstName: String, val lastName: String)m class PersonJsonAdapter :

    JsonAdapter<Person>() {a override fun fromJson(reader: JsonReader): Person? {b }k }l
  3. class Person(val firstName: String, val lastName: String)m class PersonJsonAdapter :

    JsonAdapter<Person>() {a override fun fromJson(reader: JsonReader): Person? {b lateinit var firstName: Stringc lateinit var lastName: Stringd }k }l
  4. class Person(val firstName: String, val lastName: String)m class PersonJsonAdapter :

    JsonAdapter<Person>() {a override fun fromJson(reader: JsonReader): Person? {b lateinit var firstName: Stringc lateinit var lastName: Stringd return Person(firstName, lastName)j }k }l
  5. class Person(val firstName: String, val lastName: String)m class PersonJsonAdapter :

    JsonAdapter<Person>() {a override fun fromJson(reader: JsonReader): Person? {b lateinit var firstName: Stringc lateinit var lastName: Stringd while (reader.hasNext()) {e }n return Person(firstName, lastName)j }k }l
  6. class Person(val firstName: String, val lastName: String)m class PersonJsonAdapter :

    JsonAdapter<Person>() {a override fun fromJson(reader: JsonReader): Person? {b lateinit var firstName: Stringc lateinit var lastName: Stringd while (reader.hasNext()) {e when (reader.nextName()) {f }o }n return Person(firstName, lastName)j }k }l
  7. class Person(val firstName: String, val lastName: String)m class PersonJsonAdapter :

    JsonAdapter<Person>() {a override fun fromJson(reader: JsonReader): Person? {b lateinit var firstName: Stringc lateinit var lastName: Stringd while (reader.hasNext()) {e when (reader.nextName()) {f "firstName" -> firstName = reader.nextString()g }o }n return Person(firstName, lastName)j }k }l
  8. class Person(val firstName: String, val lastName: String)m class PersonJsonAdapter :

    JsonAdapter<Person>() {a override fun fromJson(reader: JsonReader): Person? {b lateinit var firstName: Stringc lateinit var lastName: Stringd while (reader.hasNext()) {e when (reader.nextName()) {f "firstName" -> firstName = reader.nextString()g "lastName" -> lastName = reader.nextString()h }o }n return Person(firstName, lastName)j }k }l
  9. class Person(val firstName: String, val lastName: String)m class PersonJsonAdapter :

    JsonAdapter<Person>() {a override fun fromJson(reader: JsonReader): Person? {b lateinit var firstName: Stringc lateinit var lastName: Stringd while (reader.hasNext()) {e when (reader.nextName()) {f "firstName" -> firstName = reader.nextString()g "lastName" -> lastName = reader.nextString()h else -> reader.skipValue()i }o }n return Person(firstName, lastName)j }k }l
  10. class Person(val firstName: String, val lastName: String)m class PersonJsonAdapter :

    JsonAdapter<Person>() {a override fun fromJson(reader: JsonReader): Person? {b lateinit var firstName: Stringc lateinit var lastName: Stringd while (reader.hasNext()) {e when (reader.nextName()) {f "firstname" -> firstName = reader.nextString()g "lastName" -> lastName = reader.nextString()h else -> reader.skipValue()i }o }n return Person(firstName, lastName)j }k }l
  11. class Person(val firstName: String, val lastName: String)m class PersonJsonAdapter :

    JsonAdapter<Person>() {a override fun fromJson(reader: JsonReader): Person? {b lateinit var firstName: Stringc lateinit var lastName: Stringd while (reader.hasNext()) {e when (reader.nextName()) {f "firstname" -> firstName = reader.nextString()g "lastName" -> lastName = reader.nextString()h else -> reader.skipValue()i }o }n return Person(lastName, firstName)j }k }l
  12. class Person(val firstName: String?, val lastName: String)m class PersonJsonAdapter :

    JsonAdapter<Person>() {a override fun fromJson(reader: JsonReader): Person? {b lateinit var firstName: Stringc lateinit var lastName: Stringd while (reader.hasNext()) {e when (reader.nextName()) {f "firstname" -> firstName = reader.nextString()g "lastName" -> lastName = reader.nextString()h else -> reader.skipValue()i }o }n return Person(lastName, firstName)j }k }l
  13. class Person(val firstName: String, val lastName: String)m class City(val name:

    String, val country: String) class Vehicle(val licensePlate: String) class Restaurant(val type: String, val address: Address) class Payment(val cardNumber: String, val type: String) class TipAmount(val value: Double) class Rating(val numStars: Int) class Correctness(val confidence: Double)
  14. Butter Knife TextView title;a ImageView icon;b void onCreate(Bundle savedInstanceState) {c

    title = findViewById(R.id.title);d icon = findViewById(R.id.icon);e }f
  15. Butter Knife @BindView(R.id.title) TextView title;a @BindView(R.id.icon) ImageView icon;b @BindView(R.id.button) Button

    button; void onCreate(Bundle savedInstanceState) {c ButterKnife.bind(this);g }f
  16. ViewBinding( target = "FooActivity", id = 2131361859, name = "title",

    type = "field", viewType = TextView.class )
  17. public final class FooActivity_ViewBinding implements Unbinder { private FooActivity target;

    @UiThread public FooActivity_ViewBinding(FooActivity target, View source) { this.target = target; target.title = Utils.findRequiredViewAsType(source, 2131361859, // R.id.title "field 'title'", TextView.class); }a }b
  18. @BindView(R.id.title) TextView title;a void onCreate(Bundle savedInstanceState) {c ButterKnife.bind(this); }f public

    final class FooActivity_ViewBinding implements Unbinder { private FooActivity target; @UiThread public FooActivity_ViewBinding(FooActivity target, View source) { this.target = target; target.title = Utils.findRequiredViewAsType(source, 2131361859, // R.id.title "field 'title'", TextView.class); }a }b APT Runtime
  19. @AutoValuea abstract class Rider {b abstract String uuid();c abstract String

    firstName();d abstract String lastName();e abstract Address address();f }g Service Gen
  20. struct Rider { 1: required string uuid; 2: required string

    firstName; 3: required string lastName; 4: optional Address address; }
  21. @AutoValuea abstract class Rider {b abstract String uuid();c abstract String

    firstName();d abstract String lastName();e abstract Address address();f }g
  22. @AutoValuea abstract class Rider {b abstract String uuid();c abstract String

    firstName();d abstract String lastName();e abstract Address address();f static JsonAdapter<Rider> jsonAdapter(Moshi moshi) { return new AutoValue_Rider.JsonAdapter(moshi); } }g
  23. astruct Rider struct City struct Vehicle struct Restaurant struct Payment

    struct TipAmount struct Rating // And 6000 more
  24. class ModelsAdapterFactory implements JsonAdapter.Factory { @Override public JsonAdapter<?> create(Type type,

    Set<? extends Annotation> annotations, Moshi moshi) { Class<?> rawType = Types.getRawType(type); if (rawType.isAssignableFrom(Rider.class)) { return Rider.adapter(moshi); } else if (rawType.isAssignableFrom(City.class)) { return City.adapter(moshi); } else if (rawType.isAssignableFrom(Vehicle.class)) { return Vehicle.adapter(moshi); } // Etc etc return null; } }
  25. astruct Rider struct City struct Vehicle struct Restaurant struct Payment

    struct TipAmount struct Rating //aAnd 6000 more
  26. Rider - build.gradle GiftCard - build.gradle Pricing - build.gradle Driver

    - build.gradle EATS - build.gradle Payments - build.gradle
  27. Rider - build.gradle GiftCard - build.gradle Pricing - build.gradle Driver

    - build.gradle EATS - build.gradle Payments - build.gradle
  28. class RiderModelFactory // -> json // -> ridermodelfactory-fractory.bin class MyAppGlobalFactory

    // Delegates to all discovered fractories Fractory C om ing Soon™
  29. struct Rider { 1: required string uuid; 2: required string

    firstName; 3: required string lastName; 4: optional Address address; }a
  30. struct Rider { 1: required string uuid; 2: required string

    firstName; 3: required string lastName; 4: optional Address address; }a
  31. struct Rider { 1: required string uuid; 2: required string

    firstName; 3: required string lastName; }a
  32. struct Rider { 1: required string uuid; 2: required string

    firstName; 3: required string lastName; }a service UberService {a Rider getRider() }b
  33. struct Rider { 1: required string uuid; 2: required string

    firstName; 3: required string lastName; }a service UberService {a Rider getRider() }b
  34. struct Rider { 1: required string uuid; 2: required string

    firstName; 3: required string lastName; }a service UberService {a Rider getRider() }b