Building Sproutcore Apps with Statecharts (part 1)

by Evin

State Types

Introduction

In this post, we will discuss creating a sproutcore application using a modeling method called ‘Statecharts’. This was invented by a man named David Harel, who invented it in order to have a state diagram that could model things like: superstates; concurrent states; and activities as part of a state. These are starting to gain more use in the software development world because of the distinct advantages that it provides to developers. These advantages include, but are not limited to:

  • Usability Testing
  • Interaction Testing
  • Scope Definition
  • Bug Discovery (they’re in the statechart)
  • Real Bugs are easier to Find/Fix

Statecharts also provide the ability to model cross-state events and interactions on multiple levels. This reduces the complexity of the diagrams and pre-segments the application into functional areas for development. You often find that once you get an ‘area’ correct is just stays ‘correct’ and make modification to the code a lot easier. There is another great paper on use of statecharts here.

Using Statecharts in Sproutcore

One of the distinct advantages of Statecharts is that you can actually use them in your code. That way you can match your statecharts directly to the code. This is accomplished in sproutcore with a plugin that Erich Ocean wrote. You can install it with the Sproutcore Build tools:

  sc-install onitunes-statechart

The best structure for using statecharts in Sproutcore is to make two new files: core_states.js and core_actions.js.
core_states.js should look like this:

  require('core');
  require('core_actions');
  MyApp.mixin( /** @scope MyApp */{
    goStateA1: function(){
      // TODO: Settings for State A1
    },
    goStateA2: function(){
      // TODO: Settings for State A2
    },
    goStateB1: function(){
      // TODO: Settings for State B1
    },
    goStateB2: function(){
      // TODO: Settings for State B2
    },
  });

core_actions.js should look like this:

  require('core');
  MyApp.mixin( /** @scope MyApp */{
    submitLogin: function() {
      var handled = NO;
      switch(this.state.a){
          case 1:
            // TODO: More actions
            this.goState('a', 2);
            handled = YES;
            break;
      }
      if(!handled) console.log('submitLogin Action not handled in state %@[%@]'.fmt('a',this.state.a));
    },
    reauthenticate: function() {
      var handled = NO;
 
      switch(this.state.a){
          case 1:
          case 2:
            // TODO: More Actions
            alert('You need to Reauthenticate...');
            this.goState('a', 1);
            window.location = "/login.aspx";
            handled = YES;
            break;
      }
      if(!handled) console.log('reauthorize Action not handled in state %@[%@]'.fmt('a',this.state.a));
    }
  });

What do statecharts look like?

Statecharts look a lot like state diagrams and are comprised of boxes and lines with some standard styling to indicate what they are. Major areas of statecharts are divided into two different types: States and Events.

States

States are further divided into the following type of states: Start, End, Switch, External, Transient, States, State w/ substates, and History

State Types

Rules for States

There are several rules for the different state types. Start, End, External, and History States are more functional indications than real states. They tell you how the application is supposed to function and basically modify the states they are linked to. States and State w/ substates are the most common and the most used. These state are only supposed to be setting values. There should be no ‘if’ or ’switch’ statements in these states. This is where the power of statecharts is revealed when you are in a state, it looks only one way. The last two states: Switch and Transient are special. Switch states are allowed to have ‘if’ and ’switch’ statements but only those statements. Transient states are ‘holding’ states with only Auto exit events.

This is what they look like in the code:

  goStateA1: function(){
    MyApp.set('pageView', 'MyApp.loginPage.mainView');
    MyApp.set('globalNavigationMenu', 'MyApp.navigationPage.globalMenuView');
  },
  goStateA2: function(){
    MyApp.set('pageView', 'MyApp.bodyPage.mainView');
    MyApp.set('globalNavigationMenu', 'MyApp.navigationPage.globalMenuView');
  },

Events (transitions)

Events are further divided into the following types: Regular and Auto. They can linked to states and sub-states; and they can have parameters and/or conditions. They are represented by arrowed lines.

