M.E. Harris LLC

  • Archive
  • RSS
  • Ask me anything

Statecharts and Sproutcore

I just recently learned how important it is to actually design your statecharts before you code them up.  When I initially started with Ki in Sudoku, I was designing in my head — i.e. I was creating states on the fly as I needed them.   I knew I was doing something  shady as I had comments like ‘this is wrong’ and ‘create separate state for this’ and ’ duplicate code, refactor later’ all over the place.

Designing the statecharts in OmniGraffle has simplified my Sudoku app drastically.   

Here is what I came up with:

and

The great thing about having these pictures is they show you *exactly* how the app works.  This means there is no question about what events are possible in which states.  

Lets start by examining what these diagrams mean.  In the first diagram, you can see that there are 2 high-level states: 1) the playing state, and 2) the paused states.  Paused is a state with substates, which is indicated by the double border.  The little circle with the arrow to the paused state indicates that the paused state is the initial substate of root.  The arrow from play to paused indicates that you can transition from the play state to the paused state.  The text above the arrow indicates which events lead to which paused substate.  The green box attached to each state indicates which events fire in the state, but don’t cause a state transition.  

In the second diagram, I break down the paused substates. You can see the initial substate is GeneratingNew.  You will also notice the dotted border, which indicates that GeneratingNew is a transient state.  A transient state is a state the the application enters, does its thing, and then leaves with no user interaction.  From GeneratingNew the chart proceeds to BoardReady.   When the user causes the start event (via a button or a key combo), the chart proceeds to the playing state.

What did I just say in non-statechart terms?  ”When you load the app, a new board is generated, and when the user clicks start, the game starts.”

You will also notice that in the lower left and upper right of the diagram, I have references to the Playing state.  On the paused-states chart, the playing state is external, indicated by the grayed text and shadow around the box.  Its presence is just for reference, and makes explicit the various ways that you can get to the paused states and back to the playing state.

Lets follow a simple example of how the statechart defines the interactions of the user with the app.  Start in the lower left corner of the paused states, at the external playing state.  You will notice there is an arrow with the label “pause”, that points to the gamePaused state.  From that state, there is an arrow back to playing.  Hopefully you can see that this cycle on the chart shows the app behavior when the user is playing and hits the ‘Pause’ button.

Another simple example:  Start at the lower left again.  You will see an arrow that goes from playing, with the label “giveUp”, that goes to the beginGiveUp state.  From there, the user has a choice.  Either the user gives up (yes event), and proceeds to the gameOver state, or the user says no and proceeds back to the playing state.

So to figure out how the use cases of an application work, you just need to follow the arrows.

Lets look at some high level code of the startup scenario I described.  The user loads the app, and that statechart enters paused, generatingNew, and then boardReady.  From there the user can hit “Start” (i.e. cause the start event) to go to the playing state. 

Sudoku.Statechart = SC.Object.create(Ki.StatechartManager, {

    rootState: Ki.State.design({
        initialSubstate: 'paused',

        paused: Ki.State.design(Sudoku.GenerationHandlers, {
            initialSubstate: 'generateNew',
            generateNew: Ki.State.design({
                enterState: function() {
                    SC.Logger.log('entering generate new state');
                    ...
                    Sudoku.sudokuController.set('content', b);
                    this.gotoState('boardReady');
                }
            }),

            boardReady: Ki.State.design({
                enterState: function() {
                    SC.Logger.debug('Entering board ready state');
                    Sudoku.setPath('mainPage.maskMessage.value', "Click the Start Game button to begin.");
                    Sudoku.setPath('mainPage.startPauseButton.title', 'Start Game');
                },

                start: function() {
                    SC.Logger.debug('start game event');
                    this.gotoState('playing');
                }
            }),
           ...
        }),

        playing: Ki.State.design(Sudoku.GenerationHandlers, {
           ...
        })
    })
});

There it is — the code mirrors *exactly* what you see in the picture, and exactly what I described.  You see the 2 high level states, the initial substate values which drive the state transitions when the app loads, the generateNew state which proceeds to the boardReady state, and the start event handler on that state that goes to playing.  The ellipses indicate I skipped over some code that is not germaine to the point.  Notice that I also threw a little extra in there — From the state chart diagrams, you can see that the generateNew functionality can be invoked from both the playing and the paused states.  What I did was to integrate those handlers via SproutCore’s mixin system.  I created an object literal call Sudoku.GenerationHandlers, which contains just functions:

Sudoku.GenerationHandlers = {
    ...
    generateNewLow: function() {
        ...
        this.gotoState('startBoardGeneration');
        ...
    }
    ...
};

Which I could then use when designing the states.  It doesn’t get much simpler than that, and allows me to stick to the DRY (Do no Repeat Yourself) principal.

