реалии использования Mv в i os разработке
Transcript of реалии использования Mv в i os разработке
provectus.com
Реалии использования "MV*" в
iOS разработке
Darmancev NicolaiiOS Developer, Mobile Department
provectus.com
MV*
History:
provectus.com
References● https://martinfowler.com/eaaDev/uiArchs.html● http://geekswithblogs.net/dlussier/archive/2009/11/21/136454.a
spx● https://nirajrules.wordpress.com/2009/07/18/mvc-vs-mvp-vs-
mvvm/● https://realm.io/news/eric-maxwell-mvc-mvp-and-mvvm-on-
android/● https://www.linkedin.com/pulse/understanding-difference-
between-mvc-mvp-mvvm-design-rishabh-software● https://habrahabr.ru/post/321050/● https://speakerdeck.com/dalog/mvvm-plus-rac-plus-tdd● https://martinfowler.com/bliki/CQRS.html
● https://realm.io/news/slug-max-alexander-mvvm-rxswift/● https://realm.io/news/altconf-ash-furrow-functional-reactive-
swift/● http://www.slideshare.net/cocoaheadsmsk/9-mvvm-ios
provectus.com
Canonical MVC● The presentation part of MVC is made of the two remaining elements:
view and controller. The controller's job is to take the user's input and figure out what to do with it.
● In fact the view and controller do link to each other directly, but developers mostly don't use this fact
● Observers do occur in MVC, indeed it's one of the ideas credited to MVC. In this case all the views and controllers “observe” the model. When the model changes, the views react.
provectus.com
Real MVC's
provectus.com
MVC Parts● The model is the object which provide needed Data + State + Business logic● The view is the Representation of the Model. The view has a responsibility to
render the User Interface (UI) and communicate to the controller when the user interacts with the application. In MVC architecture, Views are generally pretty “dumb” in that they have no knowledge of the underlying model and no understanding of state or what to do when a user interacts by clicking a button, typing a value, etc. The idea is that the less they know the more loosely coupled they are to the model and therefore the more flexible they are to change.
● The controller is Glue that ties the app together. It’s the master controller for what happens in the application. When the View tells the controller that a user clicked a button, the controller decides how to interact with the model accordingly. Based on data changing in the model, the controller may decide to update the state of the view as appropriate.
provectus.com
Some soundbites on MVC
● Make a strong separation between presentation (view & controller) and domain (model) - Separated Presentation.
● Divide GUI widgets into a controller (for reacting to user stimulus) and view (for displaying the state of the model). Controller and view should (mostly) not communicate directly(avoid internal state!) but through the model.
● Have views (and controllers) observe the model to allow multiple widgets to update without needed to communicate directly - Observer Synchronization.
provectus.com
MVC● The controller's job is to take the user's input and figure out what to do with it.● The input is directed at the Controller first, not the view. That input might be
coming from a user interacting with a page, but it could also be from simply entering a specific url into a browser(push/websockets/etc.). In either case, its a Controller that is interfaced with to kick off some functionality.
● There is a many-to-one relationship between the Controller and the View. That’s because a single controller may select different views to be rendered based on the operation being executed.
● There is one way arrow from Controller to View. This is because the View doesn’t have any knowledge of or reference to the controller.
● The Controller does pass back the Model, so there is knowledge between the View and the expected Model being passed into it, but not the Controller serving it up.
provectus.com
Controller Concerns
● Testability - The controller is tied so tightly to the platforms APIs that it is difficult to unit test.
● Modularity & Flexibility - The controllers are tightly coupled to the views. It might as well be an extension of the view. If we change the view, we have to go back and change the controller.
● Maintenance - Over time, particularly in applications with anemic models, more and more code starts getting transferred into the controllers, making them bloated and brittle.
provectus.com
MCV → MVP● Differences:
provectus.com
Presenter
● This is essentially the controller from MVC except that it is not at all tied to the View, just an interface. This addresses the testability concerns as well as the modularity/flexibility concerns we had with MVC.
provectus.com
MVP
● The input begins with the View, not the Presenter.● There is a one-to-one mapping between the View and the associated Presenter.● The View holds a reference to the Presenter. The Presenter is also reacting to events
being triggered from the View, so its aware of the View its associated with.● The Presenter updates the View based on the requested actions it performs on the
Model, but the View is not Model aware.
provectus.com
MVP
● The presenter coordinates changes in a domain model.● Different variants of MVP handle view updates differently. These vary from using
Observer Synchronization to having the presenter doing all the updates with a lot of ground in-between.
provectus.com
MVC vs MVP● Check again:
provectus.com
MVC● MVC: Three components – View (your UI), Model (your business entities / data –
that view is displaying) & Controller (contains the logic that alters the model depending on the action triggered by UI, typically implementing a Use Case).
● It’s widely known that MVC is a compound pattern (View and Controller have Strategy implementation, View itself can be a Composite implementation & View and Model are synched through Observer).
● In this case Controller doesn’t know anything about View, and the idea is that a View can switch Controllers (for instance depending upon who has logged to the system) & a single controller can be used by multiple Views.
● View subscribes to the changes done to the model & hence both are sync from the data perspective. One of the disadvantages of MVC is that it’s difficult to unit test. Controller manipulates the data but how about asserting those changes from a view perspective. For instance on click of a button you raise an event to controller, and controller modifies the value in model. This value modification changes the font size / color in View. Unit testing this scenario is slightly difficult in MVC.
provectus.com
MVP● MVP: Again three components. But dependencies change (look at arrows in the
diagram). Over here we replace Controller with Presenter (one which presents the changes done in model back to view).
● The main difference between both is that Presenter refers back to the view while Controller doesn’t.
● Normal pattern found here is to create an abstraction of the View (in terms of properties / events) & Presenter refers to it.
● This makes the mocking of View much easier & hence the Unit Testing aspect. Presenter here hence takes the responsibility of not only manipulating model but also updating the view.
● Of course the implementations of MVP differ in real world in terms of how much thin the view is, some prefer keeping basic logic still inside view & taking complex logic in presenter, while others prefer keeping the entire logic in Presenter.
● Martin fowler describes 2 variations on MVP on these lines namely – Supervising Controller & Passive View described below
provectus.comSupervising Controller & Passive View
● (A Passive View handles this by reducing the behavior of the UI components to the absolute minimum by using a controller that not just handles responses to user events, but also does all the updating of the view. This allows testing to be focused on the controller with little risk of problems in the view.
● Supervising Controller uses a controller both to handle input response but also to manipulate the view to handle more complex view logic. It leaves simple view behavior to the declarative system, intervening only when effects are needed that are beyond what can be achieved declaratively).
provectus.com
Presenter Concerns
● Maintenance - Presenters, just like Controllers, are prone to collecting additional business logic, sprinkled in, over time. At some point, developers often find themselves with large unwieldy presenters that are difficult to break apart.
● Of course, the careful developer can help to prevent this, by diligently guarding against this temptation as the application changes over time.
provectus.com
MVC-MVP-MVVM
provectus.comUser POV:
provectus.comMVVM
● The view binds to observable variables and actions exposed by the viewModel in a flexible way.
● The ViewModel is responsible for wrapping the model and preparing observable data needed by the view. It also provides hooks for the view to pass events to the model. The ViewModel is not tied to the view however.
provectus.com
Model -View -View Model● The input begins with the View, not the View Model.● While the View holds a reference to the View Model, the View Model has no
information about the View. This is why its possible to have a one-to-many mapping between various Views and one View Model…even across technologies. For example, a WPF View and a Silverlight View *could* share the same View Model. However, my own feeling is that this is a bad practice and creates Franken-ViewModels that have too many responsibilities. It’s better to keep it as a one-to-one mapping instead.
● You’ll also notice that the View has no idea about the Model in the MVVM pattern. This is because, as far as the View knows, its “Model” IS the View Model (hence its name). Because of how data-binding and other features like commanding work in WPF and Silverlight, there is rich communication between the View and View Model, isolating the View from having to know anything about what’s really happening behind the scenes.
provectus.com
V VM M
provectus.com
Pro/contra● Evaluation● Unit testing is even easier now, because you really have no dependency on the
view. When testing, you only need to verify that the observable variables are set appropriately when the model changes. There is no need to mock out the view for testing as there was with the MVP pattern.
● MVVM Concerns● Maintenance - Since views can bind to both variables and expressions,
extraneous presentation logic can creep in over time. To avoid this, always get values directly from the ViewModel rather than attempt to compute or derive them in the views binding expression. This way the computation can be unit tested appropriately.
provectus.com
View Model Worst Practices
● Never reference the view controller● Do not import UIKit. Make it a different file.● Do not reference anything from UIKit. (You might think, “I need a button
reference, I’m going to shove it in there.” Don’t do that.)● It should only be data, i.e., strings, structs, JSON; classes that do not have
much functionality.
provectus.com
provectus.com
… vs ...
provectus.com
Discussion:
provectus.com
Discussion:
provectus.com
Discussion:
provectus.com
Evolution:
provectus.com
provectus.com
FRP: Functional Reactive Programming
● Let’s start with streams. Streams send stuff. They’re a very familiar data structure. They can send anything, just like an array can hold anything. They’re very familiar, and very close to arrays in that they hold stuff. The difference between arrays and streams is that an array can be accessed at anytime. You can always look into an array and get whatever it has, at any given time. With streams, they send stuff at a specific time. If you’re not listening for that stuff, then you miss it. You can’t just reach into a stream and grab data. If you miss it, it’s gone forever.
provectus.comFRP: Functional Reactive Programming
● The next thing you have to know is transformations. Transformations turn one thing into another. Your’re probably already familiar with this kind of idea using map and filter. Basically, if you have an array of one type of thing, you can map it into an array of a new type of thing. If you have a Person object and an array of Persons, then you can turn that into an array of their first names, their date of births, their employer’s names, or any type of data you want. You can also filter that array. You can take an array of Persons, and turn it into an array of everyone older than the age of twenty-one.
● You take something and turn it into something else. The same things apply with streams. If you have stream of people, you can turn that into a stream of their names, their employers, or a stream of all the people who are over the age of 21. When you take a stream, and transform it, you get a new stream. You don’t modify the original, but you actually create a whole new one. New streams are produced, not modified.
● The really cool thing with transformations is that you can chain them. So, you can take an array of people and turn it into an array of employers, and then turn that into an array of employer addresses. Same thing with streams — you can turn a steam of persons into a stream of employers, and then turn that into a stream of employer addresses.
provectus.com
Bindings
The third ingredients to Functional Reactive Programming. They are the secrect sauce that makes it all work. Without bindings, Functional Reactive Programming would be useless. To recap, you make a stream, transform that stuff into other stuff, and then you bind that stuff to things
provectus.com
Solutions:
● https://github.com/ReactiveCocoa/ReactiveCocoa● https://github.com/ReactiveX/RxSwift● https://github.com/ReactKit/ReactKit● …● https://github.com/markohlebar/BIND● https://github.com/markohlebar/iOSArchitectures
provectus.comBIND
provectus.comBIND
provectus.comBIND
provectus.comMVVMC :)
provectus.comMVVMC● The Data Controller is responsible for transforming the Model from external sources; i.e. a web service to a View
Model which forms a 1:1 relationship with View elements (View or View Controller). BIND offers a protocol BNDDataController which exposes the following method:
● - (void)updateWithContext:(id)context viewModelsHandler:(BNDViewModelsBlock)viewModelsHandler;● Every data controller should ideally expose only this method to the owning View Controller. Calling this method
should trigger a series of events, like fetching Model from a web service and then transforming that Model to a View Model which maps to your View.
● The View Controller holds a reference to it's Data Controller and kicks off a request for the View Model. Usually the best time to refresh the View Model would be in UIViewController's viewWillAppear: callback method.
● View BIND offers the following abstract subclasses for the View elements:● BNDView● BNDTableViewCell● BNDCollectionViewCell● BNDViewController● These subclasses hold a weak reference to the viewModel and a strong reference to an array of bindings● The View Model plays the middle man role between your business logic and the View. Upon receiving the View
Model from the Data Controller, the View Controller should assign the View Model to it's designated View so that the bindings between the View and the View Model are created. View model may contain sub viewModels but it should never create them. The creation of view models is the sole responsibility of the DataController.
● Model. Your ususal PONSO or whatever model
provectus.com
Flux/redux
provectus.com
FB FLUX
provectus.com
FLUX like
● https://github.com/clayallsopp/CLAFluxDispatcher● https://github.com/techery/FLUX● https://github.com/ReSwift/ReSwift/raw/master/Docs/img/timetravel.gif● RAC● https://habrahabr.ru/post/317992/ RAC● https://habrahabr.ru/post/215033/ RAC● https://habrahabr.ru/company/e-Legion/blog/244065/ RAC video full hd, free, without
sms :)
provectus.com
… vs ...
provectus.com
Благодарю за внимание!
Вопросы?