2

I had a debate with a friend and I'm looking for a way to resolve it and decide which approach is better for maintenance and whether there's some consensus about a best practice regarding it:

If an application shows some data on the UI (for example order ids that are added dynamically by the user) and there's a button which suppose to do some action with that data shown on the ui (e.g. send those ids to processing) - how should the data be fetched:

  • Is it better that the code handling the button click take the values directly from the UI by accessing the UI element?

    After all, UI changes the most often, so if I take the data from the UI it's more likely that the button click handling code will also have to be updated because how it consume the data from the UI might get broken.

  • Or should the data be taken from some variable that will save the state?

    But if I add a special variable just to save the state, I add a new place in code that have to be maintained on changes and that artificial state variable might not be 100% synchronized with the UI and cause bugs.

How to decide which approach to choose? Is adding a special variable just to save state considered a code smell?

1

2 Answers 2

5

You should have a "model"-"view" separation. It doesn't necessarily need to be some semi-formalized MV* pattern (e.g. MVC, MVP, MVVM, ad nauseam) or framework, but the idea of having some computational representation (the model) of some aspect of the application that gets rendered (producing the view) and is notified when inputs change has been extremely successful.

Your potential dilemma evaporates once you take this perspective. The problem is caused by having the button "send IDs to processing". The button should not be doing this. The button should only be notifying the model that it was pressed. The model should, if it decides it is appropriate, send the IDs to processing. Whether the model uses stored values or reads from UI controls is not the button's concern.

This moves the problem to the model, but the situation is clearer there. The model holds the "authoritative" values. What's displayed is just a rendering of those values. The model has no need to consult the UI for those values. Indeed, you generally want the model to be unaware of the UI altogether. This allows the model to be tested without needing to mock the UI. It also allows different or multiple UIs to use the same model. If the model is unaware of the UI, then it certainly can't go and fetch values from the UI controls, so something has to tell the model what is happening.

Essentially, you have a "language" of UI events, and a "language" of application model events and you need an adapter between these. The view model of the MVVM pattern (or something analogous) serves that role of the adapter. The application model events should be processed by the application model as atomic state transitions. The UI events, on the other hand, will typically be much finer-grained than that. The view model takes the stream of UI events and "aggregates" them into application model events. The Elm Architecture is a particularly clear rendition of this concept.

For example, consider a form for assigning players to teams. The application model is a list of teams, and a list of players on each of those teams. The application model also has an AddPlayerToTeam(player, team) event (among other things). The UI for adding a player consists of a textbox for the player name and a drop-down for the team. There are no application model events to deal with a partially completed "add player" form. Instead, a view model is introduced which has event handlers for UI events and can represent a partially completed "add player" form. As text is entered into the textbox the view model is notified and updates itself. Similarly, as teams are selected in the drop-down. A button press then notifies the view model that the user has completed the form. The view model can then notify the application model of an AddPlayerToTeam event after validating the form enough to ensure that there is an actual valid player and team to provide to that event. The application model would handle deeper validation, e.g. that a player can be on only one team. View models are created as the view is (re)rendered as the view models are part of the application-level View in the application-level Model-View split. In this approach, no component needs to directly read from UI controls (except possibly if an event handler requires reading it's own control as opposed to having the new details in a parameter to the event handler). On the other hand, the view model (let alone the application model) is more than just a "special variable just to save state".

1

Theres no way around taking the value from the UI when its user entered.

What you can do is ensure that there is a layer if abstraction between the UI (View) and underlying logic if the action (Model)

So for example you might use a ViewModel to contain all the values and commands that the view is displaying and then 'Bind' that to the View. ie

  • When you press the Add button call the ViewModel.AddButtonPressed() function.

  • When you update the Number text field, also update the ViewModel.Number variable.

The ViewModel can in turn be bound to the Model containing your business logic

  • Model.Add(ViewModel.Number)

This insulates your Model from UI changes. Various frameworks are available to help with the binding so that it happens automagicially.

Obviously you can do similar things with MVC, MVP, etc which also provide patterns for this kind of abstraction.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.