Общо показвания

януари 01, 2015

Dart (a revision at the end of 2014)

In this past year I have been using Dart on and off and then back on and then back off and I wrote a lot of articles about it (mostly critical but hey, this is who I am and this is who most people are - most people tend to emphasize negative impressions while the positive ones are accepted as 'the normalcy').

As with many other Google related things the often missed truth is that a lot of work and a lot of consideration has gone into the idea long before it became a project and still before we even have heard about it. 

Dart is not an exception. If you have been watching carefully the talks published that are related you will easily notice that even now, long after the language has reached 1.0 and have been publicized as 'stable' and 'ready to use' there are still things that are not clear and that different project members want things to be done in different ways and at the end of the day not everyone is happy with how things went. 

As a side note I think that Google should not force people to go to conferences because they (those forced people) tend to express their opinion on things in an agitated state and it makes a very very bad impression on the states of affair when an open source project is concerned especially if you are putting your neck up when advertising 'pro' it inside your company (or even worse when you are a start up or a young company and you need to make some technical decision that can cost you a lot in the short and long terms). I have seen at least 3 such videos - the first one I have talked about before and it concerns angular dart mostly. The last two I have seen only recently. One of them basically starts with 'I have picked the short straw so here I am to talk to you about dart ...'. and finishes with 'So here it was, I talked to you about those things that I know nothing about, do you have any questions?'

The second one I have in mind if given by Gilad Bracha and in it the negatives are less but still they creep in.

Why I mention this? Well, the thing is that when you go to present something on a conference (or wherever) you are expected to be enthusiastic about it, you do not go there to say bad things about what you are talking about, right? Even when it is really a stupid useless piece of moronic code that you have made in your free time and no one will ever never use (like some of the items presented at HTML5Conf, omg, I feel like this was the worse conference ever, full of really badly prepared presenters and full of really badly made software). But still those people talk like their thing is THE thing - it almost cures heart disease and cancer. They are enthusiastic and positive about it and even when almost everyone leave the room after 10 minutes of their presentation and there is this irritating guy in the front row who keeps interrupting and asking real questions that they have no real answers for they keep going explaining to everyone (who did not leave) that this is it - the next big thing.

Putting that on the side, the reality is as follows: it takes too much effort to write real world web application. Way too much. There is no standard toolkit. There is no usable / fast way of creating UI/UX. If you go for a framework you are basically stuck with it. We have seen time and again (now even Google acknowledges it) that Polymer is way too slow for real world usage, so this is a no-op for now, mastodon libraries were great once upon a time, but they are now crushed under their own weight - they are so big and so hard to write for that they simply cannot keep up with the evolving requirements of the UI/UX on the client side any longer. If you chose to go with that, you are basically stuck in the state of the art UI of year 2000.

But even if you close your eyes (for the mobile first etc UX) you still face a ton load of issues - incompatibilities in the libraries (have you seen projects where the UI is done in one library, the graphs in another, yet more dynamic things with another and so on and each of those provides its own way of doing things?), the minification (I know it is not a word, even the spell checker thinks it is not a word) and then the bloating (no mater how much you minify at the end you still push 600KB on the client on mobile connection and this is only the script, let alone the images and styles and then the live performance... oh my...).

So I think most people agree that web development is super complex today.

Where do you even start to learn if you are new to this? Do you start with simple scripts (news flash - it is not really helpful if you are then buried in half a million lines of code of an app)? Or do you start with a coach, who will have to explain exactly how browsers work today, how they fetch resources, what is blocking, what is not, when painting starts, what is re-layouting, what is the link between JS objects and DOM objects, why you should combine your read and writes to the DOM and so on and so on. Even a super intensive course on all the topics (and brace yourself, we have not even touched the SVG, canvas, webGL, audio processing, server side, noSQL DB etc yet!) would take weeks.

How much does it cost to train a new developer (not necessarily one without experience, but instead new to the client side/JS). JS is really not just the language. Its the DOM APIs as well. JS without it is not that bad, you can write simple apps in it and run them in node. And then on the other hand if you are classically trained in C++/Java JavaScript has so many underwater stones that you will be productive in... at least 6 months I dare to say. I mean really knowing what you are doing.