Here is a good example of using the statechart machinery to configure the application views.  In sudoku, when in the playing state, the clock is running, and the board is visible and enabled.  When in the paused state, the clock is paused, and the board is masked and disabled.  So on the playing state I added the following methods, which are part of the State API:

enterState: function() {
    SC.Logger.log('Entering playing state.');

    Sudoku.setPath('mainPage.board.isEnabled', YES);
    Sudoku.setPath('mainPage.startPauseButton.title', 'Pause Game');
    Sudoku.setPath('mainPage.mask.isVisible', NO);

    Sudoku.playingController.set('isPlaying', YES);
    Sudoku.clockController.set('paused', NO);
    
    Sudoku.getPath('mainPage.board').becomeFirstResponder();
},

exitState: function() {
    SC.Logger.log('exiting playing state');
    Sudoku.setPath('mainPage.maskMessage.value', "");
    Sudoku.setPath('mainPage.mask.isVisible', YES);
    // since the input pane is not modal, remove it if we go to paused
    Sudoku.InputView.pane.remove();
    Sudoku.clockController.set('paused', YES);
},

You can see here that I am just making the mask visible/not visible, starting/stopping the clock, setting some view labels, and setting some values on controllers. You will notice that in the enterState function, I set the playingController value to YES, but don’t set it to no in the exitState function — I handle that in the paused state’s enterState method so the value is initialized when the statechart is first entered.

This feature of statecharts is immensely helpful - I only put the code to configure the views in one place.  If I were managing events on controllers, then I would have to be very careful to avoid duplicating code.  

Let’s make explicit the example on how to control application flow via statecharts. You will notice that the beginGiveUp state allows the user to cancel, or proceed to game-over. Here’s the code that makes that happen:

beginGiveUp: Ki.State.design({
    enterState: function() {
        var scope = this;
        Sudoku.setPath('mainPage.maskMessage.value', "");
        var paneController = SC.Object.create({
                alertPaneDidDismiss: function(pane, status) {
                    switch (status) {
                        case SC.BUTTON1_STATUS:
                            Sudoku.sudokuController.get('content').giveUp();
                            scope.gotoState('gameOver');
                            break;
                        case SC.BUTTON2_STATUS:
                            scope.gotoState('playing');
                            break;
                    }
                }
           });
        SC.AlertPane.info("Are you sure you want to give up?", "", "", "Yes", "No", "", paneController).append();
    }
}),

Note that I had to capture the statechart scope in a closure (the ‘scope’ variable) so it pointed to the correct context in the object that acts as the pane’s controller.  Other than that, the example is the standard way yes/no panes are constructed with Sproutcore.  If you are not using statecharts, then you are probably doing this type of thing in methods on controllers that act as event handlers.

Speaking of event handlers, how do I capture events in the statechart?  If you followed the Ki setup instructions, then you are making your statechart the defaultResponder on your Panes:

mainPane: SC.MainPane.design({
    defaultResponder: Sudoku.Statechart, // <-- do that any time you have a pane and want the actions to go to the statechart

Finally, lets look at an example of how to integrate undo management into your code.  Whenever a value changes in any cell, I need to register a function with an instance of SC.UndoManager.  These functions go on the playing state:

// ---------------------------------------------------------
// Playing Events
// ---------------------------------------------------------

valueEntered: function(caller, ctx) {
    SC.Logger.debug('value entered event.');
    var content = caller.get('content');

    var undoFunction = function() {
        content.set('notes', ctx.old);
        content.notifyPropertyChange('notes');
        SC.Logger.debug('setting content index [%@] to [%@]'.fmt(content.get('index'), ctx.old));
    };

    Sudoku.undoController.get('undoManager').registerUndo(undoFunction);
},

undo: function() {
    SC.Logger.debug('undo event.');

    var undoManager = Sudoku.undoController.get('undoManager'),
        canUndo = undoManager.canUndo();

    if (canUndo) {
        var result = undoManager.undo();
        SC.Logger.debug('undo success: [%@]'.fmt(result));
     }
},

Can you spot the other use of closures here?  By declaring the variable ‘content’ (the value for which I get off the scope passed to the event), and using that variable in the undo function, I’ve created a closure.  Note that that function gets executed at some later time, when undo actually happens.  Yay closures!

So how do I invoke the valueEntered and undo functions?  In Sudoku I have a Cell view for each cell on the board, with the standard keyDown handler. In the handler, I put

var content = this.getPath('content');
Sudoku.Statechart.sendEvent('valueEntered', this, {old: this.getPath('content.notes').copy()});

I am using the sendEvent method on the statechart. The values I pass to the method are: 1) the event to fire (the ‘valueEntered’ string matches the function name on the statechart), 2) the caller argument of the handler, in this case the cell that is sending the event, and 3) an object literal that contains the information I need to set up undo.  Note that the second and third argument of the sendEvent method become the first and second argument on the actual method in the statechart.

