Slide 1

Slide 1 text

Code generating your way to happiness Zac Sweers - Uber @pandanomic

Slide 2

Slide 2 text

"Code generating your way to happiness."

Slide 3

Slide 3 text

FileSpec.builder("", "Presentation") .addComment("Code generating your way to happiness.") .addAnnotation(AnnotationSpec.builder(Author::class) .addMember("name", "%S", "Zac Sweers") .useSiteTarget(FILE) .build()) .build()

Slide 4

Slide 4 text

FileSpec.builder("", "Presentation") .addComment("Code generating your way to happiness.") .addAnnotation(AnnotationSpec.builder(Author::class) .addMember("name", "%S", "Zac Sweers") .useSiteTarget(FILE) .build()) .build()

Slide 5

Slide 5 text

FileSpec.builder("", "Presentation") .addComment("Code generating your way to happiness.") .addAnnotation(AnnotationSpec.builder(Author::class) .addMember("name", "%S", "Zac Sweers") .useSiteTarget(FILE) .build()) .build()

Slide 6

Slide 6 text

FileSpec.builder("", "Presentation") .addComment("Code generating your way to happiness.") .addAnnotation(AnnotationSpec.builder(Author::class) .addMember("name", "%S", "Zac Sweers") .useSiteTarget(FILE) .build()) .build()

Slide 7

Slide 7 text

FileSpec.builder("", "Presentation") .addComment("Code generating your way to happiness.") .addAnnotation(AnnotationSpec.builder(Author::class) .addMember("name", "%S", "Zac Sweers") .useSiteTarget(FILE) .build()) .build()

Slide 8

Slide 8 text

FileSpec.builder("", "Presentation") .addComment("Code generating your way to happiness.") .addAnnotation(AnnotationSpec.builder(Author::class) .addMember("name", "%S", "Zac Sweers") .useSiteTarget(FILE) .build()) .build()

Slide 9

Slide 9 text

// Code generating your way to happiness. @file:Author(name = "Zac Sweers") Presentation.kt

Slide 10

Slide 10 text

FileSpec.builder("", "Presentation")a .addComment("Code generating your way to happiness.") .addAnnotation(AnnotationSpec.builder(Author::class) .addMember("name", "%S", "Zac Sweers") .useSiteTarget(FILE) .build()) .build()b

Slide 11

Slide 11 text

FileSpec.builder("", presentationName)a .addComment("Code generating your way to happiness.") .addAnnotation(AnnotationSpec.builder(Author::class) .addMember("name", "%S", "Zac Sweers") .useSiteTarget(FILE) .build()) .build()b

Slide 12

Slide 12 text

FileSpec.builder("", presentationName)a .addComment(comment) .addAnnotation(AnnotationSpec.builder(Author::class) .addMember("name", "%S", "Zac Sweers") .useSiteTarget(FILE) .build()) .build()b

Slide 13

Slide 13 text

FileSpec.builder("", presentationName)a .addComment(comment) .addAnnotation(AnnotationSpec.builder(Author::class) .addMember("name", "%S", author) .useSiteTarget(FILE) .build()) .build()b

Slide 14

Slide 14 text

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 }

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

Benefits • Boilerplate avoidance

Slide 17

Slide 17 text

Benefits • Boilerplate avoidance • Correctness

Slide 18

Slide 18 text

Correctness class Person(val firstName: String, val lastName: String)m

Slide 19

Slide 19 text

class Person(val firstName: String, val lastName: String)m class PersonJsonAdapter : JsonAdapter() {a }l

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

