Saturday, May 28, 2011

My Last Comments On JSLint

Preface

I have been working with many teams and I have used JSLint on daily basis. This post is not about the tool itself, neither against Douglas work, this post is about developers often too religious about this tool.
Finally, if you follow this blog you have already read tons of other reasons to think rather than "suffer silently this tool".
It's my last post about it and I hope "it will not hurt your feelings".


Seriously guys, it's not that I think JSLint is all bad, but I cannot stop thinking it's simply an effect.
The more I hear or read about developers being so religious about this tool, the more I feel to blame it.
I am pretty sure Douglas will hate me for this post but I really hope he will read it 'till the end.

Douglas Talk At Falsy Values

Both me and big Doug were there, me for a workshop and Mr D. for his speech.
"Surprisingly" Mr Crockford talked about JSLint (again?!) and why it's so good.
While many hints for newcomers are absolutely a must know, many others are absolutely inconsistent for senior JavaScript developers.
There is a particular slide and a particular sentence Douglas said there:
... write code the way it's meant for the language ...

Above sentence was related to variables declaration, showing behind something similar to this classic example:

(function () {
// never executed
if (false) {
var something = 123;
}
}());

As all of us know, and if not we should, the reason JSLint would like to have all variables defined on top of the function is that no matter which condition, for or while loop, we have at some point, the parser will pre-consider all var in the same scope as local scope variables available since the very beginning.

(function () {
// there is no "var" in this scope
alert(something);
// throws "Can't find variable: something"
if (false) {
// eventually global in ES3 and ES5 with no strict
something = 123;
}
}());

The moment we define a variable local, even if we never reach that line, that variable is available for the whole scope, got it?

(function () {
alert(something);
// undefined and no errors
if (false) {
var something = 123;
}
}());

Good, now ...

JSLint Inconsistencies

Since the previous point is clear to everybody, I wonder if it's clear that function declaration has even more precedence than variables.

(function () {
alert(something);
// the function declared later on

function something() {
return 123;
}
}());

This is not true for function expressions, where the result will still be the same obtained with variables:

(function () {
alert(something);
// undefined and no errors

var something = function() {
return 123;
};
}());

Accordingly, function declaration is referenced on top of everything, variables included!
So why on bloody earth this piece of code does not pass JSLint?

var something = (function () {

// top reference available ever
// function declaration
function something() {
return oneTwoThree;
}

// second references available in this scope
// local scope variable
var oneTwoThree = 123;

// return the local function call
return something();

}());

Try by yourself the result:

Error:
Implied global: oneTwoThree 5

Unused variable: oneTwoThree 1 'something'

---------------------------------

Global something

1 'something'()
Unused oneTwoThree
Complexity 1

4 something()
Global oneTwoThree
Complexity 1

I can bet the amount of bullshit I can read in latter result is a shame for Douglas Crockford in first person, isn't it?

Not Only Inconsistencies

Another part covered by Doug speech was the with statement ... here summarize:

... somebody (n.d. I guess me) may argue that the with statement may be useful in certain situations, but since it is always ambiguous and there is nothing that could not be done without it, the with statement should disappear from JavaScript ....
... and this is what happened.
If we try "use strict"; activation in most recent browsers we can spot that the with statement is not allowed anymore, "thanks"!

A Tool To Rule Them All

It was actually a colleague of mine asking Douglas this question (or what I got about it) :

... so, you are saying that JS developers have no discipline, but don't you think that "dictating discipline" is not such easy task as well? ...
I honestly do not remember the answer but I am sure Douglas provided a proper one ... anyway ... what I do believe is that every developer has is own style, as long as syntax and readability are not too much compromised.
If we use this tool thinking our code will improve any how we are first of all acting like machines plus we are not considering a "little detail" ...

Your Team Does Not Know JavaScript

