SproutCore Mailing List Crosses 800

The SproutCore mailing list crossed 800 members yesterday.  Pretty impressive considering that just over a month ago fewer than 50 people were on the list.  The mailing list is growing quickly everyday as are the number of interesting cool apps people are building with the framework.

Which reminds me: the first SproutCore Demo Competition is coming to a close in just three days.  The purpose of this competition is to give you a place to show off what you achieved in just a couple weeks with SproutCore.  This is just a demo contest and everyone is new to SproutCore so no demo is too simple to show.  Let us see your work!  

I’ll review the code of at least the first 10 entries and provide feedback so you can get some help from the experts on how make your SproutCore app really shine. 

Link up your entry on the wiki page.

 

OpenSocial and SproutCore

Johannes posted a great tutorial about how to use SproutCore to create a social application using Google’s OpenSocial. It is worth a read.

http://blog.springenwerk.com/2008/07/socialsprout-using-sproutcore-in.html

Modern Models

Onitunes has been hard at work the last few weeks writing an excellent tutorial on the model portion of SproutCore Model-View-Controller architecture.  It’s a great explanation of how to use models in your own applications.

Check out SproutCores Modern Models.

Using SproutCore with ASP.net

What kind of backend server technologies does SproutCore work with?  Anything.  And to prove it, cpomer just posted an excellent tutorial on building a SproutCore app and paired backend service in ASP.net.

Way to go!

(BTW, take a look at that wiki while you are there.  It’s hard to believe its only been up a week.  The community around this project is amazing!)

 

A Podcast with Charles Jolley by Ajaxian

Ajaxian, a community of “Ajax”-ians , just posted a podcast that features Charles Jolley in an interview about SproutCore, recorded up in Palo Alto.  Give it a listen here - http://ajaxian.com/archives/audible-ajax-episode-27-sproutcore-with-charles-jolley

Dispelling some confusion about SproutCore

whump says:

While SproutCore uses Ruby to generate static HTML and JavaScript files, you are not tied to Ruby or Rails in production.

SproutCore runs in the browser, your production system can use whatever backend you want, as long as it sends JSON to the browser.

This is true, though you could use any format; not just JSON.  JSON is faster though because it is simpler in structure. Most browsers I tested could parse incoming JSON 10x faster than they could setup DOM for XML.

Anyway, whump’s post is a good clarification about using SproutCore with non-ruby backends from someone who has been there.

Read Dispelling Some Confusion About SproutCore

 

30-second Tutorial on Models

To Create a New Model

In your terminal:


cd project-name
sc-gen model contacts/contact

This creates:

 

  • The model file in clients/contacts/models/contact.js
  • The unit test in clients/contacts/tests/models/contact.js
  • A fixtures file in clients/contacts/fixtures/contact.js

 

To Create Some Models

The attributes you get from the server should be simple JSON hashes.  They must have at least two properties:

 

  • type: A string identifying the model type.  By default, use the class name.  In this case “Contact”.
  • guid: A unique identifier.  This will be used to auto-merge/update records in the future.

Here is an example of some JSON data:


var records = [
  { type: "Contact", firstName: "Charles", lastName: "Jolley", guid: "contact-1", favoriteNumber: "3" }
];

 

All models are kept in an in-memory database called the Store.  To add records to the Store, you just get these data hashes from your server in whatever way you like and add them to the store like so:

SC.Store.updateRecords(records);

records should be an array of one or more data hashes.  Note that you can call this method as often as you need.  If you pass in data hashes with a type/guid matching an existing record, then the hash will simply update the record.  Otherwise, one new record instance will be found for each item.

If you want to try the following examples without having to create a new app, you can simply add some sample records to the fixtures file created in Step 1 above.  These fixtures will be auto-loaded into the Store on app load.

To Get Records

In your app, you can retrieve some records from the store using finder functions.  This call will find all the contacts in the store (this does not contact your server, it just uses whatever is in the local datastore.  You should load your records into the store first.):

var recs = Contacts.Contact.findAll();

To Edit Records

Just set and get properties on them.  If the properties are string type, you don’t even need to declare them:


var rec = Contacts.Contact.findAll()[0];
rec.set(’firstName’, ‘Joe’); // changes the firstName to Joe.

If you have a property that is not a string but some other type, you can add a line to the Contact class declaring the type:


Contacts.Contact = SC.Record.extend({
  favoriteNumberType: Number
});

Now when you get/set the favoriteNumber property, the Contact record will automatically convert it to/from a number.  This works for dates and can even work for other model objects, but that is for another tutorial.

To Save Records

You can get back out the attributes hash of a record by getting the attributes property:


var rec = Contacts.Contact.findAll().first();
var attrs = rec.get('attributes');

This will be a JSON-compliant hash that you can serialize and send back to your server in your favorite way.

Conclusion

That’s it for part 1.  There is a lot more you can do with the model layer.  As usual, the in-source docs are best and can be views on the doc viewer page.

 

Downtime

Well that was fun.  SproutCore made it on Digg today, which was cool.  But it brought down my cheap-o dreamhost shared server that I was using as a placeholder until we launched.  We are now up on the Sproutit-sponsored VDS we had planned from the beginning and everything should be available again.

