The next web app platform?

De browser: steeds vaker een platform waarin complete applicaties komen te draaien. Het is steeds gebruikelijker om web applicaties in JavaScript te bouwen: Single Page Applications. Daarvoor worden allerlei JavaScript frameworks gebruikt zoals: AngularJS of Backbon, gecombineerd met Modernizr (ondersteuning voor oude browsers), Grunt (autobuild framework), jQuery, Jasmine (testframework) of Karma (testrunner). Voor ontwikkelaars die met de genoemde frameworks werken, zou kunnen gelden dat ze over een aantal jaren in Dart aan het programmeren zijn…

Want waarom wordt er eigenlijk JavaScript gebruikt in de huidige projecten? Is dat wel de beste oplossing voor grote webapplicaties? Google vindt dat er in ieder geval een alternatief moet zijn en volgens hen is dat Google Dart. In dit artikel wordt uitgelegd waarom er een alternatief moet zijn en onder welke omstandigheden Google Dart (nog in beta status) een betere oplossing gaat worden.

JavaScript applicaties bouwen
Om het nut en noodzaak van Google Dart goed te begrijpen, is een stapje terug in de tijd nodig. In figuur 1 is te zien dat het web eenvoudig begon en momenteel is uitgegroeid tot een complexe wirwar van technologieën, mogelijkheden en browsers. Een technologie die daarin een grote rol speelt is JavaScript (gele lijn in figuur 1). De context waarin JavaScript begon (ongeveer 1998), is totaal verschillend in vergelijking met de context van nu. Toch is de essentie van JavaScript vrijwel hetzelfde gebleven. JavaScript is duidelijk niet ontworpen om als basisplatform te dienen voor grote webapplicaties.

Figuur 1 Evolutie van het web (bron: evolutionoftheweb.com)

Vanuit ‘maintainability-‘ en ‘testability-‘oogpunt zal er snel behoefte ontstaan aan een standaard modulesysteem en een testframework. Dit zijn behoeften waarvoor geen ingebouwde voorzieningen in JavaScript aanwezig zijn. Daarnaast kent de taal de nodige gebreken. Om enkele nadelen van JavaScript te noemen: het is geen OO-taal, kent global scoping, heeft geen compile-time type checking en kent allerlei obscure constructies. Waarom wordt er dan toch gekozen voor JavaScript als platform? Omdat – wil je niet afhankelijk zijn van browser plugins – JavaScript het enige alternatief is…
Is dat wel zo? Is JavaScript wel het enige alternatief? Er kan toch ook ontwikkeld worden met bijvoorbeeld Google Web Toolkit die Java-code compileert naar JavaScript (zodat alleen de ‘binaries’ JavaScript opleveren)? In dit geval wordt er gebruik gemaakt van een bestaande ontwikkelcontext (Java), wat eigenlijk nooit bedoeld  is om webapplicaties in te bouwen. Daarom kan deze oplossing gezien worden als een tussenoplossing maar niet als eindoplossing. Kortom: tijd om een alternatief te onderzoeken.

Waarom Google Dart?
Volgens Google is Dart hét alternatief voor het maken van grote web applicaties. Google ontwikkelt veel grote webapplicaties en is bereid om flink te investeren in het ontwikkelen van een nieuw platform. Google Dart is duidelijk niet bedoeld als vervanging van JavaScript, maar wil een extra optie bieden die zich met name richt op het ontwikkelen van grotere applicaties. Als we het hebben over het Dart platform dan gaat het over: 1) de programmeertaal: Dart; 2) de tools waarin ontwikkeld wordt en 3) de manier waarop ontwikkeld wordt. Dart is dus niet alleen een taal, maar een compleet platform inclusief benodigde build- en ontwikkeltools: ‘the batteries are included’. 

Dart platform
Het Dart platform, weergegeven in figuur 2, bestaat uit verschillende onderdelen. Elk onderdeel wordt kort beschreven.
 

Figuur 2 Schematische weergave van het Dart platform

De taal Dart is een op web-ontwikkeling gerichte taal die zowel client- als server side te gebruiken is.  Dart code wordt geschreven in de ‘DartEditor’, een sterk vereenvoudigde op Eclipse gebaseerde omgeving. Deze IDE werkt intern met de packagemanager ‘Pub’, waarmee dependency management geregeld wordt. Bij het runnen van de in Dart gemaakte applicatie, zijn er twee mogelijkheden:

  • De code draait in een omgeving die niet met Dart-code om kan gaan. In dat geval wordt de Dart-code door de ‘Dart2js tool’ gecompileerd naar JavaScript en kan in elke JavaScript omgeving draaien. Deze compiler optimaliseert het gegenereerde JavaScript, wat voor een flinke performancewinst zorgt. Dit compileren dient voor het deployen van de applicatie gedaan te zijn, zodat het gegenereerde JavaScript al klaar staat.
  • De code draait in een Dart virtual machine (VM), die zowel standalone kan draaien (server-mode) als in een browser (browser-mode). ‘Dartium’ – een op Chromium gebaseerde browser – is uitgerust met een Dart VM.

