ruby – Sam & Max http://sametmax.com Du code, du cul Wed, 30 Oct 2019 15:34:04 +0000 en-US hourly 1 https://wordpress.org/?v=4.9.7 32490438 Un gros Troll de plus sur Javascript http://sametmax.com/un-gros-troll-de-plus-sur-javacscript/ http://sametmax.com/un-gros-troll-de-plus-sur-javacscript/#comments Thu, 13 Mar 2014 20:02:09 +0000 http://sametmax.com/?p=9752 Un commentaire très pertinent de Kontre m'a interpellé dernièrement : si Javascript est si pourri, pourquoi tout le monde s'y intéresse ?]]> Un commentaire très pertinent de Kontre m’a interpellé dernièrement : si Javascript est si pourri, pourquoi tout le monde s’y intéresse ?

TD;DR :

L’inertie technique.

Il faut bien comprendre que PERSONNE ne s’intéresse à Javascript directement. Les gens s’intéressent passionnément à la programmation Web. Et il se trouve que, concernant la programmation côté client, il y a QUE Javascript de disponible.

Quand Ajax est arrivé, des mecs brillants ont rendu le Web plus interactif. Et ils ont utilisé ce qui était implémenté partout : Javascript. Pas parce qu’ils aimaient Javascript. Pas parce que Javascript était un bon langage.

Parce que c’était la seule solution dispo.

Avant, personne ne s’intéressait à ce truc. C’était un langage de script kiddies pour faire des flocons de neige sur les pages HTML. Et donc tout le monde se foutait royalement que ce soit de la merde. IE l’avait implémenté parce que Netscape l’avait fait. C’était alors un gros hybride qui tentait de rassurer les codeurs C et Java. Javascript était marketing, jusque dans le choix du nom. Puis IE6 a gardé le pouvoir pendant 10 ans, et du coup, tout le monde a suivi.

Personne n’a réfléchi. Personne n’a vu venir l’explosion du Web. Personne ne s’est dit “les gars faudrait peut être faire attention, le status quo pue la merde”. A cette époque, ça n’avait pas d’importance, on a mis les efforts de guerre ailleurs.

L’heure du Web 2.0 a alors sonné, et là les business ont eu besoin de puissance de feu. Mais c’était trop tard, il n’y avait plus qu’un seul truc hideux de dispo pour la prog…

Google a utilisé massivement les pages dynamiques, et devant le constat des performances misérables de la seule techno qu’il y avait a dispo, il a pondu chrome, et sa VM Javascript ultra performante. Si on avait appliqué la même techno à n’importe quelle autre langage, on aurait obtenu 10 fois cette vitesse.

C’est quand Google a enfin pu donner des perfs décentes – c’est à dire celles qu’ont d’autres langage depuis une décennie – à Javascript que les gens ont envisagé de l’utiliser sur le serveur. Encore une fois, pas parce que Javascript était une techno dont ils étaient fondamentalement amoureux.

Parce qu’ils voulaient éviter d’écrire deux fois le même code côté client et côté serveur et que toute tentative de générer du Javascript n’a pas été satisfaisante. Et aussi parce que le besoin de faire de l’asynchrone se faisait sentir et que les Dev clients n’avaient pas envie d’apprendre un autre langage. Ben oui, l’asynchrone, vous croyez que pas que ça existe que sur JS quand même ? C’est aussi vieux que les premiers compilateurs. Les Devs clients connaissaient déjà le JS, et ça faisait du DRY, alors pouet.

Personne. J’ai bien dit, personne ! Ne s’est jamais extasié devant l’incroyable ergonomie de Javascript. Devant sa facilité de debuggage. Devant la qualité de sa doc.

Dessin humoristique sur la recherche de travail

Cherche Dev Javascript pour travailler sur projet innovant dans une start up à fort potentiel de croissance.

Ruby est un langage innovant and fun.

Python est un langage ergonomique and riche.

Php est un langage avec une super doc et une communauté noob friendly.

Lisp est un langage puissant avec un paradigme fonctionnel de référence.

Go est un langage propre avec une gestion de la concurrence très performante.

Javascript est juste là par hasard. Il ne dépasse aucun des langages ci-dessus en terme de ses qualités propres. Sa bibliothèque standard est risible. Il ne sert absolument à rien sans un framework côté serveur, et côté client il est parfaitement improductif sans une lib pour gommer les incompatibilités entre les implémentations.

Les docs sur JS sont éparpillées sur le Web. Les tutos sont déchirés entre tant de versions et de frameworks qu’on se croirait dans un script des frères wachowski.

Des notions de base comme les closures sont encore obscures pour la plupart des codeurs Javascript, alors qu’elles peuvent ruiner les perfs de votre programme ou créer des bugs énormes. Les projets innovants en Javascript sont tous faits par des gens hyper compétents parce qu’innover dans ce langage, ça demande une discipline de dingue tellement il offre d’opportunité de merder.

Javascript est un hack qu’on se traine.

C’est un bug legacy.

C’est un virus préinstallé dans les navigateurs.

Photo du film le dictateur

Ma Fureure, vous ne voulez pas utilisez le C# plutôt ? Naïne, toutes nos troupes sont déjà tatoués sur la fesse gauche, on va devoir y aller comme ça.

Oui il y a des produits à base de Javascript fantastiques. Oui les innovations techno Web actuelles intéressantes tournent toutes autour de Javascript de près ou de loin. Et oui, vous devez définitivement mettre les mains dedans parce que le monde du dev avancera en dépit de vos goûts. En tout cas, en dépit des miens, j’en ai bien conscience.

Mais ceci ne se fait pas grâce à Javascript. Ceci se fait en dépit de Javascript. Malgré le fait que c’est un langage au typage pourri, malgré son scoping dégueulasse, malgré l’absence des facilités modernes les plus basiques comme le passage d’arguments avancés ou un slicing décent.

Parce qu’il y a des gens très (TRÈS) bons qui ont eu Javascript comme contrainte, et qui en ont tiré le meilleur. Et c’est pas faute d’avoir essayé autre chose (Flash, GWT, Haxe…). Ces mecs sont incroyables, ce sont des Dieux vivant, Amen to them, mais Javascript reste à chier.

Et on va se le coltiner encore très, très longtemps.

Au cas où vous ne l’aurez pas encore compris, je vomis sur Javascript. Mais je code avec, et j’offre même des formations dessus, car je suis pragmatique. Les besoins de l’industrie, l’inertie technologie et le contexte social / technique / économique dictent bien plus souvent les standards que nous utilisons que leurs qualités intrasèques. Sinon nous n’aurions pas utilisé le format .doc ou les VHS.

En fait, je ne détesterais pas autant Javascript si je n’en avais pas besoin quotidiennement. Je le hais du plus profond de mon âme justement parce que c’est non seulement une contrainte inamovible de mon métier, mais en plus une tumeur que les chercheurs annoncent voir grossir de jour en jour. Avec le sourire, les connards !

Le VB est peut être pire que le JS, mais je m’en branle, je n’ai pas à y toucher.

Après cet argumentaire, je précise que je ne mettrai pas de tampon sur les commentaires, parce que je comprends bien que je ne peux pas lâcher une caisse et demander à tout le monde de respirer à fond et ne pas se plaindre.

Néanmoins, puisque cet article à des vocations thérapeutique – vous êtes tous un peu mes psy au fond (la confidentialité bloggeur / lecteur, ça marche ?) – voici un listing de tout ce que j’abhorre dans le Javascript.

)

Les experts recommandent d’éviter la moitié du langage

