SlideShare une entreprise Scribd logo
1  sur  44
Device Fragmentation

Clean Code
Iordanis “Jordan” Giannakakis
@iordanis_g
#fragVsCode
Introduction
•
•
•
•

Iordanis “Jordan” Giannakakis
Android Team Lead – Shazam
@iordanis_g
#fragVsCode

@iordanis_g #fragVsCode
How Shazam works

@iordanis_g #fragVsCode
Bad vs. good code

@iordanis_g #fragVsCode
How is fragmentation related to
clean code?

@iordanis_g #fragVsCode
Is fragmentation really a problem?

android.support
@iordanis_g #fragVsCode
Is fragmentation really a problem?

@iordanis_g #fragVsCode
Is clean code really a concern?

@iordanis_g #fragVsCode
Is clean code really a concern?

A couple of months later...
@iordanis_g #fragVsCode
SharedPreferences.Editor

• commit() – slow
• apply() – fast

@iordanis_g #fragVsCode
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
Fixed it!

@iordanis_g #fragVsCode
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
How to unit test?

Good luck!

@iordanis_g #fragVsCode
Dependency Injection

@iordanis_g #fragVsCode
Dependency Injection Framework

@iordanis_g #fragVsCode
New MainActivity

@Override
public void onResume() {
super.onResume();

editor.putBoolean("has_launched_before", true);
preferencesSaver.save(editor);
}

@iordanis_g #fragVsCode
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
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
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
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
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
Capabilities example – Google+

@iordanis_g #fragVsCode
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
MVP pattern

@iordanis_g #fragVsCode
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
The View

public interface GooglePlusView {
public void showGooglePlus();

public void hideGooglePlus();
}

@iordanis_g #fragVsCode
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
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
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
Device size diversity

@iordanis_g #fragVsCode
Device size diversity

@iordanis_g #fragVsCode
How about Acceptance Tests?

@iordanis_g #fragVsCode
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
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
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
Fixed it!

@iordanis_g #fragVsCode
Test frameworks

GWEN

https://github.com/shazam/gwen

@iordanis_g #fragVsCode
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
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
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
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
Fixed it!

@iordanis_g #fragVsCode
Hiring...

Questions?
@iordanis_g
#fragVsCode
github.com/iordanis/androidCleanCode

Contenu connexe

Tendances

Testable Android Apps using data binding and MVVM
Testable Android Apps using data binding and MVVMTestable Android Apps using data binding and MVVM
Testable Android Apps using data binding and MVVMFabio Collini
 
Android UI Testing with Espresso
Android UI Testing with EspressoAndroid UI Testing with Espresso
Android UI Testing with EspressoGary Cheng
 
Android testing
Android testingAndroid testing
Android testingBitbar
 
A guide to Android automated testing
A guide to Android automated testingA guide to Android automated testing
A guide to Android automated testingjotaemepereira
 
Android testing
Android testingAndroid testing
Android testingJinaTm
 

Tendances (7)

Testing on Android
Testing on AndroidTesting on Android
Testing on Android
 
Testable Android Apps using data binding and MVVM
Testable Android Apps using data binding and MVVMTestable Android Apps using data binding and MVVM
Testable Android Apps using data binding and MVVM
 
Android UI Testing with Espresso
Android UI Testing with EspressoAndroid UI Testing with Espresso
Android UI Testing with Espresso
 
Android testing
Android testingAndroid testing
Android testing
 
Clean Test
Clean TestClean Test
Clean Test
 
A guide to Android automated testing
A guide to Android automated testingA guide to Android automated testing
A guide to Android automated testing
 
Android testing
Android testingAndroid testing
Android testing
 

Similaire à Device fragmentation vs clean code

Keeping 100m+ users happy: How we test Shazam on Android
Keeping 100m+ users happy: How we test Shazam on AndroidKeeping 100m+ users happy: How we test Shazam on Android
Keeping 100m+ users happy: How we test Shazam on AndroidIordanis (Jordan) Giannakakis
 
How to build rock solid apps and keep 100m+ users happy
How to build rock solid apps and keep 100m+ users happyHow to build rock solid apps and keep 100m+ users happy
How to build rock solid apps and keep 100m+ users happyIordanis (Jordan) Giannakakis
 
Android the Agile way
Android the Agile wayAndroid the Agile way
Android the Agile wayAshwin Raghav
 
Android Wear 2.0 - New Level of Freedom for Your Action - GDG CEE Leads Summi...
Android Wear 2.0 - New Level of Freedom for Your Action - GDG CEE Leads Summi...Android Wear 2.0 - New Level of Freedom for Your Action - GDG CEE Leads Summi...
Android Wear 2.0 - New Level of Freedom for Your Action - GDG CEE Leads Summi...Constantine Mars
 
How to code to code less
How to code to code lessHow to code to code less
How to code to code lessAnton Novikau
 
Code to DI For - Dependency Injection for Modern Applications
Code to DI For - Dependency Injection for Modern ApplicationsCode to DI For - Dependency Injection for Modern Applications
Code to DI For - Dependency Injection for Modern ApplicationsCaleb Jenkins
 
Design Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesDesign Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesMichael Galpin
 
From Idea to App (or “How we roll at Small Town Heroes”)
From Idea to App (or “How we roll at Small Town Heroes”)From Idea to App (or “How we roll at Small Town Heroes”)
From Idea to App (or “How we roll at Small Town Heroes”)Bramus Van Damme
 
STYLISH FLOOR
STYLISH FLOORSTYLISH FLOOR
STYLISH FLOORABU HASAN
 
Hacking the Codename One Source Code - Part IV - Transcript.pdf
Hacking the Codename One Source Code - Part IV - Transcript.pdfHacking the Codename One Source Code - Part IV - Transcript.pdf
Hacking the Codename One Source Code - Part IV - Transcript.pdfShaiAlmog1
 
Architecture components, Константин Марс, TeamLead, Senior Developer, DataArt
Architecture components, Константин Марс, TeamLead, Senior Developer, DataArtArchitecture components, Константин Марс, TeamLead, Senior Developer, DataArt
Architecture components, Константин Марс, TeamLead, Senior Developer, DataArtAlina Vilk
 
Building a Native Camera Access Library - Part II - Transcript.pdf
Building a Native Camera Access Library - Part II - Transcript.pdfBuilding a Native Camera Access Library - Part II - Transcript.pdf
Building a Native Camera Access Library - Part II - Transcript.pdfShaiAlmog1
 
Building native Android applications with Mirah and Pindah
Building native Android applications with Mirah and PindahBuilding native Android applications with Mirah and Pindah
Building native Android applications with Mirah and PindahNick Plante
 
GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...
GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...
GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...Bruno Salvatore Belluccia
 
Alexey Buzdin "Maslow's Pyramid of Android Testing"
Alexey Buzdin "Maslow's Pyramid of Android Testing"Alexey Buzdin "Maslow's Pyramid of Android Testing"
Alexey Buzdin "Maslow's Pyramid of Android Testing"IT Event
 
Customizing Xamarin.Forms UI
Customizing Xamarin.Forms UICustomizing Xamarin.Forms UI
Customizing Xamarin.Forms UIXamarin
 
Refactoring Wunderlist. UA Mobile 2016.
Refactoring Wunderlist. UA Mobile 2016.Refactoring Wunderlist. UA Mobile 2016.
Refactoring Wunderlist. UA Mobile 2016.UA Mobile
 
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)Alina Vilk
 

Similaire à Device fragmentation vs clean code (20)

Keeping 100m+ users happy: How we test Shazam on Android
Keeping 100m+ users happy: How we test Shazam on AndroidKeeping 100m+ users happy: How we test Shazam on Android
Keeping 100m+ users happy: How we test Shazam on Android
 