De VM in server-mode stelt extra modules beschikbaar voor I/O toegang. Hiermee is het mogelijk om bijvoorbeeld een webserver te starten, verbinding te maken met het filesysteem of een database te benaderen. De VM in browser-mode stelt modules beschikbaar op gebied van DOM manipulatie en verbiedt het gebruik van I/O. Om beter zicht te krijgen op de grote verschillen met traditioneel JavaScript development en het ontwikkelen met Dart, gaan we dieper in op de taal, het gebruik van modules (libraries) en de Dart VM. 

De taal Dart
De taal Dart is geïnspireerd door Java/C# en JavaScript. Belangrijk is dat de taal eenvoudig te leren moet zijn voor ontwikkelaars die bekend zijn met talen zoals Java en C#.

Dart is ontwikkeld om zowel aan de client- als aan de serverkant gebruikt te kunnen worden. Daar springt het eerste mogelijke voordeel in het oog: namelijk dat zowel op de client als op de server in één programmeertaal ontwikkeld wordt. De belangrijkste concepten van de taal zijn:

  • Alles is een object; dus geen ‘primitive types’.
  • De taal is zowel ‘static’ typed als ‘dynamic’ typed. In voorbeeld 1 is te zien dat er zowel static types gebruikt kunnen worden (in het voorbeeld JavaDeveloper) als dat er gebruik gemaakt kan worden van het keyword dynamic.
  • Methoden hoeven niet perse in een class te staan – top-level functions.
  • Dart kent geen keywords private, protected en public. Als methoden of attributen bedoeld zijn voor intern gebruik, wordt dit aangegeven met de prefix ‘_’.
  • Dart kent alleen classes – al dan niet abstract. Een object kan van maximaal één class overerven maar kan meerdere (abstracte) classes implementeren.

 JavaDeveloper staticDev = new JavaDeveloper();
  staticDev.develop();
 
  var dynamicDev = new JavaDeveloper();
  dynamicDev.develop();
 
  void printDynamicDeveloper(dynamic dev) {
    print(dev.getFavoriteLang());
  }
 
  void printStaticDeveloper(JavaDeveloper dev) {
    print(dev.getFavoriteLang());
  }

          Voorbeeld 1 Static vs. Dynamic

De taal Dart kent allerlei constructies die het leven van ontwikkelaars eenvoudig maken. Een aantal in het oog springende features zijn bijvoorbeeld automatische string interpolatie en concatenatie, zoals weergegeven in voorbeeld 2, en het gebruik van de cascade operator, zoals weergegeven in voorbeeld 3.


var language = “Dart”;
print("Current language: $language - ${language.toUpperCase()}");
var x = "<div>"      //multiline string
          "hello world" "</div>";

          Voorbeeld 2 String interpolatie


ButtonElement button = new ButtonElement()
  ..text = "Click here"
  ..onClick.listen((e) { })
  ..classes.addAll(["btn","btn-primary"]);

          Voorbeeld 3 Gebruik van de cascade operator

Verder biedt Dart de mogelijkheid om multi-threaded zowel in de browser als op de server te programmeren. Dit betekent meestal concurrency problemen, ware het niet dat threads in Dart (daar genoemd ‘isolates’) geen gedeeld geheugen hebben en alleen middels String-based messages met elkaar kunnen communiceren.

Dart heeft standaard ondersteuning om asynchroon te programmeren, kent generics, closures en operator overloading.

Clients kunnen met behulp van Darts Web UI package volledig volgens het MVC/MVP pattern gerealiseerd worden. Er kunnen eigen HTML tags gebouwd worden wat ontwikkelaars de mogelijkheid biedt om eigen UI-componenten in Dart te bouwen.

Uit alles blijkt dat de taal Dart aanvoelt als een rijke maar hybride taal. Het is mogelijk om er op een JavaScript achtige manier in te programmeren (dynamic types) en het is ook mogelijk om op een Java/C# manier te programmeren (static types).  

In vergelijking met Java zijn er verschillen die direct aan te merken zijn als voordeel (cascade operator, string interpolatie, etc.). Voor andere verschillen is het lastig om te bepalen of iets nu een voordeel is of een nadeel. Op sommige punten lijkt het alsof er weer een stap terug gedaan wordt. Bijvoorbeeld als het gaat over globale niet-class gebonden functies.

De taal Dart geeft de indruk ontwikkeld te zijn vanuit de mogelijkheden die JavaScript biedt. Dit is enerzijds logisch, aangezien Dart-code gecompileerd moet kunnen worden naar JavaScript. Anderzijds is het de vraag hoe deze hybride taal dan server-side gebruikt gaat worden.  

De problematische aspecten die JavaScript kent, zijn niet aanwezig in Dart. Dart is wél een OO-taal, kent géén global scoping, heeft wél compile-time type checking en kent geen obscure constructies.