Il y a tellement de merdes dans JS que les plus grands experts s’accordent sur le fait que la première chose à faire est d’apprendre la liste des choses à ne PAS utiliser.

En fait, Douglas Crockford lui même a écrit un bouquin complet rien que sur le sujet.

Je n’ai pas tout en tête, mais en vrac…

Ne pas utiliser l’opérateur ==, parce que :

''        ==   '0'           // false
0         ==   ''            // true
0         ==   '0'           // true
false     ==   'false'       // false
false     ==   '0'           // true
false     ==   undefined     // false
false     ==   null          // false
null      ==   undefined     // true
" \t\r\n" ==   0             // true

Notez que même === ne retire pas toutes les ambiguïtés :

> var a = { "abc" : 1 }
> a[[[["abc"]]]] === a["abc"]
true

Ne pas utiliser parseInt sans préciser la base sinon :

> parseInt('06')
6
> parseInt('07')
7
> parseInt('08')
0
> parseInt('09')
0
> parseInt('10')
10

Bien se souvenir d’utiliser var partout. En fait activer use strict dès que possible pour éviter l’insertion de ; automatiques.

Et ne pas utiliser la syntaxe de déclaration de variable sans var puisque ça créé une variable globale. Cependant, faites gaffe quand vous convertissez du code parce que :

a = 1
1
> var a = 1
undefined

Encore une connerie. Mais vous avez l’habitude :)

Ah oui, et ne pas utiliser les mots clés new ou with pour vos propres libs. Si, si, on bannit carrément des mots clés, c’est écrit dans le livre.

Phot d'un gant de vaisselle avec des pansements

Ce gant est fantastique, si vous ignorez tous les trous il vous permettra de faire la vaisselle aussi bien que tous les autres gants. Comme ça vous êtes jardinier ? Remarquez, j'avais créé le produit pour faire des touchers rectaux à la base, donc il est adaptable !

Faire du JS propre présuppose l’utilisation de design patterns

En l’état, on ne peut pas écrire du JS propre. Écrire la plus simple instruction Javascript est déjà écrire du code sale car toute variable devient globale. Il faut tout foutre dans un conteneur quelconque, souvent dans une fonction anonyme immédiatement appelée, mais il y a d’autres techniques (services avec injection de dépendance dans angularjs par exemple).

Pour être honnête, on commence à peine à savoir écrire des grosses applis Javascript propres côté client depuis quelques années. Ca a pris un temps fou de trial / error pour gommer petit à petit tous les aspects guedin de la techno et obtenir un socle utilisable.

Un autre truc : personne ne s’est mis d’accord sur l’utilisation des objets : prototypage, simulation d’héritage, instanciation ou pas, composition uniquement ? En tout cas vous devez en choisir un, et ne pas le merder.

Au fait, vous avez déjà essayé d’expliquer le prototypage à quelqu’un ? Bonne chance !

Non seulement c’est du typage faible, mais en plus c’est du typage con

J’ouvre Firefox, je tape:

> {} + {} // Ceci n'est effectivement PAS un nombre
NaN
> {} + [] // logique IMPARABLE
0
> [] + {} // fuck la commutativité
"[object Object]"

Et après on va me dire que c’est juste l’API DOM qui est incohérente selon les implémentations. Mais non, tenez, même ça c’est cohérent. Je fais la même chose sous Node 0.8 (sur lequel j’ai par ailleurs déjà râlé):

> {} + []
'[object Object]'

Enfin quelle implémentation ? Node original ? Le fork Io.js ? Ou le fork qui doit merger les deux ?

On pourrait continuer longtemps avec ces saloperies, mais je finis sur un exemple qui résume bien tout le merdier :

> '5' + 3
'53'
> '5' - 3
2
> "Vous en étiez à... peau de couilles je crois ?" + 1
'Vous en étiez à... peau de couilles je crois ?1'
> "Vous en étiez à... peau de couilles je crois ?" - 1
NaN

Et vous pouvez toujours vous dire que si vous faites attention, vous n’aurez pas de problème, mais ça a des répercussions sur TOUT le langage, dans les recoins les plus vicieux :

> Math.min(null, 1234)
0
> Math.min('null', 1234)
NaN
> Math.min('1', 1234)
1

L’élégance d’un chameau bourré à la villageoise

On se déchaîne

Ruby :

coucou = """Ceci est une looooooooooooooooooooooooooooooooooooooooongue chaine !
Sur plusieurs lignes !
Et une autre !
Et une autre !
J'adore les sauts de ligne, c'est tellement lisible !!!
"""
puts coucou

Python :

variable = "foo"
coucou = """Ceci est une looooooooooooooooooooooooooooooooooooooooongue chaine !
Sur plusieurs lignes !
Et une autre !
Et une autre !
J'adore les sauts de ligne, c'est tellement lisible !!!
Et en prime voila une variable : %s !
""" % variable
print coucou

Javascript :

var variable = "foo";
var coucou = "Ceci est une looooooooooooooooooooooooooooooooooooooooongue chaine !\
Sur plusieurs lignes !\n\
Et une autre !\n\
Et une autre !\n\
J'adore les sauts de ligne, c'est tellement lisible !!!\n\
Et en prime voila une variable : " + variable + " !"
console.log(coucou)

C’est vrai que manipuler des chaînes, c’est pas la PUTAIN D’OPERATION INFORMATIQUE LA PLUS COURANTE DANS LE PUTAIN DE MONDE. PUTAIN.

Séquence émotion

Une autre opération qu’on fait 100 fois par jour : créer des séquences (fichiers, settings, données en base, etc), en récupérer une partie, itérer dessus, les transformer, etc.*

Soit la liste :

l = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Récupérer les carrés des nombres paires de la moité supérieure de la liste ?

Python :

l = [x*x for x in l[5:] if x %2 == 0]

Ruby :

l = l[5..10].select{|x| x % 2 == 0 }.collect{|x| x * x}

Javascript (Ma que, gracieux comme oune popotamé):

var new_list = []
l.splice(0, 5)
for (var i = 0; i < l.length; i++) {
    if (l[i] % 2 == 0) {
        new_list.push(l[i] * l[i]);
    }
}
l = new_list;

Et encore, je suis cool, je mets un code JS qui utilise l.length directement dans la boucle et pas de variable pour l[i].

Array.map arrive avec JS 1.6 et les arrays comprehensions avec la 1.7, que vous pourrez utiliser sur tous les navigateurs d'ici 2056. Ou alors juste sur le serveur, mais si c'est pour pas avoir le même code sur le client ou le serveur, pourquoi ne pas utiliser un langage qui possède tout ça et bien plus depuis 5 ans ?

DéLire

Lire un fichier ligne à ligne ? Une opération vraiment rare et compliquée...

Python :

for line in open('fichier'):
    print line

Ruby :

File.foreach('/etc/fstab') {|x| print x }

En JS... Heu, enfin avec NodeJS:

var fs  = require("fs");
fs.readFileSync('./input.txt').toString().split('\n').forEach(function (line) {
    console.log(line);
});

Ah oui, il faut installer un MODULE SUPPLEMENTAIRE pour gérer tout autre encoding que les variantes d'unicode.

PASramètre

Comment on fait ça en Javascript ?

def fonction(param, param2="valeur", **params):
    print param, param2, params

fonction(1, autre_valeur=2)

On fait pas. Du coup on se retourne vers la bonne vieille technique de "j'attends un objet en paramètre et je le fusionne avec un autre objet qui a mes valeurs par défaut".

