Skip to content
jacwright edited this page Oct 16, 2014 · 1 revision
Chip

Chip is a framework for building single-page-applications (SPA) in the same vein as Ember.js and Angular.js. It's goals are:

  • Keep It Simple (you know the rest)
  • Reduce boilerplate, without adding it elsewhere
  • Avoid being opinionated, especially about the model/business-logic
  • Use the existing tools (jQuery)
  • Favor explicitness over magic

Contributing

If you would like to contribute to Chip, open an issue to discuss what you'd like to add or fix. If it fits into the goals of Chip and nobody is already working on it, you can fork the repository and submit a pull-request with your feature or fix.

Why Another Framework

There are some great things that existing single-page-app frameworks provide, but they tend to come with a lot of unneeded extras, hidden gotchas you're still finding after months, large learning curves, and plenty of opinion. I wanted a framework that was simple enough you could read the code and understand how it worked, small enough you could fit the pieces all in your brain at once, but powerful enough to still give you the benefit of the monolithic frameworks.

There are two main pieces of functionality that we need to build single-page-apps: routing, and view binding/handling. The routing (which can be obtained in stand-alone libraries) is to allow our view to change based on the URL. The view binding greatly reduces boiler-plate view code you otherwise need to write whenever data is changed.

What about models, validation, ajax libraries, data structures, event binding, class instantiation, unit testing, etc. Most of these things are project specific, and by not providing them, we keep the framework from making you work around it in order to do things differently. jQuery does much of what we need already. And there are plenty of libraries you can use to fill in the gaps for your application.

Chip may foray into providing validations or a model library, but they will be tools to use as desired.

View Binding

There are two ways to perform data-binding to the HTML:

  1. getters/setters
  2. dirty checking

Getters/Setters

Ember and Backbone use getters/setters. Because older browsers don't support this Ember and Backbone require you to extend their Model classes. You set properties using a model's set() method and get properties using the get() method. This lets the framework know when data has been changed. Ember goes a step further allowing you to declare what properties will invalidate formatting functions, such as when the firstName or lastName is changed the getName() function should be processed as well.

While the implementation of this type of system can be a bit of clever programming, it forces the application developer to craft their whole model out of framework Xs specialized classes, sometimes requiring a lot of up-front boilerplate which we are trying to avoid, and also locking them into framework X. There are two downsides to this: 1. You can't easily take that model and provide it as an SDK for others, which is too bad since building a single-page-app with a nice JSON API opens you up to easily publishing that API for use by your customers. It sure would be nice if you could provide them a JavaScript SDK to go along with the API. 2. It is difficult to use SDKs provided by other companies, such as Facebook.js since they don't extend your framework's model.

Chip does not use getters/setters.

Dirty Checking

Angular uses dirty checking. Dirty checking is when all the "expressions" on the page are evaluated each sync cycle to determine if they've changed. This means all the data is stored redundantly (old value kept to check against new value on sync) and every single expression is checked every single time. Angular runs the sync on every keystroke when in an input field. Angular also tries to hide this syncing so your view updates magically when data is changed (e.g. after an asynchronous call returns or a user event is responded to). This is why they have their own special $http and $timeout to wrap and hide this sync call. Invariably you are bitten when you can't figure out why your view isn't updating and you end up learning about this whole hidden cycle after searching for hours (hypothetically, of course).

Dirty checking has enormous benefits. You can use it with any data you have: plain arrays, native JavaScript objects/hashes, Facebook.js, your own implemented model, even Ember and Backbone models. It just works. And the dirty checking isn't as expensive as you'd think either, since most expressions just return a simple value such as a string or number, most of the checks are essentially does 4 still equal 4?

Chip uses dirty checking. However, it does not hide the sync call. Whenever you have made changes, loaded data, processed it, responded to a user event, etc. you call sync() on the controller to update the view. There are no special ajax libraries, setTimeout wrappers, or magic.

One additional benefit Chip has over Angular (correct me if they've addressed this) is Chip's expressions are not wrapped in a try-catch construct like Angular's. This feature allows expressions asking for data that has not yet been loaded to simply show empty results, but it is horrible when you have errors in your code that are being swallowed silently up. Chip's expressions are smart (arguably the one complex part of the framework) about how they are executed, returning null if any of the parts are null, but allowing exceptions in your code to come through alerting you of errors you need to address.

Routing

There are plenty of routing libraries around, and Chip originally used another, but because of some specialized needs of the creators, a new one was created for Chip. It is based off of the Express.js library for Node.js. It allows some of the links on your site to be handled by your single-page-app and others to be redirected to, allowing for a mix. In our case, we are/were converting an existing HTML app to a single-page-app, one page at a time.

Chip's routing was built as a separate module and is used by Chip keeping it decoupled and flexible.

What About Feature X

Chip is purposely missing features that other frameworks provide. We can start at the biggest and go from there.

Components

Ember has Components and Angular has Directives. These are decently sized parts of the frameworks that allow custom bits of HTML and code to be reused throughout your application. They can be pretty cool. But they are also large pieces of functionality that need to be learned and mastered.

Chip reuses its binding mechanism for the same sort of code reuse that the other frameworks provide, without adding a new system to learn. <div bind-partial="componentName"></div> will insert the template named componentName into the div and instantiate the controller named componentName to control it. This is how bind-controller and routing works too. There is no special system. local-* is a binding that allows you to pass data into a partial (or really any controller) under a new name (e.g. ``

`.

Model and Services

As stated above, the model of an application is often very custom to your business. Chip may add model helpers in the future that can be used apart from Chip, but this part of your code shouldn't be imposed on by your framework. Remember, jQuery provides ajax functionality for you, and even custom eventing if you want. If you code all your application logic in Ember models or Angular services, you can't provide that code to your customers or change frameworks at a later time.

Dependency Injection

With Angular you are able to unit test your controllers because of dependency injection. It also seems that in many Angular apps a lot of the business logic (the parts that need unit testing) end up in the controllers. Since you need to use their ajax/$http it is easiest to make all the calls in their services, and all the logic is scattered throughout the Angular app instead of localized in your own stand-alone model classes.

If your model is separate from your app's display code, you can unit test it easily, provide it to your customers, and that leaves simple view logic to the controllers. In my experience, view logic is best tested using functional testing frameworks and if you've got functional tests, unit tests on your controllers is additional maintenance and work on the most transient part of your code-base.

It is this author's opinion that dependency injection in Angular tends to complicate the framework and steepen the learning curve without real benefit.

Hidden Problems

When building single-page-apps it is easy to wonder how many hidden problems these large frameworks are solving that you never have to worry about, since you are using the framework. There really are not, short of cross-browser compatibility which our friend jQuery has been solving for us on all our other apps. There are the main two problems mentioned above, and a few other common (not hidden) problems that can be easily solved with Chip's binding framework. Pagination was recently added for example, and validation is on the roadmap. Chip provides the framework with which you can structure your view on top of, without providing everything imaginable or telling you exactly how you need to do it.

Clone this wiki locally