Thunderbird/NextGeneration/Model
Author: Ben Bucksch (Please check with the author before modifying)
Data and functions
The model contains the pure data, as well as operations on that data.
- Data: For example, there might be a class Message with fields Author, Subject, Body, and an array of Attachments.
- Operations: The same class also has a function Reply which creates a new message with the fields populated for a reply, e.g. the Recipient will be the previous Author, and the Body will contain a quoted version of the previous message.
[This is different to some interpretations of Model, which include only pure data, no operations. The classic MVC however puts pure operations that operate on the data into the model. This is necessary to realize the benetifs of MVC.]
No access to View
The model must not contain any access to the user interface (View), ever.
The model will never call any UI function. For example, the above Message.Reply() function will not open a composer window, but return another Message model object. The caller – which is likely in the UI – will then call Composer.openWindow(replyMessage).
Likewise, the model must not open any prompts, not even for "Are you sure?" or "Where do you want to save the file?" type of questions.
Similarly, the model will never show and error prompts. See section Error handling.
The only exceptions are observers and localization strings.
Observers
The model will provide a generic change observer mechanism. Any code (including the particularly View, but not only) that is interested in changes to that model instance will subscribe to changes by this observer mechanism, and then once notified update itself.
Lists of objects are also models and observable.
- For example, the thread pane displays a list of messages. After gathering and showing the initial list of messages, the thread pane UI will subscribe to changes in that message list. If a message is added to the list, e.g. a new email arriving in the inbox, the message list will call all observers, and the thread pane will update itself by adding the new message to the UI.
- The same mechanism will be used when the user moves a message. The UI will call functions on the model to remove and add the message. The model will effect the change. Once performed, the message lists will call the observers (removal on one list, addition on the other list), and the UI will be updated. This way, the UI only has to invoke the move() function, and the UI updates happen automatically like with any other data changes.
This results in dramatically reduced code, and all places are updated at the same time.
See also Collections, which play a critical role in the model API.
All logic in model
Aside from the above rules, the model should contain as much code as possible. All logic should be contained in the model, and not in the View code.
The less code the View contains, the easier it is to adapt it, and to write new views.
In the ideal case, the View code only contains 1) code to display the data, and 2) button handlers, and they only contain calls to the model and call to display the result.
- For example, the Reply button handler would be:
- Message replyMessage = currentMessage.reply();
- Composer.openWindow(replyMessage);
Benefits
The advantages of a strict separation between model and view are huge. They are the basis for a flexible and adaptable code base.
This is also what will allow to write a somewhat different UI for mobile devices. Given that the View does not contain any logic and has little code, it should be feasible to create and maintain a separate View. The model will be shared and identical.