Photo d'un homme avec un chapeau giraffe

Dev JS qui essaye de comprendre pourquoi le callback anonyme de sa promise n'a pas rebindé correctement son this dans une closure . Oui cette phrase a parfaitement du sens en Javascript.

Javascript ça marche partout !

Node ne tourne pas sous Windows, excluant de sa pool d'apprentissage les 3/4 des foyers de la planète. Parce que je sais pas pour vous, mais moi, quand j'ai appris la programmation, j'ai pris le premier ordinateur qui m'est tombé sous la main et j'ai essayé. Parce que je n'y connaissais rien. Je ne me suis pas soucié de l'OS.

On me signale dans la comemntoreillette que j'ai dis une connerie.

Ah oui, et sans node, le Javascript on en fait quoi déjà ? Des Interface graphiques poussées comme avec QT ? Du calcul scientifique de haut niveau comme avec Scipy ? Du sys admin windows comme avec pywin32 ?

Ah non, en fait, on fait rien.

Deux structures de données devraient suffire à n'importe qui

Donc, vous avez les arrays. Et les objets. Et pour le reste, vous vous démerdez.

Des sets ? Des heaps ? Des tuples ? Des views ? C'est pour les petites bites tout ça. C'est tellement plus rigolo de réimplémenter la roue.

D'ailleurs, même les roues fournies sont carrées, juste au cas où vous vous sentiez trop à l'aise.

Qui se souvient des params de splice pour le slicing ? Vous, moi ? Nope. Jamais. C'est con parce que c'est AUSSI la seule manière d'enlever un élément au milieu d'un array sans laisser une case vide. On allait pas coder ça, ça sert pas souvent...

En parlant de trucs biens faits, mélanger une structure de données qui fait objet ET hashmap, quelle bonne idée ! Encore plus con que de mélanger les listes et le mapping en PHP. Tu veux récupérer les attributs de ton objet ? Paye ta boucle (et fait gaffe à la chaine de prototypage). Tu veux updater ton dico avec le contenu d'un autre. Écris ta méthode toi-même, c'est un truc dont on a pas besoin IRL.

Et tout est comme ça. Encore une fois, le langage tout seul te laisse à poil, il y a toujours un machin à recoder à la main à moins d'installer une (voir 2) libs pour avoir ne serait-ce que les trucs de base : faire un hash md5, générer un ID unique, filtrer des doublons sur un objet qui n'est pas une chaîne, et mon grand favoris, la division entière.

Ouai. La division entière n'est pas incluse de base en JS.

Or le JS, c'est typiquement le truc pour lequel on veut charger le MOINS DE CHOSES POSSIBLES pour que ta page s'affiche vite. Du coup on passe notre temps à créer des solutions de contournement avec de la mignification, des CDN qui aident à optimiser l'usage du cache, et tout le bordel.

Ah mais il faut utiliser coffeescript !

Oui donc pas Javascript. Point made.

Le langage est tellement à chier qu'on a inventé un autre langage pour le générer et pas avoir à s'en soucier. Et ensuite, on a inventé des libs pour automatiquement faire cette compilation pour le dev, et les outils pour le déployer. Et on a inséré dans les navigateurs une nouvelle technologie : le source map, parce que sinon c'était trop chiant à débugger. Qu'il faut aussi déployer pendant le dev. Et former les gens dessus.

Vous trouvez ça normal ?

Vous trouvez que c'est le signe d'un BON langage ?

Ouai mais ça fait un seul langage côté server et client

Oui, c'est pour ça que les gens s'y mettent. Encore une fois, ça n'a rien à voir avec les qualités de Javascript. Ca reste de la merde en boîte, mais de la merde unifiée.

Et encore, car si on a bien le même langage, on est loin d'avoir le même code. Le code serveur et le code client est, sauf dans les frameworks avancés comme météorjs, très peu partagé au final. Surtout que vous n'avez PAS la même version du moteur Javascript côté serveur et côté client.

Les libs externes bien conçues marcherons de la même façon par contre, ce qui est un avantage.

Encore une fois, la question n'est pas "est-ce que les gens doivent utiliser Javascript ?" La réponse à cette question est oui. Pas le choix.

Mais on ne l'utilise pas parce que c'est un bon langage. On l'utilise parce que c'est le status quo. Qui est tout pérave.

Arrête de baver et donne nous ta solution !

J'ai pas de solution parce qu'il n'y en a pas. C'est trop tard. Le Javascript et là et on l'a dans le cul. D'où ma frustration. La 1.7 va dans la bonne direction, mais le temps qu'elle soit adoptée partout...

Par contre si ce n'est pas trop demandé, arrêtez de mettre du Javascript partout. Limitez la contamination. Vous n'avez pas vu "28 jours plus tard" ? Il faut isoler le problème avant que la pandémie ne dévore l'humanité. Il y a des tas d'alternatives : Python, Ruby, Clojure, Go, Lua, etc.

Si vous faites un langage de scripting embarqué, si vous faites un outils de déploiement, si vous faites un premier binding pour votre outil... Ne donnez pas la prio à cette bouse. Quand je vois Gnome ou QT adopter le JS pour leur scripting, ça me met dans une rage folle. C'est de la connerie pure. Bordel, il y a un site appelé 99 bottles of beer avec des milliers de langages. Vous avez le choix !

C'est bien beau d'avoir le même langage partout, mais si c'est pour se trainer un boulet... Vous ne travaillerez pas plus vite.

D'ailleurs, vous n'aurez jamais le même langage partout. Vous aurez toujours à apprendre et utiliser 2 ou 3 langages. C'est un fait de la vie. Les humains ne parlent pas tous anglais ou chinois. Et les codeurs ne coderont jamais dans un espéranto, fusse-t-il fantastique.

Je sais, je sais, quand on vient du C, Javascript parait si facile, on se dit que c'est une amélioration de l'ergonomie au prix de la performance. Mais non, c'est comme acheter une 2 chevaux pour aller en ville à la place de son tracteur, alors qu'on vous avait proposé une smart ou une mini pour le même prix.

Par ailleurs, il y a une vie en dehors de la prog Web vous savez.

Si il n'y a pas de solution, ferme ta gueule alors

C'est mon blog, je fais ce que je veux. Na.

Photo d'un homme ayant son aspirateur coincé dans un ascenseur

Sam, passant directement du stade de la colère à la dépression dans son dueil de la programmation Web

]]>
http://sametmax.com/un-gros-troll-de-plus-sur-javacscript/feed/ 158 9752
Les mensonges des DSL http://sametmax.com/les-mensonges-des-dsl/ http://sametmax.com/les-mensonges-des-dsl/#comments Sun, 15 Dec 2013 01:36:55 +0000 http://sametmax.com/?p=8327 Un DSL, ou Domaine Specific Language, est un langage qui est dédié à un usage très pointu, et pour lequel il est donc particulièrement efficace.

Par exemple, le langage de Matlab est un DSL, dédié à l’expression mathématique. SQL est un DSL, orienté requête. PHP a commencé comme un DSL, optimisé pour le Web.

En théorie, un DSL doit vous rendre plus productif. En théorie. En pratique, une fois qu’un DSL sort de son domaine de prédilection, il est extrêmement inéficace. C’est le prix de la spécialisation.

Or, dernièrement, on a fait beaucoup l’apanage des DSL dans le cadre d’autres langages. Car oui, certains langages permettent de créer des DSL. Les macros du C et les capacités de meta programmations de Lisp permettent par exemple de créer des langages complets, avec des dialectes spécialisés.