How do I fire the undo event?  

// evt is passed to the keyDown handler on the viw
var commandCodes = evt.commandCodes();
if (commandCodes && commandCodes[0] === 'ctrl_z') {
    SC.Logger.log('ctrl_z detected.');
    Sudoku.Statechart.sendEvent('undo');
    return YES;
}

Pretty nifty, how Sproutcore wraps up multi-key events for you.  So there is a full undo functionality in about 30 lines of code, that uses keybindings, including blank lines and log statements. Not bad eh?

This post has covered a lot of ground.  The main points are:

1) A picture is worth a thousand words.  Designing the statecharts is the hard part, coding them is the easy part.  You should do the former before the latter to save yourself some headache.

2) Statecharts are an incredible abstraction for separating the code that controls how the application behaves from the rest of the code.  This leads to simpler code everywhere and helps you stay DRY.  The fact that Sproutcore has a solid statechart framework speaks to Sproutcore’s strength as an *application framework*, and not just a framework of components.

  • 2 years ago
  • Permalink
  • Share

Out of Memory with Grails and Ehcache

So for the past few months, a Grails application for one of my customers has been crashing due to an out of memory error.  Here is how I went about determining the cause and fixing it.

1.  I configured Tomcat to dump the heap on a crash by adding the following line to the Tomcat catalina.sh file

export CATALINA_OPTS=”-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdumpdir

2.  Once I got a crash, I used scp to get the heapdump onto my development computer.  I fired up jvisualvm to see what was going on in the heap.

3.  I had jvisualvm compute the retained sizes of the top 20 classes (which took a while).  Here is what I saw

4.  EhCache!! Doh!!

5.  I thought, wait a minute, surely ehcache in Grails comes with some reasonable defaults that would prevent it from, say, consuming 1.8 GIGABYTES OF MY HEAP.  It turns out it does.  The default configuration that grails uses is buried in the ehcache jar.  If you do not provide an ehcache in your grails-app/conf, this file is used.  In it is 

 <defaultCache
            maxElementsInMemory=”10000”
            eternal=”false”
            timeToIdleSeconds=”120”
            timeToLiveSeconds=”120”
            overflowToDisk=”true”
            maxElementsOnDisk=”10000000”
            diskPersistent=”false”
            diskExpiryThreadIntervalSeconds=”120”
            memoryStoreEvictionPolicy=”LRU”
            />

What happens is ehcache uses this configuration to create a cache for every domain model class you want to cache.   So, by default, every domain model class (that you cache) will have up to 10k instances in the cache.  Thats a lot, but that shouldn’t be 1.8GB worth of data.  

When I dug into the top two offending classes (Cache#15 and MemoryStore#9), I found that ehcache was also caching my queries, i.e. it was keeping the last 10,000 queries and their results in memory. It was doing that because, well, we told it to cache queries by configuring Datasource.groovy with 

hibernate {
    cache.use_second_level_cache = true
    cache.use_query_cache = true
    cache.provider_class = ‘net.sf.ehcache.hibernate.EhCacheProvider’
}

The Solution

The solution was to create a custom ehcache.xml file and drop it in grails-app/conf.  I added the following xml to it:

<cache name=”org.hibernate.cache.StandardQueryCache”
           maxElementsInMemory=”100”
           timeToIdleSeconds=”300”
           eternal=”false”
           overflowToDisk=”false”
           timeToLiveSeconds=”600”
           diskPersistent=”false”
            />

here I am limiting the query cache to the more reasonable last 100 queries.

So I dropped my new custom ehcache.xml file into my deployed app, restarted tomcat, and memory use appears stable.  We have some spikes, but we always get back to about 200MB of heap usage (so far), which seams reasonable.

  • 2 years ago
  • 1
  • Permalink
  • Share

Sudoku For Google Chrome

Sudoku is a project that started as an attempt to keep up on my Sproutcore and JS skills, and turned into one hell of a web application.  It is a fully featured HTML5 Rich Internet Application that allows players to generate sudokus of varying difficulties on the browser.  

You can find it here 

http://chrome.google.com/webstore/detail/ifaabgmcffhggbfgjknkgenljelbocin

  • 2 years ago
  • 3
  • Permalink
  • Share

About

M.E. Harris LLC has been providing high quality consulting services companies in the northern Virginia area for over 5 years. Past clients include industry leaders: Verisign, Finra, and Eloqua. M.E. Harris LLC specializes in multiple technologies across the entire application stack, from the server to the client. Feel free to contact me at meharrisllc@gmail.com
  • RSS
  • Random
  • Archive
  • Ask me anything
  • Mobile

Effector Theme by Carlo Franco.

Powered by Tumblr