TweetToo Enterprisey?
A criticism often leveled against JavaScriptMVC is that it is too enterprisey. Here’s how Wikipedia describes the term:
In this usage, the term “enterprisey” is intended to go beyond the concern of “overkill for smaller organizations”, to imply the software is overly complex even for large organizations and simpler, proven solutions are available.
I have trouble understanding this criticism. Because we’ve outright stolen the ‘best’ ideas from other libraries, most of what JavaScriptMVC does, it does as simply as possible. So I’m left with 3 reasons why someone might say this:
- They write very minimal JavaScript.
- They don’t know what they are doing and shouldn’t be programming in a team environment.
- They don’t know JavaScriptMVC.
I’ll explain why JavaScriptMVC is too enterprisey for the people in category #2, while hopefully informing the #3 crowd.
JavaScriptMVC’s Feature Set
JavaScriptMVC provides the following primary features:
- Dependency Management and Compression
- Testing
- Documentation
- Model-View-Controller architecture
Hopefully, we can all agree that the first 3 are needed on almost any project. If you disagree, please read a software engineering book. Lets assume we need dependency management, compression, testing, and documentation. How does JavaScriptMVC provide these?
Dependency Management and Compression
JavaScriptMVC 3.0 comes with ‘steal.js’. By loading this script in your page, and telling it the first file to load, it provides dependency management and compression. Lets see an example:
<script type='text/javascript'
src='path/to/steal.js?path/to/your/file.js'>
</script>
Then in file.js you just have to include your dependencies and then describe your functionality like:
steal("dependency1","dependency2").then(function(){
//code that uses these 2 dependencies.
})
How enterprisey… except almost every single loader works this way. But most of those loaders don’t combine and compress your apps into a single build. Lets look at all the craziness JavaScriptMVC forces you to do:
./js steal/compress.js path/to/mypage.html
Oh, that’s right. You don’t have to do anything else because JavaScriptMVC uses Envjs to load your page, find script tags, and join them for you. How easy is that!?
Testing
Testing is done via add ons to qUnit and selenium that lets you write one test and have it run in the browser, in Envjs and in Selenium. But first, lets look at how difficult it is.
If you are using the generators, all the testing skeleton code gets created for you, but forget that, lets do it the hard way because generators are enterprisey. Of course, I got the idea from uber-enterprisey Ruby on Rails.
To make a FuncUnit test, first create a page with the ‘standard’ qUnit structure and use steal to load your tests script. It looks something like:
<html>
<head>
<link rel="stylesheet" type="text/css"
href="../funcunit/qunit/qunit.css" />
<title>QUnit Test</title>
<script type='text/javascript'
src='../steal/steal.js?path/to/mytest.js'>
</script>
</head>
<body>
<h1 id="qunit-header">My Test Suite</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<div id="test-content"></div>
<ol id="qunit-tests"></ol>
<div id="qunit-test-area"></div>
</body>
</html>
Then in mytest.js, steal the funcunit plugin and write your tests:
steal.plugins('funcunit').then(function(){
module("a module")
test("something",function(){
S.open('path/to/the/pageIwantToTest.html')
S('#autosuggest').click().type("JavaScriptMVC is")
S('.results:contains(easy)').exists(function(){
ok(true,"JavaScriptMVC is easy");
})
})
})
To run and debug the test, open the qunit html page in your favorite browser. To run it in selenium, you just have to point to the page with the funcunit/envjs script like:
.\funcunit\envjs path\to\your\funcunitpage.html
You’ll notice that FuncUnit tests look and work almost just like jQuery. But, this is probably a lot harder than learning selenium’s APIs. Oh, and with the new mail plugin, you can easily mail the automated tests.
Documentation
JavaScriptMVC’s documentation library uses Envjs just like Compression and FuncUnit to make documenting an app very hard to setup. You have go through the hassle of making a page, any page, that has script tags. It doesn’t have to use steal. In your source, use JSDoc (JavaDoc) style commands like:
- @params
- @class
- @author
- @constructor
- @prototype
- @codestart - @codeend
And then point to your page like:
.\js documentjs\document path\to\mypage.html
And it will create documentation for you. If you spell or format the @commands wrong, it will rudely hint at the correct spelling or format. How annoying to have to do nothing extra but run a script to generate docs. It’s nice that tools like JSDoc make you list the folders or files that you want to document.
Model-View-Controller Architecture
The need for a coherent architecture is apparently not self evident. To be clear, there are (probably) other architecture choices that enforce isolation of concerns as well as the MVC approach in JavaScript. I have not found them, but I’m hedging my bets. But, it’s extremely important to pick a design approach that leaves code:
- modular
- resuable
- future-proof
jQuery’s “plugin” approach alone does not accomplish these goals. I could list off a million problems it doesn’t address, but I only need one … code reuse. How can I take someone else’s basic tabs widget, and use it in my history enabled tabs? I can’t. Instead you have to pack every feature in one widget because jQuery’s plugin approach says nothing about how to expose functionality for reuse.
I didn’t set out to create an MVC library (when JavaScriptMVC was originally called JSJunction), the library just fell out that way. This is because we found ourselves wanting a repeatable way to organize the patterns we were always re-creating with JavaScript:
- Responding to events
- Making Ajax requests
- Massaging the raw Ajax/service data into a more usable form
- Updating the DOM with HTML created with the massaged service data.
Of course, we broke into the incredibly complex MVC pattern:
- Controllers listen to events in the DOM
- Models make Ajax requests
- Models take the data from ajax requests and masssage them into instances of a model.
- Controllers get the data and use a JavaScript template to draw them onto the page.
Lets see just how annoying this is.
Controller
A controller might listen to the load of the page, and get a list of tasks like:
$.Controller.extend("TasksController",{
load : function(){
Task.findAll({},this.callback('list'))
},
list : function(tasks){
....
}
})
Do you see how JavaScriptMVC complicates things up by not doing the ajax request directly in the load function? Who really cares if someone else might need to get Tasks or add domain specific information on them?
Model
The pretty-much-pointless model does an Ajax request to find tasks and wrap that data so we know how many days remain until it is due.
$.Model.extend("Task",
{
findAll : '/todos.json'
},
{
daysRemaining : function(){
return (new Date() - Date.parse(this.dueDate))
/ (1000*60*60*24)
}
})
Talk about “too much code”!
View
After the model passes back the wrapped task data to the controller, it renders it with a view like:
list : function(tasks){
$('#tasks').html( this.view( {tasks: tasks} ) )
}
This will render the template in views/tasks/list.ejs with tasks. This path doesn’t have to be provided because JavaScriptMVC knows it is in the “list” function of TasksController. This is just another enterprisey idea lifted from rails. The template producing the html for the tasks might look like:
<% $.each( tasks, function( task ) { %>
<div class='task'>
<%= task.name %> is
<%= task.daysRemaining() %> days away
</div>
<% }) %>
Notice how JMVC enterprises it up by using templates instead of string concatentions or array joins.
Conclusions
jQuery is a fantastic, and in my opinion, the best library for interacting with the DOM. However, it lacks the structure and tools to write complex applications. JavaScriptMVC makes doing what you should be doing with extremely easy. You should be:
- Testing
- Logically separating code
- Documenting
- Compressing
But most importantly, you should be programming in a way that someone else can read your code, understand, and repeat. This is what JavaScriptMVC answers … the “HOW” to write something.
If you’ve accomplished all of these goals easier than JavaScriptMVC provides it for jQuery, please share! If you haven’t, and you think JavaScriptMVC is to enterprisey, take a look at your own work and ask if has the engineering rigor of even the most lazily constructed JavaScriptMVC application.