Deep dive into Modern Web Development, Part 1

“Developing on a BAMF stack”


This is an article where I will attempt to describe my preferred project architecture for developing web applications which I casually refer to as the BAMF stack. Along with that, there is some background on how I arrived at this stack, what my decision criteria are, and some code examples.

The web is divided into two parallel (though technically somewhat perpendicular) universes often described as front end and back end. Each of these has a different standard set of functions required to build basic web applications and each of them have dozens or hundreds or thousands of options for how to do something as simple as “Hello World”.

This article is going to be Part 1 because I’m going to take a deep dive into modern front end development and this will lead us to a fork in the road that I will then discuss in a Part 2 and perhaps Part 3, so if you like this article, stay tuned.

The Not So Olden Days

When I started building for the web almost everything I did was static HTML. Rails and PHP did not exist and .NET was something you wouldn’t dabble with as a hobbyist. CSS was barely a thing, tables and images were everything, and you could build these little animations in Macromedia to jazz things up.

Now luckily we can forget about that stuff. Things have become more streamlined and uniformed.

Today

doctype === html

A website from a front end perspective is HTML, CSS, JavaScript and media assets. That’s it.

  1. If you need to change the look of something, try to do it in CSS.
  2. If that just is not possible, make it happen with JavaScript (or in some cases SVG).
  3. If you need timed, asynchronous, or user driven events to interact with a server or redraw the page, then do it with JavaScript.

That is simple, but we are really missing out if we just stop there.

I see a lot of job descriptions out there that read something like this:

“write vanilla OO JavaScript, preferably without relying on any frameworks or libraries

I always scratch my head on this one as there are only a few times that this actually could be beneficial. I’ve narrowed it to if you are:

  1. writing a base library that needs to have no dependencies because it will be a new library for many other projects
  2. building ad units with very limited K-size
  3. publishing a site that is read-only and will have almost no interactivity
  4. limited to supporting mobile device browsers like Hand Web
  5. deliberately inflating the maintenance costs of your project for some sort of job security or vendor lock in

Otherwise vanilla JS with no dependencies is just bad architecture and here’s why:

  1. By abstracting large amounts of the code into dependencies that are heavily tested and fairly reliable, all new code can be very simple and have a one-to-one relationship with its functionality. Shorter code is often easier to read and understand, and by that logic, cheaper to maintain and easier to maintain well.
  2. You will often end up with dependencies even if you try to avoid them. Trying to avoid them means you will often not be set up with dependency injection, package management, a module loader, or concatenation. Most often it ends up being a hodge podge of script tags in the head of the HTML that can easily become out of date. I’ve seen websites like this with 70+ JavaScript files loaded into each page because they were not architected for the inevitable.

Rise of the Build Tools

No need to chronicle the evolution of the build process, but just point out that, if you are building websites, your front end should be tracked in source control, probably Git, and you should be using a package manager and compiler. Here’s what I like to use and how to use them.

Brunch

With just a few simple npm and bower commands you can scaffold out a pretty solid project that is ready to start pre-compiling, concatenating, live-reload / browser sync, gzipping and minifying your front end code.

Here is a popular protip that I wrote as a cheat sheet for Brunch, but you will need to try it yourself to find your perfect project structure and node modules.

At Bad Assembly we recently built and deployed two e-commerce sites 1 2 managed by a Wordpress CMS with a completely async AngularJS front end all tracked with npm, Bower, Git, and built with Brunch.

Gulp

This has displaced Grunt for me since it has proven to be faster and possibly more customizeable. It takes a lot of configuration and the documentation, at least when I last used it, was a lot less helpful than fellow developers and trial and error. I only use this when I need to do something that does not fit in the much easier to maintain Brunch build process.

I have also used it as sort of a post-compiler in conjunction with Brunch where we needed Blessed CSS to split our stylesheets for IE8 support on a huge AngularJS app after Brunch compiled the initial pass for all other browsers.

I’m excited to try Gulp on a larger project to include more extensive automated testing and automated Git deployment, but right now I’m playing with Roots for a few microsites and MVPs.

Roots