Precisely! I know this is hard to face, but in 11 years of JavaScript programming I have never found a reason to have such tool that changes allowed programming language syntax defined by specifications ... fucking read them and stop winging! (and pardon my french)
In few words, I have never had a single problem to understand any other piece of JavaScript code written by any possible developer out there but when I had a problem, and at the beginning of whatever programming language we all have, I have investigated, studied, and finally understood, what was going on in that piece of code and what was missing from my JS knowledge about it.
Surely I did not blame the other developer, since if we would like to be monkeys on daily basis, of course we should use as many tools as possible that throw warnings even if the piece of code we wrote is absolutely correct, and we still have my precedent example few paragraph before as proof ...
On the other hand, if we would like to master our JavaScript knowledge there is no way a piece of code that perfectly works could be screwed up because of JSLint.

Early JavaScript Days

When Douglas Crockford was still promoting JavaScript all over the world, nobody had any idea what he was talking about ... well, now we all have.
This bloody language is absolutely everywhere and those "feeling cool" Java developers that still think JS is a toy are regretting 50% of their studies because they just don't get it ... that's why projects like GWT exists: developers that think JavaScript is a toy, write Java that is gonna be translated into Javascript ... and this is how powerful and flexible JavaScript is.
In these days, and surely before, we truly need discipline and a lot of hints since as lazy developers we could not spend half a day reading ECMAScript 3rd Edition specs ... isn't it?
In these days, and for these developers, of course JSLint has to be there, they don't know what they are doing but hey, at least they are willing to learn something more from this tool (and most likely behind a syntax translator such GWT is, created to do not throw JSLint warnings ...) .
As demonstrated before, this is not enough.
Java skills into JavaScript language are similar to me pretendng to have Alex Martelli knowledge using Visual Basic 6 on daily basis ... I hope you know what I mean ...
As summary, if you think you can move knowledge from another programming language without deeply understanding the new one pretending you come from "something better" you are half way trough your own failure.
At the end of the day it may not matters, as long as the next point is clear for everybody.

TDD And Unit Tests Are The Only "Safer Way"

Yeah you read it right ... there is no way our JavaScript code is gonna be any safer because of JSLint or whatever JS validation tool: no fucking way!
If we think that === rather than == is all we need to be safe, without understanding why we may be safer or why we may do something simply redundant without considering cases where we want to ==, we have never been so wrong.
Unit Tests, and more Unit Tests on top of Unit Tests are the only answer to our code quality!
It does not matter how we write routines as long as real Senior Developers can understand it, simply asking more if they really don't, and as long as all our possible implementation cases have been considered.
If we are those kind of "my code pass JSLint, my code is better and safer and cleaner" develoeprs, we are simply demonstrating how much we still have to learn about programming.
I don't know any other language that religious or with need of these kind of "natural programming code evaluation tools" and we all know JavaSscript is not the first programming language ever, neither the last one.
If it's about some common code convention we don't need JSLint, we simply need a bloody wiki/web/infrastructure page able to explain it so that somebody else could eventually blame it the moment he's flexible enough to understand meant edge cases.
This is what I have answered as well during my workshop when somebody asked me what I think about JSLint, while the whole post is the reason I did not even start arguments or questions after Douglas speech, and the reason I will never do it.
We all have our style, Douglas has his own one, and I am happy for him he is that consistent.
Should I be a Douglas Crockford clone on daily basis? Hell no, since as I have said: I know WTF I am writing and why

16 comments:

Paul Irish said...

Linting's major value-add is enforcing coding standards for your team, ensuring more maintainable code.

Linting is a poor tool for "is it going to work (well)" and I've certainly seen developers use it for that, rather than rely on unit tests, which excel at that.

Also http://jshint.com is my preferred js linter as it's got doug's poor choices removed (and/or configurable) and doesn't make you cry.

Andrea Giammarchi said...

To be overclear, I am not against JSLint, I am against people thinking this make their code better *generally* *speaking*

Sad that, I do not believe linting makes JS code more maintainable, since we can create monsters that pass lint but are totally chaotic or nonsense, logically speaking.

Finally, this was my last post after many others, I had to put everything end emphasis as much as possible ;-)

I am pretty sure good developers got my points, as example you did ( 90% :P )

Andrea Giammarchi said...

Last, but not least, I have personally shacked Douglas Hands a year ago, the first time I have met him, for all JS things he teach us on daily basis.

JSLint? A good tool, not to be religious about. This is all I think

Paul Irish said...

Definitely.

Great post. :)

Sergio Cinos said...

People that hate 'with' usually don't understand the real usage of 'with' (and I've never seen a good example of 'with' from Mr D, neither in books nor slides).

Go on, try to do the same thing without 'with':
http://jsfiddle.net/vgjZ5/

Anonymous said...

Hey - I am definitely delighted to find this. Good job!

Oliver said...

There was kind of a similar discussion about HTML validation/validators last year (see http://www.nczonline.net/blog/2010/08/17/the-value-of-html-validation/ and http://www.highresolution.info/weblog/entry/alles_valide_oder_was/). Quite a few people seem to be super serious about having valid HTML, but still produce unnecessarily blown-up markup for example (which can be perfectly valid regarding the syntax, tag nesting etc.). So I definitely get your point, Andrea, though I don't really understand the anger I sense in your post. But that might just be another matter of style :)

My main problem with JSLint also is that I can't really customize it. But as Paul mentioned, there is JSHint for example.

@Sergio: at Falsy Values Douglas explicity mentioned that he didn't say there are no use cases for "with" (so he's probably far from "hating" it). He just thinks there are alternative ways to get the same results without the ambiguity which ->might<- come into play.

Andrea Giammarchi said...

Oliver, the anger comes after a depressing week and me tired, at the end of the same, to hear developers saying stuff like: "JSLint may avoid some code review" or "with JSLint my code is safer" or "we collect a list of warnings and we blame developers on top"

There are many cases where lint is good but unfortunately people spread around that JSLint is a must have and if JSLint is bad, it must be ... I am kinda against developers that follow in a passive way suggestions, specially those coming from an automatic parser which cannot possibly understand edge cases.

Last, but not least, I have asked years ago the possibility to avoid warnings via /*@ignore:true*/... code .../*@ignore:false*/ and nothing happen: I am still a noob for this validation tool ...

Aadaam said...

I had a tech talk at a ...khm... well-known company about jslint. Eventually, it came about to the point of list your vars in a single line (which is a switch in jslint).

It turned out, while they were pro of listing all vars on the top, but they wanted to do it with multiple var statements instead. They had such compilers I guess which would get rid of this redundancy in minified code anyway.

I said "fine, if that's your desired coding convention as a team, just patch JSLint, or choose another syntax checker".

They looked at me like I was mad...

Linting tools are tools. I believe TDD/jsunit is a tool too. Sometimes it has considerable benefits to use them, sometimes you have to cut them to your own needs.

And sometimes it's best to avoid them.

Chris said...

Sergio - safe, really?

safeEval('alert(window.document.cookie)');

No way! Please, stay away from writing code like this!

Ben said...

Were you high when you wrote this?

Seriously, there's some utility in JSLint, and indeed other lint tools, but they are not designed nor intended to be read as gospel; merely an aid to identify risky parts of your code.

Step away from the bong for a moment and consider taking the positives from tools such as this.

Andrea Giammarchi said...

Hi Ben, I wasn't but I see JSLint gives you "positive vibes" ... well, use it if you like it, I personally don't (regardless, sometimes I had to use it, quality improvements equal to zero, imo)

John Hall said...

To start with (why is the comment box so tiny?), I'm not pro-JSLint. Actually, I came to your blog after searching for some good commentary that would help me decide whether or not to use it as quality testing tool in a project I've started. I'm not a javascript guru by any means, but I noticed that no one had anything to say about your examples:


So why on bloody earth this piece of code does not pass JSLint?

var something = (function () {

// top reference available ever
// function declaration
function something() {
return oneTwoThree;
}

// second references available in this scope
// local scope variable
var oneTwoThree = 123;

// return the local function call
return something();

}());


(so the comment box is tiny and doesn't accept <blockquote>, <code> or <pre> tags... maybe that's why no one mentioned the examples)

Try running this in a browser:

var something = (function () {

// top reference available ever
// function declaration
function something() {
alert("Typeof oneTwoThree: "+ typeof oneTwoThree);
return oneTwoThree;
}

something();
// second references available in this scope
// local scope variable
var oneTwoThree = 123;

// return the local function call
return something();

}());



If you happen to call something() after you've declared it, but before you've declared the local var oneTwoThree, you've got a problem: oneTwoThree is assumed to be a global var because the local one doesn't exist yet. Therefore, in this particular case, it's a probably a good idea to stick the var declaration at the top of your anonymous function declaration.

Andrea Giammarchi said...

you probably don't realize that function declaration is available before eny variable declaration, as I've written here and explained a lot in other posts too.

in few words it does not matter if you declare func after the variable that func is using inside its scope

func(); // undefined, not an error

var whatever = 123;
function func() {
return whatever;
}

accordingly, if you do this you are messing mup much more with the code

var whatever = 123;
function whatever() {
// do something else
}

the fact JSLint tells you that variable first, then functions, in big scopes could be a big problem because you might shadow without realalizing a function with similar names.

function declaration first is a good thing ... the fact JSLint is not able to understand the scope of the function related to the function outer one is not a JS pitfall ;-)

Go JSHint 'cause JSLint is deprecated, it does not support new ES5 variables such Object.create(null) that do not require slow hasOwnProperty check in each for/in as example plus many other things.

Regards

John Hall said...


var checkWhatever = func(); // undefined, not an error

var whatever = 123;
function func() {
return whatever;
}


That first call to func() does not return "undefined". It returns "123" when you run it in a browser console (but your last statement, the function declaration, returns "undefined" so you'll actually have to examine checkWhatever). I do see your point, however I would like to rephrase the above example in terms of the previously discussed example:


var something = (function () {

  func(); // something is undefined, not an error

  var whatever = 123;
  function func() {
    alert( "something is"+ whatever );
    return whatever;
  }

  // return the local function call
  return func();
}());


Run this and you will find that the first call to func() alerts you that "something is undefined". However...

var something = (function () {

  var whatever = 123;
  func(); // something is '123'

  function func() {
    alert( "something is"+ whatever );
    return whatever;
  }

  // return the local function call
  return func();
}());


Though the first case may not be an error to the js interpreter, it would be contributing to a broken app and it may even be difficult to track down why the app was broken, because there's no "error" reported. Yet, moving the var declaration/initialization to the top of the anonymous function fixes the "not-an-error" error. Notice that I didn't move the declaration for func(){} any where. I don't know the deep-tissue, technically specific reason why this "works" (var whatever is properly defined during the invocation of func), but it's just one example of why declaring vars at the top of a function makes sense. On the other hand, here's something about JSLint that is really bothering me:

function doSomethingWithNodes(nodes){
  this.doSomething();

  for (var i = 0; i < nodes.length; ++i){
    this.doSomethingElse(nodes[i]);
  }

  doSomething(); // want to find this problem
}


jslint.com output:

Error:
Problem at line 4 character 8: Move all 'var' declarations to the top of the function.

for (var i = 0; i < nodes.length; ++i){

Problem at line 4 character 8: Stopping, unable to continue. (44% scanned).


I'm having a similar problem, but I got this example from http://stackoverflow.com/questions/4646455/jslint-error-move-all-var-declarations-to-the-top-of-the-function

What bothers me is that the jslint rule is so fanatical that even the following modification does not go through:

function doSomethingWithNodes(nodes){
  var i = 0;
  this.doSomething();

  for (var i = 0; i < nodes.length; ++i){
    this.doSomethingElse(nodes[i]);
  }

  doSomething(); // want to find this problem
}


WTF?!! JSLint just won't move forward unless I take the "var" out of the for-loop, even when it is previously declared at the top of the function. According to the "JavaScript Pocket Reference" (David Flanagan, 2012):

"It is legal and harmless to declare a variable more than once with the var statement. If the repeated declaration has an initializer, it acts as if it were simply an assignment statement."

So in the latter case, the var in the for-loop is NOT a variable declaration, but simply an assignment statement, because the variable was declared at the top of the function. That does it, I'm tossing JSLint out the window...

Andrea Giammarchi said...

this is a very old post and I already use JSHint and discussed JSLint problems all over this blog. Feel free to use it if you think is the right tool for you .. it won't be the right tool as soon as you move into ES5 world where you can control enumerability, as example, and you have new kind of objects that JSLint won't let you ignore. Moreover, problems with == null etc ... but trust me, no need to explain me anything since it's explained already here and in many other places. JSLint is not what I'd suggest to anyone out there. You do what's best for you, of course.