L'équipe derrière la version web du journal, guardian.co.uk qui, selon son rédacteur en chef, a l'auditoire le plus vaste de tous les sites de nouvelles en ligne après le New York Times, migre progressivement de Java à Scala, en commençant par l'API de contenu, qui fournit un mécanisme de sélection et de collecte du contenu du Guardian.
Le site guardian.co.uk est constitué d'environ 100.000 lignes de code. Il utilise une pile Java open-source assez typique Spring, Apache Velocity et Hibernate avec Oracle comme base de données. Comme le site Web, l'API contenu a été initialement développée en Java, mais l'équipe a décidé de passer à un autre langage de la JVM, Scala, à la place. Graham Tackley, chef d'équipe "Développements Plate-forme Web" nous a déclaré:
Nous avons été une boîte de développement principalement Java pendant un certain nombre d'années, et cela nous a plutôt largement réussi. Cependant, en tant que site d'information, nous voulons être en mesure de répondre très rapidement aux événements. La plate-forme Java de base qui supporte www.guardian.co.uk voit une mise en production de version majeure toutes les deux semaines. Comparé à beaucoup d'applications Java d'entreprise, c'est excellent. En comparaison avec d'autres sites, c'est très peu.
Nous avons donc cherché pendant un certain temps des outils, des approches et des langages qui puissent nous permettre de proposer des fonctionnalités plus rapidement. Cela inclut l'utilisation de cadres applicatifs (frameworks) Java plus légers comme Google Guice, d'approches de développement Java radicalement différentes comme le framework Play, et l'utilisation d'autres plateformes comme Python avec Django. Dans le cadre de cet exercice, nous avions joué avec Scala pendant un certain temps, mais contrairement à d'autres, nous ne l'avions pas encore utilisé pour quelque code de production que ce soit.
Nous étions très désireux que la première version non bêta de l'API Contenu (API, Open Platform) soit la première itération d'une API en constante évolution, et qui puisse rapidement évoluer à mesure que nous découvrons tous les cas d'utilisation intéressants auxquels nous n'avions pas initialement pensé. Dans ce but, et cela de manière sécurisée sans risque de casser les clients de l'API existants, nous avions besoin d'un ensemble complet de tests d'intégration. Après quelques essais d'écriture en Java de ceux-ci, nous avons décidé à la place d'écrire simplement les tests d'intégration en Scala, pour trois raisons principales:
- La flexibilité du DSL de test fourni par ScalaTest.
- Nous voulions être excités à l'idée d'écrire des tests d'intégration, plutôt que ceux-ci soient perçus comme une corvée.
- Le fait de cantonner Scala aux tests signifiait que nous pouvions l'utiliser violemment sans impact direct sur le code de production.
Après environ quatre semaines seulement à écrire les tests en Scala, nous en avons eu assez d'avoir à écrire le code principal en Java, et avons décidé de convertir le tout en Scala.
InfoQ : D'une manière générale, comment avez-vous procédé pour la migration ? Avez-vous réécris tout le code Java en Scala par exemple, ou avez-vous combiné les deux pendant un temps ?
La version bêta de l'API Contenu était basée sur un moteur de recherche propriétaire. L'API actuelle utilise l'excellent Apache Solr (une présentation sur l'utilisation de Solr par guardian.co.uk peut être trouvée ici), et est également tout à fait différente du style de la bêta - la bêta était un excellent moyen de mettre en évidence ce à quoi nous ne voulions pas que l'API ressemble. Par conséquent, avant que Scala ne rentre en scène, nous avions décidé de réimplémenter l'API plutôt que de réutiliser le code source de la bêta.
Nous avions passé environ six semaines avec trois personnes implémentant en Java avant l'instauration de Scala, il n'y avait donc pas une base de code massive à migrer. Cependant, nous n'étions pas prêts à arrêter le projet pour deux semaines de conversion à Scala, donc nous avons migré les tests d'intégration existants progressivement. Comme nous utilisions Maven comme outil de construction, l'introduction de Scala était juste une question de suivre les instructions pour utiliser le plugin maven-scala-plugin pour produire un projet mélangeant Java et Scala. Cela permet à du code Java et Scala de cohabiter dans le même projet, et de dépendre l'un de l'autre de manière bidirectionnelle. Nous pouvions donc convertir classe par classe de Java à Scala, et cela fonctionna bien mieux que nous aurions pu l'imaginer, à savoir fonctionner tout court.
Nous avons utilisé la même approche pour convertir le code principal: pendant un certain nombre de semaines, dès que nous touchions à un bout du code, nous le convertissions en Scala. À la fin, nous avons alors pris quelques jours pour nettoyer le tout.
InfoQ : Quelles sont les bibliothèques / frameworks que vous avez utilisés pour le développement ?
Comme nous utilisions un langage nouveau pour nous tous, nous avons décidé de limiter la quantité de choses nouvelles que nous aurions besoin d'apprendre. Nous avons choisi de rester sur des simples servlets et Google Guice, qui est la façon dont nous construisons nos applications Java maintenant. Nous utilisons SolrJ, la bibliothèque Java Solr, pour parler à Apache Solr, Joda-Time pour la manipulation de la date et l'heure et Mockito pour les bouchons dans les tests unitaires (ce qui a aussi bien fonctionné avec le code Scala).
Parfois, nous avons sciemment choisi de nous en tenir à ce que nous savions pour assurer la livraison en temps voulu: les points d'accès (*endpoints*) au format XML sont générés non pas en utilisant l'excellent support XML de Scala, mais en utilisant javax.xml.stream.XMLStreamWriter comme nous le ferions dans du code Java. Nous avions déjà écrit cette partie avant de passer à Scala, elle fonctionnait, était lisible, donc nous l'avons laissé. Cependant, nous avons migré vers l'excellente bibliothèque JSON de Lift - lift-json - pour générer les points d'accès au format JSON, le code était beaucoup plus clair qu'avec la bibliothèque Java JSON que nous utilisions.
InfoQ : Quel IDE utilisez-vous pour le développement ? Que donne le support de Scala dans les IDE ?
Nous utilisons JetBrains IntelliJ IDEA 10, certains d'entre nous utilisent la version communautaire et certains utilisent l'édition ultime. Le plugin Scala est assez bon, mais pas parfait. La complétion de code, la recherche d'occurrences et options de navigation similaires fonctionnent presque toujours très bien. Ce n'est pas aussi bon que Java en ce qui concerne la mise en avant des erreurs (coloration rouge du code qui n'est pas valide), et nous avons eu quelques problèmes avec la détection de méthodes de test ScalaTest, mais à part ça nous étions dans un environnement de travail familier, travaillant comme d'habitude, mais dans un langage beaucoup plus puissant.
InfoQ : Je suppose que la majorité des développeurs sur le projet étaient des programmeurs Java ? Avec quelle facilité les développeurs sur le projet ont appris Scala ?
Oui, nous étions tous des programmeurs plutôt expérimentés en Java. L'équipe initiale de quatre s'est énormément amusée en apprenant Scala: souvent l'un d'entre nous, très excité par une nouvelle fonctionnalité Scala qu’il avait découverte, songeait à la partager avec le reste de l'équipe. Nous retrouvions des sensations qui nous avaient longtemps fait défaut dans nos développements Java. Parce que nous étions tous en phase d'apprentissage ensemble, cela a très bien fonctionné. Au cours des deux premières semaines, cependant, il y a eu des occasions où nous avons cherché comment implémenter des choses à la manière de Scala, mais sans succès. Sachant que nous pouvions facilement "pondre" le code Java rendait cela particulièrement frustrant. Il y a eu quelquefois où nous sommes rentrés frustrés à la maison, en nous disant "demain on repasse à Java". Chaque fois, un regard neuf le lendemain matin était tout ce dont nous avions besoin pour continuer.
Depuis lors, nous avons eu une dizaine de développeurs Java supplémentaires qui sont passés sur Scala. Comme toujours, les gens apprennent à des rythmes différents et de manières différentes, mais tous s'en sont sortis et maintenant presque tous se sentent frustrés quand ils doivent écrire du code Java.
On compare souvent l'apprentissage de Scala à une migration vers une plateforme logicielle différente comme Python / Django ou Ruby on Rails. Avec Scala, au moins 75% du contexte est le même que dans Java. Vous pouvez utiliser les mêmes bibliothèques et les mêmes IDE, la façon dont vous construisez vos jars et wars est la même, votre environnement d'exécution et les caractéristiques d'exécution sont les mêmes. Un bon développeur Java peut apprendre à écrire du code de style Java mais en Scala en une journée, puis ils apprennent la puissance des closures et des conversions implicites et très vite ils sont plus productifs qu'ils ne l'étaient en Java.
InfoQ : L'une des critiques les plus courantes envers Scala se résume à dire que c'est un langage trop complexe. Une grande partie du temps, je pense que c'est plutôt en fait une question de lisibilité - l'idée étant qu'il est plus facile de reprendre le code de quelqu'un d'autre s'il est écrit dans un langage plus rigide comme Java. Pensez-vous que la critique est juste ? Comment y remédier ?
Je suis d'accord, la lisibilité est de loin la caractéristique la plus importante d'une base de code. Je ne me soucie pas de savoir si le code est impératif ou fonctionnel, s'il est écrit en Scala idiomatique ou en Java-sans-points-virgules, je ne me soucie que de ce que ce soit lisible. Lorsque nous apprenions de nouvelles fonctionnalités Scala, nous choisissions de les utiliser ou non selon que l'intention du code était plus évidente. Par exemple, nous avons essayé d'utiliser la classe Scala Either pour éliminer quelques If: l'équipe a collectivement conclu que les instructions If étaient plus lisibles, donc nous avons abandonné l'utilisation de Either dans ce cas.
Il est vrai qu'en raison de sa rigidité les lignes de code Java individuelles sont toujours faciles à comprendre. Mais c'est rarement le problème quand on cherche à comprendre du code source non trivial: je ne veux pas comprendre chaque détail, je veux comprendre l'intention. Une bonne conception des classes et des techniques OO aide à résoudre cela en Java, mais je m'aperçois souvent lors de la lecture du code Java que je ne peux pas distinguer l'arbre de la forêt. En Scala, j'ai le pouvoir d'exprimer l'intention de mon code d'une manière rarement faisable en Java.
Par exemple, l'API Contenu doit décider s'il faut retourner les résultats au format XML, JSON ou rediriger vers l'explorateur HTML. Nous utilisons un format de chaîne de requête =, avec l'ajout de l'extension .xml ou .json, et la spécification d'une en-tête HTTP Accept. Voici le code qui fait ça, je pense que c'est un bon exemple de la façon dont Scala aide à exprimer l'intention (par simple enchaînement des appels à la classe Scala Option):
def negotiateFormatParameter =getParam("format").
orElse(getExtension).
orElse(getExtensionFromAcceptHeader).
getOrElse("html")
Il y a aussi un argument valable que la lisibilité est au moins partiellement fonction de la quantité de code que vous avez à lire. Mon code Java a tendance à se retrouver avec beaucoup de lignes de code sans rapport avec le problème que je tente de résoudre, que ce soit des vérifications de nulls, les getters *et *setters, les constructeurs pour l'injection de dépendance ou la manipulation de collections. Tous ces problèmes s'expriment de manière beaucoup plus concise en Scala. Bien sûr, une grande partie de cela peut être généré automatiquement par votre IDE, mais en lisant votre base de code je dois encore lire votre constructeur et vos getters et setters pour voir si vous les avez personnalisés.
Un exemple classique consiste à comparer une classe simple en Java et Scala:
Java:
public class WelcomeClass {
private String name;
public WelcomeClass(String name) {
this.name = name;
}
public String sayHello() {
return "Hello " + name;
}
}
et en Scala:
class WelcomeClass(name: String) {
def sayHello = "Hello " + name
}
La version Java doit me dire à trois reprises que «name» est une chaîne (*String*) et il mentionne «name» à cinq reprises. La version Scala ne mentionne «name» que deux fois, et dit que c'est une String une fois. Bien sûr, c'est un exemple trivial, mais il est symptomatique de ce que nous avons trouvé en Scala: moins de code passe-partout et de répétitions inutiles signifie moins d'arbres et plus de forêts, c’est-à-dire qu'il est plus facile de voir l'intention, plutôt que juste le détail.
J'ai tendance à trouver que lors de la première lecture d'une ligne individuelle de code Scala cela prend parfois un peu plus de temps pour comprendre comment ça fonctionne, mais que c'est plus que compensé par la réduction drastique du nombre de lignes de codes.
InfoQ : En restant sur la complexité pour un moment, est-ce que certains aspects du langage - je pense ici principalement à des choses comme les noms symboliques et les implicites - causent des problèmes en utilisation courante ?
Les conversions implicites, en fait, nous ont vraiment aidées. Comme je l'ai mentionné, nous utilisons la bibliothèque Java SolrJ pour parler à Solr, qui est une excellente bibliothèque, mais en tant que bibliothèque Java, elle aime retourner des nulls. Pour éviter que les contrôles de null jonchent notre base de code, nous avons implicitement converti les classes clés dans des classes qui ont des méthodes plus proches de Scala. Donc, loin de causer des problèmes dans le monde réel, la conversion implicite permet d'en résoudre activement. En outre, le plugin IntelliJ Scala comprend maintenant les implicits dans presque tous les cas, si vous n'êtes pas sûr de ce qui se passe ctrl + clic vous amène à ce qui est réellement appelé.
Nous avons eu tendance à nous tenir à distance des bibliothèques usant lourdement des symboliques, ou encore de l'utilisation de symboles pour les noms de méthodes, mais je pense que c'est une fonctionnalité importante du langage, qui comme toute fonctionnalité peut être surutilisée. Des fois cela fait sens: notre méthode pour extraire des requêtes depuis la requête http s'appelle "?", ce qui se lis vraiment bien dans le code. Beaucoup plus qu'en Java, le grand pouvoir de Scala implique une grande responsabilité à se concentrer sur le fait de rendre l'intention de votre code plus visible. Juste parce que ce pouvoir peut-être mal utilisé ne veut pas dire que je n'en veux pas.
InfoQ : Une autre préoccupation pour l'utilisation de Scala dans les applications d'entreprise est que chaque nouvelle version semble casser la compatibilité ascendante - des programmes ainsi compilés avec Scala 2.8 ne sont pas compatibles avec des binaires compilés plus tôt et ainsi de suite. Quelle est selon vous l'importance de cet état de fait ? Comment gérez-vous les incompatibilités dans les projets Scala ?
Nous avons commencé à écrire en Scala 2.7.7, et avons migré vers 2.8.0 et 2.8.1 peu de temps après leur mise à disposition. C'était plutôt indolore; la migration 2.8.0 a pris moins d'un jour (et ce seulement parce que je voulais éliminer les warnings de type deprecated) et la 2.8.1 il n'y a eu qu'à changer le jar. Toutes les bibliothèques que nous utilisions publiaient déjà des versions pour de multiples moutures de Scala, donc tout ça fonctionnait.
La seule fois ou ce fût douloureux c'était sur un projet personnel, pour lequel j'avais utilisé une version 2.8.0 pre-release. Mais bon, c'était mon choix d'utiliser une version clairement estampillée "pre-release".
Nous avons tendance désormais à utiliser l'outil simple-build-tool pour les projets Scala plutôt que Maven, ce qui rend plus facile de sortir des bibliothèques internes pour des versions multiples de Scala.
Je préfère largement avoir à faire face à quelques incompatibilités quand je choisi de mettre à jour Scala plutôt que d'avoir à subir la situation de Java où certaines choses ne sont jamais changées et ne pourront jamais changer. La méthode couramment utilisée HttpServletRequest.getHeaders() retourne toujours une java.util.Enumeration, classe officiellement décommissionnée depuis java 1.2.
InfoQ : Quelle est la situation en ce qui concerne la recherche des développeurs pour la maintenance du code Scala — est-ce que les bons développeurs Scala sont aussi faciles à trouver que les bons développeurs Java, par exemple ?
Nous recrutons tout d'abord de bons développeurs de logiciels, plutôt que de rechercher spécifiquement des développeurs Scala. Nous avons tendance à constater que les développeurs de logiciels webs sont polyglottes, ont de bonnes perspectives et ont souvent au moins joué avec Groovy, Scala, Clojure, Ruby ou Python. Ces personnes ont généralement apprécié l'occasion de pouvoir travailler en Scala.
InfoQ : Environ quelle quantité de code de production guardian.co.uk exécute-t-il aujourd'hui ?
Le code source de base derrière guardian.co.uk - celui sur un cycle de mise en production de deux semaines - n'avait il y a 2 semaines qu'une seule classe Scala en son sein. Nous maintenons une politique pas-de-Scala sur ce code source jusqu'à présent, juste pour être sur que nous sommes tout à fait prêts en tant qu'équipe à embrasser Scala (et aussi pour m'empêcher de tout réécrire).
Cependant de nombreuses parties du site sont aujourd'hui propulsées par des microapps Scala, incluant la Recherche (*Search*) (qui est écris en Scala avec Lift), les Plus Visités (*Most Viewed*) et la rubrique "Punctuated Equilibrium Mystery Bird" et les composants de contenus associés sur chaque page d'article.
De plus, notre nouvelle plate-forme d'authentification (identity platform), encore en cours de développement mais avec sa première itération déjà en production, est écrite en Scala.
InfoQ : Allez-vous utiliser plus de code Scala dans le futur ?
Nous avons constaté que Scala nous a permis de livrer des choses plus rapidement avec moins de code. Cela a revigoré l'équipe. Nous allons continuer à utiliser l'outil adapté au besoin, que ce soit Scala, Python, .NET, PHP ou Bash.
Au cours des six derniers mois, tous les nouveaux projets JVM ont utilisé Scala et aucun n'a choisi Java. Je ne nous vois pas commencer un nouveau projet en Java maintenant, surtout compte tenu de l'aspect décevant des nouvelles fonctionnalités de Java 7 et de son calendrier de déploiement.
Pour les développeurs intéressés par l'apprentissage du langage, Tackley a recommandé "*Programming in Scala*" de Martin Odersky et al. La 2e édition couvre Scala 2.8. Il nous aussi dit:
Nous avons constaté qu'utiliser la REMPL (interpréteur en ligne de commande) était un bon moyen d'expérimenter avec la rédaction de code Scala. Et, malgré ce que d'autres peuvent dire, ne rechignez pas à utiliser Scala juste comme un meilleur Java-sans-points-virgules durant les premiers jours, semaines ou mois. Vous rateriez quelque chose en vous arrêtant là, mais ce n'est pas une mauvaise phase par laquelle passer. Continuez d'apprendre et d'embrasser les fonctionnalités du langage de manière incrémentielle. La possibilité de faire ça est à mon sens ce qui rend Scala si unique en tant que prochaine étape pour les développeurs Java.
Outre les aspects techniques, l'API Contenu du guardian.co.uk, et plus largement la plate-forme ouverte de services dont elle fait partie, est intéressant d'un point de vue commercial, car elle représente une approche très différente de celle favorisée par un nombre croissant de journaux de qualité au Royaume-Uni et ailleurs, c’est-à-dire de placer leur contenu derrière le mur de l'abonnement. À ce jour, le Financial Times, News International's Times et The Sunday Times ont tous décidé d'aller dans cette voie, et plus récemment le New York Times a commencé à déployer un modèle de contenu payant. Le journaliste vétéran de la BBC John Humphrys a fait valoir dans The Sun, un tabloïd d'informations internationales, que «Le bon journalisme doit être payé, tout comme nous devons payer le plombier qui répare une fuite, ou il ne survivra pas". Tackley adopte néanmoins un point de vue différent
Nous croyons fermement que l'avenir de l'édition numérique est de participer et de s'intégrer avec le reste du web, pas de se mettre en retrait.
L'API Contenu est en mesure d'étendre la portée et l'image de marque du Guardian vers des zones que nous ne serions pas autrement en mesure d'atteindre. Cela est facilité par des tiers et partenaires qui utilisent l'API, puisqu'ils peuvent investir sur un domaine et utiliser le contenu adéquat du Guardian.
Nous avons un certain nombre de différents niveaux d'accès à l'API Contenu: sans inscription, vous pouvez accéder aux métadonnées du contenu mais pas au contenu lui-même, avec un rythme de QPS (*"Query per Second*, requêtes par seconde) limité. Après inscription, vous avez accès aux corps d'articles, qui contiennent des publicités embarquées, encore une fois avec une fréquence de requête limitée. Au niveau supérieur, vous devenez un partenaire du Guardian et nous définissons un accord commercial approprié.
Un bon exemple de partenariat est WhatCouldICook.com, construit par un petit développeur indépendant. Ce site est un bon exemple d'intégration forte du contenu du Guardian: il utilise l'API pour extraire et analyser toutes les recettes que nous publions et les présente sous une forme adaptée à ceux qui souhaitent cuisiner. Qui plus est, nos lecteurs sont gagnants puisque nous intégrons des fonctionnalités de WhatCouldICook.com sur notre site, voir par exemple le champ de recherche de recette disponible sur la droite du site web du Guardian.
Notre plugin Wordpress, construit par-dessus l'API, permet à n'importe quel utilisateur de Wordpress d'inclure du contenu associé en provenance du Guardian sur leur blog.
Ce niveau d'innovation dans des secteurs spécifiques est quelque chose qui ne se produirait tout simplement pas sans l'API de Contenu. Qui plus est, nous utilisons abondamment l'API pour des projets pilotés par The Guardian pour augmenter notre rythme d'innovation: des fonctionnalités du site telles que la recherche, zeitgeist, notre site mobile ou notre application IPhone sont toutes propulsées par l'API de Contenu.