Building a project - workflow, development stack.

Building a project - workflow, development stack.

Sometimes, I need to calculate the aspect ratio of an image to make sure I resizes it correctly and because I'm to lazy to actually do the math (but I ended up doing it anyway!) or use something found on the web, I decided to build an aspect ratio calculator, because why not.

Enter arca - a simple aspect ratio calculator.

arca

I built this project in the course of a few weekend hours, and during this time I've cemented my own basic workflow and deploy process.

For the rest of this article I'm going to talk more about the stack and the deploy process I've used rather then the actual project, since, well it's an aspect ratio calculator, there's not much to talk about it anyway.

Build stack

For the actual build process I'm using and will continue using GruntJS. Now, I know there are a lot of debates at the moment on what one should use when building an app. Whether it's Grunt, Gulp or npm scripts, people seem to forget the most important thing, it doesn't matter what you use as long as it gets the job done.

I prefer Grunt because it's much more easy to set up and to understand, when for example, someone else comes along and tries to understand the logic behind your project.

The Grunt modules I generally use are as follows:

  • grunt-contrib-clean - to clean up everything in the build folder before a new build starts
  • grunt-contrib-pug - templating system, instead of placing everything in HTML files. Very versatile because it gives me the ability to use blocks and mixins.
  • grunt-contrib-sass - Sass or LESS? Sass all the way!
  • grunt-contrib-coffee - instead or writing everything in vanilla JS, I decided to use CoffeeScript, for the sake of readability and how clean the code looks.
  • grunt-contrib-uglify - after all that good looking code I compress everything.
  • grunt-contrib-jshint - because the files actually need to be valid.
  • grunt-contrib-watch - it triggers when a modification has been made to a file. I like to call it the Eye of Sauron.
  • time-grunt - I use this one to monitor how long a certain task takes to run.

Now, that we've gone through the Grunt modules that I use the most often, I'm going to share some of the things that I've added to my Grunt configuration to make it more usable.

For example I wanted a way to pass certain configuration variables to my HTML files. Luckily Jade (sorry Pug!) knows how to do this, as you can read bellow.

jade: {
    build: {
        options: {
            data: function(dest, src) {
                return require('./lib/settings.json');
            }
        },
        files: {
            './bin/index.html': './lib/views/index.jade'
        }
    }
},

By passing a .json file into the data parameter, I can easily configure anything I want.

Another thing that I found useful was to add the option to build the project while I issue a grunt watch command. I did this like so:

watch: {
    options: {
        atBegin: true
    },
    ...
    [rest of the config]
    ...
}

I'm not going to go through the whole Grunt configuration file, that's another article for some other time.

Now on to the language part of things.

Language stack

I try to keep the language stack as small as possible. I don't like to mix and match too many languages when working on a project. Bellow are the languages I use on a general basis when starting a new project. In the future I may introduce new ones but for now I'm sticking to these ones.

CoffeScript

As you're already aware, from what I've written above, I'm using CoffeScript instead of regular, good old vanilla JS. The main reason behind this approach is that the code is much more readable than regular JS. At least that's how I perceive it. And using GruntJS allows me to easily compile that CoffeScript into regular JS.

Sass

I won't start a debate why Sass is better than LESS. I use Sass because it's easier to handle, there are a lot of mixins out there or frameworks that already have support for Sass and the community behind it is amazing. Probably in the near future when the support for CSS variables will be improved I'll switch, but until then I like my nesting, variables and mixins.

Jade

Or Pug, as it's now called. I prefer using a templating system because it offers me the ability to modularise each section of the application into more manageable pieces. For example I want to have a mixin for a certain component.

Pug allows me to use logic inside HTML and thus minimizing the JS code that I write. It also gives me the ability to pass certain constant values to the actual code. I usually generate a settings.json file that will help me use a name, a description, a color in multiple places without having to copy/paste that value everywhere.

PHP

When I started working on uptimey I was still developing a lot of WordPress websites and eCommerce platforms so naturally I went with something I already knew and could easily handle and maintain. So for server side scripting I generally used PHP to handle anything that I might need.