Roots is a Jenius tool (pun intended) for building static sites but it also serves pretty well for building static source files for SPA sites that are rendered clientside. It is going through some major performance upgrades that I hope kick in soon because it is not as fast as the other two builds, but the tech stack it is built on is a work of art worth studying itself. Roots is the BAMF stack out of the box with Jade + Coffee + Stylus as defaults and support for YAML and your choice of substitute templating language.

Once you

npm install -g roots

you can

roots new your-project

and bam, you have a BAMF stack pre-compiler that you can also deploy on Heroku or Divshot with environment variables for different compiling conventions and overrides.

The negative to using Roots is that if you need to work outside of the conventions it provides, it is far less forgiving and versatile than Brunch or Gulp. It should be that way though, that’s the whole point. Jeff Escalante, the craftsman behind Roots, is very humble in admitting that the tool is really not for everyone and that he has tried to make a tool that offers all of the most advanced time saving best practices by default while sacrificing support for developers with custom needs. I think that tradeoff has made the tool a standout for what it is, and I tend to agree with the Jade / Coffee / Stylus stack he has chosen. The revamp of my personal site will be up soon here, built on Roots.

The Rise of Compiled Languages

As long as you end up with HTML, CSS and JavaScript, it doesn’t much matter what code you start with.

I believe that the following are the best precompiled languages for readability, DRYness, compatibility, and easy learning curve.

Stylus for CSS

If you can write CSS, you can write Stylus. If you can write Sass, you can write Stylus. If you want to do something fancy with mixins and variables, like you can do in Sass or Less, you can do it in Stylus. Best part is, all colons are optional! Check out this input:

$brand-color = lighten(seagreen, 30%)
.some-custom-component
reset-box-model()
+above(mobile)
size 12rem
border 2px solid $brand-color
transition border .3s ease
&:hover
border-color darken($brand-color, 30%)
  +below(mobile)
padding .5rem
background $brand-color
color white
height auto

and this output:

.some-custom-component {
margin: 0;
padding: 0;
border: 0;
outline: 0;
}
@media only screen and (min-width: 640px) {
.some-custom-component {
width: 12rem;
height: 12rem;
border: 2px solid #54c686;
-webkit-transition: border 0.3s ease;
-moz-transition: border 0.3s ease;
-o-transition: border 0.3s ease;
-ms-transition: border 0.3s ease;
transition: border 0.3s ease;
}
.some-custom-component:hover {
border-color: #31945d;
}
}
@media only screen and (max-width: 640px) {
.some-custom-component {
padding: 0.5rem;
background: #54c686;
color: #fff;
height: auto;
}
}

That is a lot less typing!

Losing the colons can be jarring for some people, but when you are in a text editor with proper syntax highlighting, and not previewing this code on Medium, Stylus is way easier to read. Also note that the +above() and +below() mixins are not built into Stylus, though size and reset-box-model are part of nib the default Stylus mixin library. When going back to SASS for a ROR project recently, I found myself frequently befuddled by accidental colon ommission that would crash Rails asset pipeline. In Stylus, you add in a colon or you leave them out and it compiles all the way without issue and although it might make your source code slightly inconsistent visually, from an output perspective it all gets compiled to CSS so it has no impact on the quality of your product. More on the language’s flexibility here.

Jade for HTML

If you are familiar with writing CSS style selectors, which you have to be to write CSS, then you should be able to write competent Jade templates which will compile to HTML. This stuff is amazingly terse and will spare you from all the brackets and keep your code readable. Sometimes I even copy paste my Jade code into my CSS or Stylus then add some spaces or commas where needed and voila I have a perfect CSS selector.

section
.left-column
img(src="image.png", alt="image")
.right-column
ul
li: a(href="home/")
li: a(href="page1/")
li: a(href="page2/")

Isn’t that much easier to read and write than this?

<section>
<div class=”left-column”><img src=”image.png” alt=”image”/></div>
<div class=”right-column”>
<ul>
<li><a href=”home/”></a></li>
<li><a href=”page1/”></a></li>
<li><a href=”page2/”></a></li>
</ul>
</div>
</section>

And let’s say I wanted to target the active state of the links in the right column…

Stylus:

.right-column
ul
li a
color #888

Eerily similar to this…

Jade:

.right-column
ul
li: a(href=”home/”)

Having the syntax of the markup language match the syntax of the stylesheets is very gratifying. Your brain can spend time solving better problems than constantly transliterating disparate syntaxes.