Vient alors le premier problème : on créé un nouveau langage. Récent. Supporté et donc débuggé et (mal) documenté par l’auteur. Ensuite, on se rajoute un niveau d’indirection. Car du coup ça nous fait une abstraction supplémentaire, et il faut savoir ce que ça fait sous le capot. En prime, on freine l’entrée de nouveaux venus dans le projet, puisqu’il faut qu’ils apprenent à faire avec le DSL en plus, là où une simple lib aurait pu faire l’affaire.

Et on touche ici à une seconde problématique, les faux DSL : des libs ordinnaires qui se déguisent en DSL. Typiquement, je pense à Ruby, ici.

Les rubistes prétendent partout qu’ils peuvent créer des DSL avec leur langage. Encore un mensonge, puisque tout ce qu’ils font c’est utiliser le chaînage de méthode, le namespacing, la surcharge des opérateurs et les parenthèses/virgules facultatives pour donner l’impression qu’un nouveau langage est créé.

Tout comme on donne l’illusion de retourner deux paramètres dans une fonction en Python en retournant un tuple et en faisant de l’unpacking. C’est du sucre syntaxique, mais on est très loin de ce que ça prétend être.

Pourquoi c’est important ? Parce que cela laisse à croire qu’il y a quelque chose de spéciale là dedans, alors qu’il s’agit ni plus ni moins que d’une bête lib avec une API fluide. Ce qu’on peut faire dans tout autre langage (excepté l’absence de parenthèses, sur lequel il faudra que j’écrive un article tellement c’est une FBI).

Donc plutôt que de faire du bruit et du hype autour de cela, et amener les gens à se concentrer sur l’aspect “comment obtenir une syntaxe exotique”, il serait plus intéressant de dire tout simplement : voilà comment on peut faire une belle API, voici les bonnes pratiques, appliquez les.

Et aussi écrire une doc…

J’ai horreur en informatique quand on donne 40 noms différents à la même chose. Comme par exemple pour les promises, les futures, les deferred, etc. Merde, non seulement ça n’aide personne, mais en plus ça rend la comprehension de principes plus difficile. Déjà que c’est rarement bien expliqué…

Au final, un DSL est rarement une bonne idée, que ce soit un vrai ou un faux. SQL nous aura bien servi, il faut le reconnaitre, même si on aurait pu faire mieux. Mais la plupart du temps, ce sont quelques heures de gagnées en redaction de code, et des jours de formation et maintenance perdus, ou alors juste une masquarade cachant simplement derrière le hype des principes sains de programmation.

Languages are more than just languages, they are a form of culture, and by being culture they tend to enforce (indirecty or directly) a certain way of doing things, i.e. standards or conventions. This means that if you know the language and its culture, there are less surprises and a longer learning or adaptation curve

(Extrait de Is Lisp Too Powerful ?)

]]>
http://sametmax.com/les-mensonges-des-dsl/feed/ 6 8327
Le choix d’un langage influence le fun de votre carrière http://sametmax.com/le-choix-dun-langage-influence-le-fun-de-votre-carriere/ http://sametmax.com/le-choix-dun-langage-influence-le-fun-de-votre-carriere/#comments Tue, 14 May 2013 09:47:04 +0000 http://sametmax.com/?p=6095 Les langages de programmation sont censés être des technologies neutres, mais comme toute chose utilisée dans le monde réel pour des usages concrets et nombreux, l’humain finit par leur donner une orientation, une préférence.

De fait, chaque langage finit par être plus utilisé dans certains types de métiers ou d’activités, pour certains types de projets, dans certains environnements. Plus important encore, un langage appelle d’autres outils, et un certain type de collègue, et même si, comme d’habitude, la généralisation est un piège à con, il y a bien des stéréotypes visibles qui se dégagent.

Ainsi, Java et PHP sont des langages pour lesquels il est très facile de trouver du travail. Il y a une telle base de code là dehors qu’il y a des annonces partout, et tout le temps. En revanche, les environnements Java sont généralement très très lourds à manipuler. Pas en terme de performance (Java est aujourd’hui très rapide), mais en terme de charge de travail : énormément de configuration, beaucoup d’abstractions et de design pattern imbriqués, des APIs et des formats très verbeux…

Travailler dans un monde Java, c’est généralement travailler à un rythme lent, plus souvent dans des grosses boîtes, pour des systèmes assez larges avec un grosse inertie. Ne vous attendez pas à des Java-party avec vos collègues après le boulot.

PHP, c’est la même chose, avec des projets et composants plus simples (dans des entreprises de toutes tailles), et souvent bien plus dégueulasses. Non pas qu’on ne puisse pas écrire du PHP propre, mais 15 ans de PHP codé à l’arrache ne s’effacent pas avec quelques années de Symfony, et autre cakePHP. Du coup on hérite souvent d’un projet moche comme ta mère.

Bref, Java et PHP vous garantissent un job, mais les projets sont rarement marrants, et l’ambiance au taff sera pas pumped up. Par contre il y a de la doc et des tutos, même si généralement ceux pour PHP sont de meilleure qualité que pour Java (qui peuvent être assez indigestes).

Il y a une alternative intermédiaire : le C#. Beau langage, beaux outils, c’est propre sans être trop lourd, et la base de code est pas à vomir. Mais on reste dans le corporate, et la plupart du temps, sur du 98% Microsoft ou affiliés.

Après vous avez des langages spécialisés comme Erlang, Scala, Lisp. Là, trouver du taff sera généralement un challenge. Ce n’est pas le genre de truc qu’on voit partout. Et le niveau sera difficile : un débutant peut arriver avec la bite et le couteau dans un projet PHP, mais si vous vous pointez avec 3 mois d’expérience sur une gateway jabber haute tolérance, le bidouillage ça va pas le faire.

Ce sont des langages qu’il faut choisir si on aime le taff de haut niveau, la débrouillardise et les solutions intelligentes. En général les missions sont super intéressantes, mais la reconversion est dure. Par contre, vous rencontrerez des collègues qui valent le détour.

Puis il y a les langages de bas niveau, type C/C++. Aujourd’hui, c’est massivement des missions scientifiques ou de l’embarqué : analyse d’image, cartes électroniques, petites machines, etc. Il y a encore des trucs pas cool genre Windev (j’ai un pote coincé là dedans, c’est triste, fuyez ces annonces), mais ce n’est plus la majorité. Ces langages, c’est une question de tempérament. Est-ce que vous aimez la minutie ? L’efficacité des algos ? Le travail sous contrainte technique ? Si oui, alors ce genre de taff peut être très sympa. Sinon, choisissez un langage plus dynamique.

Ensuite il y a les langages de niches : Cobol, Power Builder, etc. Là c’est généralement des projets de merde très bien payés. Plus personne ne veut coder avec ces trucs, mais ça coûte trop cher à changer. Les jeunes sont acceptés, les formations offertes, le salaire de début de carrière est bon, mais par contre, le code est un truc de mémé. C’est pas mal pour commencer une carrière et se faire un peu de thune, mais faut savoir en sortir, et ça ne donne pas de bonnes habitudes en prog.

Et pour finir il y des langages dit “modernes” (ce qui est un abus… de langage, car ils ne datent pas d’hier) comme Python, Ruby ou Javascript. Le côté “moderne” vient surtout du fait qu’ils sont maintenant très adaptés à des projets modernes, où la souplesse de développement a priorité sur le reste des caractéristiques. Choisissez ces langages si vous visez des missions, principalement Web, sur des produits récents. Ce sont les communautés les plus sympas et dynamiques, ça brasse pas mal dans le milieu et c’est assez jeune. Mais un grand nombre de start up, donc il faut pas chercher la sécurité de l’emploi.