I have worked with people coming from back-end to the dark side (the front end): its not the event loop that trips them first: its the fact that you have multiple entry points to the same application. The fact that if you change the order of script tags things tend to break badly.  The fact that you are declaring things but some things are immediately executed while other are not and finally the fact that you cannot just do your work in a loop, you have to break things to smaller pieces because otherwise you kill the UX.

This and much more need to be learned before one developer can even start  (to let say port his ideas from the mental model he or she is used to on the back-end to the front-end coding arena).

Now about Dart.

They have got some things right, and mind you, those might seem like trivial things for seasoned JS developers, but are super important to people coming from other languages and from the back-end.

Single point of entry for your application: you cannot believe how much of a help that is! I have seen it with my eyes and now I am a believer. Well, this is nothing new, some frameworks/libraries have been doing this for a long time, but most do not provide any guidance about it. Now compare this to multiple 'onload' handlers and multiple immediately invoked function spread over tens of files. If you already know the internal design of the application it might not sound so bad, but usually you do not. And it is bad!

Built in libraries: I do not even know how to compare the dart (and most other languages) libraries with the way things work in the browser. I have worked with a young designer that has been learning JavaScript for some time now. He still does not get the order of execution of JavaScript libraries, well because the language does not provide a built in way to require another library and most do not even bother - lets assume a UI plugin for jQuery: it requires jquery, this is simple, but then again in the docs it requires another plugin, but instead of requiring it at use time it requires it at creation time (i.e. the required plugin needs to be present when the new plugin is registering with jqeury) - this is a hard dependency. Now imagine how many times I have been asked to resolve a "problem" that turns out to be incorrectly ordered script tags. You might say 'oh, but this is because the plugin is written in a stupid way' or even worse, you can say 'the guy is stupid, he should read the documentation'.  The truth is different: simply JS was not designed to handle this kind of usage - dependency tracking and handling was never part of the language and every one does it differently. I, for one, like how closure does it but this is just my opinion. I have used AMD as well. I also used simple script tags... but JS does not provide a standard way of doing this sort of things and while we as JS developers may be dazzled by its flexibility (to implement things that are missing) for new developers this is off-putting in immense ways. Yes, this problem is solve-able, but do we need to solve THIS problem - really? Yet we need to solve this with every new project and even worse in the middle of the project we often need to re-solve this because not all libraries comply with the solution we have chosen - be it browserify, amd, commonJS, closure library or whatever more solutions you can think about just because all of a sudden we require a new dependency that does not mach our dependency solution. Let alone the fact that libraries tend to solve this same problem in their own way, 99% incompatible with the rest of the world.... Well - Dart solved this for us! Once and for all. There are cases where this is not working perfectly (for example when we need to inter-operate with JS land in our app - we still need to manage those dependencies on our own. This is also why I am advocating on a rewrite where possible and doable within the project, because I want to get out of that JS grip and use modern tools for my projects. Even if I chose TypeScript (which I have done once) still the external libraries need to be loaded. And yes, I know about concatenation, guess what, order still maters!)

Fixed up DOM APIs: This is somewhat a double sword; on one hand it does simplify the DOM interaction (which means it makes it look more natural and close to the language as opposite to how JS handles this, but of course this is purely a fault of the committees and specs creators). On the other it does not always comes at zero price: I have written about that as well, for example in (maybe older) some version of Dart the image data arrays have been 'manually' converted to regular arrays in the generated JavaScript which had a really big penalty (mostly GC pauses but still CPU as well). This was of course a lack of consideration when it comes to the implementation of the dart2js process, I hope this was fixed, if not - it should be. Never the less the benefits of having a consistent API outweighs the edge cases when it comes at performance cost. Depending on your project you might need to consider what you are doing more carefully than usually. This is I think one of the weak sides of the html package - it makes things so easy that you sometimes forget that there are perfs that you need to account for. Again with an example - I have seen people I work with that had to 'translate' what jQuery is doing and then searching in google how to do it. This 'translation' work is terrible and I think no one should really do it! Consistent APIs for the win... also this is not only my point of view, lots of talks have been made where regrets have shared about how many APIs were designed without really looking at anything else in the list of DOM APIs and how different they look from one another.

