Top Banner
VIPER Make your MVP cleaner Dmytro Zaitsev Senior Mobile Developer @ Lóhika
43

SE2016 Android Dmytro Zaitsev "Viper make your MVP cleaner"

Apr 11, 2017

Download

Mobile

Inhacking
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

VIPERMake your MVP cleaner

Dmytro ZaitsevSenior Mobile Developer @ Lóhika

Page 2: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"
Page 3: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"
Page 4: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"
Page 5: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"
Page 6: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"
Page 7: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"
Page 8: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

MVP/MVC/MVVM is NOT an Architecture!It’s only responsible for the presentation layer delivery mechanism

Page 9: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

Real-world Android app

● Hard to understand

● Hard to maintain

● The business logic is mixed in Activity/Fragment

● High coupled components

● MVC -> Massive View Controllers

● Hard and often impossible to test

Page 10: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"
Page 11: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

Clean Architecture

● Independent of Frameworks

● Testable

● Independent of Database

● Independent of any external agency

● Independent of UI

Page 12: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

““The Web is an I/O Device!

-Robert Martin

Page 13: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"
Page 14: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"
Page 15: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

What is VIPER?

● A way of architecting applications which takes heavy inspiration from the Clean Architecture

● Divides an app’s logical structure into distinct layers of responsibility

● Makes it easier to isolate dependencies● Makes it easier test the interactions at the boundaries between

layers● Eliminates Massive View Controllers

Page 16: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

Main parts of VIPER

● View

● Interactor

● Presenter

● Entity

● Router

Page 17: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"
Page 18: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

ViewDisplays what it is told to by the Presenter and relays user input back to the Presenter

Page 19: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

View

● Is passive

● Waits for the Presenter to give it content to display

● Never asks the Presenter for data

● Determines how the content is displayed

● Handles user interaction and input

● Simply delegates user’s actions to the Presenter

● Awaits for a response telling it what should be displayed next

Page 20: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

internal interface CheeseViewCallbacks {

fun onNewCheese(cheese: Collection<CheeseViewModel>)

fun showError()

fun hideProgress()

fun showProgress()

}

Example of View

Page 21: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"
Page 22: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

class CheeseView : ConstraintLayout, CheeseViewCallbacks {

@Inject internal lateinit var presenter: CheesePresenter

private lateinit var progressDialog : ProgressDialog

private lateinit var adapter : CheeseAdapter

/** ... */

override fun onNewCheese(cheese: Collection<CheeseViewModel>) {

adapter.setModels(cheese)

adapter.notifyDataSetChanged()

}

override fun showError() {

Toast.makeText(context, R.string.error, Toast.LENGTH_SHORT).show()

}

override fun hideProgress() = progressDialog.dismiss()

override fun showProgress() = progressDialog.show()

}

Example of View

Page 23: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

PresenterContains view logic for preparing content for display (as received from the Interactor) and for reacting to user inputs (by requesting new data from the Interactor)

Page 24: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

Presenter

● Knows about the content it maintains and when it should be displayed

● Receives input events coming from the View

● Applies view logic over this data to prepare the content

● Tells the View what to display

● Sends requests to an Interactor

● Works like a bridge between the main parts of a VIPER module

● Receives the data structures coming from the Interactor

● Knows when to navigate to another screen, and which screen to navigate to

Page 25: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

class CheesePresenter(private val getCheeseInteractor: GetCheeseInteractor) {

var view: CheeseViewCallbacks? = null

var router: MainRouter? = null

/** ... */

fun fetchCheese(amount: Int) {

view?.showProgress()

getCheeseInteractor.execute({ cheese -> // onNext

view?.onNewCheeses(cheese)

view?.hideProgress()

},

{ // onError

view?.showError()

view?.hideProgress()

},

amount)

}

fun onItemClicked(model: CheeseViewModel) = router?.navigateToDetails(model)

}

Example of Presenter

Page 26: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

InteractorContains the business logic as specified by a use case

Page 27: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

Interactor

● Represents use cases

● Regular Java object

● No Android framework dependency

● Encapsulates application specific business rules

Page 28: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

class GetCheeseInteractor @Inject constructor(

private val subscribeOn : Scheduler,

private val observeOn : Scheduler,

private val cheeseStorage: CheeseStorage) {

private val subscriptions = CompositeSubscription()

fun execute(subscriber: Subscriber<Collection<Cheese>>,

amount : Int) {

subscriptions.add(cheeseStorage.getCheese(amount)

.subscribeOn(subscribeOn)

.observeOn(observeOn)

.subscribe(subscriber))

}

}

Example of Interactor

Page 29: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

EntityContains basic model objects used by the Interactor

Page 30: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

Entity

● POJOs

● Encapsulates different types of data

● Model objects manipulated by an Interactor

Page 31: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

data class Cheese(

val id : Long,

val name : String,

val price : Long,

val description : String,

val type : String,

val texture : String,

val fatContent : String,

val animalMilk : String,

val regionOfOrigin: String

)

Example of Entity

Page 32: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

RouterContains navigation logic for describing which screens are shown in which order

Page 33: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"
Page 34: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"
Page 35: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

Router

● Responsible for passing data between screens

● Receives input commands from the Presenter

● Responsible for the navigation logic between modules

Page 36: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

internal interface MainRouter {

fun navigateToDetails(model: CheeseViewModel)

fun navigateToPreferences()

fun navigateToRegistration()

}

Example of Router

Page 37: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

class MainActivity : AppCompatActivity(), MainRouter {

override fun navigateToDetails(model: CheeseViewModel) {

startActivity(Intent(this, DetailsActivity::class.java).apply {

with(this) {

putExtra(DetailsActivity.NAME, model.name)

putExtra(DetailsActivity.CHECKED, model.isChecked)

}

})

}

override fun navigateToPreferences() {

startActivity(Intent(this, SettingsActivity::class.java))

}

override fun navigateToRegistration() {

supportFragmentManager.beginTransaction()

.replace(R.id.content, LoginFragment())

.commit()

}

}

Example of Router

Page 38: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

Why should you use VIPER?

● It’s easier to track issues via crash reports

● The source code will be cleaner, more compact and reusable

● Adding new features is easier

● There are less conflicts with the rest of the development team

● It’s easier to write automated tests

Page 39: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

When should you NOT use VIPER?

● It’s an overkill for small projects

● Causes an overhead when starting new projects

● MVP/MVC/MVVM-VIPER mix can cause headaches

● Lots of code all over the project

Page 40: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

Testing

● Presentation layer

○ Espresso, Robolectric

● Domain layer

○ JUnit, Mockito, PowerMock

● Data layer

○ Robolectric, JUnit, Mockito, PowerMock

Page 41: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

References

● http://mutualmobile.github.io/blog/2013/12/04/viper-introduction/

● http://www.mttnow.com/blog/architecting-mobile-apps-with-bviper-modules

● http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/

● http://fernandocejas.com/2015/07/18/architecting-android-the-evolution/

● https://www.objc.io/issues/13-architecture/viper/

● https://github.com/RxViper/RxViper

● https://www.ckl.io/blog/ios-project-architecture-using-viper/

● http://luboganev.github.io/post/clean-architecture-pt2/

Page 42: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

Demo

Page 43: SE2016 Android Dmytro Zaitsev "Viper  make your MVP cleaner"

Dmytro Zaitsev@DmitriyZaitsev

Questions?

Thank you!