Une petite parenthèse pour Python tout de même : il n’est pas autant limité au Web et on le voit aussi beaucoup dans le secteur scientifique et bancaire. C’est sa versatilité et la facilité de reconversion qu’il offre qui me fait dire que c’est un très bon choix comme premier langage. Mais. Car il y a un “mais”. Trouver une offre Python sera plus difficile qu’une offre Ruby, et BEAUCOUP plus difficile qu’une offre PHP ou Java. Après perso je n’ai jamais connu le chômage.

Warning ! Il faut faire gaffe à se lancer dans le dev Web. C’est très tentant, mais contrairement aux autres carrières, ça veut dire une courbe d’apprentissage beaucoup plus longue. Vous ne pouvez pas juste apprendre votre langage, ses libs et son env et vous vendre comme “expert”.

J’ai laissé pas mal de truc de côté, comme l’objective C, Haskell, Smalltalk, le Bash, Perl et quelques milliers d’autres langages. On ne peut pas tout faire, et je voudrais surtout peindre un tableau global du marché. En me relisant, je me dis que c’est bourré d’idées reçues, qu’il y a plein d’exceptions, etc. Mais je pense que les infos données peuvent permettre à des gens qui se posent la question de l’orientation de prendre une décision moins mauvaise que “je lance un D20 et on verra bien”.

]]>
http://sametmax.com/le-choix-dun-langage-influence-le-fun-de-votre-carriere/feed/ 32 6095
Python, Ruby et PHP sont lents http://sametmax.com/python-ruby-et-php-sont-lents/ http://sametmax.com/python-ruby-et-php-sont-lents/#comments Tue, 30 Oct 2012 16:44:54 +0000 http://sametmax.com/?p=2787 Ce matin je lançais ma petit recherche Python/Django/Git habituelle sur Twitter pour voir ce qui s’y tramait, quand je suis tombé sur plusieurs tweets qui m’ont fait tiquer.

Il y en a un qui résume très bien l’idée:

Cay de la merde je préfère les langages plus bas niveau, Python c’est lent.

C’est un argument que je lis souvent, et qui est aussi utilisé contre Ruby ou PHP.

Si j’ai la personne en face de moi, généralement la question qui suit est:

Ouai je comprends. C’est quoi ta contrainte ? Tu dois exécuter quel calcul sous quelle limite de temps ?

Il n’y a jamais aucune réponse autre qu’un bafouillement, car une personne qui a une réelle contrainte de temps d’exécution ne sort pas ce genre d’ânerie: il utilise le bon outil pour le bon travail selon des metrics précises, pas selon le nom du langage.

Ceux qui trollent, généralement des étudiants en informatique qui n’ont encore jamais codé d’utile de leur vie (je l’ai fait, donc je +1, d’ailleurs parfois je le fais toujours :-p), ont entendu / lu que Python, Ruby et PHP étaient lents, et donc les rejette car ils ne correspondent pas à l’idée qu’il se fait de la programmation, encore naissante dans sa tête.

La vérité est que les personnes qui ont des contraintes de temps d’éxécution auquel langage X, n’importe quel langage, ne peut pas répondre, font partie des 0.00000001 de la population des programmeurs: le plus souvent dans l’embarqué (voiture, satellite, microchips, etc) et les systèmes temps réels (navigation, chaîne de productions, bourse d’échange…). Pour les autres, nous, quasiment tous, les problèmes de performances se joueront sur l’algo, les libs, les serveurs Web et BDD, le caching, etc. On peut programmer en Basic ou en GOTO++, ça ne change rien.

Languages, libraries and frameworks don’t scale. Architectures do.

Cal Henderson

Dans certains cas, par exemple le calcul scientifique, les interfaces graphiques ou les jeux videos, la rapidité est importante, et on le sait sans même mesurer. Mais ces problèmes-là sont résolus depuis longtemps: il existe des bindings en C extrêmement rapides qui permettent de coder dans son langage interprété favori tout en bénéficiant d’algos Speedy Gonzalez sous le capot.

Par ailleurs, ça a déjà été dit 1000 fois, mais ça ne fait pas de mal de le répéter:

Le salaire du développeur et l’impact commercial de la lenteur d’un développement coûtent immensément plus cher qu’un ordinateur plus puissant. Qui d’ailleurs ne coûtera plus rien dans 6 mois.

Alors OK, ce n’est pas une invitation à coder avec ses pieds sous prétexte qu’on la puissance à disposition (ce qui se fait malheureusement de plus en plus).

Mais choisissez une techno parce que vous êtes productif avec, pas pour ses performances. Sauf si vous avez des mesures chiffrées qui s’imposent à vous. Auquel cas vous n’avez de toute façon pas besoin de lire cet article, vous êtes plus compétent que moi.

]]>
http://sametmax.com/python-ruby-et-php-sont-lents/feed/ 30 2787
Réponse à l’article “Ruby -vs- Python” de Bodo Tasche http://sametmax.com/reponse-a-larticle-ruby-vs-python-de-bodo-tasche/ http://sametmax.com/reponse-a-larticle-ruby-vs-python-de-bodo-tasche/#comments Thu, 04 Oct 2012 14:44:29 +0000 http://sametmax.com/?p=2461 C’est pas encore vendredi, mais je ne  pouvais pas laisser passer ça. Petite réponse à Bodo Tasche, affûtez votre english car j’ai la flemme de traduire sa prose (si quelqu’un se propose, il aura droit à un tampon :-p).

Ruby and Python. Two languages. Two communities. Both have a similar target: to make software development better. Better than Java, better than PHP and better for everyone. But where is the difference? And what language is “better”? For the last question I can say: none is better. Both camps are awesome and do tons of great stuff. But for the first question the answer is longer. And I hope to provide that in this little article

Is the difference in the toolset around the language? No, I don’t think so. Both have good package managers, tons of libraries for all kind of stuff and a few decent web frameworks.

Heu… si. Il y a une énorme différence.

Ruby a RVM, un truc enorme et très difficile à mettre en oeuvre. Python a virtualenv, un truc léger et très simple à faire passer. Conséquence ? Une grande partie des rubistes n’utilisent pas RVM et leurs projets souffrent de problèmes constant de compatibilité. Combien de fois j’ai vu des gems install planter à cause de ça…

Et combien y a-t-il de RAD pour faire des applications en Ruby ? Ca influe sur le nombre d’applications desktop écrites en Ruby.

Combien y a-t-il d’outils pour facilement interfacer Ruby avec d’autres technologies ? Python est utilisé massivement comme langage d’extensions à cause de ça (Sublime Text, Blender, Nautilus, Inscape, etc).

Quant aux libs. On utilise Ruby pour quoi en dehors du Web ? Développement de jeu ? Sur tablette tactile ? Simulation scientifique ? Application desktop ? Très peu. Alors que Python est utilisé pour tout ça. La raison est justement le large panel de libs. Python a beaucoup, beaucoup, beaucoup plus de libs que Ruby.

Youhou ! Pour accéder à Internet, on utilise un ordinateur plein de trucs qui ne sont pas sur Internet ! Pour servir un site Web aussi !

L’écosystème, c’est la moitié de l’intérêt d’un langage. Je ne retire pas à Ruby le mérite de la qualité du sien: il est innovant, dynamique, sa communauté est fantastique. Mais on est loin d’avoir dans Ruby le dixième des outils et libs qu’on a en Python. C’est pour ça que Mac embarque embarquait Python par défaut et pas Ruby. C’est pour ça qu’Ubuntu est massivement codé en Python et pas en Ruby. Ca fait toute la différence.

