Building scalable applications inspired into Micro-service Architecture

Building scalable applications inspired into Micro-service Architecture

Experiences using modular arquitectures in android.

9f523401a845a29c93ff73cde4c3db2b?s=128

Erik Jhordan Rey

June 26, 2019
Tweet

Transcript

  1. Building scalable applications inspired into Micro-service Architecture · June 2019

  2. Why writing high-quality software is complicated?

  3. Not Architecture

  4. Architecture with smell implementations

  5. Monolithic Architecture

  6. Monolithic Architecture • All code in a single module •

    Coupled code • Different code styles • Hard to maintain • Hard to add new functionalities • Wrong dependency injection implementations • Unreliable test or not tests • Not CI • Demotivated Teams
  7. Writing healthy software...

  8. Architecture In most successful software projects, the expert developers working

    on that project have a shared understanding of the system design. This shared understanding is called ‘architecture.’ This understanding includes how the system is divided into components and how the components interact through interfaces. These components are usually composed of smaller components, but the architecture only includes the components and interfaces that are understood by all the developers.
  9. Microservice Architecture Way of designing software applications as suites of

    independently deployable services.
  10. Microservice Characteristics • Componentization • Organized around Business Capabilities •

    Decentralized Governance • Decentralized Data Management • Design for failure • Evolutionary Design
  11. Modular Component Architecture

  12. Modularized Library Architecture

  13. None
  14. Modularized Library Architecture • Different android projects • Complicated navigation

    between libraries • Difficult upgrades (implies a new library release) • Hard to maintain multiple libraries / projects • Hard to handle library version • Transitive dependencies
  15. Modularized Feature Architecture

  16. None
  17. Modularized Feature Architecture • Different android modules inside an android

    project • Modules organized around business functionality • Coupled & cyclic feature modules • Hard to maintain cyclic dependencies • Hard to share resources (custom views, colors, strings)
  18. Modularized Layer Architecture

  19. None
  20. Modularized Layer Architecture • Different android modules inside an android

    project • Modules organized around layer functionality • Coupling Modules (strong dependencies) • Hard upgrades • Exposed to create a bunch of git conflicts
  21. Inspired into Microservices Architecture

  22. Modularized Feature/Layer + Clean Principles

  23. None
  24. Modularized Layer Architecture • Faster build time • Decoupled of

    DI library (not dagger in everywhere) • Better structure • Componentization • Decentralized Data • Maintainability • Designed to failure • Let's to write reliable tests
  25. App Android Architecture

  26. Dependency Inversion Principle Hide implementation details creating layers with different

    responsibilities.
  27. Android Stack • Kotlin • Architecture Components ◦ ViewModel ◦

    LiveData ◦ Room • RxJava / RxAndroid • Retrofit • OkHttp • Gson • dagger 2 (dagger-android) • JUnit • Mockito • Hamcrest • MockWebServer • Persistence Room Testing • Barista
  28. None
  29. How it works?

  30. Data Layer

  31. None
  32. None
  33. Removing an extra abstraction class LoginRepositoryImpl(val loginRemoteDataSource: LoginRemoteDataSource) : LoginRepository

    { override fun signIn(userCredentials: UserCredentials): Single<Session> = loginRemoteDataSource.signIn(userCredentials).map { it.toSession() } } interface LoginRepository { fun signIn(userCredentials: UserCredentials): Single<Session> }
  34. We can replace collaborators and test it @Test fun callSignInRepository()

    { val userCredentials = givenUserCredentials() val session = givenSession() given(loginRepository.signIn(userCredentials)).willReturn(Single.just(session)) signInUseCase.signIn(userCredentials) verify(loginRepository, times(1)).signIn(userCredentials) }
  35. Domain Layer

  36. None
  37. None
  38. interface Scheduler { fun io(): Scheduler fun computation(): Scheduler fun

    newThread(): Scheduler fun ui(): Scheduler } Scheduler Abstraction
  39. Taking advantage of kotlin fun <T> Observable<T>.runOnIo(scheduler: Scheduler): Observable<T> =

    subscribeOn(scheduler.io()).observeOn(scheduler.ui()) fun <T> Single<T>.runOnIo(scheduler: Scheduler): Single<T> = subscribeOn(scheduler.io()).observeOn(scheduler.ui()) fun <T> Flowable<T>.runOnIo(scheduler: Scheduler): Flowable<T> = subscribeOn(scheduler.io()).observeOn(scheduler.ui()) fun Completable.runOnIo(scheduler: Scheduler): Completable = subscribeOn(scheduler.io()).observeOn(scheduler.ui())
  40. Use Case Component class SignInUseCase(val loginRepository: LoginRepository, val scheduler: Scheduler)

    { fun signIn(userCredentials: UserCredentials): Single<Session> = loginRepository.signIn(userCredentials).runOnIo(scheduler) }
  41. Presentation Layer

  42. None
  43. None
  44. MVP -> MVVM

  45. Architecture components • ViewModel • LiveData

  46. Multiple LiveData & Observers class LoginViewModel : ViewModel() { var

    liveDataLoading = MutableLiveData<Any>() // Show progress bar var liveDataSession = MutableLiveData<Session>() // Show user session var liveDataError = MutableLiveData<SessionError>() // Show some error
  47. States Sealed Class sealed class StateData { object Loading :

    StateData() data class Success(var data: Any) : StateData() { inline fun <reified T> responseTo() = data as T } object Complete : StateData() data class Error(val error: Throwable) : StateData() { inline fun <reified T> errorTo() = error as T } }
  48. LiveData class LoginViewModel : ViewModel() { var _stateDataLogin = MutableLiveData<StateData>()

    var stateDataLogin : LiveData<StateData> get() = _stateDataLogin
  49. / SCHIBSTED MEDIA GROUP class LoginFragment : Fragment() { ...

    private fun handleState(stateData: StateData?) { when (stateData) { is StateData.Loading -> { showProgress() } is StateData.Success -> { val session = stateData.responseTo<Session>() showUserSession(session) } is StateData.Error -> { handleError(stateData) } } }
  50. What's next?

  51. Modular Dynamic features + Arch Components + Coroutines

  52. https://github.com/erikjhordan-rey/People-MVVM-Jetpack (work-in-progress ⛏ v2.0)

  53. https://martinfowler.com/articles/microservices.html Microservices - Martin Fowler http://files.catwell.info/misc/mirror/2003-martin-fowler-who-needs-an-architect.pdf Who needs an architect

    - Martin Fowler http://worrydream.com/refs/Brooks-NoSilverBullet.pdf Essence and Accident in Software Engineering - Frederick P. Brooks, Jr. Service Oriented Ambiguity - Martin Fowler https://martinfowler.com/bliki/ServiceOrientedAmbiguity.html Further Reading
  54. Erik Jhordan Rey Software Engineer erikjhordan.rey@gmail.com @ErikJhordan_Rey github.com/erikjhordan-rey Thank You!