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
Y U NO CRAFTSMAN
Search
Xavi Rigau
October 09, 2014
Programming
3
170
Y U NO CRAFTSMAN
Presentation we gave at Droidcon Stockholm "Y U NO CRAFTSMAN".
By Paul Blundell and Xavi Rigau
Xavi Rigau
October 09, 2014
Tweet
Share
More Decks by Xavi Rigau
See All by Xavi Rigau
Android UI Testing with Espresso
xrigau
5
1.3k
Other Decks in Programming
See All in Programming
なぜSQLはAIぽく見えるのか/why does SQL look AI like
florets1
0
410
Claude Codeの「Compacting Conversation」を体感50%減! CLAUDE.md + 8 Skills で挑むコンテキスト管理術
kmurahama
1
830
Oxlintはいいぞ
yug1224
5
1.2k
dchart: charts from deck markup
ajstarks
3
980
Data-Centric Kaggle
isax1015
2
730
16年目のピクシブ百科事典を支える最新の技術基盤 / The Modern Tech Stack Powering Pixiv Encyclopedia in its 16th Year
ahuglajbclajep
5
950
フルサイクルエンジニアリングをAI Agentで全自動化したい 〜構想と現在地〜
kamina_zzz
0
390
余白を設計しフロントエンド開発を 加速させる
tsukuha
7
2.1k
高速開発のためのコード整理術
sutetotanuki
1
360
AIエージェントの設計で注意するべきポイント6選
har1101
7
3.3k
AI 駆動開発ライフサイクル(AI-DLC):ソフトウェアエンジニアリングの再構築 / AI-DLC Introduction
kanamasa
11
6.1k
Vibe codingでおすすめの言語と開発手法
uyuki234
0
210
Featured
See All Featured
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
0
310
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
231
22k
Designing for Performance
lara
610
70k
Build The Right Thing And Hit Your Dates
maggiecrowley
38
3k
How to Talk to Developers About Accessibility
jct
2
120
Ethics towards AI in product and experience design
skipperchong
2
190
Designing Powerful Visuals for Engaging Learning
tmiket
0
210
Rails Girls Zürich Keynote
gr2m
96
14k
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
3.9k
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
117
100k
So, you think you're a good person
axbom
PRO
2
1.9k
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
230
Transcript
Y U NO CRAFTSMAN Xavi Rigau & Paul Blundell
Who we are @xrigau @blundell_apps
What is craftsmanship? craftsmanship ˈkrɑːf(t)smənʃɪp/ the quality of design and
work shown in something
Coder vs Craftsman “Make a chair”
We’re gonna talk about... - Improving day to day craftsmanship
- Creating a positive working environment - The final few steps to awesomeness - Opinionated Bonus material
Improving day to day craftsmanship
Whiteboard ideation
Brainstorming sessions
Helping non dev team members WTF??
Pair programming
Pairing tennis
Driver & Navigator Mistakes Driver Would make Mistakes Navigator Would
make Actual Mistakes
Best coding practices
Code reviews
Selfies & Gifs https://github.com/thieman/github-selfies
Caring about the CI
Static analysis reports
Testing is caring
CI Game LOL
Using the latest tools
Be “agile” build features the way that makes sense
YAGNI Overengineering You Ain’t Gonna Need It GSD
Pragmatism
Creating a positive working environment
Continuous communication
Morning standups
Daily news
Hack & Tells
Dojos
Zero walls office
2 keyboards 2 mice per desk
Standing desks
Remote working
Remote working
Hal9000/Jukebox music
CI Alarm
Xbox downtime
PUB!
Hire the best (for you)
The final steps to awesomeness
That extra 5%
Optimise & leave the main thread alone
Strict Mode private void initializeStrictMode() { if (BuildConfig.DEBUG) { ThreadPolicy
threadPolicy = new ThreadPolicy.Builder() .detectAll() .penaltyLog() .penaltyDeath() .build(); StrictMode.setThreadPolicy(threadPolicy); VmPolicy vmPolicy = new VmPolicy.Builder() .detectAll() .penaltyLog() .penaltyDeath() .build(); StrictMode.setVmPolicy(vmPolicy); } }
GPU Profiling
Show Overdraw
Polish the app
Animate all the things
User features - Second screen / Chromecast - Widget -
Wear - Daydream - LiveWallpaper
Behind the scenes - Content provider - Sync Adapter -
Deep linking / Web search deep linking
Listen for feedback
Measure the data
Measuring Tools Splunk MINT (a.k.a. Bugsense) Crashlytics
Follow the guidelines
What happens when you don’t follow the guidelines
Ensure your app listing is legit
Ensure your app content is legit
Debug screens
Gradle all the things
Build types buildTypes { debug { versionName "${VERSION_NAME}_${GIT_SHA}" runProguard false
signingConfig signingConfigs.debug buildConfigField "String", "BUGSENSE_KEY", 'BuildConfig.INVALID' buildConfigField "boolean", "AB_TEST", 'false' } qa { runProguard false signingConfig signingConfigs.debug buildConfigField "String", "BUGSENSE_KEY", '"disSecret"' } release { runProguard true signingConfig signingConfigs.release buildConfigField "String", "BUGSENSE_KEY", '"lolNotTellingYou"' } }
Versioning
Proper versioning ext { GIT_SHA = gitSha() CI_BUILD_NUMBER = jenkinsBuildNumber()
VERSION_CODE = 19101 // scheme: MINSDK-VERSION dd-ddd VERSION_NAME = "1.0.1" } def jenkinsBuildNumber() { // Local builds will always trump jenkins return System.getenv().BUILD_NUMBER?.toInteger() ?: 9999 } def gitSha() { return 'git rev-parse --short HEAD'.execute().text.trim() } // ... versionCode "${VERSION_CODE}${CI_BUILD_NUMBER}" as Integer versionName "${VERSION_NAME}_${GIT_SHA}"
Opinionated Bonus
The dark side of AOSP try { mWallpaper = getCurrentWallpaperLocked(context);
} catch (OutOfMemoryError e) { Log.w(TAG, "No memory load current wallpaper", e); } try { BitmapFactory.Options options =new BitmapFactory.Options(); return BitmapFactory.decodeStream(is, null, options); } catch (OutOfMemoryError e) { Log.w(TAG, "Can't decode stream", e); } https://android.googlesource.com in WallpaperManager.java - line 263
Follow the examples - but not too closely
Patterns that work well for us
minSdkVersion 15 For more info: https://developer.android.com/about/dashboards/index.html
Activity lifecycle callbacks public interface ActivityLifecycleCallbacks { void onActivityCreated(Activity activity,
Bundle savedInstanceState); void onActivityStarted(Activity activity); void onActivityResumed(Activity activity); void onActivityPaused(Activity activity); void onActivityStopped(Activity activity); void onActivityDestroyed(Activity activity); void onActivitySaveInstanceState(Activity activity, Bundle outState); } public class MyActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks { … } public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); registerActivityLifecycleCallbacks(new MyActivityLifecycleCallbacks()); } }
Harden! Do not crash out there public class LoggingUncaughtExceptionHandler implements
Thread.UncaughtExceptionHandler { private static final String TAG = "MyApp"; @Override public void uncaughtException(Thread thread, Throwable ex) { Log.wtf(TAG, "Swallowed an uncaught exception.", ex); } } private void swallowExceptionsInRelease() { if (!BuildConfig.DEBUG) { Thread.UncaughtExceptionHandler handler = new LoggingUncaughtExceptionHandler(); Thread.currentThread().setUncaughtExceptionHandler(handler); } }
newInstance all the things! public class WidgetImageLoader { private final
Retriever memoryRetriever; private final Retriever fileRetriever; public static WidgetImageLoader newInstance(Context context) { Retriever memoryRetriever = MemoryRetriever.getInstance(); Retriever fileRetriever = FileRetriever.newInstance(context); return new WidgetImageLoader(memoryRetriever, fileRetriever); } WidgetImageLoader(Retriever memoryRetriever, Retriever fileRetriever) { this.memoryRetriever = memoryRetriever; this.fileRetriever = fileRetriever; } }
Hexagonal architecture cc. Alistair Cockburn
In summary
None
Questions?
We are hiring Liverpool, London, Berlin & New York
[email protected]