Slide 1

Slide 1 text

Bohemian Wrapsody Dmytro Danylyk Atlassian

Slide 2

Slide 2 text

“Wrapping third-party APIs is a best practice.” Robert C. Martin

Slide 3

Slide 3 text

Benefits - define the API of the wrapper - more flexible to changes - ease updates during breaking changes - experiment with new technologies - share common logic - predefined configuration - additional functionality - loosely coupled system - easier to test - reuse modules across apps

Slide 4

Slide 4 text

Glide.with(context) .load("https://...") .apply(RequestOptions() .placeholder(R.drawable.placeholder) .transform(CircleCrop())) library api

Slide 5

Slide 5 text

Glide.with(context) .load("https://...") .apply(RequestOptions() .placeholder(R.drawable.placeholder) .transform(CircleCrop())) library api ImageLoader(context).load( model = ImageModel.URL("https://..."), placeholder = Placeholder.FromResource(R.drawable.placeholder), transformation = Transformation.Circular ) Your api

Slide 6

Slide 6 text

Benefits - define the API of the wrapper - more flexible to changes - ease updates during breaking changes - experiment with new technologies - share common logic - predefined configuration - additional functionality - loosely coupled system - easier to test - reuse modules across apps

Slide 7

Slide 7 text

main-module image-loader-module glide-library

Slide 8

Slide 8 text

main-module image-loader-module glide-library Glide 4.9.0 Breaking changes Glide 4.8.0 Breaking changes Glide 4.7.0 Breaking changes Glide 4.6.0 Breaking changes Glide 4.5.0 Breaking changes Glide 4.4.0 Breaking changes Glide 4.3.0 Breaking changes

Slide 9

Slide 9 text

main-module image-loader-module glide-library Glide 4.9.0 Breaking changes Glide 4.8.0 Breaking changes Glide 4.7.0 Breaking changes Glide 4.6.0 Breaking changes Glide 4.5.0 Breaking changes Glide 4.4.0 Breaking changes Glide 4.3.0 Breaking changes Resolve here

Slide 10

Slide 10 text

Benefits - define the API of the wrapper - more flexible to changes - ease updates during breaking changes - experiment with new technologies - share common logic - predefined configuration - additional functionality - loosely coupled system - easier to test - reuse modules across apps

Slide 11

Slide 11 text

main-module image-loader-module uil-library 2014

Slide 12

Slide 12 text

main-module image-loader-module uil-library main-module image-loader-module glide-library 2014 2019

Slide 13

Slide 13 text

Benefits - define the API of the wrapper - more flexible to changes - ease updates during breaking changes - experiment with new technologies - share common logic - predefined configuration - additional functionality - loosely coupled system - easier to test - reuse modules across apps

Slide 14

Slide 14 text

ImageLoader(context).load( model = ImageModel.URL("https://..."), placeholder = Placeholder.Default, transformation = Transformation.Circular ) Default placeholder

Slide 15

Slide 15 text

Benefits - define the API of the wrapper - more flexible to changes - ease updates during breaking changes - experiment with new technologies - share common logic - predefined configuration - additional functionality - loosely coupled system - easier to test - reuse modules across apps

Slide 16

Slide 16 text

main-module image-loader-module glide-library * SVG support * authentication * transformations

Slide 17

Slide 17 text

Benefits - define the API of the wrapper - more flexible to changes - ease updates during breaking changes - experiment with new technologies - share common logic - predefined configuration - additional functionality - loosely coupled system - easier to test - reuse modules across apps

Slide 18

Slide 18 text

fun test() { val repository = UserRepository( analytics = mock(MyAnalytics::class) ) // test code omitted }

Slide 19

Slide 19 text

Benefits - define the API of the wrapper - more flexible to changes - ease updates during breaking changes - experiment with new technologies - share common logic - predefined configuration - additional functionality - loosely coupled system - easier to test - reuse modules across apps

Slide 20

Slide 20 text

jira-module confluence-module image-loader-module glide-library project 1 project 2

Slide 21

Slide 21 text

When? - if you have multiple projects - if you work on a long-term project - if you use library as a temporary solution

Slide 22

Slide 22 text

When? - if you have multiple projects - if you work on a long-term project - if you use library as a temporary solution

Slide 23

Slide 23 text

When? - if you have multiple projects - if you work on a long-term project - if you use library as a temporary solution

Slide 24

Slide 24 text

When? now later effort

Slide 25

Slide 25 text

How? - class - package - module - speeds up builds (cache + parallel) - separate dependencies - prevents from accidental usage of internal code/resources

Slide 26

Slide 26 text

How? - class - package - module - speeds up builds (cache + parallel) - separate dependencies - prevents from accidental usage of internal code/resources Prefer this

Slide 27

Slide 27 text

Tips - don’t leave library references in wrapper API - make wrapper API as abstract as possible - wrap API which you use, incrementally - put proxy on UI libraries - document things which cannot be wrapped

Slide 28

Slide 28 text

ImageLoader(context).load( model = GlideURL(url), placeholder = Placeholder.Default, transformation = Transformation.Circular ) Glide reference

Slide 29

Slide 29 text

Tips - don’t leave library references in wrapper API - make wrapper API as abstract as possible - wrap API which you use, incrementally - put proxy on UI libraries - document things which cannot be wrapped

Slide 30

Slide 30 text

val observable: Observable = AndroidPermissions() .observe(permission = Permission.LOCATION) val publisher: Publisher = AndroidPermissions() .observe(permission = Permission.LOCATION)

Slide 31

Slide 31 text

val observable: Observable = AndroidPermissions() .observe(permission = Permission.LOCATION) val publisher: Publisher = AndroidPermissions() .observe(permission = Permission.LOCATION) io.reactivex

Slide 32

Slide 32 text

val observable: Observable = AndroidPermissions() .observe(permission = Permission.LOCATION) val publisher: Publisher = AndroidPermissions() .observe(permission = Permission.LOCATION) io.reactivex org.reactivestreams

Slide 33

Slide 33 text

Tips - don’t leave library references in wrapper API - make wrapper API as abstract as possible - wrap API which you use, incrementally - put proxy on UI libraries - document things which cannot be wrapped

Slide 34

Slide 34 text

Tips - don’t leave library references in wrapper API - make wrapper API as abstract as possible - wrap API which you use, incrementally - put proxy on UI components - document things which cannot be wrapped

Slide 35

Slide 35 text

val indicatorView = findViewById(R.id.indicator) indicatorView.showIndicator(index = 1) val controller = IndicatorController(indicatorView) controller.showIndicator(index = 1) Direct usage Proxy

Slide 36

Slide 36 text

Tips - don’t leave library references in wrapper API - make wrapper API as abstract as possible - wrap API which you use, incrementally - put proxy on UI libraries - document things which cannot be wrapped

Slide 37

Slide 37 text

Library Candidates - logger - analytics - image loader - http client - android permissions - schedulers - etc.

Slide 38

Slide 38 text

@dmytrodanylyk slides.com/dmytrodanylyk medium.com/@dmytrodanylyk S speakerdeck.com/dmytrodanylyk S