Types: Types in combination with generics and the fact that those are optional makes the language approachable by a much larger audience imo: I know that the type information is completely ignored at run time, but if you are a 'typed' developer you don't care, you still consider it essential. Types in Dart are also somewhat not ideal (at least for me) for one single reason: I am so used on union types from closure/typescript that I basically want to make each and every method accept an union of several very different things: just an example - how about an union of string, Node and NodeList - this could be for example the content of an element. Also enumerations came only recently and are still experimental. But still the advantage you get from using types and more precisely the work of the analizer on it is simply fantastic! All of a sudden you can use a much larges code surface without actually knowing it or used it before because of the type inference and the inline help/completion you get. This frees your mind to be bothered much more with the aspects of your own code than with the API surface of the supporting libraries. It simply enables a JavaScript developer to 'know and do more with less'. I know it sounds like a cliche but it is the truth. Want to give it a try - simply try posting complex code to dart. First you will notice that a lot of the code in JS is 'tricks' (like turn this node list into a real array so iterating we can remove some of the items and then make a new iteration on the shortened list and many other such examples where we as developers are spending too much time solving inefficiencies in the language or APIs than actually working with our ideas). One other thing missing from dart types is the so called 'non-nullable' types. In typed variants of JS you can state that a value (especially function params) can never be null and then you safe on type checks, not so in Dart and because there is no such annotation the users of your code are allowed to submit null values as valid ones for every type and the type checker will not warn them, so you have to check the values for null... blah...



Not all is perfect in Dart either. As with many other languages and tools it has some darker sides. One of those is that it works well enough only in Dart Editor. While it is supported on sublime text for example, the support is very limited and does not provide the great experience you get when using the Dart editor. Also the attempt to bring the same productivity to the web for now does not provides what it was expected. The implementation (chrome dev editor) is really a crappy experience compared to more robust and seasoned applications. Even Vim performs better with polymer (because of how it can handle matching tags) than CDE. CDE implements git but only partially and only with some predicaments. It is supper slow compiling to JS (so if you have a large dart code base you can take small naps when you press the 'run' button before the result is shown in the browser). They have had some terrible performance issue with it comes to dart/js integration in the past (I am not 100% sure it is solved now). As such one of the largest user facing projects written in dart does not look so great and does not put dart in a nice place really. There is hope (at least in me) that this will change if DartVM is bundled with Chrome but this seem to not be coming soon...

Another pitfall is that pub does not allow un-publishing your packages. While this is done for a good reason, it makes it pretty much full of dead code. Even more is the number of 'crap' packages (just like in npm you can easily get 10 packages that should do the same, but 10 of them are useless of full of bugs and there is no real review process in place nor a way to know how many projects use it in production and which version). As the times goes the number of really good projects is not increasing with the rate of the badly constructed ones. Having this in mind can make some of us (adopters) cry out loud for the time of monolithic, carefully curated libraries. One stark example is closure library and often related projects (again usually coming out of google) - old code is preferably not removed but just deprecated, all tests are run, everything is tested and performance measured. This means that you need to do more work (reviewing the package and its performance on your own), but I guess this can be improved once more people start using dart (if this ever happens).

Another thing to consider is this: when dart first appeared it was twice as fast as JS and the gap between generated code and handwritten code was very small. One year later the things look a bit different:

DeltaBlue: Dart VM is almost back to the level it was in the beginning of 2014 (~5% improvement). Dart2js has not moved at all, but v8 is now much faster (starting the year around the 400 mark and now it is above 600).

FluidMotion: Dart VM improved by 2 points. dart2js has lost a bit, bit is very close to where v8 is, and v8 is on the same place it was in the start of 2014.

Havlak: it appeared somewhere in the middle of the year so no date prior to that, but v8 substantially beats the dart2js code on this test, as of the last month hand written js code  is closer to DartVM than dart2js is to v8. The really bad performance of dart2js is shame on this test - really! Both v8 and dartVM performance has been improved this year, while the dart2js has not moved at all.

