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
33
Single-responsibility principle meets the real world!
ragunathjawahar
0
140
Making sense of large Java and Kotlin classes
ragunathjawahar
1
240
Building Robust Software, Episode 3
ragunathjawahar
1
150
Building Robust Software, Episode 2
ragunathjawahar
1
110
Building Robust Software (Episode 1)
ragunathjawahar
1
330
Speed as a workplace habit
ragunathjawahar
1
290
Building Robust Apps (Swift Edition)
ragunathjawahar
0
220
Re-architecture
ragunathjawahar
0
450
Other Decks in Programming
See All in Programming
Memory API : Patterns, Performance et Cas d'Utilisation
josepaumard
0
140
SEAL - Dive into the sea of search engines - Symfony Live Berlin 2025
alexanderschranz
1
140
VitestのIn-Source Testingが便利
taro28
6
2k
Making TCPSocket.new "Happy"!
coe401_
1
1.5k
AI Coding Agent Enablement - エージェントを自走させよう
yukukotani
14
6.1k
メモリウォールを超えて:キャッシュメモリ技術の進歩
kawayu
0
1.9k
趣味全開のAITuber開発
kokushin
0
200
Fiber Scheduler vs. General-Purpose Parallel Client
hayaokimura
1
100
国漢文混用体からHolloまで
minhee
1
190
MCP調べてみました! / Exploring MCP
uhzz
2
2.3k
Unlock the Potential of Swift Code Generation
rockname
0
260
The Evolution of the CRuby Build System
kateinoigakukun
0
710
Featured
See All Featured
It's Worth the Effort
3n
184
28k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
34
2.2k
The Cult of Friendly URLs
andyhume
78
6.3k
Embracing the Ebb and Flow
colly
85
4.6k
Git: the NoSQL Database
bkeepers
PRO
430
65k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
52
2.4k
Done Done
chrislema
183
16k
The Cost Of JavaScript in 2023
addyosmani
49
7.7k
Scaling GitHub
holman
459
140k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
29
1.6k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
233
17k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
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