I think there is something else that is way more important. The culture.

+ 1. Et Ruby en a une excellente. Faites un bisou aux gars de 37 signals.

Okay, now what is the difference in the culture? It is pretty easy. Python folks are really conservative and afraid of change, Ruby folks love the new shiny stuff even if it breaks older things. It’s that simple. But it has huge consequences.

Ce n’est pas la seule différence, mec. Les rubistes sont vachement plus sympa, d’une manière générale. Les pythonistes que je connais sont généralement assez blafards. Compétents, mais pas funny fun. Et les rubistes sont plus actifs socialement, du coup: plus d’events, plus d’articles de blog, plus de vidéos… Et ça, c’est un gros plus pour Ruby.

Mais d’un autre côté, Python a la culture des comptable: du code lisible, et de la documentation. Et comme c’est un peu mon job de lire le code 500 fois par jour et de fouiller dans la doc, c’est très important pour moi. Les docs Ruby, parfois, c’est vraiment une grosse blague. Regarder dans le code source n’est pas un bon palliatif. Une doc indique une manière officielle de faire, une manière figée, stable, qu’on va pouvoir utiliser et supporter sur des années. C’est important.

One you can see for example in the adaption of Ruby 1.9 vs Python 3. Both new versions did tons of breaking changes. A lot of code needed changes to run on the new plattform. In the Ruby world the transition went pretty quick. In the Python world it is very troublesome. Some Python people even say that Python 3 is broken and all energy should be focused on the 2.x-branch of the language. The Ruby community saw the opportunities. The Python community only saw the update problems. Yes, there have been update problems in the Ruby world, but we found an easy way to fix this: isitruby19.com. A simple plattform that showed if the gem is ready for 1.9. And if it wasn’t and the gem was important, it got fixed with pull requests or something similar. And the problems went away fast.

Ouai mais tu vois (tu me permet de te tutoyer ? en anglais on s’en fou de toute façon…), c’est vachement plus facile de tout péter quand on a pas deux OS majeurs qui se basent dessus. Je sais pas si tu as déjà essayé de faire upgrader un repo complet de milliers d’apps open sources, mais ça prend du temps.

Oh, et Python est là depuis vachement plus longtemps que Ruby. Python était même là avant Java. Chaque corps de métier à un sacret paquet de code à faire migrer, et ils sont pas tous en lean management super agile mega scrum mode, eux. Les biologistes qui utilisent Python pour faire leurs simulations depuis 10 ans, ils ont pas que ça à foutre d’upgrader leur code. Pour eux la prog, c’est pas “Fuck yeah, new features, I’m going to touch myself on Vx and migrate”. Pour eux c’est 7 ans de scripts d’analyse de génome à se retaper alors que ce n’est qu’un outil ennuyeux à leurs yeux.

Both models of thinking have pros and cons. The Python world is more stable, you can update your django installation without much troubles. But that also means new technology is only added very slowly. The Ruby world loves changes.

La différence majeur entre Rails et Django ? Rails: chaque version stable possède des gros trous qu’ils bouchent au fur et à mesure, parce que c’est pas grâve, on est flexible et adaptif mec, on release early et often. Django, en version 0.96, tout le monde l’utilisait déjà en production car le truc était rock solide.

Alors oui, y a moins de features. Mais ma plateforme ne m’explose pas à la gueule. Et pip installe fonctionne.

So much that most of the “new stuff” in the Python world was tested in the Ruby world first.

Ca c’est vrai. Merci d’ailleurs. Mais encore une fois, on parle d’une catégorie de libs qui se limitent au dev Web. C’est le même débat que “Mac est innovant”. C’est certain, quand on a une archi et 3 modèles à supporter, c’est plus facile de faire un truc innovant: on a pas à supporter de compatibilité.

We love changes so much that the Rails core is build around that idea. You can easily change nearly everything and extend everything. Most of the new stuff the Rails Core Team is testing right now for version 4 is available as plugin for Rails 3. This is pretty interesting if you love new things, love change, and love playing around with stuff. If you don’t and hate the idea of breaking changes, you maybe are better suited with the Python way. But don’t be afraid of breaking changes. They are all pretty well documented in the release guides. It’s not voodoo.

Si. C’est carrément du voodoo. Le monkey patching des objets built-in, c’est la porte ouverte à toutes les fenêtres, et quand deux libs le font en même temps, BOUM.

Et le nouveau, c’est marrant. Je suis pour le nouveau. Max m’engueule tout le temps car je veux essayer les trucs nouveaux. Mais pas instable. L’écosystème de Ruby est instable. Si les langages étaient des OS, Java serait Debian, Python serait Ubuntu LTS, Ruby serait Ubuntu RC. J’utilise la dernière Ubuntu pour mon desktop, parce qu’avoir Unity qui plante une fois par jour ne me dérange pas. Mais sur le serveur, je prends la version la plus stable, parce que j’ai pas besoin de <blink>, j’ai besoin de <strong>.

I for myself love the Ruby mindset. Something like Rails or Asset Pipelines or all the other things would not be possible if we are stuck with “no, don’t change that, it works pretty well that way”. Someone has to be the leader. Someone has to play around with new ideas. Yes, some ideas won’t fly, some are removed pretty quickly. But at least we tried them. Yes, I know that some people prefer the conservative way. If you consider yourself to be like that, you should at least try Python. I stay with Ruby.

C’est vrai qu’on ne fait rien d’innovant en Python: programmation du rasberry py, simulation neurale, facilitation du parsing d’arguments, création du meilleur protocole d’échange en P2P au monde… Ah, par innovation tu veux dire une énième lib Web ? Pardon, je croyais qu’on parlait de programmation au sens large du terme.

Dans ce cas: Twisted était là bien avant event-machine (ou même NodeJs). Wep.py était là avant Sinatra. Virtualenv était là avant RVM. Zope était là 6 ans avant ROR avec son ORM et son langage de template.

Et oui, vous avez bien amélioré tout ça. Et c’est génial. C’est comme ça que ce doit être. Mais arrêtez de vous prendre pour l’élément indispensable de l’innonvation de la programmation Web moderne. Vous n’êtes pas tous des Jason Fried. Et là plupart des choses que l’on fait aujourd’hui on été inventé par les mecs de Lisp, Haskel et Smalltalk de toute façon, qui eux même se sont inspirés de l’amont. On giant shoulders, tout ça, tout ça…

]]>
http://sametmax.com/reponse-a-larticle-ruby-vs-python-de-bodo-tasche/feed/ 22 2461
Un peu de Ruby dans du Python http://sametmax.com/un-peu-de-ruby-dans-du-python/ http://sametmax.com/un-peu-de-ruby-dans-du-python/#comments Wed, 26 Sep 2012 13:58:13 +0000 http://sametmax.com/?p=2297 compass. Mais du coup, gem install compass ne marche pas, il faut soit faire un sudo, soit plonger dans les méandres de rvm. Pas glop.]]> Si vous utilisez un virtualenv, vous n’avez pas envie d’installer des libs au niveau du système.

Et si vous n’êtes pas racistes, vous utilisez peut être quelques tools Ruby, comme compass.

Mais du coup, gem install compass ne marche pas, il faut soit faire un sudo, soit plonger dans les méandres de rvm. Pas glop.

Petit astuce

