update: this post has been moved to my blog
Welcome! Today I'd like to talk about another subject which can't be emphasized enough: Code Quality. This entails a lot of tools and patterns that ultimately come together to make your game more solid and programmer friendly. Even if you're working alone on a project, these tools can save you some precious debugging time by pointing out simple errors, if not more complex ones. I'll be using my current project, c as an example where possible.
A few notes before we get started:
- Some of the following tools are specific to the JavaScript ecosystem.
- Some of the following tools are only free for open source projects, so bear in mind that you might be missing out on the awesome!
Some of the easiest tools you can set up for your project are JSHint and JSCS. These tools provide basic static analysis capabilities (basically, checking code correctness at compile-time instead of runtime) and are highly customizable. JSCS even provides a preset
option to allow you to better adopt the habits of the pros developing more widely-used software.
JSHint provides some static analysis capabilities, and is more geared towards semantics instead of style (in recent releases). Some things it can do for you:
- Warn when you have an undefined variable that you're trying to use
- Warn when you're not using a variable
- Enforce quotation standards (comparing
'
and"
) - Enforce usage of curly braces where applicable (not using them was what caused the Apple SSL security exploit)
- Enforce strict type comparisons
Each of these things are very good, but everyone has their own opinions. The take-away here is that you should be using something to keep your codebase consistent and free of lint!
An easy way to integrate JSHint into your project is to use it with Gulp or Grunt. The added bonus here is that mistakes will fail a build if you use it with Continuous Integration (to be discussed further down in the article). If you don't want to specify any options, JSHint will use sensible defaults.
If you're interested, you can see my .jshintrc
here.
note: I strongly prefer JSHint to JSLint because JSLint is far too pedantic, even for me. It's another valid tool you could use, however
JSCS is a tool dedicated to enforcing very specific style constraints. This can prevent you from having a code standards guide, as it is simply enforced by the tool. Some might consider this pedantic, but I think it's a great tool to keep code consistent without much effort, as errors simply fail the build!
JSCS has a very in-depth list of options, and the best part is that they all have inverses. If you want to require semi-colons, you can tell it that. If you want to enforce a no-semi-colon rule, you can do that too. Here are some of the styles I use JSCS for:
- No empty code blocks
- Require
var func = function(){}
instead offunction func()
- Require
else
to be on the same line as the closing}
for anif
statement - Require dot notation for accessing variables (
obj.var
instead ofobj['var']
) - Require spaces after arguments / parameters in a function call, and in a
for
loop - Disallow trailing commas in arrays and objects (this actually breaks old versions of Internet Explorer)
The easiest way to integrate this into your workflow is to use Gulp or Grunt. Like JSHint, a failure will fail your build.
The best part is that if your code doesn't match, it can fix it for you! If you specify the fix
option, you'll never be warned of these problems, instead they'll just be fixed for you.
If you're interested, you can see my .jscsrc
here.
Dependency checking is a simple way to ensure that your dependencies are up to date. If all of your dependencies follow Semantic Versioning, this system becomes quite useful to you. Currently, I use Gemnasium and bitHound to watch dependencies for c. Gemnasium only watches dependencies, but it's still very nice to know when something becomes outdated. I'll talk more about bitHound later, as it does more than dependency version checking.
Gemnasium is (I think) free to use for open source projects, you just have to sign in with your GitHub account.
Continuous Integration, or CI, is a tool you would typically use to verify the integrity of individual commits, pull requests, or builds. I'll cover a few tools that can do this for you, and they're both free for open source projects!
For GitHub, if you're using Travis CI, you get some very nice integration:
The nice thing about CI is that it shows historical data, so you can see every build that ever occurred for your repository. Travis is very easy to set up. For example, here's my .travis.yml
file:
language: node_js
node_js:
- "0.12"
- "iojs"
before_script:
- npm install -g gulp
Simply: I build against the latest version of node and iojs, and I have to make sure to install gulp before running any tests or they won't even run. By default, Travis runs the command npm test
. Of course, without a system like gulp in place, Travis would not be that useful.
Hound CI is another form of CI, and it's a bit more opinionated than Travis. You can use them both in conjunction, too. Hound will be much more in your face, and only triggers on PRs. The coolest part is that it only looks at the code that was added, so you don't get any unnecessary messages. It has a default JSHint profile that it runs, but you can specify that it use a specific one, too.
In the odd event that your contributor misses both your local JSHint settings (if you have it), and Travis (if you have it), you'll see some messages like this. This was before I told Hound to use my styles, so the messages were superfluous.
Hound requires no extra setup to use. You just have to auth with your GitHub account.
Static Analysis tools provide a bit more insight into your code. You'll see various metrics like lines of code (more = higher maintainability cost), complexity (too much going on = higher maintainability cost) and a few others. I have a few tools hooked up to c right now.
At first glance, bitHound might be a bit overwhelming. It can do quite a bit: analysis, dependency checking, technical debt warnings, etc. It really is quite simple to use though. Here is my bitHound dashboard for c. The first thing you'll notice is the chart -- that's the overall score, over time. I haven't been able to break past 97 yet, but I'm sure it will get there in time. bitHound is very nice because it shows you all of your over-time metrics in a simple, digestible fashion. Nicely enough, it also lets you change what you want to look at. Here's the full history of c, as told by bitHound:
(the faded items are on different branches)
Yikes! What happened in the middle there? Let's take a look at the commit where my score dipped quite a bit. Since my overall score is an average of all my other file scores, having one file tank is a pretty serious blow to a small project. Specifically, in this commit, my main feature added was saving and loading. Here's the problem file. If you expand, you see that.. wait, that's a pretty simple function, isn't it?
To most, yes, this function is pretty simple, but it also has a glaring amount of repetition and some unnecessary nesting. As far as I can tell, complexity is a combination of:
- number of lines in a function
- number of branches in a function
- number of assignments in a function
- levels of nesting in a function
And having too many of these makes your function inherently more complex. The fix required a little bit of refactoring, but in the end it took a bunch of loose variables and tied them together in a more sensible way.
bitHound takes very little effort to set up, and has few options (it's another tool you simply have to sign up with GitHub to use). Namely, you can tell it what to ignore and what to test. I use it to ignore content files, my gulpfile, and files that I didn't write.
Code Climate, at first glance, is a bit less complex. All it really does is static analysis, which is fine; it looks at things different from bitHound and there's no harm in having multiple services run the same types of analysis -- each tool does it differently. With a greater variety of tools, you can either use them all in tandem, or figure out which ones you like best and cease using the others.
Here's my dashboard in Code Climate. If I had Unit Tests (described more below), I could hook those in here, too. Otherwise, Code Climate seems to pull open source projects daily and analyze them. Nicely enough, you can get a full file listing at a glance and see if there are any major issues. There's also a general issues dashboard where they mention everything they see that could be improved with your codebase.
Overall, this is a bit more of a shallow view in comparison to the previous one, but they're two tools that do similar things, just a tinge of difference between them.
This tool requires very little effort to set up, just sign up with GitHub.
I also checked out Codacy. I can't talk much about it yet, since it doesn't yet support ECMAScript 6 (ES6). I've added it in the hope that soon it will support ES6 and the analysis will actually help me. I let them know, and hopefully it will come soon! If you're not using ES6, though, it should be another valuable tool in the toolbox.
For fun, here's what they think my problems are. They just don't like template strings, it seems!
Another simple tool, all you have to do is sign up with GitHub! Although, I don't know the specifics here as I wasn't able to utilize it very well.
Unfortunately not yet present in c, but still a very valuable thing to do. Unit testing adds yet another layer of confidence on top of your code so you can refactor relentlessly and ensure your code still works (provided your code coverage is high enough). You can use tools like Jasmine, Mocha, and Karma to accomplish these goals.
Presumably, when something gets introduced into c, this space will be updated.
You might be thinking "man, the more services I use, the more I have to check if I want to see progress on my project." Nope! All of the tools above provide badges that you can embed into your README, so any time someone looks at it, they see your project status. On GitHub, this means they show up right on the front page. Here are what the badges correspond to:
Go forth and make your code better!
Why no mention of ESLint? It's far better than JSHint.