CoffeeScript for JavaScript

This is a hotly debated area in front end development. I’ll start with the cons.

  1. you can’t use CoffeeScript everywhere
  2. not that many people know how to write CoffeeScript but lots of developers know JavaScript
  3. CoffeeScript is hard to learn
  4. how could indentation be less error prone than curly braces for lexical scoping?

Obviously I disagree that these issues outweigh the benefit.

  1. You can use CoffeeScript in almost all the popular build tools and server side frameworks and since it compiles to JavaScript you can always add that pre-compilation to your build process before whatever step requires vanilla JS. Is it always worth that extra step? Of course not, but when setting up a project, the right way, it is never hard to add.
  2. Even if not everyone has experience with it, CoffeeScript is easy to learn.
  3. If you know JavaScript well, CoffeeScript is JavaScript with just “the good parts” and with some syntactic sugar. Tools like js2.coffee make it crazy easy to transition back and forth from JS to Coffee.
  4. Using a pre-compile language breaks your compiler whenever there is a syntax error, so you simply can’t move forward with code that has bad closures. This is not the case with vanilla JS, where you are not forced into compiling and testing your code and can just throw things into the wild that will run, but create all sorts of hard-to-trace bugs. Since switching to CoffeeScript, I’ve seen a tenth of the number of language related bugs that I did in JavaScript. I will admit that CoffeeScript does have a confusing hoisting pattern where it defines variables more globally than you might anticipate but with an anonymous function wrapper for protection. This is mostly an idiosyncrasy in nested operations like in this protip I mocked up, but things like this can be a deal killer for some developers.

But now there’s “the good parts.”

Check out these syntax helpers in CoffeeScript

Let’s say you need a function to traverse a collection and return an array of two concatenated fields.

In CoffeeScript you write:

getPersonList = (persons) ->
for person in persons
person.first_name + “ “ + person.last_name

And the equivalent JavaScript is:

getPersonList = function(persons) {
var person, i, len, results;
results = [];
for (i = 0, len = persons.length; i < len; i++) {
person = persons[i];
results.push(person.first_name + “ “ + person.last_name);
}
return results;
};

Once you get over the magic that the last line in a function returns its value by default, and that the ( ) -> notation creates a function ( ) { }; I just can’t understand what is easier about JavaScript than CoffeeScript other than it being older. BTW, you can always write return explicitly, which I often do for lookup and filter methods if it makes it more readable.

We can make it a little more tricky

Let’s say you only wanted to get a list of persons that were in the right city and were not annoying.

getPersonList = (city) ->
for person in persons
if person.location is city and not person.annoying
person.first_name + “ “ + person.last_name

In JavaScript:

getPersonList = function(city) {
var person, _i, _len, _results;
_results = [];
for (_i = 0, _len = persons.length; _i < _len; _i++) {
person = persons[_i];
if (person.location === city && !person.annoying) {
_results.push(person.first_name + “ “ + person.last_name);
} else {
_results.push(void 0);
}
}
return _results;
};

Perhaps that’s not a fair comparison because you would likely have a common helper library for doing just that kind of filtering, but it is amazingly easy in raw Coffee.

Another great example is the existential selector in CoffeeScript

This syntax looks almost identical, just drop the semicolon and var.

# In CoffeeScript
price = data.orders[index].product.price * 1.0975
// In JavaScript
var price = data.orders[index].product.price * 1.0975;

But what if you could not rely on an order to exist at the index or if you could not rely on product having a price set?

In CoffeeScript you can soak up these errors like this:

price = data.orders[index]?.product?.price * 1.0975

In JavaScript it is more like this:

price = ((_ref = data.orders[index]) != null ? (_ref1 = _ref.product) != null ? _ref1.price : void 0 : void 0) * 1.0975;

Try saying that five times fast -_-b

On the client side this is only helpful in that returning undefined or null prevents an error in the console, but in NodeJS this is huge because an error like that might 500 your entire server, when in fact it may not be a real breaking error, just an undefined value nested in an undefined object that you can safely handle as just an undefined value.

To MVC or Not

if you are using a framework that does not use jQuery as a dependency and you use jQuery, then you are not using the framework correctly or the framework is not effective enough