Virtualenv wrapper vient avec des scripts qui se déclenchent à des évenements. Typiquement, env/bin/postactivate est le script déclenché après l’activation de l’env.

Mettez dedans:

export GEM_HOME="$VIRTUAL_ENV/gems"
export GEM_PATH=""
export PATH=$PATH:"$GEM_HOME/bin"

Et voilà, gem install va maintenant installer les gems dans le virtualenv.

]]>
http://sametmax.com/un-peu-de-ruby-dans-du-python/feed/ 4 2297
Je voulais juste installer une gem. http://sametmax.com/je-voulais-juste-installer-une-gem/ http://sametmax.com/je-voulais-juste-installer-une-gem/#comments Wed, 19 Sep 2012 11:46:50 +0000 http://sametmax.com/?p=2183 sudo gem install xiki [sudo] password for sam: Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: sexp_processor-3.2.0.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: ruby_parser-2.3.1.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: ruby2ruby-1.3.1.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: tins-0.5.4.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: file-tail-1.0.11.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: sourcify-0.5.0.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: multi_xml-0.5.1.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: httparty-0.9.0.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" When you HTTParty, you must party hard! Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: i18n-0.6.1.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: activesupport-3.2.8.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: method_source-0.8.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: net-ssh-2.5.2.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: net-scp-1.0.4.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: net-sftp-2.0.5.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: rspec-core-2.11.1.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: diff-lcs-1.1.3.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: rspec-expectations-2.11.3.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: rspec-mocks-2.11.2.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: rspec-2.11.0.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: trogdoro-el4r-1.0.7.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: daemons-1.1.9.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Fetching: xiki-0.6.3.gem (100%) Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Successfully installed sexp_processor-3.2.0 Successfully installed ruby_parser-2.3.1 Successfully installed ruby2ruby-1.3.1 Successfully installed tins-0.5.4 Successfully installed file-tail-1.0.11 Successfully installed sourcify-0.5.0 Successfully installed multi_xml-0.5.1 Successfully installed httparty-0.9.0 Successfully installed i18n-0.6.1 Successfully installed activesupport-3.2.8 Successfully installed method_source-0.8 Successfully installed net-ssh-2.5.2 Successfully installed net-scp-1.0.4 Successfully installed net-sftp-2.0.5 Successfully installed rspec-core-2.11.1 Successfully installed diff-lcs-1.1.3 Successfully installed rspec-expectations-2.11.3 Successfully installed rspec-mocks-2.11.2 Successfully installed rspec-2.11.0 Successfully installed trogdoro-el4r-1.0.7 Successfully installed daemons-1.1.9 Successfully installed xiki-0.6.3 22 gems installed Invalid gemspec in [/var/lib/gems/1.8/specifications/tilt-1.3.3.gemspec]: invalid date format in specification: "2011-08-25 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/libv8-3.3.10.4-x86_64-linux.gemspec]: invalid date format in specification: "2011-11-15 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/sinatra-1.3.1.gemspec]: invalid date format in specification: "2011-10-05 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/rack-protection-1.1.4.gemspec]: invalid date format in specification: "2011-10-04 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-0.8.8.gemspec]: invalid date format in specification: "2011-10-21 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/em-websocket-0.3.5.gemspec]: invalid date format in specification: "2011-10-24 00:00:00.000000000Z" Invalid gemspec in [/var/lib/gems/1.8/specifications/guard-livereload-0.3.1.gemspec]: invalid date format in specification: "2011-09-01 00:00:00.000000000Z" Installing ri documentation for sexp_processor-3.2.0... Installing ri documentation for ruby_parser-2.3.1... Installing ri documentation for ruby2ruby-1.3.1... Installing ri documentation for tins-0.5.4... Installing ri documentation for file-tail-1.0.11... Installing ri documentation for sourcify-0.5.0... Installing ri documentation for multi_xml-0.5.1... Installing ri documentation for httparty-0.9.0... Installing ri documentation for i18n-0.6.1... Installing ri documentation for activesupport-3.2.8... unrecognized option `--encoding' For help on options, try 'rdoc --help' ERROR: While generating documentation for activesupport-3.2.8 ... MESSAGE: exit ... RDOC args: --ri --op /var/lib/gems/1.8/doc/activesupport-3.2.8/ri --encoding UTF-8 lib --title activesupport-3.2.8 Documentation --quiet

Je sais, je sais, c’est encore un troll. Mais ça fait 5 ans que c’est mon expérience avec Ruby. J’en est marre des trucs qu’il faut toujours bricoler pour que ça marche. J’ai plus 16 ans.

Et encore, si le message d’erreur, ou une doc quelque part me disait comment fixer ça….

C’est encore pire avec npm, évidement.

]]>
http://sametmax.com/je-voulais-juste-installer-une-gem/feed/ 7 2183
Lettuce (and cucumber) is bullshit http://sametmax.com/lettuce-and-cucumber-is-bullshit/ http://sametmax.com/lettuce-and-cucumber-is-bullshit/#comments Thu, 23 Aug 2012 12:58:54 +0000 http://sametmax.com/?p=1845 BDD (le développement orienté par le comportement). La mauvaise nouvelle, c'est que comme tout mouvement, il vient avec son lot de trucs hype super cool.]]> La bonne nouvelle, c’est qu’il y a de plus en plus de mecs qui se mettent au BDD (le développement orienté par le comportement), qui est une forme de TDD (le développement orienté par les tests) mais dans lequel on test les fonctionnalités en priorité.

La mauvaise nouvelle, c’est que comme tout mouvement, il vient avec son lot de trucs hype super cool, et notamment cucumber de chez les rubystes. Bah oui, c’est fashion, ça vient forcément de Ruby. Évidement, comme les pythonistes peuvent pas supporter que les codeurs Ruby aient un truc qu’ils aient pas, même si c’est un truc parfaitement inutile, ils se sont dit qu’ils allaient pondre un équivalent : lettuce.

Les deux outils sont aussi inutiles l’un que l’autre, même si ont fait abstraction de leurs noms douteux, car après tout, c’est une marque de fabrique dans notre métier.

Le principe

Vous écrivez un scénario de tests:

Feature: Manipulate strings
  In order to have some fun
  As a programming beginner
  I want to manipulate strings

  Scenario: Uppercased strings
    Given I have the string "lettuce leaves"
    When I put it in upper case
    Then I see the string is "LETTUCE LEAVES

Vous écrivez des étapes:

>>> from lettuce import *
>>> @step('I have the string "(.*)"')
... def have_the_string(step, string):
...     world.string = string
...
>>> @step('I put it in upper case')
... def put_it_in_upper(step):
...     world.string = world.string.upper()
...
>>> @step('I see the string is "(.*)"')
... def see_the_string_is(step, expected):
...     assert world.string == expected, \
...         "Got %s" % world.string

Et pour chaque scénar, lettuce va rejouer chaque étape et voir si ça se passe bien. Avantages annoncés par rapport à la manière des pauvres mortels de coder les tests:

  • c’est élégant;
  • un non technicien peut comprendre les tests.

La faille

En plus d’être un excellent film dans lequel brille Anthony Hopkins, la faille est le détail qui caractérise la plupart de ces merveilles technologiques, à savoir: on rajoute une surcouche sur un truc que les gens ont déjà du mal à faire.

Concentrez-vous: rassemblez dans votre tête la liste de tous les gens que vous connaissez qui ont jamais écris du code.

Éliminez la majorité qui ne sait même pas ce qu’est un test unittaire.

Dans cette liste, combien écrivent des tests unittaires par eux même ? (je ne le fais pas systématiquement moi-même)

