How to build rock solid apps and keep 100m+ users happy

  • 994 views
Uploaded on

 

More in: Engineering , Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
994
On Slideshare
0
From Embeds
0
Number of Embeds
6

Actions

Shares
Downloads
10
Comments
0
Likes
4

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. How to build rock-solid apps and keep 100m+ users happy Iordanis Giannakakis
  • 2. About me • Iordanis “Jordan” Giannakakis • Android Team Lead at Shazam • @iordanis_g @iordanis_g
  • 3. How Shazam works @iordanis_g
  • 4. 100+ million users @iordanis_g
  • 5. Happy users @iordanis_g Even developers?
  • 6. Android testing @iordanis_g
  • 7. Faster release cycles @iordanis_g
  • 8. Better code @iordanis_g
  • 9. Cheaper @iordanis_g http://testdroid.com/testdroid/5851
  • 10. Easy @iordanis_g
  • 11. A user walks into a bar... @iordanis_g
  • 12. Doing it the test-driven way @iordanis_g Write UI test Implement Refactor Write unit test BDD TDD
  • 13. “To TDD or not to TDD? @iordanis_g ...That is not the question” Seb Rose http://claysnow.co.uk/to-tdd-or-not-to-tdd/
  • 14. Test-first @iordanis_g • Generally easier • Eliminates external dependencies • Easily repeatable
  • 15. The Acceptance tests cycle @iordanis_g Write UI test Implement Refactor Write unit test BDD TDD
  • 16. Acceptance criteria @iordanis_g Given: arrange When: act Then: assert
  • 17. Example @iordanis_g Given a user is near a music venue And the server always returns a known result When the user Shazams Then the user can check-in their discovery
  • 18. gwen @iordanis_g given(user).isNear(lexington()) given(server).returns(lustForLife()) when(user).shazams() then(user).canCheckIn(lustForLife(), lexington()) https://github.com/shazam/gwen
  • 19. Acceptance tests technologies @iordanis_g • Instrumentation • JUnit 3 • Robotium & Espresso • gwen • HamMock Server
  • 20. The Unit tests cycle @iordanis_g Write UI test Implement Refactor Write unit test BDD TDD
  • 21. What we don’t test @iordanis_g Activities & Fragments https://github.com/xxv/android-lifecycle/
  • 22. What we don’t test @iordanis_g
  • 23. What we do unit test @iordanis_g • Presentation logic • Business logic • That’s all!
  • 24. The MVP pattern @iordanis_g Presenter Model View
  • 25. The MVP pattern, for Android @iordanis_g Presenter Model View start stop Android
  • 26. The MVP pattern @iordanis_g • Makes presentation logic testable • No need to test the “slave” view • Avoid Android dependencies
  • 27. Dependency Injection, Yourself (DIY) @iordanis_g • Break hardcoded dependencies • Behaviour vs implementation • Swappable dependencies for test and production runtimes
  • 28. Hard-coded dependencies @iordanis_g Client Feature X Feature X
  • 29. Dependency Injection @iordanis_g Client Injector Feature X Interface
  • 30. Model @iordanis_g public interface VenueRetriever { void findClosestVenue(VenueFoundCallback callback); } public class NetworkVenueRetriever implements VenueRetriever { public void findClosestVenue(VenueFoundCallback callback) { // Some slow networking } } public class LocalVenueRetriever implements VenueRetriever { public void findClosestVenue(VenueFoundCallback callback) { // DB look-up / caching layer, perhaps? } }
  • 31. Activity @iordanis_g public class ResultActivity extends Activity implements ResultView { private final VenueRetriever venueRetriever; private ResultPresenter resultPresenter; public ResultActivity() { venueRetriever = venueRetriever(); } public void onCreate(Bundle savedInstanceState) { // TODO: Setup layouts & views Result result = resultToDisplay(); resultPresenter = new ResultPresenter(this, venueRetriever, result); } public void onStart() { resultPresenter.startPresenting(); } }
  • 32. Presenter @iordanis_g public class ResultPresenter { public ResultPresenter(ResultView resultView, VenueRetriever venueRetriever, Result result) { this.resultView = resultView; this.venueRetriever = venueRetriever; this.result = result; } public void startPresenting() { resultView.showResult(result); venueRetriever.findClosestVenue(new VenueFoundCallback() { public void venueFound(Venue venue) { resultView.showCheckInPrompt(venue); } }); } }
  • 33. View @iordanis_g public interface ResultView { void showResult(Result track); void showCheckInPrompt(Venue venue); }
  • 34. Activity @iordanis_g public class ResultActivity extends Activity implements ResultView { public void showResult(Result result) { //TODO show the result screen & bind result data } public void showCheckInPrompt(Venue venue) { //TODO bind the venue with check-in prompt view } }
  • 35. Unit tests technologies @iordanis_g • JUnit 4 • Robolectric java.lang.RuntimeException: Stub! • Hamcrest • JMock
  • 36. Test execution @iordanis_g
  • 37. Continuous Integration @iordanis_g
  • 38. Speed (Hint: slow) @iordanis_g
  • 39. Usual execution @iordanis_g Test Suite
  • 40. Spoon @iordanis_g http://square.github.io/spoon/
  • 41. Fork @iordanis_g Test Suite
  • 42. Fork @iordanis_g • Inspired by Spoon, but faster • Infinitely scalable • Current setup 1 test / 2 secs • Pooled execution
  • 43. Flakiness monitor @iordanis_g
  • 44. ADB Remote @iordanis_g https://github.com/sleekweasel/CgiAdbRemote
  • 45. If all else fails... @iordanis_g
  • 46. If all else fails... @iordanis_g
  • 47. If all else fails... @iordanis_g
  • 48. Summary @iordanis_g • Testing is easier than you may think • Practice, practice, practice • Toolset is limited • Ship it!
  • 49. @iordanis_g Questions? Hiring...