PHP is a vary versatile language and I enjoy writing code in it, but if I were to start a new project now, I would probably use something else.

Dependencies

The dependency list isn't that long either. A must have for me is require.js, so bellow I'll explain how I normally use it.

require.js

Because require.js gives the ability to load scripts based on their dependencies, it's a real life saver when it comes to speed and loading times. Bellow you'll notice the actual configuration file that I normally use when starting a blank project. The main script file will, usually, require jQuery and because of that, jQuery is the first thing loaded before the actual app.

requirejs.config({
    baseUrl: 'js',
    paths: {
        jQuery      : '//ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min',
        app         : 'app.min'
    },
    shim: {
        'app'       : {
            deps    : ['jQuery']
        }
    }
});

moment.js

Another example from the uptimey project is moment.js. Moment allows anyone to easily work with dates. We all know dates and formatting them can be a hassle, that's why moment.js is a must have if you're planning on working with dates.

Segment.com analytics

Instead of using good old fashion Google Analytics or GoSquared, I'm using the services provided by segment.com because they allow me to integrate almost any tracking service by adding just a single script. Using only a single script and sending all the params through that, I can hook up things like Pingdom and Mixpanel, that allow me to visualise how things are going.

Structuring

I spent a lot of time thinking about a projects structure and how to best implement it. I finally came to the bellow formula after many hours of trail and error.

Jade (Pug) structuring

In terms of structuring the templates, I usually use this type of structure:

footer.pug
head.pug
index.pug
layout.pug
meta.pug

The footer file contains the analytics, require.js scripts and sometimes the copyright info. The head file has all the CSS references. The index files ties everything together. The layout file is the most important one, because it's the actual structure of the whole project. Sometimes the layout file might be the basis for other pages, if the project requires it. And last but not least the meta file has all the meta tags that the project I'm working on needs.

All these files receive constant values from the settings.json file while they're compiled via Grunt.

Folder structuring

The basic folder structure that I use, is as follows:

- bin # the destination folder when things are compiled
 -- css
 -- img
 -- js
 index.html
- lib # the source folder contains all the files that will be compiled
 -- controllers # files that define what the app can do
 -- helpers # files that contain functions that I use in multiple places
 -- models # all the files for server side scripting
 -- style # all the Sass files
 -- views # all the Pug files
 settings.json

Deploy

The deploy part of this workflow I've only just finished perfecting. When I discovered how useful Travis CI can be, I stopped searching for an alternative. I was able, using a single configuration file, like the example bellow, to test and deploy in a matter of minutes.

env:
  global:
  - ENCRYPTION_LABEL:
  - COMMIT_AUTHOR_EMAIL: "[email protected]"
language: node_js
node_js:
  - "5"
  - "4"
  - "0.12"
  - "0.10"
before_install: 
  - npm install -g grunt-cli
  - gem install sass
install: npm install
before_script: grunt
after_success: 
  - chmod a+x deploy.sh
  - ./deploy.sh

The above configuration is just an example that I've used on multiple occasions. You should try modifying the above params and see how they best work for you.

You'll notice that after the build is finished I run a script for deploy. That script will deploy the project, in this case to Github pages, if all tests have passed successfully. You can find an example of a deploy.sh here. Basically what it does is, it will clone the repo into the Travis CI VM and then replace the files in the gh-pages branch with the ones from the bin folder and then push the updated files to Github without me having to intervene. You can add anything you want to the deploy.sh file so you can deploy to your choice of environment.

If you want a more in-depth look on how that script works, have a look here, at this brilliant tutorial, where the whole process is explained.

Conclusion

I hope this article will be the basis for a discussion that we can all contribute to. I'm saying this because, many beginners, when starting in our field don't have the slightest idea where to start. So with this article I'm hoping to get people to share there own workflows and development stacks so that we can all benefit and improve. If you've written an article that describes your flow, hit me up @stefanbc, I would love to read it.

In a future article I'll describe my hardware stack and the way I set up my code editor. but until then code long and prosper!

Image credit: Guillaume Kurkdjian