Dans cet échantillon réduit, combien écrivent des tests unittaires AVANT d’écrire le code testé (je le fais rarement moi-même) ?

Dans ce microrésidu d’individus éparse mais dont la volubilité bucolique nous incite à nous poser la question “Pourquoi Dieu a-t-il créé la limule”… Pardon je m’égare.

Donc dans ce qu’il reste, combien il y en a qui écrivent les tests en les orientant comportement en priorité, volontairement ?

Bien.

So… On va écrire tout un outil pour rajouter en travail et en complexité pour faire des tests que déjà il est terriblement difficile de motiver le dev lambda à faire (je n’ai pas dis que c’était une bonne chose, je constate, c’tou).

Parce que “c’est élégant” ? Ahem.

Parce que “un non technicien peut comprendre les tests” ?

Laissez-moi démonter ces assertions avec plaisir.

Les tests, dans la vraie vie vivante (ou VVV)

Évidement, si vous allez sur les sites des deux outils cités. Dans le premier, trouver un tuto clair prend 20 minutes (normal, c’est une communauté Ruby, c’est souvent comme ça). Dans la version Python, leur tuto fait un test sur la fonction factoriel.

Excusez-moi messieurs mais:

1 – si c’est un code aussi simple qu’une fonction factorielle, une doctest règle le problème facilement, sans avoir à apprendre une techno en plus, tout en contribuant à la documentation.

Entre leur exemple qui implique deux fichiers, dont l’un contient ça:

Feature: Compute factorial
  In order to play with Lettuce
  As beginners
  We'll implement factorial

  Scenario: Factorial of 0
    Given I have the number 0
    When I compute its factorial
    Then I see the number 1

  Scenario: Factorial of 1
    Given I have the number 1
    When I compute its factorial
    Then I see the number 1

  Scenario: Factorial of 2
    Given I have the number 2
    When I compute its factorial
    Then I see the number 2

  Scenario: Factorial of 3
    Given I have the number 3
    When I compute its factorial
    Then I see the number 6

  Scenario: Factorial of 4
    Given I have the number 4
    When I compute its factorial
    Then I see the number 24

Et une version de tests en doctests propre, pythonique, concise et qui ajoute de la doc (faudra d’ailleurs faire un article…):

def factorial(number):
    """
        Calculate the factorial of a number.

        E.g:

        >>> factorial(0)
        1
        >>> factorial(1)
        1
        >>> factorial(2)
        2
        >>> factorial(3)
        6
        >>> factorial(4)
        24
    """
    number = int(number)
    if (number == 0) or (number == 1):
        return 1
    else:
        return number*factorial(number-1)

J’ai comme un doute sur l’efficacité de leur truc.

J’en profite au passage pour signaler qu’une factorielle en Python, ce serait plutôt ça:

def factorial(number):
    number = int(number)
    if number in (0, 1):
        return 1
    return number * factorial(number - 1)

Mais là je mérite vraiment le tampon drosophilia fucker.

2 – moi dans la vraie vie vivante, mes tests ils ressemblent plutôt à ça:

    def test_get_tasks_chain_status(self):
        states = ('PENDING', 'PROGRESS', 'SUCCESS')
        try:
            celery.conf.CELERY_ALWAYS_EAGER = False
            res = chain(full_chain.s({'subject_url': 'http://www.service.com/?id=tPEE9ZwTmy0',
                                          'subject_id': 'test',
                                          'service': "service_name"}),
                   task_1.s(), task_2.s()).apply_async()

            tasks_id_list = get_task_id_list(res)

            tasks = set()
            while res.state != 'SUCCESS':
                task_status = get_tasks_chain_status(tasks_id_list)
                tasks.add(task_status['name'])
                self.assertTrue(task_status['state'] in states)

            task_status = get_tasks_chain_status(tasks_id_list)
            tasks.add(task_status['name'])
            self.assertTrue(task_status['state'] in states)

            self.assertEqual(tasks,
                             set(["tasks.full_chain",
                                  "tasks.task_1",
                                  "tasks.task_2"]))

        finally:
            celery.conf.CELERY_ALWAYS_EAGER = True
            # Since we are using a separate celery process for this one with
            # a different set of settings, we have to remove the generated file
            # manually
            try:
                shutil.rmtree(os.path.join(self.OLD_CONTENT_FILE_ROOT, 'test'))
            except:
                pass

On est loin de la factorielle: c’est un test de récupération de statu d’une chaîne de tâches asynchrones. Désolé les gars mais on arrête de coder des factorielles à la sortie de la fac.

Allez me décrire ça dans le DSL de lettuce/cucumber. Oh, c’est possible, ça va juste me prendre du temps. Beaucoup de temps. Parce que ce test, j’ai mis une demi-heure à l’écrire tel qu’il est: c’est la résultante de moult essais, sans compter les modifs a posteriori, car le code qu’il teste n’est pas resté en jachère.

Donc j’ai appris à me servir des tests unitaire, incluant les doctests, j’ai rajouté unittests2 et nose à ma boîte à outil, je connais le tests runner de Django, et par dessus, on voudrait rajouter une surcouche, qui me rajoute du travail dans l’écriture de mes tests. Tests déjà bien chiant à faire, j’ai vraiment PAS besoin d’un démotivateur supplémentaire.

Mais z’attendez, si encore le coût se faisait uniquement à l’écriture du test…

Ces libs, c’est une doc à lire, puis du temps sur leurs fora, et une transposition du concept pour des vrais tests et pas des fonctions playmobiles. Plus le débuggage, plus la dépendance, plus le fait que toute personne qui passe derrière moi devra perdre le même temps.

Tout ça parce que “c’est élégant” ?

Nan, le code est un langage naturel pour moi, le langage ordinaire pour écrire du code n’est pas naturel pour moi. Je suis un dev, je lis du Python au pti dej, c’est Python qui est naturel pour moi, pas un DSL boiteux qui me limite dans ce que je peux écrire histoire de se la toucher en ressemblant à un haïku. Ce n’est pas élégant.

Alors tout ça parceque “un non technicien peut comprendre les tests” ?

Vous croyez qu’une quelconque explication va permettre à une personne lambda de comprendre l’essence du test test_get_tasks_chain_status ? Je ne parle même pas de l’écrire, hein (ce que suggère la doc des outils).

Parce que si c’est juste pour que le stagiaire regarde un tableau et soit capable de citer le nom du test qui a chié, un serveur Jenkins fait très bien l’affaire, merci.

Donc, chers développeurs qui bossez sur ces outils, vous êtes brillant, compétant et vous avez la foi de faire ce faire un dev si énorme. Par pitié, transposez ce potentiel sur des trucs utiles pour la majorité des gens comme une version asynchrone de Django qui puisse concurrencer NodeJs et qui soit plus facile que Twisted, une interface Git humainement acceptable, l’édition de code collaborative qui marche out of the box pour Sublime Text, un blog qui mélange shaarli + status net + wiki + wordpress en une seule interface, un lecteur de flux RSS destop qui ait un historique des articles lus et une recherche qui marche, un jeu video de course de bagnoles qui fasse s’affronter la batmobile, la doloréanne et Bumbo, un film sur le voyage dans le temps qui ait un scénario cohérent, un téléphone non smartphone avec un lecteur mp3 décent et un clavier AZERTY, la paix dans le monde et la disparition des black mambas qui décidément ne servent vraiment à rien.

Merci

]]>
http://sametmax.com/lettuce-and-cucumber-is-bullshit/feed/ 22 1845