Architecture


It's helpful to understand some of the philosophies behind Mojo at a very high level. These are abstract concepts, but will help construct a mental model of how to develop applications in a scalable, elegant way.

What is MV*?

MVC, MVP, MVVM, HMVC, these are design patterns to help develop web, or server-side applications. Let's disect a little bit what MVC actually means in Mojo.

The "M" in MVC represents a Model. A model can be anything that represents data, such as a person, message, or a collection of messages. Models might also have properties, and/or methods specific to the data it's representing. A good example might be Messages.markAllRead, Message.markRead, or User.logout.

The "C" in MVC represents a Controller. Controllers contain logic specifc to the view it's representing. The controller typically (but not always) displays information from a model, or many models to the view, and also relays any user interaction from the view, to the models. The controller effectively guards the model, or any part of the application from view-specific logic.

The "V" in MVC represents a View (or templates). Views take information from the controller, and display it to the user. Views also take any interaction, and relay them back to the controller.

In Mojo, it's possible to include the view with the controller (it's easier to implement up-front), but this practice is discouraged since it makes maintanence a bit more difficult. Designers for instance might have a harder time modifying templates if it means they have to dive into JavaScript files.

Notice the order of these terms - MCV - this is how data flows to the user . You typically start with a model which provides information to the controller, to the view, then finally to the user (model -> controller -> view -> user). Think of this like layers of your application.

Framework Layers

It might be easy to think of your application in layers, where each new layer is supported by the previous layer. In MVC, the layers might look something like:

service -> models -> controllers -> views -> user.

Each proceding layer can interact with the previous layer, but not vice-versa. This means that, as a rule of thumb, controllers can interact with models, and service, but models should never interact with controllers. Views can interact with controllers, but controllers shouldn't ever really interact with the views. And the obvious - users can interact with the view, but a view cannot interact with the user.

This sort of model also comes with many other benefits. For one, it'll make your application more maintainable, and testable. Another benefit is that parts of your application will become modular. For instance, you could theoretically take out just the service, and models and re-use them for an API server.

Thinking about applications development in layers also reduces the cognitive overhead of planning your application architecure. Layering encourages you to focus on what you need immediately, and nothing else. If you're focusing on the views, just focus on that, not their relationship between other parts of the application. This includes models, and the HTTP router.

Planning

See structuring your application for more info.

When starting a new project, it's helpful to know the application requirements before jumping into code. This usually involves a few things:

  1. What does the application look like?
  2. What sort of data does the application need to represent?

The first step is probably easier to tackle since we can visually breakdown our application, and know exactly how, and where the views should be laid out into a heirarchial folder structure.

For instance, when you look at a list of items in a mock-up, you can assume it's a list view. If you see a view that's clearly toggling between two states (pages), it's probably a stack view. Everything else is just a base view.

This sort of practice is easy to pick-up between other team members, and creates a consistent way to handle how view components are created. It's also easy for non-developers to follow, especially designers looking to change some of the UI elements. Maintaining a hierarchy of views in Mojo also makes it easy to move components around within your application if you need to perform any sort of maintainence, or refactoring.

Once you have an idea of how your application should be broken apart, you can start building your views with the data it needs to represent - step two.

You typically write fixtures (fake data) along with views, so you know what properties the view needs. Fixtures allow you to construct views independently from models - great for encapsulation. Mojo easily allows you to write views with just fixtures, then later on, swap them out for real models - like a flip of a switch.

Developing views with fixtures is also a great way of building apps indendently from any API (especially with teams of people, you can easily write front-end and backend apps in parallel with this method). Fixtures also make your views more testable, and give you an additional idea of what model relationships look like - similar to the practice of looking at your mock-ups before building your views.

After you've created your views with fixture data, you should have a clear idea of the models your application needs. This is a pretty straight forward process. See structuring models for more information.

After developing your models, you can add other parts of your application, such as an HTTP router, realtime data, offline mode, or internationalization. These sort of features are non-fundamental, and should always be added after you've figured the structure of your models & views.

If you're interested to see the above concepts applied in practice, checkout this demonstration of a reader application developed in less than 2 hours:


Structuring your application


See Also https://github.com/mojo-js/mojo-todomvc-example

models

Models consist of items, and collections, and should be structured based on their relationship to one another. Collections are also considered models since they might also contain logic specific to the items it contains. A Messages collection for instance might have a markAllRead method.

It's easier to store models & collections in the same models/ directory without any hierarchy, since it's common for models to share relationships between each other.

Here's an example of how you might structure your models directory:

application/
  index.js - The application class
  models/
    user.js - uses friends collection
    messages.js
    message.js
    tags.js
    tag.js
    room.js
    rooms.js
    friends.js - uses user model

views

Structuring your views is a pretty straight forward process. The easiest way to start is by separating your mock-ups into smaller components. For example:

From there, we have a mental model of how are application should be structured. Here's what our folder structure might look like if we follow the diagram above, and build our application:

application/
  index.js - the application class which ties everything together
  models/ - your models
  views/ - your views
    main/
      index.js - main controller
      index.pc
      sidebar/
        index.js
        index.pc
        avatar.js
        avatar.pc
        schools.js
        schools.pc
        tips.js
        tips.pc
      classTiles/
        classTile.js
        classTile.pc
        index.js
      addClassButton.js
      addClassButton.pc
      archiveButton.js
      archiveButton.pc

This sort of structure is easy to follow at a top-level glance, and we can easily figure out what the purpose of each file is just by looking at the folder structure.

Notice the pc files - these are the templates that get displayed to the user. The js file is the view controller - it contains all the logic for the template, and handles any sort of user interaction.

Keep in mind that it's totally fine to build out an application without an HTTP router - that can be added last without affecting your application structure. -->

HTTP router

the HTTP router is a module that can be added at any time during the development process, since the HTTP router generally handles the application states at the root view. Those states get propagated, and used by stack views throughout the entire application.

unit tests

It's easier to keep tests alongside the file you're testing. For example:

application/
  index.js - The application class
  models/
    user.js - uses friends collection
    user-test.js
    messages.js
    messages-test.js
    message.js
    message-test.js
    ...
  views/
    main/
      index.js
      index-test.js
      sidebar/
        index.js
        index-test.js
    ...

This convention does a few things:

  1. It allows you to see at a glance what files are, and aren't tested.
  2. It ensures that your application is broken out into smaller units.
  3. It's easier, and much faster writing unit tests.
  4. It's an easy pattern to follow.
  5. Doesn't break if you need to source files around.

Here's a short example of a messages model unit test:

var Messages = require("./messages"),
expect       = require("expect.js");

describe(__filename + "#", function () {
  var messages;

  beforeEach(function () {
    messages = new Message({
      data: [
        { message: "Hello World", read: false },
        { message: "What's up?", read: true },
        { message: "My favorite color is blue", read: false }
      ]
    });
  });

  it("can mark all items read", function () {
    expect(messages.filter(function (message) {
      return !message.read;
    }).length).to.be(2);

    messages.markAllRead();

    expect(messages.filter(function (message) {
      return !message.read;
    }).length).to.be(0);
  });
});