Tips and Tricks for Productive Mobile Development. Given in Droidcon Egypt on October 21st, 2022.
Ahmed El-Helw October 21, 2022Productive Mobile DevelopmentTips and Tricks for Productive Mobile Development
View Slide
Source
Factors affecting SpeedThings to Consider• Distractions
Factors affecting SpeedThings to Consider• Distractions• Communication Problems
Factors affecting SpeedThings to Consider• Distractions• Communication Problems• Conflicting Priorities
Factors affecting SpeedThings to Consider• Distractions• Communication Problems• Conflicting Priorities• Technical Debt
Factors affecting SpeedThings to Consider• Distractions• Communication Problems• Conflicting Priorities• Technical Debt• Production Fires
Factors affecting SpeedThings to Consider• Distractions• Communication Problems• Conflicting Priorities• Technical Debt• Production Fires• Hardware
Process BottlenecksMobile Bottlenecks• Company release process• Application store review process• Application store rejections• Adoptions take time
Experiments and Toggles
Tim Campos“Data wins Arguments”
Customer BehaviorUnderstanding and Monitoring Customer Behavior• Dashboards• critical business statistics• conversion funnels• Slice by application version• Alerts
Dealing with ProblemsHow to React to Problems• Ignore it for now• Hot Fix in Production• Release takes time• Adoption takes time• Risky
What if we just turn it off?
Other ConsiderationsThings to Keep in Mind• Be mindful about:• The effect of experiments on each other• The effect of featureflags on each other• Dead Experiments increase Technical Debt• Can tooling help here?
Data
DataSome odds and ends about Data• Building trust with Customers• Compliance• App Stores• Governments
Policy Changes are often aSurprise
MetaFilter via Forbes Article“If you're not paying for it, you become theproduct”
As a company grows, so toodoes the value of its data
Structuring Code
ModularizationStructuring Code• Have a set of rules and guidelines• Split APIs and Implementation
ModularizationStructuring Code/ /in profile-api moduleinterface Profile {fun isLoggedIn(): Booleanfun currentCustomer(): Customer?fun editCustomerIntent(context: Context): Intent?}
ModularizationStructuring Code/ /in profile moduleclass ProfileImpl constructor(private val profileRepository: ProfileRepository) : Profile {override fun isLoggedIn(): Boolean = currentCustomer()!=nulloverride fun currentCustomer(): Customer? {return profileRepository.provideCustomer()}override fun editCustomerIntent(context: Context): Intent {return Intent(context, EditProfileActivity::class.java)}}
ModularizationStructuring Code/ /in profile-noop moduleclass ProfileNoop : Profile {override fun isLoggedIn(): Boolean = trueoverride fun currentCustomer(): Customer =Customer(123L, "Test")override fun editCustomerIntent(context: Context) = null}
ModularizationStructuring Codefun provideProfile(): Profile {return if (isDebug) {ProfileNoop()} else {ProfileImpl(ProfileRepository())}}
Benefits of ModularizationStructuring Code• Better isolation of Features• Easier sharing• Easier and faster testing• Ability to stub implementations• Standalone apps
Sharing Code Across Platforms
How do we Save Time?
OptionsSharing Code Between Platforms• Frameworks that handle Everything• Do it yourself Tooling
React Native
5 Part SeriesReact Native at Airbnb
Flutter
Frameworks that Handle EverythingSharing Code Between Platforms• Pros• Potentially easier to hire for• Write once, use everywhere• Faster development (hot reload, etc)• Potential for hot loading code
Frameworks that Handle EverythingSharing Code Between Platforms• Cons• Need to explicitly build separate UI for iOS and Android• Doesn’t “feel” native irrespective• New platform features are difficult to adopt - need to wait• Overhead on binary size• Rejections Likely
C/C++
C/C++Sharing Code Between Platforms• Pros• High performance• Easier to obfuscate code
C/C++Sharing Code Between Platforms• Cons• Difficult• Still have to handle differences between platforms• Custom development environment
Dropbox Blog PostThe (not so) hidden cost of sharing codebetween iOS and Android
Kotlin Multiplatform
Kotlin MultiplatformSharing Code Between Platforms• Pros• Completely native• Easy to learn for engineers writing Swift• Lots of third party libraries• Backed by JetBrains and Google• Supports a plethora of platforms
Kotlin MultiplatformSharing Code Between Platforms• Cons• iOS inter-op with Objective-C instead of Swift• Convincing iOS Engineers is Difficult• Tooling• Still in the process of maturing
Alternatives
AlternativesSharing Between Platforms• Code generation• Annotation processors• Compiler plugins, Gradle plugins• Templating code generators (Stencil, …)
Sharing CodeGenerating Codecomponent:name: Carfields:make: stringmodel: stringvin: stringvendor: string
Sharing CodeGenerating Codedata class Car(val make : String,val model : String,val vin : String,val vendor : String,)
Sharing CodeGenerating Codestruct Car {let make: Stringlet model: Stringlet vin: Stringlet vendor: String}
Sharing CodeGenerating Codedata class {{ component.name }}({% for key, value in component.fields %}val {{ key | lowerFirstLetter }} : {{ value | upperFirstLetter }},{% endfor %})
Sharing CodeGenerating Codestruct {{ component.name }} {{% for key, value in component.fields %}let {{ key | lowerFirstLetter }}: {{ value | upperFirstLetter }}{% endfor %}}
What to Share
Things to ShareSharing Between Platforms• Analytics• Business Logic• Vocabulary• Architecture• Design System• Versioning• Release Process
CI/CD
Catching Mistakes Early SavesTime and Money
First Lines of DefenseCatching Issues Early• The build process itself• Automated checkers• Lint• Code styling enforcers• Code smell detection• Coverage• Code Review helps catch issues early
TestsCatching Issues Early• Tests• Unit Tests• Integration Tests• On-Device Integration Tests (“UI Tests”)• Screenshot Tests• Maestro Tests
Expose Hidden ChangesCatching Issues Early• Transitive Dependencies
Dependency-Diff-TldrExposing Hidden ChangesUpgraded Dependencies com.squareup.moshi:moshi-adapters:1.14.0, (changed from 1.13.0) org.jetbrains.kotlin:kotlin-stdlib:1.7.20, (changed from 1.7.10) org.jetbrains.kotlin:kotlin-stdlib-common:1.7.20, (changed from 1.7.10) org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.20, (changed from 1.7.10) org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.20, (changed from 1.7.10)
Expose Hidden ChangesCatching Issues Early• Transitive Dependencies• Binary Size
DiffuseExposing Hidden Changes│ compressed │ uncompressed├───────────┬───────────┬──────────┼───────────┬───────────┬──────────APK │ old │ new │ diff │ old │ new │ diff──────────┼───────────┼───────────┼──────────┼───────────┼───────────┼──────────dex │ 11.6 MiB │ 11.6 MiB │ -107 B │ 29.4 MiB │ 29.4 MiB │ -336 Barsc │ 1.8 MiB │ 1.8 MiB │ -992 B │ 1.8 MiB │ 1.8 MiB │ -988 Bmanifest │ 5.6 KiB │ 5.6 KiB │ +1 B │ 27.6 KiB │ 27.6 KiB │ 0 Bres │ 1.1 MiB │ 1.1 MiB │ -3 KiB │ 1.3 MiB │ 1.3 MiB │ -4.8 KiBasset │ 404.2 KiB │ 404.2 KiB │ 0 B │ 678.6 KiB │ 678.6 KiB │ 0 Bother │ 173.6 KiB │ 173.1 KiB │ -550 B │ 336.9 KiB │ 335.7 KiB │ -1.3 KiB──────────┼───────────┼───────────┼──────────┼───────────┼───────────┼──────────total │ 15.1 MiB │ 15.1 MiB │ -4.6 KiB │ 33.5 MiB │ 33.5 MiB │ -7.4 KiB
Expose Hidden ChangesCatching Issues Early• Transitive Dependencies• Binary Size• Binary compatibility breaking changes
Binary Compatibility ValidatorExposing Hidden ChangesFAILURE: Build failed with an exception.* What went wrong:Execution failed for task ':miniapp:apiCheck'.> API check failed for project miniapp.--- /bitrise/src/miniapp/api/miniapp.api+++ /bitrise/src/miniapp/build/api/miniapp.api@@ -16,6 +16,7 @@public abstract interface class com/careem/superapp/lib/miniapp/IntegrationDependencies {public abstract fun provideEventBus ()Lcom/careem/superapp/lib/eventbus/EventBus;+ public abstract fun provideLocationPickerSdk ()Lcom/careem/globalexp/locations/api/LocationPickerSdk;}You can run :miniapp:apiDump task to overwrite API declarations
Expose Hidden ChangesCatching Issues Early• Transitive Dependencies• Binary Size• Binary compatibility breaking changes• Permissions
Expose Hidden ChangesTooling• diffuse• dependency-diff-tldr / dependency-guard• metalava-gradle / binary-compatibility-validator
ReleasesCatching Issues Early• Beta program• Staged rollouts to production• Release early, release often• Release should be a train, not a bus
Dashboards and DataCatching Issues Early• Do not hide crashes• Handled exceptions and breadcrumbs are useful• Developer and performance metrics• Development Tooling• Chucker• LeakCanary
Engineering Culture
Engineers are HumansEngineering Cultures• All humans make mistakes• Blame is bad• Blame is the enemy of ownership
When Issues AriseEngineering Cultures• How could this have been prevented?• Why was this not caught earlier?• Combinefixes with verification tests.• Post mortem
Keep Learning and Improving
Focus on Impact
Android Mid Level Roles Android Senior Level RolesWe are hiring! 🤖
Thank You