Enyo MVC Intro
Clone this wiki locally
Enyo MVC: An Introduction
In this doc:
- Enyo's Component Model
- MVC in Enyo
- Design Goals
- Models and Collections
- Bootplate MVC
- Where Things Stand
- Getting Started
- Feedback and Discussion
This document provides an overview of the Model-View features we've built into Enyo, why we built them, where things are headed, and how you can help us move things forward.
If you are more interested in getting your hands dirty with those features now, visit the following page:
Separation of concerns is a fundamental principle of good software design. Generally speaking, you'll write better and more manageable code if you break your project up into discrete modules with well-defined purpose and scope, and strive to minimize redundancy and dependencies between modules.
Enyo's Component Model
If you've spent much time with Enyo, you've probably noticed that we talk a lot about modularity and encapsulation. Enyo promotes separation of concerns by helping you factor your application into components. Each component encapsulates a subset of your app's functionality and exposes it to other components via a public API (a set of properties, methods and events).
For example, you might implement a specific part of your app's UI by defining an
enyo.Control (a kind of component). This control would be responsible for
"composing" itself out of simpler components, rendering itself into the DOM,
capturing user input events, interacting with its parent and child components
using their APIs, and cleaning up after itself when its work is done.
Experience has shown us that apps made from thoughtfully-designed components are easy to test and easy to modify to meet changing needs. In addition, they often yield building blocks that can be reused in other projects or shared with other developers.
There's more than one way to separate concerns, though. While Enyo has always made it easy to organize your app along functional lines, historically, it hasn't done anything to help you isolate app data and business logic from presentation. It's actually fairly common for a single Enyo component to compose a view, handle input, manipulate data and update application state.
What if you want to keep these aspects separate? That's where MVC comes in. MVC (Model-View-Controller) is a well-established pattern for separating an app into distinct, loosely-coupled layers. While frameworks vary in their specific interpretations of MVC, the basic concepts are essentially the same:
Models define the types of data an app deals with and the rules/logic for manipulating data. They are also responsible for interacting with the databases or services that house the data.
Views are responsible for presenting data to the user and providing ways to act on that data.
Controllers mediate between models and views, manipulating models in response to user actions and updating views when models change.
MVC-style separation of concerns comes with its own set of benefits. Perhaps even more so than the component model, MVC enhances testability--models and controllers readily lend themselves to automated testing, since they're decoupled from UI.
MVC also makes it easier to have specialized roles within your team, with different developers focusing on different layers. In principle, MVC even makes it possible to replace one layer entirely, with minimal impact on the other layers. You might reimplement your models to support a different backend datastore, for example, or build an entirely new set of views to support a radically different type of device.
MVC in Enyo
Not surprisingly, MVC support has been one of our top feature requests since Enyo 2 debuted. With Enyo 2.4, we've taken the first steps in expressing such a system within in an Enyo context.
We considered a number of possibilities, including doing nothing--after all, we've seen developers employ MVC in Enyo apps without any help from us, often by loosely coupling Enyo with Backbone.js.
Ultimately, though, we decided that there was much to be gained from adding first-class support to Enyo. As implemented, this support is not a true MVC system, as we have foregone the implementation of controllers. Instead, we have added features that make it easy to create models to contain data and views, which are merely components, that can use the models. To tie it all together, we have added support for data binding, observers and computed properties.
Having decided to implement a Model-View system, we identified the following design goals:
Make it 100% optional. MVC is great, but it's not necessarily for every developer, or for every project. Existing Enyo apps need to function exactly as before, and developers should be free to adopt the new features or not, as their tastes and needs dictate.
Offer a well-lit path, but be flexible. For developers who want an out-of-the-box solution, we should provide an easy-to-use Enyo MVC app template. We have provided that with https://github.com/enyojs/bootplate-mvc bootplate-mvc. But we should also make sure that the pieces of our MVC implementation are useful on their own and in various combinations, enabling developers to mix and match.
Keeping these design goals in mind, we experimented with (and vigorously debated) a variety of approaches. In the end, we came up with a design that we like a lot--one that enables MVC-style development while preserving the nature and the unique strengths of Enyo.
In a nutshell, when you develop an Enyo app using the Model-View pattern:
You'll implement your model layer using two new Enyo kinds,
You'll build views that derive from
enyo.Control. As in "traditional" Enyo development, you'll compose views from widgets and subviews using the declarative
You'll use bindings to update your views automatically when underlying models and collections change.
Support for bindings is built into the Enyo core, as is the base
enyo.Controller kind; these constructs are general enough to be useful even in
apps that don't fully adopt a Model-View structure. We've also created a version of our
Bootplate app template to help get you started.
More detail is provided in the sections that follow.
The goal of bindings is to greatly simplify the plumbing needed to keep views in sync with their underlying data, whether in the view's published properties, properties on models and collections, or even properties of two components within a single view.
Starting in Enyo 2.2, bindings are a first-class feature of the Enyo core,
enyo.Object. With bindings, any two properties of any two
enyo.Object (or its subkinds) may be bound either
unidirectionally or bidirectionally, such that when the value of the source
property changes, the target property is automatically updated with the new
Bindings may be managed directly via a low-level API, but more typically you'll
set up bindings within the definition of an
enyo.Component, using the new
Models and Collections
a mechanism to assign default values and methods to fetch data from REST endpoints.
Where Model is designed to wrap a single object,
enyo.Collection is designed to wrap an array of objects.
Enyo also includes collection-aware Repeater and List controls, which allow you to bind list template properties to model properties of a collection. The repeater or list will monitor the underlying collection (or any models contained within), re-rendering itself automatically if changes are detected.
Finally, we are releasing a new "Bootplate MVC" app template to complement the
existing "Bootplate". The new template (found in the
bootplate-mvc repo on
GitHub) is a ready-made generic Enyo app using MVC; it conveniently brings
together all the pieces you need to start developing your own MVC application.
Where Things Stand
Enyo MVC is still very much a work in progress, but it has progressed to the point where we'd like you to take a look and give us your feedback.
The best source of documentation for the data binding features of Enyo is the Enyo site: http://enyojs.com/docs. Other options include:
This document, which provides a top-down conceptual overview.
Exploring the Bootplate MVC app a good way to get a concrete picture of how data driven applications in Enyo work. Not only does it illustrate how an app should be structured, but it also provides an interactive "playground" you can use to see these features in action along with a fully annotated view of its own source code.
Feedback and Discussion
Please use the Enyo forum for feedback and discussion: