MVC Pattern with Javascript

We’ve been pushing pretty hard at work recently to become masters of the javascript language.  Since we use it so extensively, and recent browser improvements such as compilation to native code of javascript … it means that it’s certainly not going away.  On the server-side, we use ASP.NET MVC and have come to be quite fond of the pattern. I wanted to explore what it would look like to use the MVC pattern in javscript so that we can use it some of our more complex pages.

The first thing I did was poke around on the web to see if there were any existing frameworks I could simply use.  I found a few such as:

Most of what I saw was either a bit too heavyweight for my tastes, or had the wrong focus, such as moving databinding from the server to the client.  So I decided to try my hand at implementing it for myself. 

The sample app/page that I implemented was a super simple list application that lets you type in some text, which gets sent to the server in an ajax call.  The status of the operations would be collected in a list on the page.  Although this is a fairly simplistic example, it has enough moving parts to show off the pattern.

The Dependencies

jQuery, my favorite uber framework of choice.

I tried to make this as simple of an example as possible. However, I recently purchased the book “Pro JavaScript Design Patterns, and there was a pattern in there that I really liked and wanted to use.  This pattern is the observer pattern.  I didn’t take the full code provided in the book, just what I needed.

//– publisher class —
function Publisher() {
    this.subscribers = [];
};

Publisher.prototype.deliver = function(data) {
    this.subscribers.forEach(function(fn) { fn(data); });
};

//– subscribe method to all existing objects
Function.prototype.subscribe = function(publisher) {
    var that = this;
    var alreadyExists = publisher.subscribers.some(function(el) {
        if (el === that) {
            return;
        }
    });

    if (!alreadyExists) {
        publisher.subscribers.push(this);
    }
    return this;
};

I used this so that the model can essentially raise events that the controller can listen to.

The View

Getting started, the first thing I implemented was the view.  I started with a few very simple html elements.

<input type="text" id="name" />
<input type="button" value="add" id="addButton" />
<ul id="list">
</ul>

Then I implemented the view.  Note that I’m using the literal object notation instead of the classic object oriented syntax to declare these classes.  I did this because I only need one instance of these classes.

var view = {

    init: function() {
        this.name = $("#name");
        this.addButton = $("#addButton");
        this.list = $("#list");

        this.addButton.click(function() {
            controller.addItem(view.name.val());
        });
    },

    appendItemToList: function(item) {
        this.list.append($("<li>").text(item));
    }
};

The init function uses jquery to pull references to the UI elements and also to set event handlers.  It also exposes the “appendItemToList” function, which concerns itself with taking a line of text and adding it to the list.

The Model

Next, I wrote the model, which would be responsible for communicating with the server in this case.  All of the issues surrounding server communication would be handled in this class (ie. ajax calls, callbacks, etc.). 

var model = {

    itemAddedEvent: new Publisher(),

    submitNewItem: function(item) {
        $.getJSON("/home/addnewitem/" + escape(item), null, this.submitNewItemCallback);
    },

    submitNewItemCallback: function(data) {
        model.itemAddedEvent.deliver(data.result);
    }
};

Note also that there is an itemAddedEvent which uses the Publisher class defined above.  This is used so that the model can notify the controller once the ajax call has returned.

The Controller

Finally, the controller … which can contain all of the business logic for the page without having to be muddied up with any knowledge of the page’s html structure, or any knowledge of how to communicate with the server.

var controller = {

    addItem: function(item) {
        var valueToDisplay = ‘entered: ‘ + item;
        view.appendItemToList(valueToDisplay);
        model.submitNewItem(item);
    },

    serverItemAdded: function(item) {
        view.appendItemToList(item);
    },

    init: function() {
        this.serverItemAdded.subscribe(model.itemAddedEvent);
    }
};

The server-side action method is defined as such using ASP.NET MVC:

public ActionResult AddNewItem(string id)
{
    return Json(new
    {
        result = string.Format("’{0}’ was added by the server", id)
    });
}

Putting it all together

The last bit is simply some glue code that lets the view and controller initialize themselves.

$(document).ready(function() {
    view.init();
    controller.init();
});

As you can see, with just a few very simple techniques, the code ends up very clean and easy to maintain.  Although for smaller/simple forms even this would probably end up being way too much complexity … some of the more complex forms will certainly benefit from the added separation of concerns.

I would love to get feedback on pros/cons of this approach.  Any alternative ideas would greatly be appreciated :-)

Comments

Avoid Caching of Ajax Requests

So we recently experienced a subtle little bug in an ajax enabled asp.net mvc application that only showed up in IE7.  Turns out that the browser was caching an ajax request.  To get around it, we made the following addition to the global.asax http application class:

public abstract class MyWebApplication : HttpApplication
{
    protected MyWebApplication()
    {
        this.BeginRequest += new EventHandler(MyWebApplication_BeginRequest);
    }

    void MyWebApplication_BeginRequest(object sender, EventArgs e)
    {
        string requestedWith = this.Request.Headers["x-requested-with"];
        if (!string.IsNullOrEmpty(requestedWith) && requestedWith.Equals(”XMLHttpRequest”, StringComparison.InvariantCultureIgnoreCase))
        {
            this.Response.Expires = 0;
            this.Response.ExpiresAbsolute = DateTime.Now.AddDays(-1);
            this.Response.AddHeader(”pragma”, “no-cache”);
            this.Response.AddHeader(”cache-control”, “private”);
            this.Response.CacheControl = “no-cache”;
        }
    }
}

Basically, any request that comes in with the x-requested-with header (which most or all ajax libs use) will get these extra headers added to the response to tell the browser to avoid caching.

Hope it helps someone else out there :-)

Comments (2)

VSClean Command Line Tool