Libraries in Dart
Voor met name Java ontwikkelaars is de manier waarop Dart ‘accessability’ oplost wezenlijk anders dan men gewend is. Java kent (nog) geen standaard modulesysteem. Dart daarentegen wel. Een ‘library’ is een eenheid binnen Dart om functionaliteit ter beschikking te stellen. Een library bestaat uit een verzameling van functies en- of classes. Alles wat binnen een library begint met ‘_’ is van buitenaf niet benaderbaar. Accessability veranderen betekent dus altijd een rename. In voorbeeld 4 is te zien hoe een library opgezet wordt die één publieke klasse (de Logger) en daarnaast 3 publieke functies aanbiedt. De interne functie _internalLog en interne klasse _LoggerImpl zijn alleen benaderbaar binnen de library.


library loglib;
part "databaselogger.dart"; //voeg andere dartfile aan loglib toe
 
class _LoggerImpl implements Logger { }
class Logger {
  void info(String msg) {}
}
void _internalLog(String msg) {...}
 
//Drie publieke – niet class gebonden functies
debug(msg) => print("DEBUG: $msg");
warn(msg) => print("WARN: $msg");
info(msg) => print("INFO: $msg");

          Voorbeeld 4: Voorbeeld van library in Dart

Middels een bestand in YAML-formaat wordt aanvullende informatie over de library beschreven (zie het als een soort pom.xml).  Daarin worden versie-informatie en afhankelijkheden opgegeven.

Voorbeeld 5 laat zien hoe afhankelijkheden aangegeven worden en dat integratie met bijvoorbeeld GitHub mogelijk is. Het voorbeeld laat eveneens het onderscheid zien tussen ‘gewone’ afhankelijkheden en ‘test’-afhankelijkheden.


name: NlJugApp
version: 3.2.1
description: A sample NLJUG Dart application
dependencies:
  json_object: 1.0.0
  browser:
    git: https://github.com/teunh/dart
  web_ui: any
dev_dependencies:
  unittest: '>=0.6.0'  

          Voorbeeld 5: Pubspec.yaml

Ten behoeve van maintainability zal de mogelijkheid om libraries te kunnen definiëren en te kunnen versioneren direct als groot voordeel ervaren worden.  Zeker met de integratie van de tool Pub (packagemanager) voelt de Dart editor direct prettig aan.

Op gebied van testability van libraries levert Dart een standaard API voor unit-testen inclusief allerlei matchers en support voor mocking. Het is winst dat deze noodzakelijke voorzieningen in het platform ingebakken zijn.

Dart Virtual Machine
Waarom introduceert Google weer een virtual machine nadat gebleken is dat de VM’s Flash, Java en Silverlight het niet gaan worden op het web? Hiervoor zijn twee belangrijke redenen te noemen. In de eerste plaats kan Dart code daarmee zowel in de client (browser) als op de server ingezet worden (vergelijkbaar met Java). In de tweede plaats vanwege performance redenen. Het Dart platform is sterk gericht op performance. Een van de dingen die deze VM doet, is de geheugen toestand van een applicatie na de eerste keer starten opslaan in een ‘snapshot’. De volgende keer wordt eenvoudig de snapshot ingeladen. Dit leidt volgens Google tot een 10x snellere opstarttijd, wat zeker bij grotere applicaties (denk aan Gmail die nu vaak een progressbar laat zien) tot een betere gebruikerservaring gaat leiden. Daarnaast kent deze VM allerlei optimalisaties zoals we die ook uit andere omgevingen kennen zoals: JIT compilatie en garbage collection (geen stop-the-world GC). Alles is erop gericht om een platform te kunnen bieden waarin de ‘grotere applicaties’ ook kunnen draaien.

Conclusie
Wordt er over een aantal jaren volop in Dart geprogrammeerd? Het is zeker niet uit te sluiten. Met Dart is Google een veelbelovende richting ingeslagen: het ontwikkelen van een taal, platform en IDE speciaal gericht op het maken van grote complexe webapplicaties die draaien in een willekeurige browser (gecompileerd naar JavaScript en HTML) of in een virtual machine. De uitvoering laat echter vooralsnog te wensen over. Om een paar voorbeelden te noemen: het is te onduidelijk hoe Dart server side gebruikt gaat worden.  Tevens lijkt het niet eenvoudig om end-to-end testen te maken; iets wat in de context van complexe webapplicaties wel makkelijk zou moeten zijn. De adoptie van Google Dart bij andere leveranciers wordt steeds groter wat onder andere blijkt uit de beschikbare IDE ondersteuning in IntelliJ IDEA, Sublime en Eclipse. Daarnaast heeft Adobe een framework ter beschikking gesteld dat gebruikers moet helpen om Flash applicaties te migreren naar Dart. Google Dart bevindt zich nog in de status ‘Technology preview’ en het is de bedoeling dat in 2013 een 1.0 versie bereikt gaat worden.


Wil je aan de slag met Dart?
Ga naar dartlang.org, download de SDK en IDE en go Dart!