class Person(val firstName: String, val lastName: String)m class PersonJsonAdapter : JsonAdapter() {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

Slide 24

Slide 24 text

class Person(val firstName: String, val lastName: String)m class PersonJsonAdapter : JsonAdapter() {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

Slide 25

Slide 25 text

class Person(val firstName: String, val lastName: String)m class PersonJsonAdapter : JsonAdapter() {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

Slide 26

Slide 26 text

class Person(val firstName: String, val lastName: String)m class PersonJsonAdapter : JsonAdapter() {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

Slide 27

Slide 27 text

class Person(val firstName: String, val lastName: String)m class PersonJsonAdapter : JsonAdapter() {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

Slide 28

Slide 28 text

class Person(val firstName: String, val lastName: String)m class PersonJsonAdapter : JsonAdapter() {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

Slide 29

Slide 29 text

class Person(val firstName: String, val lastName: String)m class PersonJsonAdapter : JsonAdapter() {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

Slide 30

Slide 30 text

class Person(val firstName: String?, val lastName: String)m class PersonJsonAdapter : JsonAdapter() {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

Slide 31

Slide 31 text

class Person(val firstName: String, val lastName: String)m

Slide 32

Slide 32 text

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)

Slide 33

Slide 33 text

Benefits • Boilerplate • Correctness

Slide 34

Slide 34 text

Recognizing • Boilerplate • Correctness Boilerplate Ceremony Value types! Especially if you have specs! Tests too

Slide 35

Slide 35 text

Tools

Slide 36

Slide 36 text

Tools •JavaPoet/KotlinPoet

Slide 37

Slide 37 text

Tools •JavaPoet/KotlinPoet •Templating

Slide 38

Slide 38 text

Tools •JavaPoet/KotlinPoet •Templating •SPI

Slide 39

Slide 39 text

Tools •JavaPoet/KotlinPoet •Templating •SPI •Compile Testing

Slide 40

Slide 40 text

Tools •JavaPoet/KotlinPoet •Templating •SPI •Compile Testing •Annotation Processing (APT)

Slide 41

Slide 41 text

Tools •JavaPoet/KotlinPoet •Templating •SPI •Compile Testing •Annotation Processing (APT) •Gradle

Slide 42

Slide 42 text

Examples

Slide 43

Slide 43 text

Butter Knife

Slide 44

Slide 44 text

Butter Knife TextView title;a void onCreate(Bundle savedInstanceState) {c title = findViewById(R.id.title);d }f

Slide 45

Slide 45 text

Butter Knife TextView title;a ImageView icon;b void onCreate(Bundle savedInstanceState) {c title = findViewById(R.id.title);d }f

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

Butter Knife @BindView(R.id.title) TextView title;a @BindView(R.id.icon) ImageView icon;b void onCreate(Bundle savedInstanceState) {c ButterKnife.bind(this); }f

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

Butter Knife @BindView(R.id.title) TextView title;a void onCreate(Bundle savedInstanceState) {c ButterKnife.bind(this); }f

Slide 50

Slide 50 text

@BindView(R.id.title) TextView title;

Slide 51

Slide 51 text

// FooActivity @BindView(R.id.title) TextView title;

Slide 52

Slide 52 text

// FooActivity @BindView(R.id.title) TextView title;

Slide 53

Slide 53 text

// FooActivity @BindView(R.id.title) TextView title;

Slide 54

Slide 54 text

// FooActivity @BindView(2131361859) TextView title;

Slide 55

Slide 55 text

// FooActivity @BindView(2131361859) TextView title;

Slide 56

Slide 56 text

// FooActivity @BindView(2131361859) TextView title;

Slide 57

Slide 57 text

// FooActivity @BindView(2131361859) TextView title;

Slide 58

Slide 58 text

ViewBinding( target = "FooActivity", id = 2131361859, name = "title", type = "field", viewType = TextView.class )

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

@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

Slide 61

Slide 61 text

Butter Knife

Slide 62

Slide 62 text

RxBinding

Slide 63

Slide 63 text

RxBinding KotlinGenTask Generates all these!

Slide 64

Slide 64 text

public static Observable clicks(View view) { return new ViewClickObservable(view); }

Slide 65

Slide 65 text

fun View.clicks(): Observable = RxView.clicks(this)a

Slide 66

Slide 66 text

fun View.clicks(): Observable = RxView.clicks(this)a

Slide 67

Slide 67 text

fun View.clicks(): Observable = RxView.clicks(this)a public static Observable clicks(View view) { return new ViewClickObservable(view); }b

Slide 68

Slide 68 text

fun View.clicks(): Observable = RxView.clicks(this)a public static Observable clicks(View view) { return new ViewClickObservable(view); }b

Slide 69

Slide 69 text

fun View.clicks(): Observable = RxView.clicks(this)a public static Observable clicks(View view) { return new ViewClickObservable(view); }b

Slide 70

Slide 70 text

fun View.clicks(): Observable = RxView.clicks(this)a public static Observable clicks(View view) { return new ViewClickObservable(view); }b

Slide 71

Slide 71 text

fun View.clicks(): Observable = RxView.clicks(this)a public static Observable clicks(View view) { return new ViewClickObservable(view); }b

Slide 72

Slide 72 text

fun View.clicks(): Observable = RxView.clicks(this)a public static Observable clicks(View view) {a return new ViewClickObservable(view); }b

Slide 73

Slide 73 text

public static Observable clicks(View view) {a return new ViewClickObservable(view); }b

Slide 74

Slide 74 text

// RxView public static Observable clicks(View view) {a return new ViewClickObservable(view); }b

Slide 75

Slide 75 text

BindingMethod( target = "RxView", name = "clicks", type = View.class, returnType = "Observable" )b

Slide 76

Slide 76 text

BindingMethod( target = "RxView", name = "clicks", type = View.class, returnType = "Observable" )b

Slide 77

Slide 77 text

fun View.clicks(): Observable = RxView.clicks(this)a

Slide 78

Slide 78 text

RxBinding

Slide 79

Slide 79 text

Service Gen

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

interface UberService {a @GET("/rider")b Rider getRider()c }d

Slide 82

Slide 82 text

interface UberService {a @GET("/rider")b Single getRider()c }d

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

@AutoValuea abstract class Rider {b abstract String uuid();c abstract String firstName();d abstract String lastName();e abstract Address address();f static JsonAdapter jsonAdapter(Moshi moshi) { return new AutoValue_Rider.JsonAdapter(moshi); } }g

Slide 86

Slide 86 text

service UberService {a Rider getRider() }b

Slide 87

Slide 87 text

service UberService {a Rider getRider() (path="/rider") }b

Slide 88

Slide 88 text

interface UberService { @GET("/rider") Single getRider() }

Slide 89

Slide 89 text

service UberService { Rider getRider() }

Slide 90

Slide 90 text

astruct Rider

Slide 91

Slide 91 text

astruct Rider struct City struct Vehicle struct Restaurant struct Payment struct TipAmount struct Rating

Slide 92

Slide 92 text

astruct Rider struct City struct Vehicle struct Restaurant struct Payment struct TipAmount struct Rating // And 6000 more

Slide 93

Slide 93 text

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; } }

Slide 94

Slide 94 text

astruct Rider struct City struct Vehicle struct Restaurant struct Payment struct TipAmount struct Rating //aAnd 6000 more

Slide 95

Slide 95 text

//aAnd 6000 more

Slide 96

Slide 96 text

//aAnd 6000 more Rider EATS Payments Driver GiftCard Pricing

Slide 97

Slide 97 text

Rider GiftCard Pricing Driver EATS Payments

Slide 98

Slide 98 text

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

Slide 99

Slide 99 text

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

Slide 100

Slide 100 text

Rider GiftCard Pricing Driver EATS Payments

Slide 101

Slide 101 text

xclass RiderModelFactory class GiftCardModelFactory class PricingModelFactory class DriverModelFactory class EATSModelFactory class PaymentsModelFactory

Slide 102

Slide 102 text

xclass RiderModelFactory

Slide 103

Slide 103 text

xclass RiderModelFactory // -> json

Slide 104

Slide 104 text

xclass RiderModelFactory // -> json // -> ridermodelfactory-fractory.binx

Slide 105

Slide 105 text

class RiderModelFactory // -> json // -> ridermodelfactory-fractory.bin class MyAppGlobalFactory // Delegates to all discovered fractories

Slide 106

Slide 106 text

class RiderModelFactory // -> json // -> ridermodelfactory-fractory.bin class MyAppGlobalFactory // Delegates to all discovered fractories Fractory C om ing Soon™

Slide 107

Slide 107 text

.thrift Thrifty "Jenga" .java APT AutoValueProcessor auto-value-moshi fractory Pre-build Compilation *SPI* Project Gen *Gradle* *Templating* *JavaPoet*

Slide 108

Slide 108 text

Tools •JavaPoet •KotlinPoet •Templating •SPI •Compile Testing •Annotation Processing (APT) •Gradle

Slide 109

Slide 109 text

Pitfalls

Slide 110

Slide 110 text

BLOAT

Slide 111

Slide 111 text

Rider app a

Slide 112

Slide 112 text

Rider app a b 10% Dagger

Slide 113

Slide 113 text

Rider app a b 10% Dagger c 25% Models

Slide 114

Slide 114 text

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

Slide 115

Slide 115 text

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

Slide 116

Slide 116 text

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

Slide 117

Slide 117 text

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

Slide 118

Slide 118 text

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

Slide 119

Slide 119 text

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

Slide 120

Slide 120 text

Rider app a b c

Slide 121

Slide 121 text

Rider app a b c $$

Slide 122

Slide 122 text

Fin Zac Sweers - Uber @pandanomic