Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Code Generation for Fun & Profit (Swift Edition)
Search
Ragunath Jawahar
April 22, 2017
Programming
1
220
Code Generation for Fun & Profit (Swift Edition)
Presented in April '17 Swift Delhi meetup.
https://www.meetup.com/Swift-Delhi/events/239248482/
Ragunath Jawahar
April 22, 2017
Tweet
Share
More Decks by Ragunath Jawahar
See All by Ragunath Jawahar
Single-responsibility principle meets the real world! (Dubai Edition)
ragunathjawahar
0
38
Single-responsibility principle meets the real world!
ragunathjawahar
0
140
Making sense of large Java and Kotlin classes
ragunathjawahar
1
260
Building Robust Software, Episode 3
ragunathjawahar
1
160
Building Robust Software, Episode 2
ragunathjawahar
1
120
Building Robust Software (Episode 1)
ragunathjawahar
1
340
Speed as a workplace habit
ragunathjawahar
1
300
Building Robust Apps (Swift Edition)
ragunathjawahar
0
240
Re-architecture
ragunathjawahar
0
470
Other Decks in Programming
See All in Programming
Compose Multiplatform × AI で作る、次世代アプリ開発支援ツールの設計と実装
thagikura
0
140
CloudflareのChat Agent Starter Kitで簡単!AIチャットボット構築
syumai
2
470
AWS発のAIエディタKiroを使ってみた
iriikeita
1
180
Namespace and Its Future
tagomoris
6
700
テストカバレッジ100%を10年続けて得られた学びと品質
mottyzzz
2
570
さようなら Date。 ようこそTemporal! 3年間先行利用して得られた知見の共有
8beeeaaat
3
1.4k
実用的なGOCACHEPROG実装をするために / golang.tokyo #40
mazrean
1
250
奥深くて厄介な「改行」と仲良くなる20分
oguemon
1
510
Android 16 × Jetpack Composeで縦書きテキストエディタを作ろう / Vertical Text Editor with Compose on Android 16
cc4966
0
180
今だからこそ入門する Server-Sent Events (SSE)
nearme_tech
PRO
0
110
Navigation 2 を 3 に移行する(予定)ためにやったこと
yokomii
0
130
AI Coding Agentのセキュリティリスク:PRの自己承認とメルカリの対策
s3h
0
200
Featured
See All Featured
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
22k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
252
21k
[RailsConf 2023] Rails as a piece of cake
palkan
57
5.8k
Statistics for Hackers
jakevdp
799
220k
Fireside Chat
paigeccino
39
3.6k
Producing Creativity
orderedlist
PRO
347
40k
Stop Working from a Prison Cell
hatefulcrawdad
271
21k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
46
7.6k
Faster Mobile Websites
deanohume
309
31k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.4k
Building Flexible Design Systems
yeseniaperezcruz
328
39k
Unsuck your backbone
ammeep
671
58k
Transcript
Code Generation for Fun & Profit (Swift Edition) Ragunath Jawahar
A mobile app developer walks into the bar…
A mobile app developer walks into the bar office…
None
Tracking Code (Swift) let properties = [ "Gender": "Female", "Logged
in": false, "Source": "Twitter" ] Mixpanel.mainInstance() .track(event: "Signup", properties: properties)
Tracking Code (Swift) let properties = [ "Gender": "Female", "Logged
in": false, "Source": "Twitter" ] Mixpanel.mainInstance() .track(event: "Signup", properties: properties)
Tracking Code (Swift) let properties = [ "Gender": "Female", "Logged
in": false, "Source": "Twitter" ] Mixpanel.mainInstance() .track(event: "Signup", properties: properties)
Tracking Code (Java) MixpanelAPI mixpanel = MixpanelAPI.getInstance(this, token); try {
JSONObject payload = new JSONObject(); payload.put("Gender", "Female"); payload.put("Logged in", false); payload.put("Source", "Twitter"); mixpanel.track("Signup", payload); } catch (JSONException exception) { Log.e("Frodo", "JsonException", exception); }
Tracking Code (Java) MixpanelAPI mixpanel = MixpanelAPI.getInstance(this, token); try {
JSONObject payload = new JSONObject(); payload.put("Gender", "Female"); payload.put("Logged in", false); payload.put("Source", "Twitter"); mixpanel.track("Signup", payload); } catch (JSONException exception) { Log.e("Frodo", "JsonException", exception); }
Tracking Code (Java) MixpanelAPI mixpanel = MixpanelAPI.getInstance(this, token); try {
JSONObject payload = new JSONObject(); payload.put("Gender", "Female"); payload.put("Logged in", false); payload.put("Source", "Twitter"); mixpanel.track("Signup", payload); } catch (JSONException exception) { Log.e("Frodo", "JsonException", exception); }
Tracking Code (Java) MixpanelAPI mixpanel = MixpanelAPI.getInstance(this, token); try {
JSONObject payload = new JSONObject(); payload.put("Gender", "Female"); payload.put("Logged in", false); payload.put("Source", "Twitter"); mixpanel.track("Signup", payload); } catch (JSONException exception) { Log.e("Frodo", "JsonException", exception); }
GREMLINS
None
None
…and only 300 more rows
MAY THE “BRUTE” FORCE BE WITH YOU
Problems •Slow •Boring •Inaccurate •Error Prone •Hard to Test •Difficult
to Change •Multiple Platforms •Multiple Apps
Requirements • Accuracy • Accommodate Changes • Don’t Leak Cognitive
Resources • Testability • Support Multiple Apps and Platforms
None
WORKFLOW – SCREEN – EVENT
workflow().screen().event()
SOLVING MYSTERY
Java Poet – Method MethodSpec mainMethod = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(String[].class, "args") .addStatement( "$T.out.println($S)", System.class, "Hello, World!” ).build();
Java Poet – Method MethodSpec mainMethod = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(String[].class, "args") .addStatement( "$T.out.println($S)", System.class, "Hello, World!” ).build();
Java Poet – Method MethodSpec mainMethod = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(String[].class, "args") .addStatement( "$T.out.println($S)", System.class, "Hello, World!” ).build();
Java Poet – Method MethodSpec mainMethod = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(String[].class, "args") .addStatement( "$T.out.println($S)", System.class, "Hello, World!” ).build();
Java Poet – Method MethodSpec mainMethod = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(String[].class, "args") .addStatement( "$T.out.println($S)", System.class, "Hello, World!” ).build();
Java Poet – Method MethodSpec mainMethod = MethodSpec.methodBuilder("main") .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(String[].class, "args") .addStatement( "$T.out.println($S)", System.class, "Hello, World!” ).build();
Java Poet – Class TypeSpec greeterClass = TypeSpec.classBuilder("Greeter") .addModifiers(Modifier.PUBLIC) .addMethod(mainMethod)
.build();
Java Poet – Class TypeSpec greeterClass = TypeSpec.classBuilder("Greeter") .addModifiers(Modifier.PUBLIC) .addMethod(mainMethod)
.build();
Java Poet – Class TypeSpec greeterClass = TypeSpec.classBuilder("Greeter") .addModifiers(Modifier.PUBLIC) .addMethod(mainMethod)
.build();
Java Poet – Class TypeSpec greeterClass = TypeSpec.classBuilder("Greeter") .addModifiers(Modifier.PUBLIC) .addMethod(mainMethod)
.build();
Java Poet – Class TypeSpec greeterClass = TypeSpec.classBuilder("Greeter") .addModifiers(Modifier.PUBLIC) .addMethod(mainMethod)
.build();
Java Poet – Compilation Unit JavaFile greeterFile = JavaFile.builder("in.kitecash", greeterClass).build();
greeterFile.writeTo(System.out);
Java Poet – Compilation Unit JavaFile greeterFile = JavaFile.builder("in.kitecash", greeterClass).build();
greeterFile.writeTo(System.out);
Java Poet – Compilation Unit JavaFile greeterFile = JavaFile.builder("in.kitecash", greeterClass).build();
greeterFile.writeTo(System.out);
Java Poet – Compilation Unit JavaFile greeterFile = JavaFile.builder("in.kitecash", greeterClass).build();
greeterFile.writeTo(System.out);
Java Poet – Generated Class package in.kitecash; import java.lang.String; import
java.lang.System; public class Greeter { public static void main(String[] args) { System.out.println("Hello, World!"); } }
BLUEPRINT
Objective workflow().screen().event()
ITERATE ON PAPER
Components •CSV Parser •Source Code Generator
High-Level Design •Generated abstract Tracker class •Generated Analytics class •Generated
Workflow classes •Generated Screen inner classes
Class Diagram … more workflow classes
Class Diagram … more inner screen classes
Tracker public abstract class Tracker { public abstract void track(String
event, Map<String, String> payload); }
Tracker public abstract class Tracker { public abstract void track(String
event, Map<String, String> payload); }
Tracker public abstract class Tracker { public abstract void track(String
event, Map<String, String> payload); }
Tracker public abstract class Tracker { public abstract void track(String
event, Map<String, String> payload); }
Analytics •Instantiated by supplying a Tracker implementation •Entry-‐point to event
tracking
workflow().screen().event() •Generated as top-level classes •Encapsulates screen inner classes
workflow().screen().event() •Workflow inner classes •Encapsulates event tracking methods
workflow().screen().event() •Event tracking methods •Resides inside screen classes •May accept
parameters for collecting additional data
ACCURACY
WRITE CODE TO GENERATE CODE
WRITE CODE TO GENERATE CODE
CHANGES
CSV Removals – Red Markers
CSV Removals – Red Markers
CSV Additions – Gray Methods
CSV Additions – Gray Methods
PRODUCTIVITY
Auto-Completion
Auto-Completion
Checklist
Checklist
Checklist
Checklist
Checklist
Checklist
Checklist
TESTING
HOW? •Schemes (iOS) & Product Flavors (Android) •Dependency Injection
Trackers •Log Tracker •Mixpanel Tracker •Dialog Tracker •Verifying Tracker
iOS + Swift
DIFFICULTIES •Swift •No Transpilers •No Code Generation Libraries
J2ObjC
J2ObjC Java Objective-C Swift
J2ObjC Java Objective-C Swift
J2ObjC Java Objective-C Swift
PEACE
PEACE
abstract class(es) NOT interface(s)
J2ObjC NUANCES •Runtime Library •Adds ~10 MB
CODE GENERATION TIPS • Doesn’t have to be DRY •
Iterate through the design several times • Add “Auto-Generated” comments and documentation • Prefer abstract classes over interfaces • Extract platform-specific code and provide abstraction • Communicate with Business Intelligence team
ragunathjawahar GitHub / Twitter / Speakerdeck