I don’t know about you, but I have a lot of code on my computer.  As anyone who follows me on Twitter knows, I’m often running out of space on my laptop.  So yesterday, I was running WinDirStat on my harddrive to see what I could clean up.  I found that I had a significant amount of space spent on the contents of my /bin/* folders.  As any developer would know, this is where Visual Studio places binary files when it compiles.  So any time I have a visual studio solution from some old project, inevitably, I’ll have tons and tons dlls and exes just sitting around, not to mention content that may be part of the solution such as .mdb files, and in the more extreme cases, XNA game content.

So I started opening the folders and deleting them when I lamented that I wished I could just tell visual studio to run a Clean Solution command on all these files.  Then it hit me, visual studio uses MSBuild to do it’s compiling.  So why not write a simple tool that recurses through my dev directory and runs the msbuild clean command on all the solutions it finds.  Brilliant!

To that end, I’d like to introduce the command line tool VSClean. 
Download here: http://codecube.net/bloguploads/VSClean.zip

The zip file above is the source code.  Once you compile it, just run it from the command line and pass in your root source code directory as the first parameter:

> VSClean “c:\dev”

Once you run this, it’ll iterate through all the folders in that directory looking for .sln files.  Once it finds them, it runs this command:

C:\Windows\Microsoft.NET\Framework\v3.5\MSBuild.exe “c:\dev\theSolution.sln” /m /t:clean

Of course, if you’ve installed the framework in a different path, you’ll have to change the const variable at the top of the class.  Once this is done, you can feel good that all of your old source code isn’t taking up unnecessary space :-)

Comments (2)

Bayesian Filtering with C#

Introducing nBayes, a new open source projectnbayes_logo which can be found here:

http://nbayes.codeplex.com/

nBayes is a simple implementation of the naive bayesian spam filter described by Paul Graham in his essay "A Plan for Spam" (http://www.paulgraham.com/spam.html). The API is very simple, there are just 3 classes that you need to be familiar with.

You can train the Index by adding entries to it, and then use an Analyer to categorize a new entry as belonging to one index or another. In the spam filtering example, one index would be the Spam, while the other would be the "not-Spam".

Sample Code

Index spam = Index.CreateMemoryIndex();
Index notspam = Index.CreateMemoryIndex();

// train the indexes
spam.Add(Entry.FromString("want some viagra?"));
spam.Add(Entry.FromString("cialis can make you larger"));
notspam.Add(Entry.FromString("Hello, how are you?"));
notspam.Add(Entry.FromString("Did you go to the park today?"));

Analyzer analyzer = new Analyzer();
CategorizationResult result = analyzer.Categorize(
     Entry.FromString("cialis viagra"),
     spam,
     notspam);

switch (result)
{
    case CategorizationResult.First:
        Console.WriteLine("Spam");
        break;
    case CategorizationResult.Undetermined:
        Console.WriteLine("Undecided");
        break;
    case CategorizationResult.Second:
        Console.WriteLine("Not Spam");
        break;
}

The example above uses an extremely small index of words … however, the reported result is indeed that it categorizes it as spam. Larger indexes are required to get better results. The sample project provided in the source code shows how to create two indexes by doing a search of twitter for two different terms. The top 100 results of that twitter API query will be trained into each respective index, and then it will ask you to type in a sample phrase. This phrase will be categorized into one of each index.

Comments

Computing for Children

I’ve mentioned to a few people that I recently set my kids up with PCs.  I think back to my first interactions with a computer when I was very young.  My parents bought an Acer IBM Clone from Fingerhut.  I learned so much from using that machine … in an effort to play prince of persia at school, my brother taught me how to make a boot disk to boot the library computer’s into DOS, then launch the game from the command line.  It really taught me a lot about the basics of how the computer works … knowledge that I know has been useful in my career.

So I wanted them to have that same opportunity.  I wanted them to be able to play games, and access learning tools on the internet; but wanted them to do it in as safe an environment as I could manage. So to that end, here’s their setup:

I did quite a bit of research before running out and getting the kids the netbooks.  Although they were relatively cheap in the grand scheme of things, I didn’t want to spend $600 bucks (for two of them) if it wasn’t going to be safe.  I made sure that their user account was *not* an administrator, and the use of Firefox with adblock gave me a pretty good feeling that they’d be safe from exploits. 

My choice of Safe Eyes was done after reading a lot of reviews.  One of my favorite features was that you could log in and manage the site whitelist from any browser … so if there was some site they needed that was getting blocked, I could just unblock it from work after a phone call from them.  Also, safe eyes can do partial filtering of sites like youtube and google search pages so they can still use the sites, without inadvertently running into content I didn’t want them seeing.

Another little trick I set up was that I made network shortcuts to each other’s laptop and taught them how to move files back and forth.  Unfortunately, this wasn’t very easy … it involved having to manually set some permissions via the command line.  I wish I would have written the steps down so I could share, but alas.  At least they can do some simple file sharing.  I figure that as long as I log on with my admin account periodically and do the windows updates, that they should remain safe.

Of course, I know that nothing is foolproof … we also employ other counter-measures such as making sure to monitor their use.  This ensures that even if there was a way around the parental controls, that there was a physical deterrent, and also it ensured that my investment is secured (ie, they don’t break them).

Wow … It literally *just* occurred to me that both my first computer, and my kid’s first computers were Acers. Go figure :-)

Comments

Twitter Search via C#

While there are some examples of accessing the Twitter API via C# on the web, I couldn’t really find any good samples of how to do a search.  There were some examples that took the REST route and used raw http requests.  While others explored the JSON formatting capabilities of the twitter API.  In the end, I didn’t really care for a lot of the code I saw, and I wasn’t really concerned with what format I got the results in, just that I got the results.

After a bit of fiddling about, I decided to use the ATOM format, and the SyndicationFeed API that came with WCF.  I came up with this simple command line tool that lets you type a search query, and it’ll list the top 10 results.  The code is quite short and simple to understand.

    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("twitter -> ");
            var input = Console.ReadLine();

            while (input != "exit")
            {
                var scrubbed = HttpUtility.UrlEncode(input);
                var reader = XmlReader.Create(
                     string.Format("http://search.twitter.com/search.atom?lang=en&q={0}", scrubbed));
                var feed = SyndicationFeed.Load(reader);

                foreach (SyndicationItem item in feed.Items)
                {
                    Console.WriteLine("\t{0} - {1}", item.Authors[0].Name, item.Title.Text);
                }

                Console.Write("\ntwitter -> ");
                input = Console.ReadLine();
            }
        }
    }

To use it, you just need to add references to System.ServiceModel.dll, and System.Web.dll.

Enjoy!

Comments (3)

Innovation and Startups in Orlando, FL

So I’m reading this book, Founders at Work.  In the book Jessica Livingston, one of the co-founders of Y-Combinator, interviews a bunch of founders of famous companies who started off in basements and bedrooms. I haven’t completely finished it yet, but I wanted to make an observation that so far has been almost universal in all of the founder interviews.

Many of them took Venture Capital to get them started, and many of them moved to the west coast.

Now, much has been written and said by people like Joel Spolsky on the benefits of bootstrapping your business instead of taking VC.  But that’s not really the part that I wanted to comment on (perhaps another day).  I wanted to comment on the exodus from the east coast that always seemed to happen (if they weren’t already on the west coast).

Brewster Kahle, of Alexa says in the book:

Boston, especially back in 1990/91, was in recession and having trouble. California was also in recession, but in California there were dreamers. There were people who wanted to think about new and different things and wouldn’t think we were crazy to try to build this thing.

Even YCombinator itself moved out to California:

But we did worry that the Boston groups were losing out. Boston just doesn’t have the startup culture that the Valley does. It has more startup culture than anywhere else, but the gap between number 1 and number 2 is huge

Now, despite the fact that the two examples I chose moved out of Boston specifically, you can find lots of other examples if you look hard enough. Living here in Orlando, fl … it kind of makes me wonder what it is about the culture over there that seems to breed such innovation.  Or rather, what attracts it.  I know for a fact that innovation is happening here every day.

For example, a local developer (Paul Varcholik) is doing some awesome research at UCF on Multi-Touch interfaces.  Bill Reiss is starting up a venture to host and monetize games written in Silverlight (Tampa, but close enough :-P ). And locally run blog GameJobHunter (written by Paul Teall) has a post detailing local Video Game studios in Orlando.  These are definitely bright spots … however, what will happen when they create their inevitable innovation or breakthrough? Will these pioneers feel that they need to move out west for people to take them seriously or to fund them?  Will they find a lack of community, or even talent to help them locally?

I’m hopeful that this is not the case.  The number and size of user groups in the area have been steadily growing of the last few years. There are a large number of free codecamps put on in Florida which offer a huge amount of sessions.  There has never been as much community available as there is now … and that’s great!  However, the mere presence of these user groups does not equal success.

On both sides of the fence, I feel that things need be brought to the proverbial “next step”. The opportunities for brainstorming, sharing knowledge, and even recruiting help from like-minded individuals are there. Everyone needs to start dreaming bigger, taking chances, executing on ideas. And I’m not the only one that sees this … others have made similar observations,

The fact is that we can’t expect to improve the tech startup climate on the east coast if we don’t come together and make it what we want it to be. And that means we need to stop looking over our shoulder at the west coast and start building businesses here and now …

This is a call to action to the local development community … show up to that next user group meeting.  Bring your ideas with you, there are lots of ways to foster discussion about your idea without talking about it directly (if you fear it’ll be poached by others).  And if you don’t think you could actually execute on your idea, talk freely about it.  Perhaps it will spark someone else’s imagination.  I want to see Central Florida in the news touting our innovative startups, products, and high-tech services.

I’d love to hear other’s thoughts on how we can encourage this :-)

Comments (3)

XNA GS 3.1 and Scurvy.Media

So unless you’ve been living  under a rock (and/or don’t care about XNA :-P ), you obviously know that v3.1 was announced last week during the GDC.  Not a lot of info has really been put out there as far as specifics go, this seems to be one of the best sources so far:
http://blogs.msdn.com/astebner/archive/2009/03/24/9506368.aspx

    • Support for customized Avatars
    • Support for Xbox LIVE Party features
    • Video playback
    • Updated audio APIs for “fire-and-forget” scenarios
    • Support for XACT3
    • Automatic XNB serialization
    • XNA Framework multi-targeting in the Visual Studio 2008 and/or Visual C# 2008 Express Edition IDE
    • Downloadable content for Xbox LIVE Arcade titles that use XNA Game Studio 3.1
    • Consumer notifications when an Xbox LIVE Community Game that they have purchased has been updated

Of course, the video playback feature stood out for me, as it would seem that it will affect the Scurvy.Media project.  I’ve been getting some questions on the matter so I figured I’d just put my current thoughts out there.

Basically, I think it’s great :-) even if it ends up making the library completely obsolete.  I imagine that they will have ways around some of the roadblocks I encountered such as large filesize issues, and texture compression.  Depending on how their feature is factored, there *may* still be a place for Scurvy.Media … for example, I believe I read somewhere on the forums that it will only support WMV (don’t quote me on this, I may have misread or am not remembering right).  But if this is the case, and they’ve factored some level of extensibility into their API, then Scurvy.Media may add support for AVI videos.

In the end, I’m quite happy to see this and the other features coming out … looking forward to giving the beta a shot when it’s announced eventually :-D

Comments (2)

MapReduce in C# using LINQ

I recently remembered reading this article by Dare Obasanjo (Functional Programming in C# 3.0: How Map/Reduce/Filter can Rock your World) a long while ago, which was partly a response to Joel Spolsky’s article (Can Your Programming Language Do This).  In that article, Dare maps the map/reduce/filter functions to the following Linq equivalents:

  • map -> Enumerable.Select
  • reduce -> Enumerable.Aggregate
  • filter -> Enumerable.Where

At the time, I hadn’t really had a business need to play with Linq aside from casual curiosity … all of the projects at work were using other techniques for data access.  But more recently, we’ve been using linq more and more, and I experimented with how a rewrite of a feature might look if it had been written using a functional programming style with LINQ.

My experience with that reminded me of something I had read even longer ago, Google’s famous MapReduce paper (MapReduce: Simplified Data Processing on Large Clusters). Now, most of that paper deals with how they distribute the load across a large cluster of computers.  But near the very beginning, they have some small examples of the types of problems that could easily be solved by mapreduce, and even a sample pseudocode implementation of one of those programs.

map(String key, String value):
    // key: document name
    // value: document contents
    for each word w in value:
        EmitIntermediate(w, "1");

reduce(String key, Iterator values):
    // key: a word
    // values: a list of counts
    int result = 0;
    for each v in values:
        result += ParseInt(v);
    Emit(AsString(result));

Note the structure of the various inputs and outputs … in particular, the output of map (which serves as the input to reduce).  It’s a key along with an iterator of values that matched that key.  That sounds exactly like what GroupBy does.  Check out the description from this article:

The standard query operators also include the GroupBy operator, which imposes a partitioning over a sequence of values based on a key extraction function.

Using linq, I can implement the mapreduce program described above:

var wordOccurrences = words
                .GroupBy(w => w)
                .Select(intermediate => new
                {
                    Word = intermediate.Key,
                    Frequency = intermediate.Sum(w => 1)
                })
                .Where(w => w.Frequency > 10)
                .OrderBy(w => w.Frequency);

as you can see … based on google’s definition of MapReduce, I think that Dare was incorrect in asserting that select maps to map (no pun intended), and aggregate maps to reduce.  In this example, the GroupBy method is acting as the map, while the Select method does the job of reducing the intermediate results into the final list of results.

The obvious caveat here is that this isn’t distributed, it will run locally in memory.   But even without the massive scaling that google’s mapreduce data center can provide, it can be useful to think of problems in this mindset.  And when the parallel extensions for linq are finally released, you might even be able to easily take advantage of multiple cores.

Comments (1)

InstantRails: First Impression

So on a lark, I installed InstantRails last night to see what all the hubbub was about.  I grabbed the latest (v2.0) and set to following some getting started steps from a book. 

Unfortunately, it seems that things aren’t quite as easy as just downloading and getting started.  Just trying to start up a sample/demo site responded with a bunch of errors … so I ended up having to do a bunch of updates to the environment.  These are the commands I had to run to get to a point that I could run “rails demo”

gem update rails –include-depencies
gem install activerecord
gem install rake
gem install actionpack
gem install actionmailer
gem install activeresource
gem update –system

I mean, it was ultimately not too bad, but at the same time, not a great first impression.  So far, lots of the same concepts that I’ve gotten used to in ASP.NET MVC seem like they found their roots in RoR … so it’s good to see them in their original context.

Comments (1)