Event Types

  submitLogin: function() {
    var handled = NO;
    switch(this.state.a){
        case 1:
          // TODO: More actions
          this.goState('a', 2);
          handled = YES;
          break;
    }
    if(!handled) console.log('submitLogin Action not handled in state %@[%@]'.fmt('a',this.state.a));
  },

Miscellaneous State Objects:

In addition to the major components of States and Events, there are several other elements that are useful. They include:

  • Grouping: This is where you box a few state that have the same exit\entry events so that you can clean up the diagram
  • Parallel States: These are concurrent states that are mutually exclusive. This happens rarely.
  • Indexing: Once you create the state chart you index the states numerically and group them by alphabetical area

Where To Use Statecharts

GUI Interactions

The primary use of statecharts in development is to describe the function of the application. This is a interaction map of the application.

Object Life Cycle

For complex models, you can use statecharts to handle the life cycle of the object. This allows different interactions to occur and can gate the object.

Server Communications

Statecharts are perfect for handling complex calls to the server and lazy loading of information. You can use them for interactive speed gains such as a quick load of object followed by a larger load of objects in the background.

Conclusion

Statecharts are a great tool to use in developing interactive applications. They provide a great way to segment and develop the application with fewer bugs. Sproutcore comes with great plugin to help you create solid applications. We will have a follow up post to show you what is really looks like.

This entry was posted on Sunday, February 22nd, 2009 at 2:18 pm and is filed under Best Practices. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

3 Responses to “Building Sproutcore Apps with Statecharts (part 1)”

  1. Kristian Mandrup Says:

    Hi Evin, Nice article! :) But it was pretty hard (even after reading the 2nd part) to understand how to use it in a real life app.

    After browsing through the code, this is how I understand it.

    main.js
    ——–
    main() {
    // set initial state of application
    ContactsTool.goState(‘a’,1);
    }

    core.js
    ——-

    ContactsTool StateChart object initialized here, contains function for each app. state (as per statechart diagram)

    // ContactsTool.goState(‘a’,1); becomes a call to state handler function ContactsTool.goStateA1
    // the initial login screen is loaded (see login.js)
    goStateA1: function() {
    //login screen
    this.set(‘mainView’, ‘ContactsTool.loginPage.mainView’);
    }

    login.js
    ——–
    Custom page is created with a button. Clicking the button results in the action ’submitLogin’ on the target ContactsToll (StateChart)
    Thus the StatChart will handle this action

    Back in core.js
    —————-
    //core actions

    submitLogin: function() {
    var handled = NO;

    switch(this.state.a){
    // if I came from state A1 (initial login screen)
    case 1:
    // I will go to state A2
    this.goState(‘a’,2);
    handled = YES;
    break;
    }
    // error! I shouldn’t end up here. Only valid entry point is from initial login screen!
    if(!handled) console.log(‘ContactsTool#submitLogin Action not handled in state %@[%@]‘.fmt(‘a’,this.state.a));


    and so on from here… :)

    Any comments?

  2. Evin Says:

    @Kristian

    If you are going to do a very simple straight forward application it is probably better to use the rootresponders like in /sproutcore/apps/tests/states…

    The implementation that I used and wrote about is for most complex applications that need to keep track of parallel states, history states and complex substates.
    Looks like you have a good grasp of what is going on in the state charts… it is really hard to understand what to do until you start to actually code an app with a state chart. The idea is all ‘actions’ take place on the global application namespace. So in your application if you have a ‘target’ and ‘action’. ie Buttons, dropdowns etc that trigger events on you app. Then you are able to sort out based off of where you are on the application (state) to trigger events or processes.

    if you would like, I can set up a web meeting to show you some advanced stuff with state charts that we are doing…jsut send me an email.

    Evin (etgryphon)

  3. Larry Siden Says:

    I had the honor of hearing D. Harel talk about state-charts back in the early ’80s at our regular symposium when I was a grad-student at the Hebrew U. of Jerusalem. I was quite impressed even then. This example w/ login is example what I need for the next stage of my app development and I plan to use it! Thank you, Erich O.!

Leave a Reply