Building Maintainable Android Apps (DroidCon NYC 2014)
-
Upload
kevin-schultz -
Category
Software
-
view
250 -
download
2
description
Transcript of Building Maintainable Android Apps (DroidCon NYC 2014)
![Page 1: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/1.jpg)
Building Maintainable Android Applications!
Kevin Schultz (@kevinrschultz) DroidCon NYC 2014 !kevinrschultz.com github.com/krschultz/AndroidWeatherBuoyDemo
![Page 2: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/2.jpg)
Apps vs Applications
![Page 3: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/3.jpg)
![Page 4: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/4.jpg)
Treading WaterTime spent on features dwindles
Infrequent releases due to high QA costs
Heisenbug whack-a-mole
Fear of change
Bugs
Features
Infrastructure
![Page 5: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/5.jpg)
Drowning
Platform Changes
Business Pivot
Competitors
Panic
How many regressions will you cause when
implementing Material Design?
![Page 6: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/6.jpg)
Refactor! Rewrite!
![Page 7: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/7.jpg)
The codebase is a mess!
![Page 8: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/8.jpg)
Unlikely to be better next time
Clean code is necessary but insufficient for maintainability
We are state of the art today, what about next year?
Why do Android apps always seem to become unmaintainable?
![Page 9: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/9.jpg)
Android was initially for Apps
Documentation & samples are small scale
Old build system was deficient
Testing tools are still sub-par
Framework was not designed for testability
Performance trumped clean code
![Page 10: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/10.jpg)
You must build a system to counter software entropy
![Page 11: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/11.jpg)
Software Entropy
“Legacy code is code without tests” - Michael Feathers
“As a system is modified, its disorder, or entropy, always increases. This is known as software entropy.” - Ivar Jacobson
![Page 12: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/12.jpg)
System
CI Server
Build
UI Tests
Functional Tests
Unit Tests App
Espresso
![Page 13: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/13.jpg)
System Thinking
How will each component be tested over its lifetime?
What leads to the minimum cost of development including QA time?
If a library makes it easy to add a feature but harder to test, is it worth it?
If a tool breaks CI, is it worth it?
![Page 14: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/14.jpg)
Testing Strategy
Customers in Production
Manual QA by Team
Unit Tests
Integration tests
Automated UI Tests
![Page 15: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/15.jpg)
Manual Testing
Low initial cost
Need to acceptance test every feature at least once
Never can be completely eliminated
Does not scale with complexity
Extremely expensive long term
![Page 16: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/16.jpg)
QA Options
Helps make manual testing cheaper & more effective
Network connectivity
Environment
Mock Data
![Page 17: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/17.jpg)
QA Specs
Look at Gherkin / Cucumber for examples
Helps to make tests more repeatable
Can use to outsource testing to other firms
Painful & expensive
![Page 18: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/18.jpg)
Automated UI Testing
Appium / UIAutomator type tests
Usually leveraging the accessibility IDs
Expensive, flakey
Can be layered onto most apps after the fact
![Page 19: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/19.jpg)
Functional Testing
Most Android ‘unit testing’ examples are functional
Robolectric & InstrumentationTests
Generally scoped to an Activity / Fragment / Service
Time consuming to run and nearly as flakey as UI tests
Useful but should be minimized
![Page 20: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/20.jpg)
Functional Testing ChallengesGeneric Problems
Asynchronous
Network based
!
!
Android Specific
Lifecycle
Context
Platform singletons
![Page 21: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/21.jpg)
Functional Test in Theory
assertEquals(conditions, label.getText());
insertMockDataIntoPreferences(conditions)
waitForActivityAndFragmentToInitialize()
label = findViewById()
waitForDataToLoad()
Actual Test
BoilerplatePreconditions
testWindSpeedLabel_MetricSystem
![Page 22: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/22.jpg)
Functional Test in Practice
![Page 23: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/23.jpg)
Pitfalls for a Functional TestIs the user logged in?
Wait for Activity, Fragment lifecycle to load screen
Wait for network call to finish
Wait for data to load from DB
Find the TextView
Finally, check the TextView’s content & color
![Page 24: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/24.jpg)
Unit Testing
Narrow in scope, each test is 1 case for 1 method
Do not test Android platform, therefore run quickly
Cheap to write if architecture is designed for testing
Flexible for refactoring
Should be 80% of your tests
![Page 25: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/25.jpg)
Unit Test in Theory
assertEquals(conditions, label.getText());
given(conditions)
testWindSpeedLabel_MetricSystem
![Page 26: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/26.jpg)
Unit Tests in Practice
![Page 27: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/27.jpg)
So why is this so hard?
![Page 28: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/28.jpg)
Activity Fragment Adapter
ForecastActivity ForecastFragment ForecastAdapter ForecastModel
![Page 29: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/29.jpg)
Keep Android At Arm’s Length
![Page 30: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/30.jpg)
StrategiesCovered
Dealing with K/V Store
ViewModels, Presenters, Custom Views
Not Covered
Testing network calls
Testing SQLite / ContentProviders / ORMs
![Page 31: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/31.jpg)
Weather Buoy
Master list of buoys
Detail screen with wind & wave forecast
Setting to choose units
github.com/krschultz/AndroidWeatherBuoyDemo
![Page 32: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/32.jpg)
ToolsExamples uses only
Android standard JUnit & InstrumentationTests
Mockito
AssertJ
Better tools exist
Espresso
Robolectric
Dagger
![Page 33: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/33.jpg)
SharedPreferences
![Page 34: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/34.jpg)
How do you catch this?
![Page 35: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/35.jpg)
How do you catch this?
![Page 36: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/36.jpg)
Wrapping Preferences
![Page 37: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/37.jpg)
Testing Preferences Wrapper
![Page 38: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/38.jpg)
Using wrapped Preferences
![Page 39: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/39.jpg)
Using mock Preferences
![Page 40: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/40.jpg)
Wrapping Shared Preferences
+ Only 1 place to test interaction w/ SharedPreferences
+ Handle versioning
+ Keys don’t leak out
+ Can now mock SharedPreferences w/o Context
- More code
![Page 41: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/41.jpg)
UI Unit Testing Strategies
![Page 42: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/42.jpg)
Custom Views
![Page 43: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/43.jpg)
Optional TextView
What happens when we refactor the layout?
How do we know this feature doesn’t break?
![Page 44: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/44.jpg)
Optional TextView
![Page 45: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/45.jpg)
Testing Optional TextView
![Page 46: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/46.jpg)
Instrument View
LabelValue & Units
![Page 47: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/47.jpg)
Custom View
+ Clean API
+ Reusable view logic
- Compose-ability issues
![Page 48: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/48.jpg)
ViewModels
![Page 49: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/49.jpg)
SharedPreferences
Views
ForecastFragment
WaveForecast
ViewsViews
WindForecast
Preferences
API Client
![Page 50: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/50.jpg)
View Models
Add presentation logic to underlying models
Combine multiple models
Do not have a concept of Activity/Fragment lifecycle
Do not have a reference to View
![Page 51: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/51.jpg)
Using a ViewModel
Fragment is responsible for loading models, networking, finding views, threading
ViewModel is responsible for business logic
Fragment should fail in all cases
![Page 52: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/52.jpg)
“Presentation” Logic
Colors, visibility
Interaction between multiple views
Formatting / humanizing properties
i18n
![Page 53: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/53.jpg)
Combining Models
BuoyDetailViewModel
WaveForecast PreferencesWindForecast
![Page 54: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/54.jpg)
SharedPreferences
Views
ForecastFragment WaveForecast
ViewsViews
WindForecast
Preferences
ViewModel
API Client
![Page 55: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/55.jpg)
ViewModel Creation
No reference to view at all
All models can be immutable
![Page 56: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/56.jpg)
Using a ViewModel
Create view model at the end of network call or DB fetch
Pass Views to ViewModel for updating
![Page 57: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/57.jpg)
Logic in a ViewModel
![Page 58: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/58.jpg)
PitfallsCreating a ViewModel getter for every view property
Keeping references to views in the ViewModel
![Page 59: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/59.jpg)
Testing
![Page 60: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/60.jpg)
Use Cases
Great for screens displaying detail about an object
Not ideal for collections of items, but Adapters can be tested similarly
Not a great fit for screens with many interactions
![Page 61: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/61.jpg)
Presenters
![Page 62: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/62.jpg)
Presenters
Same general idea as ViewModel, but includes reference to View
Requires coordinating with Activity/Fragment lifecycle
Potential for Context leaks if not handled correctly
More full featured, can take ownership of fetching data, threading, network calls, etc
![Page 63: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/63.jpg)
Views
ForecastFragment WaveForecast
ViewsViews
WindForecast
Preferences
Presenter
View Interface
![Page 64: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/64.jpg)
Fragment
![Page 65: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/65.jpg)
Presenter
![Page 66: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/66.jpg)
Fragment Continued
User interactions delegated to presenter
Can test using the same methods on the presenter
![Page 67: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/67.jpg)
Presenter Continued
All business logic belongs in presenter
Calls back to view for update, remember the view may be gone
![Page 68: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/68.jpg)
Use Cases
Can handle state changes caused by user interaction very well
Really should use Espresso / InstrumentationTests to ensure that click handlers call appropriate methods in presenter
![Page 69: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/69.jpg)
Summary
You are building a system, not just an app
Cost of testing over long term becomes extremely expensive
Find ways to keep the platform at arms length
Consider how to test each component from the start
![Page 70: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/70.jpg)
Further Reading
www.objc.io/issue-13/viper.html
martinfowler.com/eaaDev/uiArchs.html
![Page 71: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/71.jpg)
Contact
@kevinrschultz
github.com/krschultz/AndroidWeatherBuoyDemo
kevinrschultz.com
![Page 72: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/72.jpg)
Questions?
![Page 73: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/73.jpg)
Backup
![Page 74: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/74.jpg)
Law of Demeter w/ Context
![Page 75: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/75.jpg)
Image Attribution
!
Tent -
House - https://www.flickr.com/photos/18702768@N04/2294709357
Cake - https://www.flickr.com/photos/personalcreations/14888675499
![Page 76: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/76.jpg)
Long Term Cost
0
17.5
35
52.5
70
1 2 3 4 5 6
Manual Unit Tests UI Tests Test Fixtures
![Page 77: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/77.jpg)
Stage 1 -> No desire for tests
Stage 2 -> Desire tests, but can’t build the test suite
Stage 3 -> Have a test suite
Stage 4 -> Nirvana. Bugs find themselves.
![Page 78: Building Maintainable Android Apps (DroidCon NYC 2014)](https://reader033.fdocuments.in/reader033/viewer/2022051513/54655ec0af7959871b8b6448/html5/thumbnails/78.jpg)
But I Don’t Have Business Logic!
“It’s just simple data in the UI!”
Not for long (PDP examples)
Creating a place for the tests to go from the start makes it easy to add them (UUID example)
Every single thing is small, but the sum of testing them all is expensive