Blog-Archiv

Samstag, 25. März 2017

Data Binding in MVP and MVC

Data Binding has not been modelled as class-rectangle when MVC was invented ( UML did not yet exist at that time). It has been rendered as arrows between model and view (view as model listener), and controller and model (controller as model-updater). But, instead of using just controllers, we should implement bindings and controllers. Bindings being responsible for mapping model-properties to view-fields, and controllers being action-listeners to views.

What's Wrong?

Presentation-layer responsibilities are:

  1. Provide the possibility to set different model instances
  2. Map model properties to view fields
  3. Dispatch user events and perform according actions, mostly updating model-properties from view-fields
  4. User guidance by manipulating the view-state, e.g. enabling and disabling action-buttons

For MVP, all of that is done by the Presenter.
For MVC, (2.) is done partially by the view, everything else by the Controller.

I'd like to call (2.) a read-only data binding, because it is sufficient for display-only user-interfaces. The other way round, from view to model, always goes through some presentation-logic, but also ends up in some kind of mapping between view fields and model properties.

So, let's repeat:

  • In MVP, the data binding is done by the presenter only. But, to be a shiny God-Class, the presenter also dispatches view events - it cumulates responsibilities.

  • In MVC, read-only data binding is done by the view, but, to be a funny Shotgun Surgery, input events' data binding is done by the controller. In other words, when you add a new model-property, you have to change its binding in both view and controller.

We should try to write OO classes like we wrote structured-language functions:

one function has just one purpose
one class has just one responsibility

This is called the Single Responsibility Principle. I would propose to separate data binding as a separate responsibility. So neither controller nor presenter nor model nor view should know which model-property maps to which view-field.

Data Binding Specification

Binding mediates between model and view, it knows both of them. Thus either the view provides abstractions of its components (field, table, row, tree, node, ...), or the binding will be windowing-system dependent (like the view is).

Main responsibilities:

  • Mapping: Data binding is mapping between model-properties and view-fields
    • Mapping model to view is sufficient for read-only views
    • Mapping view to model is needed for read/write views, here presentation-logic will participate

  • Many-to-Many: Several fields may be bound to just one property (e.g. day/month/year-fields that map to just one date-property), one field may map to several properties (e.g. a date/time-chooser maps to a date- and a time-property)

A data binding must cope with:

  • Converters: The data-type of a property may be different from the type the according field supports, i.e. binding includes data conversion between model and view

  • Validation: Fields may have validators, and an invalid value may or must not arrive in the according property

  • Field Factories: Fields may not exist yet when a model is propagated (e.g. table or tree cell editors, created on demand only), so properties must be bound to field-factories, not fields

  • Read/Write: Read-only fields may be coupled to writable fields, responsible for the same model property, (e.g. user can push an "Edit" button to make a view editable)

  • Buffering: The binding of fields can be buffered, i.e. they do not write back to the model immediately when changed (e.g. when having "Save" and "Cancel" actions on an input form)

  • Commit: When buffered, a 2-phase commit mechanism is required when fields are validated, i.e. when one field is invalid, none must be written to the model

  • Ignores: Some properties may not be shown in the view, some fields may not have a model representation

All of these can be moved to the field-side, i.e. fields can have converters, validators, there can be factories that create fields on the fly, fields can have a setReadOnly() method, can support setBuffered() and commit(). Finally, when using generic bean bindings (that bind all properties of a bean), an @Ignore annotation can hide a property.

Although these secondary responsibilities can be assigned to the view-side, data binding must work together closely with them. And mind that they will be windowing-system specific when being on the view-side!

Keep the View Anemic

Quite a lot of things that make up such a presentation layer. Where will we put all these?

Views suck. They suck up the application. The windowing system wants to be everywhere. That is what I observe all the time. Important and wise application logic ends up in some view class. Change the windowing system, and you will have to rewrite your application completely. Nobody wants to miss these nice presentation layer classes in Swing, JavaFX, Vaadin, ... (ssslurp, you have been sucked up :-)

Most people don't care about user interface implementations. They hire cheap students or beginners and rewrite the UI any time a new technology comes up. But they forget how expensive the bugfixing and maintenance of all that spaghetti code is, and they do not notice how the UI sucks up the application.

In my next Blog I will present an example where data binding has been implemented as separate class, keeping away all mapping logic from presenter and view. Measuring the lines of code needed on view side will show us how expensive rewriting views is.




Keine Kommentare: