Move over Java, I have fallen in love with JavaScript

April 7th, 2010 · 44 Comments ·

I spent the past year developing <angular/> in JavaScript (client) and Ruby on the server, and I have totally changed my opinion of dynamic languages, and I wanted to share some thought with you.

Tests are a must

Compilers are great at telling you that you have miss-typed something or that you assumptions about classes are wrong, but so is executing the code. So if all of my code is already exercised by the tests, than why do I need to have additional check of the compiler. Compile does not make the need for tests to go away, but the tests do make the need for compiler to go away. So if you have close to 100% coverage than you don’t need compiler to tell you that you mistyped something.

To get close to 100% coverage, you need to do tests first, and it has to be second nature to you. I run all of my JavaScript tests on every save across most browser using JSTestDriver and all my tests execute under a second. This instant feedback on every save is as good as having Eclipse underline your code that you made a mistake, and so I really don’t miss the compiler.

I can see how a dynamic language can be a nightmare if you don’t have tests.

Tests are easier to write

Since there are is no compiler to harrass you about types, it is very easy to fake out dependencies. Are you expecting a complicated class, but you know that in your test you are only exercising one method which should return a constant? Piece of cake! Create a nameless object with a single property which has the method and you are done.

Typing is a lot of typing

Typing as the name implies, is just that a lot of typing.

Java:
  List<Book> books = new ArrayList<Book>();

JavaScript:
  var books = [];

Look how much longer java line is and how much shorter JavaScript is. Is there any information missing? Both say that I have a list of Books, but one says it by convention (variable names ending in ‘s’ are arrays of the name) where as the other is explicit and makes me repeat myself by typing book three times and List twice. (Tests, prove that my code works, no need for compiler.)

Code Density

Code Density in dynamic languages are phenomenal! All of the endless casting, coercing and repetition in declaration simply is not there resulting in very dense code. But, I am master Eclipse jedi and  can generate all of that verbosity with few keystrokes so typing is not an issue! True, but reading/compression is! 10 lines of code are easier to understand than 100, and in JavaScript those 10 lines often do more than 100 in Java. (To start with 100 lines of code does not fit on my screen at once.) Turns out JavaScript is still wordy and CoffeeScript is even better!

Functions as first class citizens & Classes with single methods are functions

Having functions as first class citizens which can be passed around is awesome! See Execution in the Kingdom of Nouns! Functions are verbs, and you need both, verbs and nouns to make a sentence.

Recently I got an email from someone pointing out that doing proper Single Responsibility Principle, often resulted in classes which had exactly one method. Odd? Well, actually, it is a function in disguise.

Function closure == Constructor injection

If Class with one method is a function, than dependency injection for that class is the functions closure. Where the function is created specifies what are its dependencies and its visibility, nicely solving the dependency injection problem for functions.

JavaScript is so simple

I am constantly in awe, just how simple JavaScript really is! I can explain all of the rules of JavaScript to you in few hours, something which I can not do with Java. And yet, I feel like JavaScript is so much more powerful than Java because it has functions as first class citizens.

Everything is still true

All of the things which I have talked about in my blog is still true. Dependency Injection is a must and JavaScript’s dynamic nature does not make go away. Anyone who claims that DI is only for Java and that his language somehow makes it exempt form the rules of managing your dependencies, needs to lear more about DI. Similarly global state is a bad idea, and JavaScript is extra bad here, as global is the default and you have to do extra typing to get propers scoping, same goes to functions and their default affinity to global state. Bad JavaScript, Bad! Separation of wiring from logic still holds true and no amount monkey patching, will keep you sane in the long run.

Where did the inheritance go?

I have written 10,000′s of lines of JavaScript and I am yet to come across a need for inheritance. Where did it go? Proper use of inheritance == polymorphic behavior but one can get that with duck typing just by implementing the right kind of methods.

Scaling the Team

I have heard this many times before: I like (insert your dynamic language here) for the first 1000 lines than I miss my types. Well, I have written 10,000′s of lines and I don’t miss the compiler one bit, quite the opposite I have learned to loath when I am back in Java and the compiler gets in the way. So why is my experience different? One word: Tests! I am very serious about testing, and so are my team mates! As long as you have tests, lack of compiler is not a problem and the code scales just fine across more team members. But argument can be made that it scales better:

  1. Less code to maintain, write and understand
  2. If you can’t understand it, just rewrite it, after all its just couple of hundred lines, how long can it take you?

JavaScript on the Server

Developing web-applications means that you have to be expert in both Java and JavaScript, but lets fix that problem by moving JavaScript to the server. Node.js is a perfect example of that, and I love it.

Non-blocking API

Non-blocking API are a stroke of Genius! In short it makes it impossible to write slow tests. After all how can you make the tests slow if all method calls return immediately? That is the reason why I can execute 400 test in under 500ms an every save.

Tags: Uncategorized

44 responses so far ↓

  • Juho Veps // Apr 7, 2010 at 11:32 pm

    I got bitten by the JS bug a few weeks ago. It’s an amazing little language. Though the object model is somewhat simple, it’s powerful enough.

    Pretty much the only major features I have missed from Python so far are operator overloading and a proper way to handle imports. Apart from that I have been really happy with the language. It reminds me of Lua in a good way.

  • Steve // Apr 7, 2010 at 11:44 pm

    It looks like you’re doing this project by yourself.

    Next time you work in a team and you have to read, refactor and review code you didn’t write, you will realize why types are so important.

  • Richard Paul // Apr 7, 2010 at 11:57 pm

    Great article, Java really does become tiresome after using Javascript or Groovy.

    What are your thoughts on Groovy? It offers a lot of the great features like duck typing, closures, method missing etc with the added benefit that it is interoperable with Java.

  • Martin Vysny // Apr 8, 2010 at 12:18 am

    Nice optimistic article, thanks! :) Just two questions: how about refactoring, do you feel you don’t need it anymore? Second question, don’t you miss the ability to immediately know the types of objects a method requires, or what kind of methods it requires on the input object?
    Okay, additional third question: non-blocking API is nice but don’t you have to wait for the result to assert on?

  • Jonathan Hartley // Apr 8, 2010 at 5:15 am

    Totally agreed all round, although I’m coming from the Python world rather than Javascript.

    >> This instant feedback on every save is as good as having Eclipse underline your code that you made a mistake

    Better, surely? Your tests are carefully tuned to confirm that your code is behaving correctly. This is much more valuable and detailed than compile-time checks can ever be. Merely confirming that you are conforming to some arbitrary rules about type-checking – this is somewhat orthogonal to knowing whether your code is correct.

    >> Typing, as the name implies, is just that: a lot of typing.

    Interestingly, although typing all that extra verbiage is inconvenient, the real problem is not typing the code – it is reading it afterwards.

    One common way of reduce the amount of typing in static languages is to have your IDE generate a lot of the code for you, using auto complete and inference of repeated type declarations, templates for class creation, etc. The problem with this is that although it helps to make the typing convenient, it does not help at all with reading the code – which is way more important. If anything, this ‘solution’ promotes the production of huge tracts of auto-generated code, with no thought given as to the length or readability of it.

    The dynamic solution, of reducing the vebiage and needless clutter, is better. Python is especially good at this – it has been one of the fundamental tenets of the language design.

    It is true that static typing has benefits. Obviously speed of execution is one of them, since things like vtables can all be pre-computed, etc. Also, catching some elemetary errors due to mismatched types is another benefit. However, in my experience of using dynamic languages after many years as a C/C++/C# jockey, I have found that those typing errors that a compiler catches are (a) not especially frequent, compared to all the other errors programmers make, and (b) generally very easy to fix – one passed parameters to a function in the wrong order or something. So these are amongst the most trivial errors a programmer has to deal with. So the benefits of static typing are not really as big a deal as one imagines when one is deeply immersed in a static language.

    Conversely, and what is often overlooked, is that static typing comes with some costs. These are easy to overlook when you are using a static language, because you become immersed in its rules and systems – they start to govern the way you think about programming, so that you imagine there is no other way to do it. But when you move away, to a dynamic language, you start to realise all the hoops you previously had to jump through just to keep the compiler happy. You suddently realise that major languages features such a generics are really just a big ugly kludge grafted onto the language so as to allow you to do what you want to do while still keeping the type system happy. In dynamic languages, the need for all that simply goes away – everything is generic, all the time. The same is true of many language features. Dynamic languages, as a result, are much simpler and much more powerful at the same time.

    I once wrote a big rant about this here:
    http://tartley.com/?p=456

    Best regards,

    Jonathan

  • Jonathan Hartley // Apr 8, 2010 at 5:21 am

    oooh, and, with reference to the redundancy of checking types once tests are in place. Jay Fields describes it thus:

    Type checking can confirm that your function to add two integers always returns an integer.

    Tests will confirm that, for various different integers, 1+1=2.

    2 is an integer. The type checking is now redundant and can safely be removed.

    (cue spluttering from people in the audience working on writing static language compilers)

  • Alexander Poluektov // Apr 8, 2010 at 5:23 am

    Hi Misko,

    > Typing is a lot of typing

    I wonder whether statically typed languages which have type inference are best of both worlds?

    Like, you have all nice type checking it’s compiler’s business to infer types of variables?

    Best regards,
    Alexander Poluektov.

  • Jonathan Hartley // Apr 8, 2010 at 5:24 am

    Oh, and, can you explain more about the non-blocking API? I don’t understand that. Are new threads or processes getting launched to complete the execution of each test? Where does that happen? Doesn’t running many tests in parallel eventually bog down the machine, so they all take a long time to run?

  • misko // Apr 8, 2010 at 7:10 am

    @Jonathan,
    Non blocking API:

    say you want to read from HTTP, you can do something like this (pseudo code):
    console.log(‘request’);
    xhr.requeast(‘GET’, ‘http://server’, function(response){
    console.log(‘resoponse’);
    });
    console.log(‘done’);

    when you execute this you get:
    request, followed immediately by ‘done’ with no delay, at some later point in time, the system calls you back with response. This means that in tests you have no choice, but to mock out the request, as the response would come back after the test would complete (and fail). This makes it easy to know what calls to mock out in order to get fast test.

  • misko // Apr 8, 2010 at 7:13 am

    @Alexander,
    I have spent some time with scala, which has that feature. I have not done a large scale project, but here is what I know of Scala:
    1) the code is a lot more dense
    2) functions are first class citizens
    3) It is strongly typed, so mocking is not as easy as in JavaScript
    4) There are plenty of times when inference does not work.

    I have not coded enough, but I think scala is a step in the right direction, and is a great improvement over java

  • misko // Apr 8, 2010 at 7:16 am

    @ Jonathan, well said! thanks for your support

  • misko // Apr 8, 2010 at 7:19 am

    @Martin,

    re-factoring is a bit of a pain. IDEs are getting better and they can do some limited renames, inline, etc, but no where as good as what you are used to. But it turns out that in practice it is not that big of a need, as most refactorings, even in java require a lot of copy and paste. The advantage is that you have less code to refactor so it makes it little less painful. Finally, rewriting a piece of code becomes more realistic option since it is only few hundred lines of code.

  • misko // Apr 8, 2010 at 7:21 am

    @Richard,
    I have used Groovy, only a bit, and Scala, a bit more, and I like it a lot. Java is becoming a bit stagnant, which is why we see all of the proliferation of JVM compatible languages such as Groovy, Scala, etc..

  • misko // Apr 8, 2010 at 7:26 am

    @Steve,

    is done by me and Adam. So that is two people, but I do most of the JavaScript. Every time Adam, has to change something he says, “I don’t know how the whole system works, so I tried to add it here, and than your tests broke, which forced me to move it there. Do you think that is right” and I usually say, yes. So it is interesting to see that even thought it is a large system and he does not know it as well as I do, the tests force him to do the right thing.

    Second at work I use angular to build an internal app with 3 other people (for a total of four) and so far it has not been a problem, but i am supper draconian about making sure that they write a lot of tests, even more than in Java. Here is what one developer which was a big skeptic, and had the same thoughts as you has to say: http://theshyam.com/2010/03/is-strong-typing-really-needed/ (he is coming around)

    The think which I am trying to say is that, your experience is true, and dynamic languages, do not scale if you have no automated tests, but tests are a great equalizer. However, writing tests, takes skill, a skill which is not required for static languages. So it is possible that you can build bigger things with less skilled labor if you give them static typing.

  • misko // Apr 8, 2010 at 7:27 am

    @Juho,

    Yes, import statements are very broken, actually, a lot of things about JavaScript ‘the environment’ are broken, but JavaScript ‘the language’ is mostly amazing.

  • bummerhan // Apr 8, 2010 at 7:37 am

    this is strange, I don’t see Java and Javascript as being on the same line, nor python etc…

    i love Groovy, it will be the superglue to empower Java – which is bogged in copious code writing and configurations – making it available to application developers.

    Ruby is fast-and-dirty and i use it a lot via sinatra but javascript i keep to a minimal (strongly suggest all javascripters to check out coffeescript)

    still believe developers should use the best-fit language for the task, and dealing with increasingly complex querying, interactions, filtering, api calls, page flows – you need dynamic aspects to keep code expressive & manageable.

    so…to me personally, Java is a language to build reliable large components and javascript is a language meant to be read by browsers.

    we all have our favourite silver bullets, but i think the future is going to be more polyglot – while we are arguing one language over the other

  • misko // Apr 8, 2010 at 7:43 am

    @bummerhan,

    “javascript is a language meant to be read by browsers” this is changing with http://nodejs.org JavaScript is becoming a language to build servers with. But you are right all languages have their strengths and we all have our favorites.

  • Itay Maman // Apr 8, 2010 at 7:46 am

    Your points exactly fit with my experience. Javascript was the first dynamically-typed language that I seriously used and indeed I was deeply impressed with the flexibility it offered via dynamic tying and closures.

    The only thing that worried me back then was the lack of a proper (fast) unit testing. Now that I have JSTestDriver, this concern is gone.

  • Jan Szumiec // Apr 8, 2010 at 9:11 am

    Node.js looks like really cool stuff – thanks. If you’re an Emacs fanboy I recommend js2-mode by Steve Yegge – it makes editing JavaScript a breeze and warns you about misspells, proper variable declarations and adds syntax highlighting.

  • Brendan Miller // Apr 8, 2010 at 10:39 am

    It blows my mind that so many people are still doing Java development, when there are such better tools available…

    It’s kind of difficult to get the word out though. I used to be really skeptical of dynamic typing being superior to static typing as well…

    I’d also take a look at Python or Ruby if you need to do server side stuff. Python also supports really easy bindings of native code with ctypes. Much easer than Java or Spidermonkey(JS) bindings.

  • Josué // Apr 8, 2010 at 11:00 am

    Hi misco,

    Just curious, did you ever considered to use GWT (Google Web Toolkit) to program in the client side? I know it is the contrary what you like. You have to program in Java. But there is some advantages.

    This presentation (a bit old) has some (I think) advantages. I don´t agree with all of that but some in my opinion are true: http://www.scribd.com/doc/7679998/GWT-the-Technical-Advantage

  • misko // Apr 8, 2010 at 12:27 pm

    @Josue,

    yes, we started of working with GWT and than after 4 months, scraped it and rewrote it in in 2 weeks.

  • Simon // Apr 9, 2010 at 3:08 am

    Hi misco

    Really interesting … though I am still trying to make it into the Functional Paradigm

    re: dependency injection/function closures etc … so I have a data retrieval object which takes an authentication object as part of it’s construction (as well as a definition of the data to be retrieved) … and then has a single retrieve-type which retrieve different data

    are you suggesting that it would be better design to

    a) inject a function instead of an object
    b) make the data retrieval class a series of functions each receiving their own authentication parameter
    c) … something else

    Thx again (sorry if it is a dumb q)

    S

  • misko // Apr 9, 2010 at 6:57 am

    @Simon,

    I am not suggesting that you go crazy with functions, instead I am saying that there are many cases where you have a class which has exactly one method, in those cases consider using a function instead. Typical things are callbacks which have single method notify.

  • Fadzlan // Apr 10, 2010 at 9:46 am

    I agree when you have a team of really smart people, you may actually have a chance of success in big scale project using javascript as your main language.

    However, those of use who are stuck in consulting companies, working on enterprise technologies, that may not be the case. A lot of people are working in an environment where the project have to met certain margins, thus, are having a lot of developers who are fresh from University, with only few seniors who can guide them.

    Getting those fresh people on proper software design and easily testable system are hard enough. Heck, they are already having hard time making things work.

    Still, the project has to be done on schedule and within budget (sometimes with ridiculously low margin as it is). Choosing javascript as the main language would be suicide.

    Java(or even C# in this perspective) is a language that protects us from shooting our foot in most cases. When you are working in a team that is easy to have someone else shoot your foot, going safe is not a bad option.

    Of course, by working at Google, it helps to use a language that provides more powers and freedom since you can handle the safety by test. Its just that, its a different world out there.

  • misko // Apr 10, 2010 at 10:15 am

    @Fedzlan,

    I agree with you that to get away with building large systems in JS you need to have more senior people. However one advantage of JS is that the code you produce is shorter, and hence you need fewer people to deliver the same set of functionality. So I simply don’t buy the argument that Java is cheaper to develop since you can hire cheaper people, since you will have to hire more of them.

    People always compare things as if all other things were equal. But all other things are not equal and hence the comparison is not that simple.

  • Lukasz Konopski // Apr 11, 2010 at 8:07 am

    Interesting, but… compiler is on my side, machines are generally better in calculations so why should I gave up its help?
    Other thing is readability of code. Java as inspired by C introduces some overhead. CoffeScript looks really concise – on other hand most people did began with C, therefore many of idioms look more readable than concise, sometimes cryptic versions ( eg. -> for functions, see also some Scala constructs).

  • Max // Apr 12, 2010 at 7:45 pm

    welcome to the “Client Side!” Nice article!

  • Josué // Apr 13, 2010 at 12:37 pm

    @misko

    If I understand you (my language is not english), you dropped GWT from the project to use JavaScript direct. If you could tell something about why you did that I think it would be interesting.

    Here at work we are migrating to RIA. The debate was to use GWT or Flex. GWT won because we have a Java background. We did not considered to implement direct in JavaScript because:

    - we already use Java in the server side. Less a thing to learn;

    - in many places we could reuse code in the client and in the server side as it all Java. Less duplication;

    - we could use the same things available do the server side development to the client side: IDEs, frameworks(JUnit for example), refactoring, debug (no everybody here do TDD);

    - GWT compiles de Java code to the specific JavaScript code associated to the browser. So the problem to adjust the JS to each browse is a GWT problem, not my problem;

    The GWT compiler do various tricks in the generated JS code to be gain more performance and to be smaller. For example a method name transferFromOrigemToDestiny in Java could became t in the compiled JavaScript. So the code became smaller and takes less time to download. But we still have the beatiful names in the Java code.

    So if you could share your thoughts on it, I will really appreciate.

    Thanks.

  • misko // Apr 15, 2010 at 10:02 pm

    @Josue,

    the reasons are complex

    * Web development requires a lot of callbacks and closures, something which java does not have, and hence it is the wrong language for the job.
    * GWT does not allow for reflection, which limits the kind of thinks you can write.
    * You can not use existing Java libraries as they don’t cross compile
    * You can not use existing JavaScript libraries, since you have to create JSNI APIs for them and many are fundamentally incompatible, such as JQuery
    * The resulting code is much bigger than hand rolled JavaScript
    * You end up writing a lot more code.

  • Josué // Apr 20, 2010 at 10:00 am

    @misko

    Thanks misko. I understand yous points and I think they are true. And I think you forget one. The time to compile. :)

    Anyway, I still think that GWT pros in my context make worth use it. Of course YMMV.

  • Timo Reitz // Apr 21, 2010 at 1:33 pm

    The first time I tried to post a comment, it did not appear. Maybe because JS was not activated? Would have been nice to warn me if that was the cause.

    I disagree with your conclusion. I think this is not a dynamic-vs-static-typing case, it’s a matter of functions as first-class objects and a matter of explicit type typing instead of type inherence.

    Just compare PHP and Haskell. The former is dynamic, but lacks functions as first-class objects (at least until 5.3) and it sucks, really (I programmed a lot with PHP lately, it is _not_ fun). The latter, Haskell, has static typing, but type inference, so you don’t have to write your types explicitely (at least not always, when I remember correctly). And it has the belovable functions as values.

    Oh, I totally agree with you in this point: Object-oriented programming done right (and really right) has a lot in common with functional programming.

  • Esko Luontola // Apr 26, 2010 at 5:48 am

    Which unit testing framework would you recommend for JavaScript? In one month I’ll be leading a project which needs a complex web UI, so now I’m reading “JavaScript: The Good Parts”. I don’t know what testing frameworks there are for JavaScript, although making one that suits my style would only be a couple of hundred lines (recently I wrote NanoSpec.go to bootstrap GoSpec, and it’s only a bit over 200 lines production code).

    Are there some JavaScript testing frameworks for testing visuals? The system under test would draw some component, and the test would compare a screenshot of the component to the last known good value. Each new unique screenshot is validated manually by a user (does it satisfy a list of human-readable textual assertions), but on the following runs, if the visuals are not changed, the test will remember that it has been validated.

  • misko // Apr 26, 2010 at 8:49 am

    For Unit tests I like JsTestDriver(http://code.google.com/p/js-test-driver/) + Jasmine (http://github.com/pivotal/jasmine) + JSTD Adapter(http://github.com/mhevery/jasmine-jstd-adapter)

    For end to end tests Selenium is the standard: http://seleniumhq.org/

  • Pedro Newsletter 06-11.04.2010 « Pragmatic Programmer Issues – pietrowski.info // May 5, 2010 at 3:51 pm

    [...] TDD expert leave Java and have fallen in love with [...]

  • jneira // May 30, 2010 at 3:25 am

    soon you’ll be prepared for next step in functional paradigm progress :-P : a lisp (clojure) or a ml (scala)

  • Adios, Java! I hardly knew ye « Seeing things as they could be… // Jul 30, 2010 at 12:19 pm

    [...] After some sincere reflection on how I spent my time building a little firewall logger/reporter, I realized that I’d spent way more time digging through Java documentation to get JSP calls working than I had designing or developing anything else. Java is a very complex programming language and I wonder if that complexity is often mistaken for powerfulness. Apparently, I’m not the only one who wondered. Misko Hevery wrote a treatise on this topic. [...]

  • Skilldrick » Why JavaScript is AWESOME // Jun 2, 2011 at 1:32 am

    [...] Move over Java, I have fallen in love with JavaScript: Miško Hevery usually writes great things about testing – here he talks about JavaScript, from the perspective of a Java programmer. [...]

  • Krishna kumar // Aug 30, 2011 at 11:26 am

    Totally agree , Ya it might to be…. i am with you make it 100% success.

    JavaScript All The Way………..

  • gmadar // Jan 16, 2012 at 3:57 am

    like any other solution. it has it’s good part and it’s bad parts. But hey – I love JavaScript :)

  • Introducing onedb: Connect Small Data in the Cloud « Missing Link // May 5, 2012 at 3:56 pm

    [...] language in a large number of use cases. JavaScript, in contrast, achieves generalizability through simplicity; for one, it’s much easier to implement a basic JavaScript interpreter than a JVM+JDK. [...]

  • Whouzou // Jun 15, 2012 at 8:24 pm

    The example
    “Java:
    List books = new ArrayList();

    JavaScript:
    var books = [];”

    is pretty missleading. Imagine you want your own hashset, binary tree or another custom data structure. Suddenly it is “var books = new YourCustomStructure();” and this is really not much less than the java code.
    Also, typing a few characters on your keyboard is _nothing_ against searching only one bug caused by using wrong types/objects in javascript. I know that as i am currently working in a team of 12 developers.

    Also, its nice if you write tests for your software, but in our case the execution of all of our tests takes about 10 minutes. Your tests may not take as long as ours – but why should i care about your tests? If you want to argue that type checking is not needed because you have tests, you can not only consider your own software and its tests.

  • Marc // Nov 16, 2012 at 11:17 am

    Whilst I hate Java and love JavaScript it cannot escapte notice that JavaScript applications are inherently fragile. One error in an obscure script somewhere can bring your whole application down. In many cases it’s the kind of issue a compile would have caught. Sure you can write tests to catch type errors but then the argument about less code meaning less bugs (which I accept) falls down because you need more test code (which must also be written and maintained) to compensate for not having a compiler. I think we’re a long way from efficient professional JavaScript applications. We have professional JavaScript applications today yes, but the effort which is required is several factors greater than in a compiles scenario. Compare say the development effort of GMail with that of a desktop mail client written in .NET or Java and this becomes clear.

  • Kai // May 23, 2013 at 1:14 pm

    @Marc, I think the unit tests you write for JS will do _more_ than just catch things that a compiler would have caught. These unit tests will provide more security. So the things you get “for free” with the compiler are less than the things you get with unit tests. And if you do unit tests for the compiled language, you need to spend the effort on it, too.