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
Pro builds in your small startup (Berlindroid 2...
Search
Nelson Osacky
November 29, 2017
Technology
2
470
Pro builds in your small startup (Berlindroid 29-Nov-2017)
How we scaled our build system at Zenjob.
Nelson Osacky
November 29, 2017
Tweet
Share
More Decks by Nelson Osacky
See All by Nelson Osacky
Android Dev to Backend Polyglot
runningcode
1
14
Develocity Reporting and Visualization
runningcode
4
200
Becoming and Staying a Productive Developer with Build Scans, Build Validation Scripts and Gradle
runningcode
1
90
Keeping your Gradle builds in top shape
runningcode
1
350
Keeping your team in top shape with the Gradle Enterprise API
runningcode
3
420
What is the Android Cache Fix plugin and why do I need to solve my own cache misses.
runningcode
1
260
What is the Android Cache Fix plugin and why do I need to solve my own cache misses.
runningcode
1
540
Perspectives from a Solutions Engineer
runningcode
1
560
Beyond Modularization: Scaling your Android Build with Gradle
runningcode
9
2.9k
Other Decks in Technology
See All in Technology
東京大学「Agile-X」のFPGA AIデザインハッカソンを制したソニーのAI最適化
sony
0
150
AWS re:Invent 2025事前勉強会資料 / AWS re:Invent 2025 pre study meetup
kinunori
0
730
.NET 10のBlazorの期待の新機能
htkym
0
150
DMMの検索システムをSolrからElasticCloudに移行した話
hmaa_ryo
0
120
abema-trace-sampling-observability-cost-optimization
tetsuya28
0
340
re:Inventに行くまでにやっておきたいこと
nagisa53
0
660
Observability — Extending Into Incident Response
nari_ex
1
560
ViteとTypeScriptのProject Referencesで 大規模モノレポのUIカタログのリリースサイクルを高速化する
shuta13
3
220
20251024_TROCCO/COMETAアップデート紹介といくつかデモもやります!_#p_UG 東京:データ活用が進む組織の作り方
soysoysoyb
0
120
MCP ✖️ Apps SDKを触ってみた
hisuzuya
0
400
もう外には出ない。より快適なフルリモート環境を目指して
mottyzzz
13
11k
書籍『実践 Apache Iceberg』の歩き方
ishikawa_satoru
0
200
Featured
See All Featured
The Power of CSS Pseudo Elements
geoffreycrofte
80
6k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.2k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.5k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
249
1.3M
A Tale of Four Properties
chriscoyier
161
23k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
10
890
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
1.7k
Bootstrapping a Software Product
garrettdimon
PRO
307
110k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
48
9.7k
Typedesign – Prime Four
hannesfritz
42
2.8k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
285
14k
Visualization
eitanlees
150
16k
Transcript
Pro builds in your small startup Nelson Osacky
About me • Android developer since before Uni • New
to Berlin - Started working in September • Formerly at Square in San Francisco • Worked on Reader Experience, Square Register and build systems: Buck
Every build is a special snowflake
In the beginning there were no tests, no CI…
None
None
Why Travis? • Other engineering teams at Zenjob teams were
already using it • Integrates easily with GitHub • Good Android examples and documentation • There’s a million options, this isn’t really the point.
How to add Travis? language: android jdk: - oraclejdk8 android:
components: - tools - platform-tools - tools - build-tools-25.0.0 - android-26 script: ./gradlew assemble check notifications: email: false cache: directories: - $HOME/.gradle
Only ran checkstyle and unit tests
Next step: Boot emulator before_install: - start emulator install:
./gradlew assemble before_script: android-wait-for-emulator script: ./gradlew check connectedCheck
before_install: # Install the system image. - sdkmanager “system-images;android-19;default;armeabi-v7a" #
Create and start emulator for the script. # Meant to race the install task. - echo no | avdmanager create avd --force -n test -k "system- images;android-19;default;armeabi-v7a" - $ANDROID_HOME/emulator/emulator -avd test -no-audio -no-window &
Travis takes: 15 min 13 sec
Next: Run UI tests
Hard to debug • Button isn’t visible? Why? • No
screenshots • Spoon doesn’t support AGP 3.0 (yet) • Screenshot on failure is tricky • Unsolved problem
After enabling our first UI test
None
2 tests later
None
Soon we had a problem
None
Make the tests faster • Replace SystemClock.sleep() in tests with
Espresso idling resources • Replace real API calls with mock API calls • Make mock API calls return instantly
Success…?
None
Time to try something else
AWS Device Farm
• AWS Device Lab failed with cryptic error and no
support • AWS Device Lab $10/hr • Firebase Test Lab $1/hr virtual and $5/hr real devices
Easy Decision
So much faster!
Why faster? • Do not have to download or install
emulator • Emulator doesn’t slow down the rest of the build • Tests are now run on faster emulator
None
111 secs = 1m 51 secs
None
Can we go faster?
if [ "$COMPONENT" == "checkstyle" ]; then ./gradlew checkstyle elif
[ "$COMPONENT" == "unit" ]; then ./gradlew test elif [ "$COMPONENT" == "lint" ]; then ./gradlew lint elif [ "$COMPONENT" == "release" ]; then ./gradlew assembleRelease elif [ "$COMPONENT" == "instrumentation" ]; then ./gradlew assembleDebug assembleAndroidTest .travis/run-ui-tests.sh else echo "This module doesn't exist" exit 1 fi
None
Yes, but…
Faster individual builds but slower with multiple builds.
if [ "$COMPONENT" == "build" ]; then ./gradlew checkstyle check
assembleRelease elif [ "$COMPONENT" == "instrumentation" ]; then ./gradlew assembleDebug assembleAndroidTest .travis/run-ui-tests.sh else echo "This module doesn't exist" exit 1 fi
None
Less is more!
Problems solved!
…but then we wrote more UI tests
None
60+ Tests, 11 mins
Sharding?
Flank!
• https://github.com/TestArmada/flank • Splits up UI tests amongst Firebase Test
Lab devices • Splits up tests to minimize costs
Test time stays constant
None
Prints out cost
Still one problem; manual uploads
Automation
before_deploy: # Verify that the apk was signed. - apksigner
verify -v app/build/outputs/apk/release/app-release.apk # Publish to GitHub releases only on tagged commits. deploy: provider: releases api_key: secure: blah-blah-blah file: - "app/build/outputs/apk/debug/app-debug.apk" - "app/build/outputs/mapping/release/mapping.txt" - "app/build/outputs/apk/release/app-release.apk" skip_cleanup: true on: tags: true condition: $COMPONENT = build # Publish to Google Play after successful deployment to GitHub releases. after_deploy: - ./gradlew publishApkRelease
before_deploy: # Verify that the apk was signed. - apksigner
verify -v app/build/outputs/apk/release/ app-release.apk
before_deploy: # Verify that the apk was signed. - apksigner
verify -v app/build/outputs/apk/release/app-release.apk # Publish to GitHub releases only on tagged commits. deploy: provider: releases api_key: secure: blah-blah-blah file: - "app/build/outputs/apk/debug/app-debug.apk" - "app/build/outputs/mapping/release/mapping.txt" - "app/build/outputs/apk/release/app-release.apk" skip_cleanup: true on: tags: true condition: $COMPONENT = build # Publish to Google Play after successful deployment to GitHub releases. after_deploy: - ./gradlew publishApkRelease
# Publish to GitHub releases only on tagged commits. deploy:
provider: releases api_key: secure: blah-blah-blah file: - "app/build/outputs/apk/debug/app-debug.apk" - "app/build/outputs/mapping/release/mapping.txt" - "app/build/outputs/apk/release/app-release.apk" skip_cleanup: true on: tags: true condition: $COMPONENT = build
before_deploy: # Verify that the apk was signed. - apksigner
verify -v app/build/outputs/apk/release/app-release.apk # Publish to GitHub releases only on tagged commits. deploy: provider: releases api_key: secure: blah-blah-blah file: - "app/build/outputs/apk/debug/app-debug.apk" - "app/build/outputs/mapping/release/mapping.txt" - "app/build/outputs/apk/release/app-release.apk" skip_cleanup: true on: tags: true condition: $COMPONENT = build # Publish to Google Play after successful deployment to GitHub releases. after_deploy: - ./gradlew publishApkRelease
None
None
Automatic upload to the play store
apply plugin: 'com.github.triplet.play' android { playAccountConfigs { defaultAccountConfig { jsonFile
= file('keys.json') } } defaultConfig { playAccountConfig = playAccountConfigs.defaultAccountConfig } }
before_deploy: # Verify that the apk was signed. - apksigner
verify -v app/build/outputs/apk/release/app-release.apk # Publish to GitHub releases only on tagged commits. deploy: provider: releases api_key: secure: blah-blah-blah file: - "app/build/outputs/apk/debug/app-debug.apk" - "app/build/outputs/mapping/release/mapping.txt" - "app/build/outputs/apk/release/app-release.apk" skip_cleanup: true on: tags: true condition: $COMPONENT = build # Publish to Google Play after successful deployment to GitHub releases. after_deploy: - ./gradlew publishApkRelease
# Publish to Google Play after successful deployment to GitHub
releases. after_deploy: - ./gradlew publishApkRelease
None
TODOs • Automate bumping version numbers • Run UI tests
on more real devices with different APIs before release • Move to AWS or another service with faster machines
TODOs • Screenshots on failure ( should be built in)
• Gradle plugin for Firebase tests • Gradle plugin for Flank (for running locally)
TODOs • Merge on green button • Automate release branch
cutting • Speed up local builds (Buck?)
Thank you
[email protected]
https://www.zenjob.de/careers/