14 min read
So, you and your co-founder have this great idea for a business, right?
You’ve been adding features in your mind.
Frequently, you ask potential customers for their opinions, and they all love it.
Ok, so people want it. There’s even some money to be made. And the only reason they can’t have it is because you haven’t implemented it—yet.
So finally, you sit down one day and say, “Let’s do it!” Soon, you’re trying to figure out how to implement your app’s business logic, the killer feature that will drive the product forward: you have an idea of how to do it, and you know you can do it.
“Done! It works!” you say. Your proof of concept is a success! All that’s left is to package it up into a web app.
“Ok, let’s create the site”, you say.
And then, you realize the truth: you need to choose a programing language; you need to choose a (modern) platform; you need to choose some (modern) frameworks; you need to configure (and purchase) storage, databases, and hosting providers; you need an admin interface; you need a permissions system; you need a content manager.
You have tens upon tens of architectural decisions to make. And you want to make the right ones: you want to use technologies that allow for rapid development, constant iteration, maximal efficiency, speed, robustness, and more. You want to be lean, you want to be agile. You want to use technologies that will help you succeed in the short- and long-term. And they’re not always easy to pick out.
“I’m overwhelmed,” you say, as you feel overwhelmed. Your energy is not the same as it once was. You try to piece things together, but it’s too much work.
Your proof of concept slowly withers and dies.
After abandoning tons of ideas myself in this way, I decided to engineer a solution. I call it the ‘Init’ project (or, init.js).
The core of the idea is to have a single project to start them all, to let the developer or the technical founder make all of these essential decisions at once, and receive an appropriate starting template based on those decisions. I know what detractors are going to say, “One solution can’t apply to every problem” (haters gonna hate). And they might be right. But we can do our best to create an approximate solution, and I think Init comes pretty close.
To best achieve this objective, we have to keep a few key ideas in mind. When developing Init, I considered:
Componentization is a key characteristic of any system as it allows you to reuse software components across different projects—which is the main objective of Init. But componentization also comes with a by-product, “replaceability”, which will be our best ally in attacking several different problems with “almost” the same solution.
Ease of Development
Some problem, somewhere has a solution best written in Brainf*ck. But implementing that solution (in Brainfuck) will be nearly impossible to write, let alone read. It will cost you time and a tremendous amount of effort. In general, you should use languages and platform that make development easier, not harder for you (or anyone that might work on it later).
Whatever platform you choose, make sure it has a big community, and one that can help you with the most common and uncommon problems. Remember: jQuery might not be the fastest, cleanest, or most elegant library—but is a winner just because of its community.
Keeping these goals in mind, I’ll next show you how I made my own decisions in creating Init.
Dynamic Objects and Prototypal inheritance
Object-Oriented Programming without classes (and without endless hierarchies of classes) allows for fast development (create objects, add methods, and use them) but, most importantly, reduces refactoring time during maintenance tasks by allowing the programmer to modify instances of objects instead of classes. This speed and flexibility paves the way for rapid development.
MongoDB is a schema-less database that allows you to persist your objects in a flexible way and thus adapt faster to changes in requirements. Plus, it’s highly scalable and map-reduce based, which make it suitable for big data applications. MongoDB is so flexible that it can be used as a schema-less document database, a relational datastore (although it lacks transactions), or even as a key-value store for caching responses.
Server Componentization with Express.js
Server-side componentization is never easy. But with Express.js (and Connect.js) came the idea of ‘middleware’. In my opinion, middleware is the best way to define components on the server. If you want to compare it to a known pattern, it’s pretty close to pipes and filters.
The basic idea is that your component is part of a pipeline. The pipeline processes a request (input) and generates a response (output), but your component isn’t responsible for the entire response. Instead, it only modifies what it needs to and then delegates to the next piece of the pipeline. When the last piece of the pipeline finishes processing, the response is sent back to the client.
We refer to these ‘pieces of the pipeline’ as ‘middleware’. Clearly, we can create two kinds of middleware:
Intermediates: Those that process the request and the response, but are not fully responsible for the response itself, so they delegate to the next middleware.
Finals: Those with full responsibility over the final response. They process and modify the request and the response, but don’t need to delegate to the next middleware. In practice, it’s recommended that you delegate to a next middleware anyway to allow for architectural flexibility (i.e., adding more middleware later), even if that middleware doesn’t exist (in which case the response will go straight to the client).
As a concrete example, consider a ‘user manager’ component on the server. In terms of middleware, we’d have both finals and intermediates. For our finals, we’d have such features as creating a user and listing users. But before we can perform those actions, we need our intermediates for authentication (as we don’t want un-authenticated requests coming in and creating users). Once we’ve created these authentication intermediates, we can just plug them in anywhere we want to turn a previously un-authenticated feature into an authenticated feature.
The Init project focuses on creating single-page applications (SPAs). Most web developers have been tempted more than once to try their hand at SPAs. I’ve built several (mostly proprietary), and I can say with confidence that they are simply the future of web applications. Have you ever compared an SPA to a regular web app on a mobile connection? The difference in responsiveness is on the order of tens of seconds.
SPAs are the future of the web—so why would you build your product in a legacy form? A common argument I hear is that people are worried about SEO. But if you handle things correctly, this shouldn’t be an issue: Google itself has a very good tutorial on how to do so, and there are some good comments here as well.
Client Side MV* with Backbone.js, Marionette.js, and Twitter Bootstrap
All three are very well regarded. But which one is best for you?
Unfortunately, I must admit that I have very limited experience with Angular.js, so I’m going to leave it out of this discussion (for more on this, reference the Angular.js tutorial). Now, Ember.js and Backbone.js represent two different ways of attacking the same problem.
Backbone.js is minimal, simplistic, and offers you just enough to create a simple SPA. Ember.js, on the other hand, is a complete and professional framework for creating SPAs. It has a more bells and whistles, but also a bigger learning curve.
Depending on the size of your application, the decision can be as easy as looking at the featuresUsed/featuresAvailable ratio, which will give you a big hint.
In the case of Init, I wanted to cover most scenarios, so I picked Backbone.js for easy SPA creation, with Backbone.Marionette.View for componentization. In this way, every component is a simple application, and the final app can be as complex as we want it to be.
Styling is a challenge as well, but we can again count on frameworks to bail us out. For CSS, there’s no better than Twitter Bootstrap, which offers a complete set of styles that are both ready to use out of the box and easy to customize.
Bootstrap was created using the LESS language, and it’s open source, so we can modify it if need be. It comes with a ton of UX controls that are well documented on the Bootstrap site. Plus, there’s a customization model that allows you to create your own. It is definitely the man for the job.
Best Practices: Grunt.js, Mocha.js, Chai.js, RequireJS, and CoverJS
Finally, we should define some of our best practices, and look at how Init can help you implement and maintain them. Our solution is centered on several tools, which are based on Node.js themselves.
Mocha.js and Chai.js:
The long answer: it has two important features (interfaces, reporters) and one significant absence (assertions). Let me explain.
Interfaces: maybe you’re used to TDD concepts of suites and unit tests, or maybe you prefer BDD ideas of behavior specifications with “describe” and “it should”. Mocha.js lets you use both approaches.
Reporters: running your test will generate reports of the results, and you can format these results using various reporters. For example, if you need to feed a Continuous Integration server, you can find a reporter to do just that.
Lack of an assertion library: far from being a problem, Mocha.js was designed to let you use the assertion library of your choice, giving you even more flexibility. There are plenty of options, but here is where Chai.js comes into play.
Chai.js is a flexible assertion library that lets you use any of the three major assertion styles:
Assert: Classic assertion style from the TDD old school. E.g.:
Expect: Chainable assertion style, most commonly used in BDD. E.g.:
Should: Also used in BDD, but I prefer Expect because Should sounds repetitive with the behavior specification ‘it (“should do something..”)’. E.g.:
Chai.js combines perfectly with Mocha.js. Using just these two libraries, you can write your tests in TDD, BDD, or any style imagineable.
Grunt.js allow you to automate build tasks, anything ranging from simple copy-paste and concatenation of files, to template pre-compilation, style language (i.e., SASS and LESS) compilation, unit testing (with mocha.js), linting and code minification (e.g., with UglifyJS or Closure Compiler). You can add your own automated task to Grunt, or search the Grunt registry, where there are hundreds and hundreds of plugins available (again, using tools with great communities behind them pays off). Grunt can also monitor your files and trigger actions when they are modified.
RequireJS may sound like just another way to load modules with AMD, but I can ensure you that it is much more than that. To understand why, we first need to mention the idea of module namespacing (e.g., demo.views.hello), which avoids polluting the global namespace by wrapping each module in its own namespace. The problem is, these modules are not reusable: if you modify the namespace of one ‘instance’, you’re modifying the namespace of all ‘instances’. In contrast to that, RequireJS lets you define reusable modules right from the start. (In addition, it’ll help you embrace Dependency Injection to avoid having your modules accessing global variables.)
Code coverage is a metric for evaluating your testing. As the name implies, it tells you how much of your code is covered by your current test suite. CoverJS measures your tests’ code coverage by instrumenting statements (instead of lines of code like JSCoverage) in your code and generating an instrumented version of your code. It can also generate reports to feed your Continuous Integration Server.
Using Branches to Toggle Features
When I started Init, I needed a way for users to activate and deactivate various features that they might want in their project. I decided to take a radical approach to git’s branch system to implement this functionality.
In essence, each branch represents a feature or functionality that a user may want to include. If you’re starting a project from the ground up, begin on the minimal branch you’d need, and then add other technologies by merging with the desired branches. For example, let say that you want to start your project with Backbone.js and Marionette.js. Well, you can start on the Backbone.js branch and merge it with Marionette branch, continuing onward for every bit of functionality you want to add.
For now, this idea of merging to add functionality can only be used for technology templates (e.g., Backbone, Node, Express). But in the future, you’ll be able to switch between back-end (e.g., from MongoDB to Postgres) and client implementations.
Start a Project with Init and Deploy to Heroku Today
There has never been an easier way to start a project. Just head to the GitHub repo, check for the branch with the latest commits (right now it’s usermanager, although this might change in the future) and then:
- Create the directory for your project (or use an existing one).
- Create your repository with “git init” (or use the existing repository).
Add a remote with init
git remote add init git://github.com/picanteverde/init.git
Get the branch you want
git pull init usermanager
Get the Heroku process file
git pull init heroku-webprocess
With the Heroku Toolbelt installed, create a Heroku app
Push your master branch to Heroku
git push heroku master
- Visit your app, up and running on Heroku!
Now you can start to develop your killer feature with just a few lines of code. Not only that, but you’ll be developing with the latest, most efficient technologies in a development suite that’s as automated as it can be.
I hope that you can use Init to kick start your next big idea. Remember to check the Init repository for new fixes and features—its development is very much live, and I look forward to hearing your feedback.