How to build rock solid apps and keep 100m+ users happy
How to build rock solid apps and keep 100m+ users happyHow to build rock solid apps and keep 100m+ users happy
How to build rock solid apps and keep 100m+ users happy
 
Android the Agile way
Android the Agile wayAndroid the Agile way
Android the Agile way
 
Android Wear 2.0 - New Level of Freedom for Your Action - GDG CEE Leads Summi...
Android Wear 2.0 - New Level of Freedom for Your Action - GDG CEE Leads Summi...Android Wear 2.0 - New Level of Freedom for Your Action - GDG CEE Leads Summi...
Android Wear 2.0 - New Level of Freedom for Your Action - GDG CEE Leads Summi...
 
How to code to code less
How to code to code lessHow to code to code less
How to code to code less
 
Ruby conf2012
Ruby conf2012Ruby conf2012
Ruby conf2012
 
Code to DI For - Dependency Injection for Modern Applications
Code to DI For - Dependency Injection for Modern ApplicationsCode to DI For - Dependency Injection for Modern Applications
Code to DI For - Dependency Injection for Modern Applications
 
Design Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesDesign Patterns for Tablets and Smartphones
Design Patterns for Tablets and Smartphones
 
From Idea to App (or “How we roll at Small Town Heroes”)
From Idea to App (or “How we roll at Small Town Heroes”)From Idea to App (or “How we roll at Small Town Heroes”)
From Idea to App (or “How we roll at Small Town Heroes”)
 
STYLISH FLOOR
STYLISH FLOORSTYLISH FLOOR
STYLISH FLOOR
 
Hacking the Codename One Source Code - Part IV - Transcript.pdf
Hacking the Codename One Source Code - Part IV - Transcript.pdfHacking the Codename One Source Code - Part IV - Transcript.pdf
Hacking the Codename One Source Code - Part IV - Transcript.pdf
 
Mini curso Android
Mini curso AndroidMini curso Android
Mini curso Android
 
Architecture components, Константин Марс, TeamLead, Senior Developer, DataArt
Architecture components, Константин Марс, TeamLead, Senior Developer, DataArtArchitecture components, Константин Марс, TeamLead, Senior Developer, DataArt
Architecture components, Константин Марс, TeamLead, Senior Developer, DataArt
 
Building a Native Camera Access Library - Part II - Transcript.pdf
Building a Native Camera Access Library - Part II - Transcript.pdfBuilding a Native Camera Access Library - Part II - Transcript.pdf
Building a Native Camera Access Library - Part II - Transcript.pdf
 
Building native Android applications with Mirah and Pindah
Building native Android applications with Mirah and PindahBuilding native Android applications with Mirah and Pindah
Building native Android applications with Mirah and Pindah
 
GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...
GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...
GDG Mediterranean Dev Fest Code lab #DevFestMed15 da android ad android wear ...
 
Alexey Buzdin "Maslow's Pyramid of Android Testing"
Alexey Buzdin "Maslow's Pyramid of Android Testing"Alexey Buzdin "Maslow's Pyramid of Android Testing"
Alexey Buzdin "Maslow's Pyramid of Android Testing"
 
Customizing Xamarin.Forms UI
Customizing Xamarin.Forms UICustomizing Xamarin.Forms UI
Customizing Xamarin.Forms UI
 
Refactoring Wunderlist. UA Mobile 2016.
Refactoring Wunderlist. UA Mobile 2016.Refactoring Wunderlist. UA Mobile 2016.
Refactoring Wunderlist. UA Mobile 2016.
 
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
Встреча Google Post IO ( Владимир Иванов, Катерина Заворотченко и Сергей Комлач)
 

Dernier

MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...apidays
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Principled Technologies
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingEdi Saputra
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vázquez
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 

Dernier (20)

MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 

Device fragmentation vs clean code

  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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