Sorry for the offline!

Understanding the IE DOM

Many developers I know don’t like working with IE because it is so “incompatible” with Firefox and Safari.  This is true, but what most people don’t know is that 90% of IE’s problems are actually isolated to just one part of it’s JavaScript implementation and if you work with that one part correctly, you can largely avoid the potholes that make cross-browser such a pain.

A Tail of Two Doms

The DOM is the in-memory representation of an HTML document.  Most people know the DOM from its familiar JavaScript API like insertBefore(), removeChild(), cloneNode() and so on.  But actually, the DOM is much more than that.  Whenever a web browser reads in an HTML document, it builds an in-memory representation of that document — a graph of objects called the “Document Object Tree”, but which people usually refer to as the “DOM”*.

Now the real DOM used by wedding browsers is not really JavaScript; it’s native code, written in C++.  This makes the browser very fast and parsing and displaying HTML but it presents a problem for the JavaScript.  How do JavaScript scripts get access to the objects in the DOM?  It turns out that IE and FireFox/Safari/Opera diverge significantly on this point and it is the single biggest cause of browser incompatibilities that I know.

The Peer Model

Intentional or not, both Webkit and Firefox as I understand handle this problem in a similar way.**  They create, in effect, a parallel tree of semi-pure JavaScript objects that match exactly the C++ DOM objects used to render and display the page.  The figure below shows how this works. (Using my handy Skitch whiteboard…)

(Interesting aside, btw, most browsers actually have a third parallel tree of peer objects called Display Tree or something like that.  This is a set of native objects written in C++ that actually handle drawing the DOM objects in your window.  A web page is really much more sophisticated than it looks!)

It turns out that the peer model for JavaScript is actually a very nice one because the DOM objects you see when you write JavaScript are real JavaScript objects.  They have prototypes, inherit methods, throw exceptions, and can even have their properties overridden.  This makes it easy to do nifty tricks like enhancing the root HTMLElement class to add the $() method like jQuery and Prototype do.  It also means that DOM objects tend to have largely the same behavior as other objects so you can reliably predict how they will behave in most situations.

The Wrapper Model

IE, on the other hand, takes a much different approach to exposing the DOM in JavaScript.  DOM objects in IE are essentially “wrapped” by a thin veneer in the JScript engine that makes it possible for you to query and set properties and call methods on these native C++ objects through script.  The figure below shows the difference with this model.

Now, actually, wrapping the DOM elements like this in IE does have its advantages.  In some ways you are much closer to the metal of the browser so to speak and therefore able to exert a bit more control.  The dreaded hasLayout property for example exposes some good internal information about how IE will treat the rendering of an element that would be useful in other browsers when trying to deal with complex layouts.  (The programming by side-effects model required to manipulate this property, of course, is another matter.)

On the downside, however, wrapping DOM elements makes IE subject to the effect of leaky abstractions.  Since DOM objects are not real JavaScript elements, sometimes they don’t behave just like you expect.  In fact, if you’ve ever hit one of these doozies, you’ve been bitten by the DOM-Wrapper IE bug:

 

  • You set a property on a DOM object and that property mysteriously changes to some other value; even if it is not part of the DOM’s published API.
  • You tried to modify the prototype of the DOM element (i.e. HTMLElement) and discover it doesn’t show up on existing DOM objects.
  • You added a method to the Function prototype, yet certain functions on DOM objects seem not to have them.
  • You try to iterate through the key/value pairs on a DOM element and certain keys you expect to see are not included (actually this one can happen in FF at times because of their own leaky-abstractions.)
  • You store a JS objects in some property on a DOM element and now it leaks when you leave the page. Yep, the dreaded IE memory leaks are caused by wrapping behavior in IE.

 

The list goes on and on.  Weird, seemingly unexplainable behavior suddenly makes sense when you realize the object you are working with is not JavaScript, even though it pretends to be so; it is a native C++ object only posing as one instead.

How to Program IE with Less Pain and More Joy

The models used by Firefox/Webkit and IE are plainly very different when it comes to the DOM.  How can we use this power to our advantage?  The answer is quite simple:  treat all DOM objects like foreign objects.  Forget that they are JavaScript in Firefox and Safari.  Don’t add properties or methods to DOM elements.  Don’t fiddle with their prototype definitions.  Only work with their published APIs.

Use the best practice followed by the browsers and create a peer tree of pure JavaScript objects that can mange your DOM elements for you.  These view objects can have all of your special high-level methods for manipulating the DOM build in and manage the DOM objects in your tree for you.  Conveniently, this also creates a nice abstraction layer you can use to hide other browser differences as well.  

This is the strategy used by SproutCore Views.  Each SC.View manages a single DOM object and sometimes a few of its children.  They reimplement much of the API actually used by the DOM.  This way DOM objects remain pure DOM elements manipulated by a pure JS layer defined by the view.