There is a definite fork in the road here and it depends on the project what is best to use.

In general I have avoided jQuery for the past couple years on most of my new projects. Not because jQuery is bad, but because if you are using a framework that does not use jQuery as a dependency and you use jQuery, then you are not using the framework correctly or the framework is not effective enough.

Here are some exemplary project criteria that lead to totally different best practices in the BAMF stack concerning front end libraries.

I have a super custom UX and users interact with a lot of dynamic data, possibly in real time, possibly merging multiple async APIs

Single Page Web App (SPA) is the way to go.

I find AngularJS to be miles ahead for everything SPA. Within that I use Jade templates with this amazing library, and Angular UI-Router.

My site is really read-only, I have lots of articles, lots of page loads, and want great SEO

Server side routing and rendering is the way to go. Build it on Rails, Express, Wordpress, Django, whatever you like, but stick to progressive enhancement over graceful degradation. Make sure all of the site data renders semantically through the server side templates and use the front end JavaScript only to make the finer details of the UX work for non-bot traffic.

I have successfully used Vue in this scenario a few times and rather liked how similar it is to Angular for writing directives but without the heavy library (~57K when minified). In the future we might use web components or native 2-way data binding, but for now lightweight directive based libraries like Vue are very nice.

I’m getting paid to be impressive and bleeding edge even if it hurts our bottom line

Web components appear to be the next big wave of web development and right now at Bad Assembly we’re expirimenting with Polymer and React for some of our smaller projects.

Some of the design principles behind web components and much of their syntactic implementation are a bit esoteric and obfuscated but the idea of focussing on lightweight, encapsulated, re-usable and modular blocks of code to represent components with a shadow DOM is definitely a step in the right direction. What is clear to me though is that building entire projects around the web component model will not be a replacement to the MVC / MVVM / MVW paradigm of SPA, but that it will be an alternative widely used for applications that rely heavily on server side templating, or something that is parallel and complimentary to the SPA universe once native support is provided in browser.

JavaScript on crack

I often include Underscore for any situation where I have to traverse data models, whether that’s a JSON API or a ThreeJS object.

Get the index of a value in an array
native CoffeeScript

index = undefined
yourArray.some (item, i) ->
if item.value == ‘matchthis’
index = i
return true
return

with Underscore

index = _.indexOf(yourArray, ‘matchthis’)

Find an object in an array based on a key value pair

native CoffeeScript

findById = (source, id) ->
for item in source
return item if item.id is id
result = findById sourceArray, ‘qz1e35'

with Underscore

result = _.findWhere sourceArray, id: ‘qz1e35'

This setup packs a lot of punch and is particularly useful when building REST API’s on NodeJS or interacting with API’s that you don’t control.

CSS Libraries?

Developers who have a background in design like myself are often very eager to get their content looking good quickly and easily. CSS is very important for that so it is only natural to use libraries the same way they get used in JavaScript.

Luckily when pre-compiling CSS from Stylus (or SASS) it is really easy to @import or @require various mixins and libraries and to concatenate and minify everything together.

Mixins are probably the best innovation from a design perspective in many years. My CSS stack looks like this:

Stylus
Nib
Rupture
Jeet
Custom subset of Axis

Note that you don’t see Bootstrap or Normalize. That’s because using mixins you can write very clean semantic markup and apply very localized styles without having to include vendor classes.

using the BAMF stack you can write this

.some-css-scope
reset()
label
no-select()
nav a
reset-link()
img
grayscale()
.columns
cf()
+above(mobile)
.left, .right
col(1/2, cycle:2)

And you get this output.

You can create global styles but you don’t have to. Because CSS cascades so deeply I find it often annoying to use Bootstrap, Foundation, and other boilerplate libraries as a starting point because you so often have to reset and override values that trickle down.

I have found though that Skeleton has been pretty on point with design trends without adding too many intrusive defaults if you’re cool with Raleway.

Summary

The BAMF stack is really not for everyone, but if the ease of reading and writing code is important to you, the BAMF stack offers the best total package of modern tools and languages to make your development fast enough to keep up with even the worst scope creap.


About the author
Dustin Johnson is a Technical Lead at Bad Assembly, an Award Winning creative agency based in downtown Los Angeles.