Richards: somewhere at the end of 2013 dart2js and v8 got in parity and stuck that way for the whole year - no change there. DartVM got better at this test by about 10%.

Tracer: I bet this is the fave test of all Dart lovers - v8 got just a tiny amount better at it, but dart2js has always been faster, more at the end of the year than on its start. DartVM also made a great leap this year in this test.

Looking at those tests an interesting picture is forming: DartVM is no longer (if it ever was) twice as fast as v8 - it is now about 20 to 25 percent faster. V8 made some great progress in 2014. Note that this does NOT represent advances in other JSVM so if you have some free time on your hands please do this: compare JS code to dart generated js code in other browsers - please!

dart2js did not moved a lot in 2014 and IMO is still pretty much work in progress. One things I cannot get from those test is the flags used to compile JS from Dart: for example is it minified, is it type optimized, are the boundary checks preserved and so on. Would be interesting to turn on all possible optimizations and then try again. Why? Because Google has been doing type optimizations and in-lining and virtualization and what not to its JS code for almost a decade and using Dart it is possible to do the same. I wonder if it really makes the code run faster as they say. It is known that the closure compiler for example sometimes break hot functions (because of code in-lines basically breaking the compilation to native speed code in v8 because of type alteration or because the function becomes too large (larger function are not compiled)). This is what perf tests are for. There was a recent blog post describing ~14% increased speed in some code so I guess it is worth a try. For this to work however you need to be really diligent  about those type annotations, just like with closure compiler. Which basically excludes some (actually most) pub packages....

This all was about CPU performance, which is fine and well, we see that dart VM is advancing little by little and that v8 is still strong and catching up, dart2js has much to be desired. But what about the other type of performance - memory?

Oh, Memory! There is a really good explanation about why memory is much better topic to talk about when it comes to DartVM vs. V8. Ask Gilad Bracha.

The whole thing is really simple: Dart works differently and the internal representation of things require less memory, which on its own is a big win - remember the talk about static JS? The fact that for a garbage collected environment to work optimally (and fast!) you need to have ~8 times the RAM that your application requires at any given time. Then you can be sure that the GC will not interfere with performance while still doing its job. It is not only limited to JS, but it is important for JS because apps are getting bigger and bigger and bigger, JS heap sometimes is reaching for the gigabyte mark and yet most people do not have 8GB installed...

In the blog post about game development with dart and stageXL I have mentioned that the memory profile of the exactly same app run as Dart and JS generated code is very different, both in the way memory allocations are accumulating in the game loop (mostly fault of the dart2js transformation) and in the memory consumed as a whole. JS code was 3 to 4 more memory hungry and was making more and larger allocations and GC was running more often as a result. Back then I blamed dart2js for the whole things and also I was not sure  if DartVM was reporting the correct values, now that we have better tooling for dart it is proved - having a bigger app in dart is better than having it in js. This is why I really really hope that dart and chrome team can finally integrate and chrome starts to ship with DartVM by default.

Yes, I know that most people are not using chrome (which is not really true, around 50% are using chrome but this is a whole other story), but even for the sake of android this will be a big win both for devs and users: first of all android is usually more memory constrained (as well as those chromebooks!), also being faster means less CPU for the same tasks even if ti is only 20% less, it still can translate to an hour of battery life. But not only that - it will become easier to ship web apps with native feel like (UX). At HML5Conf there was a talk about why app stores should die. Well, they are not dying as far as I can see, but for some apps it is really bothering that you need the cordova wrap just to be accessible for the sake of the store. Google is making some great progress in that direction with recent changes (separating tabs in A5 and so on). I hope the whole cordova thing can go away in 2015 and capabilities are granted to https served apps without real installation (sort of like service worker).

Yes, most apps still need to serve to IE/opera/ff/safari. I for once need to continue to support those, but still, if at least on one platform things get much better the market will react, especially if great apps come out of it. If the users see the difference and feel the difference they will react. So hopefully 2015 will be the year. if not, next year is fine also, but not more... I am getting older after all:)

Happy new year to everyone and may all your dreams of virtual machines and fast code come true!

Публикуване на коментар