Unfortunately, most JS libraries today follow exactly the opposite approach.  Almost all of them try to modify the root prototypes of elements to add their own methods.  This isn’t really possible to do in IE since DOM objects are not real JavaScript so instead these libraries will try to infect each element they come in contact with with their methods to try to simulate the effect instead.  This is not only slow but leads to a wide variety of bugs.

Less DOM, more JS

So there you have it.  There of course are a lot of other minor differences between how the JavaScript language in FireFox and Safari and JScript in IE work, but most of them are easy to paper over.  The real tricky bugs that keep you up all night, however, are often driven from the differences in the DOM models.  To solve this problem, simply treat your DOM objects like foreign objects.  Follow the published APIs on these objects but avoid adding your own properties or enhancements on top.   

Or use a framework that does this for you like SproutCore. ;-)

Either way, if you understand this difference you’ll find debugging IE is not only easier but sometimes it a little bit fun.  Like learning a foreign dialect of your own native tongue; a little weird but mostly harmless and interesting,

 

* OK, for the pedants out there, technically the Document Object Model, or DOM, is the API defined by the W3C that the Document Object Tree (DOT?) conforms to.  Most people I know however simply refer to the Document Object Tree as the DOM, so I’m going to stick with that convention here as well.

** Also for the pedants: I am aware that both FireFox and Safari do not strictly keep a “peer” tree of JavaScript objects for all DOM elements in page.  However, this is the direction they appear to be moving conceptually and from a developer’s standpoint it’s easier to keep this mental model in the head than to deal with the actual complexity of the situation that is FireFox and Safari both blend the peer-tree and the wrapper models to some extent, mostly for historical reasons.  Either way if you follow my suggestion and always 

 

How to write a fast (and readable) method in JavaScript

Good methods should read like a story.  They should have an introduction, a climax, and a conclusion.  Here is what a good method might look like:

/**
Returns the first content object in the receivers content array whose key
matches the passed value.  
*/
findContentForValue: function(key, value) {
//
  // INTRODUCTION:  Collect data you will need into local variables.
  // Any data you might reference repeatedly should be collected here (such
// as the array length)
// Normalize your data here when possible to make the rest of the method
// flow...
  var content = Array.from(this.get('content')) ;  // The source content array
  var loc = content.get('length') ;  // The current search location.
  var ret = null ;  // The return value (or null if none found)
//
// CLIMAX:  Do the operation.
  while(!ret && (--loc >= 0)) {
    var obj = content.objectAt(loc) ;
    if (obj.get(key) === value) ret = obj;
  }
//
// CONCLUSION:  Cleanup and return the values.
  return ret ;
}

The Introduction

The introduction is where you collect all of your variables and setup your context.  A solid introduction is important to a good method because it both makes your method easier to read and improves performance.  

By declaring the variables you will work with up front, you help make clear to readers of your code what data you expect to work with.  This will prepare them to understand the rest of your code as it comes along.  It is also helpful to put commented explanations here describing what each method will do.  This way as a reader tries to digest your code, they will have a glossary to refer to when they see an unfamiliar variable.

If readability alone weren’t enough, JavaScript actually rewards you for using this style by making your code faster as well.  Every time you reference a variable (’foo’), JavaScript will search up a “scope” chain to find the value.  This chain begins with your current function and terminates with the “window” object, where global values will go.  By bringing all of the values you will be working with into local variable, you help to short-circuit this process for most calls.

The Climax

This is the part of your code that actual does the work.  Perform some processing, search through some data, whatever.  This code should generally try to work mostly with variable declared in your introduction and it should avoid returning early.  Instead, you should store the return variable somewhere and save it for your conclusion.

I’ve instituted a no-early-return policy for many years and often get a lot of pushback on it; but there are some good reasons for it.  I contend that early returns are one of the biggest barriers to maintaining code over the long term for two reasons.  First, early returns make your code a lot harder to follow.  There is nothing more frustrating than adding a console log or tracing some code only to have it return early before it gets to the part you wanted to investigate.  Second, early returns make it hard to re-factor your code.  How many times have you had to readjust a method because you needed to add some extra step to the process but some earlier code tried to exit before it ever got there?

That said, there are some good reasons to do an early return and I do use them in code when it makes sense.  For example, if you use a cached value to determine if a method needs to run at all, then an early return is fine.  I often put this code into the introduction-portion of the method in fact so that it is obvious to everyone when a method might not run at all.  Second, sometimes your code will have so many exit conditions that not using early returns will make the code harder to read.  This kind of code usually means you need to refactor anyway, but if it is unavoidable, early returns are preferrable to unreadable code.

The Conclusion

Conclusions should be simple.  They should not contain critical logic to your method and they should wrap up any loose ends so a reader can clearly see what they will get back when the function exits.  If you need to notify anyone of property changes or perform any other general housekeeping like that, do it here as well.  You should clearly indicate when you go into your cleanup phase, though, through comments so the reader knows they should not expect to see more application logic there.

My Conclusion

So that’s how you write a good method.  Pretend it is a story.  Introduce your variables at the beginning, do something interesting in the middle and return at the end.  Avoid referencing variables that are not in a local scope and avoid early returns.  If you do this, your JavaScript code will not only be far more readable, but it will perform better too.