Your SlideShare is downloading. ×
0
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Device fragmentation vs clean code
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Device fragmentation vs clean code

895

Published on

Trying to implement the same functionality on Android on different devices, OS versions, manufacturers etc. can be more eventful than it should. …

Trying to implement the same functionality on Android on different devices, OS versions, manufacturers etc. can be more eventful than it should.

This presentation is a guide about how you can achieve your task at hand without compromising code quality and readability. Specifically, I demonstrate how to use Dependency Injection, the MVP pattern and other techniques to your favour, for graceful handling and degrading experience at production code and automated tests.

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
895
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
2
Comments
0
Likes
2
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. Device Fragmentation Clean Code Iordanis “Jordan” Giannakakis @iordanis_g #fragVsCode
  2. Introduction • • • • Iordanis “Jordan” Giannakakis Android Team Lead – Shazam @iordanis_g #fragVsCode @iordanis_g #fragVsCode
  3. How Shazam works @iordanis_g #fragVsCode
  4. Bad vs. good code @iordanis_g #fragVsCode
  5. How is fragmentation related to clean code? @iordanis_g #fragVsCode
  6. Is fragmentation really a problem? android.support @iordanis_g #fragVsCode
  7. Is fragmentation really a problem? @iordanis_g #fragVsCode
  8. Is clean code really a concern? @iordanis_g #fragVsCode
  9. Is clean code really a concern? A couple of months later... @iordanis_g #fragVsCode
  10. SharedPreferences.Editor • commit() – slow • apply() – fast @iordanis_g #fragVsCode
  11. API example – MainActivity protected void onResume() { super.onResume(); SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences.Editor editor = sharedPreferences.edit(); prefEditor.putBoolean("has_launched_before", true); // Will only be available for versions after Froyo if(VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) { editor.apply(); } else { editor.commit(); } } @iordanis_g #fragVsCode
  12. Fixed it! @iordanis_g #fragVsCode
  13. What are the issues? protected void onResume() { super.onResume(); SharedPreferences sharedPreferences = Glue PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences.Editor editor = sharedPreferences.edit(); Business prefEditor.putBoolean("has_launched_before", true); Logic // Will only be available for versions after Froyo if(VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) { editor.apply(); } else { editor.commit(); } Glue } @iordanis_g #fragVsCode
  14. How to unit test? Good luck! @iordanis_g #fragVsCode
  15. Dependency Injection @iordanis_g #fragVsCode
  16. Dependency Injection Framework @iordanis_g #fragVsCode
  17. New MainActivity @Override public void onResume() { super.onResume(); editor.putBoolean("has_launched_before", true); preferencesSaver.save(editor); } @iordanis_g #fragVsCode
  18. Before & After protected void onResume() { super.onResume(); SharedPreferences sharedPreferences = PreferenceManager .getDefaultSharedPreferences(this); SharedPreferences.Editor editor = sharedPreferences.edit(); prefEditor.putBoolean( "has_launched_before", true); // Will only be available for versions after Froyo if(VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) { editor.apply(); } else { editor.commit(); } } public void onResume() { super.onResume(); editor.putBoolean( "has_launched_before", true); preferencesSaver.save(editor); } @iordanis_g #fragVsCode
  19. New MainActivity – Constructors // Constructor the system will call to instantiate this activity public MainActivity() { this(sharedPreferencesEditor(), preferencesSaver()); } // Constructor that can be used in production and test code public MainActivity(Editor editor, PreferencesSaver preferencesSaver) { this.editor = editor; this.preferencesSaver = preferencesSaver; } @iordanis_g #fragVsCode
  20. Module classes public class SharedPreferencesEditorModule { public static SharedPreferences.Editor sharedPreferencesEditor() { Context context = getApplication().getApplicationContext(); SharedPreferences preferences = getDefaultSharedPreferences(context); Editor editor = preferences.edit(); return editor; } } public class PreferencesSaverModule { public static PreferencesSaver preferencesSaver() { if(VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD) { return new ApplyPreferencesSaver(); } return new CommitPreferencesSaver(); } } @iordanis_g #fragVsCode
  21. Application public class MyCoolApplication extends Application { private static MyCoolApplication application; @Override public void onCreate() { application = this; } public static MyCoolApplication getApplication() { return application; } } @iordanis_g #fragVsCode
  22. How to unit test? @Mock Editor editor; @Mock PreferencesSaver saver; @Test public void canSaveLaunchFlag() { mockery.checking(new Expectations() {{ atLeast(1).of(editor).putBoolean("has_launched_before", true); oneOf(saver).save(editor); }}); MainActivity activity = new MainActivity(editor, saver); activity.onResume(); } @iordanis_g #fragVsCode
  23. Capabilities example – Google+ @iordanis_g #fragVsCode
  24. Capabilities example public void onCreate(Bundle savedInstanceState) { // Set layout View googlePlus = findViewById(R.id.google_plus); try { getPackageManager().getApplicationInfo("com.android.vending", 0); googlePlus.setVisibility(VISIBLE); } catch (PackageManager.NameNotFoundException e) { googlePlus.setVisibility(GONE); } } @iordanis_g #fragVsCode
  25. MVP pattern @iordanis_g #fragVsCode
  26. The Model public class GooglePlayAvailability { private PackageManager packageManager; public GooglePlayAvailability(PackageManager packageManager) { this.packageManager = packageManager; } public boolean googlePlayIsAvailable() { try { packageManager.getApplicationInfo("com.android.vending", 0); return true; } catch (PackageManager.NameNotFoundException e) { return false; } } } @iordanis_g #fragVsCode
  27. The View public interface GooglePlusView { public void showGooglePlus(); public void hideGooglePlus(); } @iordanis_g #fragVsCode
  28. Activity as View public class MainActivity extends Activity implements GooglePlusView { public void onCreate(Bundle savedInstanceState) { //Set layout... googlePlus = findViewById(R.id.google_plus); //Injected googlePlusPresenter googlePlusPresenter.setView(this); googlePlusPresenter.present(); } public void showGooglePlus() { googlePlus.setVisibility(VISIBLE); } public void hideGooglePlus() { googlePlus.setVisibility(GONE); } } @iordanis_g #fragVsCode
  29. The Presenter public class GooglePlusPresenter { private GooglePlayAvailability googlePlayAvailability; private GooglePlusView googlePlusView; public GooglePlusPresenter(GooglePlayAvailability availability) { googlePlayAvailability = availability; } public void present() { if (googlePlayAvailability.googlePlayIsAvailable()) { googlePlusView.showGooglePlus(); } else { googlePlusView.hideGooglePlus(); } } } @iordanis_g #fragVsCode
  30. How to unit test? @Mock GooglePlayAvailability googlePlayAvailability; @Mock GooglePlusView googlePlus; private GooglePlusPresenter presenter; @Test public void hidesGooglePlusIfNotAvailable() { mockery.checking(new Expectations() {{ allowing(googlePlayAvailability).googlePlayIsAvailable(); will(returnValue(false)); oneOf(googlePlus).hideGooglePlus(); }}); presenter.present(); } @iordanis_g #fragVsCode
  31. Device size diversity @iordanis_g #fragVsCode
  32. Device size diversity @iordanis_g #fragVsCode
  33. How about Acceptance Tests? @iordanis_g #fragVsCode
  34. How about Acceptance Tests? public class ShazamTest extends ActivityInstrumentationTestCase2<ActivityUnderTest> { private static final int TIMEOUT = 5000; private Solo solo; protected void setUp() { solo = new Solo(getInstrumentation()); } } @iordanis_g #fragVsCode
  35. How about Acceptance Tests? public void testCanShazamOnPhone() { // Action // User hits the big Shazam button View shazamButton = solo.getView(R.id.big_button); solo.clickOnView(shazamButton); // Assertions // Track details are showing on full screen assertThat(solo.waitForCondition(titleShowsOnFullScreen(), TIMEOUT), is(true)); } @iordanis_g #fragVsCode
  36. How about Acceptance Tests? public void testShazamingOnTablet() { // Action // Hit small Shazam button and wait for animation to finish final View shazamButton = solo.getView(R.id.small_button); solo.clickOnView(shazamButton); waitForAnimationToFinish(); // Assertions // Track details are showing on side-panel assertThat(solo.waitForCondition(titleShowsOnSidePanel(), TIMEOUT), is(true)); } @iordanis_g #fragVsCode
  37. Fixed it! @iordanis_g #fragVsCode
  38. Test frameworks GWEN https://github.com/shazam/gwen @iordanis_g #fragVsCode
  39. New Acceptance Test protected void setUp() { solo = new Solo(getInstrumentation()); user = new User(solo); } public void testCanShowTrackAfterShazaming() { when(user).shazams(); then(user).seesDetailsForTrack(); } @iordanis_g #fragVsCode
  40. User class public class User implements Actor, Asserter { private final Solo solo; public void shazams() { Action<Solo, Void> action; if (isTablet()) { action = new ShazamTabletButtonAction(); } else { action = new ShazamPhoneButtonAction(); } action.actOn(solo); } public void seesDetailsForTrack() { Assertion<Solo> assertion; if (isTablet()) { assertion = new TabletDetailsAssertion(); } else { assertion = new PhoneDetailsAssertion(); } assertion.assertWith(solo); } } @iordanis_g #fragVsCode
  41. Actions public class ShazamPhoneButtonAction implements Action<Solo, Void> { public void actOn(Solo solo) { View bigButton = solo.getView(R.id.big_button); solo.clickOnView(bigButton); } } public class ShazamTabletButtonAction implements Action<Solo, Void> { public void actOn(Solo solo) { View smallButton = solo.getView(R.id.small_button); solo.clickOnView(smallButton); } } @iordanis_g #fragVsCode
  42. Assertions public class PhoneDetailsAssertion implements Assertion<Solo>{ public void assertWith(Solo solo) { assertThat(solo.waitForCondition(titleShowsOnFullScreen(), TIMEOUT), is(true)); } } public class TabletDetailsAssertion implements Assertion<Solo> { public void assertWith(Solo solo) { waitForAnimationToFinish(); assertThat(solo.waitForCondition(titleShowsOnSidePanel(), TIMEOUT), is(true)); } } @iordanis_g #fragVsCode
  43. Fixed it! @iordanis_g #fragVsCode
  44. Hiring... Questions? @iordanis_g #fragVsCode github.com/iordanis/androidCleanCode

×