Developing Android apps like Navy Seals
Ivan Kušt, Android team leader
Infinum Android team
How it all began?
How it all began
First steps
• Android plugin for Eclipse
• tests? who needs them
• Activities with > 1k lines
First steps
• no segregation of duties
• no code review
• poor code structure
Aint nobody got time for that
Regression testing?
So what did we do?
• Improved implementation process
• Included testing to development process
• Improved release process and analytics
Implementation process
Working in a team
• git conflicts
• different code styles
• environment switching (test, production)
Working in a team
• bugfixing while developing a new feature
• weekly meetings and progress reports
branching / merging process
Pull Requests
debug staging release
obfuscated no yes yes
logs yes yes no
crash reporting no yes in most cases
Build types
Gradle
• Build types - debug, staging, release
• Product flavors - test API server, production API server
Product flavors
• number of flavours = number of API environments
Build variants
• flavor x buildType
• example productionDebug
• production API
• debuggable, unobfuscated, logs enabled
Model Presenter View
Code architecture
MVP
• a derivative from MVC
• Models and Views never communicate directly
Model Presenter View
View
• Activity, Fragment, View
• propagates UI events to presenter
• exposes methods that control presentation of data
Model Presenter View
Presenter
• middle man between View and Model
• updates the UI - difference to MVC
Presenter ViewModel Presenter
• Activity, Fragment, View
• propagates UI events to presenter
• exposes methods that control presentation of data
View
View
Model
• gateway towards the business logic
• methods for data retrieval
Model Presenter
ExampleshowLoading() hideLoading() setUsernameError() setPasswordError()
LoginPresenterlogin(username, pass)
LoginView LoginModellogin(username, pass, listener)
showLoading() hideLoading() setUsernameError() setPasswordError()
LoginActivityloginPresenter
login(username, pass)
LoginPresenterImplloginView loginModel
LoginModelImpl
login(username, pass, listener)
Testing
Instrument testing
• Robotium, Espresso
• runs on emulator or real device
Unit testing
• Robolectric
• write mock View and Interactor
• unit test Presenter
Dependency injection
• Dagger 2
• https://github.com/reisub/Dagger-2-Example
• simplifies writing tests
• Model / View / Presenter can easily be replaced
Without DI
@Overrideprotected void onCreate(Bundle savedInstanceState) { //... //dependencies loginPresenter = new LoginPresenterImpl(this, new LoginModelImpl());}
LoginView LoginPresenter LoginModel
LoginActivity LoginPresenterImpl LoginModelImpl
With DI
@Overrideprotected void onCreate(Bundle savedInstanceState) { //... //dependencies DaggerLoginComponent.builder() .loginModule(new LoginModule(this)) .build() .inject(this); }
With DI
• decoupling dependencies from implementation
• easier to replace dependencies
• more about Dagger:http://google.github.io/dagger/
Robolectric
• mock Android VM (tests run on desktop machine)
• View doesn’t have to be mocked
• full control of Activity / Fragment lifecycle
• http://robolectric.org/
MockWebServer
• part of OkHttp library
• server that runs on localhost
• responses can be enqueued
• https://github.com/square/okhttp/tree/master/mockwebserver
Mocking network layer
• network layer can be replaced with MockWebServer
• no additional mock classes
Continuous integration
• if not forced, you won’t run tests
Idea
• commit to a branch starts test execution
• CI server clones the repo, compiles and runs tests
• test results are archived and notified via mail / chat
CI servers
• Jenkins
• Travis
• Circle CI
• https://circleci.com/
• works only with GitHub
Static code checks
Findbugs
• http://findbugs.sourceforge.net/
• java.net.URL.hashCode()
Android Lint
• android related checks
• missing translations
• unused drawables
Checkstyle
Releasing and analytics
Infinum Labs
Infinum Labs
• internal app store
• gradle task increments version name
• upload app via web, CLI tool or AS plugin
• library that notifies when new version is available
Analytics
Recap
• Improved implementation process
• Included testing to development process
• Improved release process and analytics
Implementation process
• organise teamwork - git flow
• monitor code quality - pull requests
• one click build - build variants
• code structuring - MVP
Testing
• Unit testing
• Continuous integration
• Static code checks
Releasing and analytics
• internal store for clients
• automatic notification when new version is up
• analytics / crashlytics
• initial project setup takes more time
• steeper learning and onboarding curve
• developing new features initially takes more time to cover the code with unit test
Cons
• confidence in builds(so much that we believe we’re Navy Seals)
• more maintainable code
• regression testing
Pros
Implementation Testing Release Post Release
ArchitectureBuild Types
MVP
Dependency injection
Unit TestsRobolectric
MockWebServer
Manual testsHuman tester
Infinum Notifier lib
AnalyticsGoogle analytics
Crashlytics
Play Store
Top Related