Sauter au contenu
24 décembre 2011

Benchmarking Java – Tableaux contre Vecteurs

Java fait partie de ces langages de programmation qui offrent beaucoup d’outils d’aide au développement sensés faciliter et améliorer nos productions. Cependant, certains d’entre eux sont parfois utilisés de manière contre-productive.

Les Vecteurs

Un “vecteur” désigne un ensemble d’éléments stockés de manière contigüe les uns à la suite des autres. On appelle également les vecteurs des “tableaux”. Les tableaux sont des types primitifs des langages de programmation et n’offrent souvent en eux-mêmes que peu d’outils aidant à leur gestion. Il faut en général passer par des fonctions spécifiques.

Java intègre une autre approche en proposant des classes utilitaires (dans le package java.util) dont la classe Vector qui reproduit l’illusion d’un vecteur en ajoutant tout en tas de fonctionnalités améliorées (réallocation dynamique de la taille du tableau, insertion en milieu de tableau, …).

Mais comme nous allons le voir, tout cela a un coût.

Le test

Pour évaluer les performances des Vector Java contre les tableaux primitifs du langage, je procède à l’addition des 100 000 premiers entiers (0 inclus) et ce 10 000 fois successives.

Les résultats sont sans appel :

Entiers directs - Compteur classique :
======================================
Somme obtenue : 4999950000
Durée totale : 339 ms
Durée moyenne d'une itération : 0,033900 ms

Entiers directs - Boucle Java :
======================================
Somme obtenue : 4999950000
Durée totale : 601 ms
Durée moyenne d'une itération : 0,060100 ms

Vecteur - Compteur classique :
======================================
Somme obtenue : 4999950000
Durée totale : 41245 ms
Durée moyenne d'une itération : 4,124500 ms

Vecteur - Itérateur :
======================================
Somme obtenue : 4999950000
Durée totale : 41500 ms
Durée moyenne d'une itération : 4,150000 ms

Vecteur - Boucle Java :
======================================
Somme obtenue : 4999950000
Durée totale : 41874 ms
Durée moyenne d'une itération : 4,187400 ms

Les Vector sont jusqu’à 122 fois plus lents que les tableaux primitifs.

Mais pourquoi ?

Les tableaux primitifs sont capables de stocker l’ensemble des types proposés par Java, des entiers primitifs aux Object. On accède donc directement à l’élément primitif sans conversion de type et sans appel de fonction superflu.

En revanche, les classes génériques comme Vector n’acceptent que des Object ou leurs dérivés (dans notre cas, des objets de la classe Integer). Notre addition provoque donc des allocations d’objets et des conversions vers les types primitifs du langage qui sont très coûteux en temps, et cela réduit donc considérablement les performances.

Mais cela n’est pas tout, la classe Vector effectue tout un tas de vérification lors de l’accès aux éléments et c’est cette étape qui est très gourmande en ressource de calcul. En effet, en reproduisant le test dans notre tableau en remplaçant des entiers primitifs par des objets Integer, les Vector sont toujours 30 fois plus lents.

Conclusion

  • Si votre programme nécessite des performances très élevées, privilégiez des tableaux classiques
  • Si votre programme nécessite des variations fréquentes dans la taille du tableau alloué, envisagez éventuellement des Vector si la première règle n’est pas contredite.

Code du test

import java.util.Iterator;
import java.util.Vector;

public class Benchmark {

    public static final int NB_INTS = 100000;
    public static final int NB_PASS = 10000;
    
    public static void main(String[] args) {
        int[] directInts = new int[NB_INTS];
        Vector<Integer> intVector = new Vector<Integer>(NB_INTS);
        
        // Remplissage
        for (int i = 0; i < NB_INTS; i++) {
            directInts[i] = i;
            intVector.add(i);
        }
        
        // Parcours du tableau en utilisant un compteur classique
        long start = System.currentTimeMillis();
        long sum = 0;
        for (int i = 0; i < NB_PASS; i++) {
            sum = 0;
            for (int c = 0; c < directInts.length; c++)
                sum += directInts[c];
        }
        long elapsed = System.currentTimeMillis() - start;
        
        System.out.println("Entiers directs - Compteur classique :");
        System.out.println("======================================");
        System.out.format("Somme obtenue : %d\n", sum);
        System.out.format("Durée totale : %d ms\n", elapsed);
        System.out.format("Durée moyenne d'une itération : %f ms\n", (double) (elapsed / (double) NB_PASS));
        System.out.println("");
        
        // Parcours du tableau en utilisant la boucle Java
        start = System.currentTimeMillis();
        sum = 0;
        for (int i = 0; i < NB_PASS; i++) {
            sum = 0;
            for (int c : directInts)
                sum += c;
        }
        elapsed = System.currentTimeMillis() - start;
        
        System.out.println("Entiers directs - Boucle Java :");
        System.out.println("======================================");
        System.out.format("Somme obtenue : %d\n", sum);
        System.out.format("Durée totale : %d ms\n", elapsed);
        System.out.format("Durée moyenne d'une itération : %f ms\n", (double) (elapsed / (double) NB_PASS));
        System.out.println("");
        
        // Parcours du vecteur en utilisant un compteur classique
        start = System.currentTimeMillis();
        sum = 0;
        for (int i = 0; i < NB_PASS; i++) {
            sum = 0;
            for (int c = 0; c < intVector.size(); c++)
                sum += intVector.elementAt(c);
        }
        elapsed = System.currentTimeMillis() - start;
        
        System.out.println("Vecteur - Compteur classique :");
        System.out.println("======================================");
        System.out.format("Somme obtenue : %d\n", sum);
        System.out.format("Durée totale : %d ms\n", elapsed);
        System.out.format("Durée moyenne d'une itération : %f ms\n", (double) (elapsed / (double) NB_PASS));
        System.out.println("");
        
        // Parcours du vecteur en utilisant un itérateur
        start = System.currentTimeMillis();
        sum = 0;
        for (int i = 0; i < NB_PASS; i++) {
            sum = 0;
            Iterator<Integer> it = intVector.iterator();
            while (it.hasNext())
                sum += it.next();
        }
        elapsed = System.currentTimeMillis() - start;
        
        System.out.println("Vecteur - Itérateur :");
        System.out.println("======================================");
        System.out.format("Somme obtenue : %d\n", sum);
        System.out.format("Durée totale : %d ms\n", elapsed);
        System.out.format("Durée moyenne d'une itération : %f ms\n", (double) (elapsed / (double) NB_PASS));
        System.out.println("");
        
        // Parcours du vecteur en utilisant une boucle Java
        start = System.currentTimeMillis();
        sum = 0;
        for (int i = 0; i < NB_PASS; i++) {
            sum = 0;
            for (int c : intVector)
                sum += c;
        }
        elapsed = System.currentTimeMillis() - start;
        
        System.out.println("Vecteur - Boucle Java :");
        System.out.println("======================================");
        System.out.format("Somme obtenue : %d\n", sum);
        System.out.format("Durée totale : %d ms\n", elapsed);
        System.out.format("Durée moyenne d'une itération : %f ms\n", (double) (elapsed / (double) NB_PASS));
        System.out.println("");
    }

}
24 novembre 2011

Intouchables

Philippe (François Cluzet) est un riche homme d’affaires des beaux quartiers parisiens. Driss (Omar Sy) est quant à lui un zonard de banlieue classique. Le premier est devenu tétraplégique suite à un accident de parapente, le deuxième est une victime parmi tant d’autres du chômage français et de la marginalisation des cités. Lors d’un entretien d’embauche pour un poste d’aide de vie pour Philippe qui ne devait être qu’une simple formalité pour le renouvellement de ses droits, Driss se retrouve propulsé dans le monde du handicap de son nouveau patron. L’un comme l’autre vont voir leurs repères bousculés et une relation tant inédite que fusionnelle va se créer entre les deux hommes.

2011 aura été une année d’une rare originalité dans le cinéma français. Après Michel Hazanavicius qui a brillamment relevé avec The Artist le défi du cinéma muet, Eric Toledano et Olivier Nakache se sont attaqué au difficile mélange de la comédie et du handicap avec Intouchables. Lorsque deux sujets aussi éloignés sont traités ensembles, on peut se demander comme Pierre Desproges à son époque si l’on peut réellement rire de tout avec tout le monde. Cependant, dans le cas présent, rien ne l’interdit. Le handicap de Philippe n’est finalement qu’un prétexte à la rencontre entre ces deux personnages.

Bien entendu, pour nous, public valide pleinement capable de nos mouvement, la tétraplégie est une inconnue et notre perception du film est nécessairement différente de celle des personnes atteintes de handicaps similaires. Mais, à aucun moment dans le film la maladie ou, ici, les traumatismes du personnage ne sont montrés comme motif de moquerie ou ne sont déclencheurs de rire. Au contraire, Philippe est un homme riche, tant financièrement que culturellement, maître de sa vie et qui ne laisse personne lui dicter sa conduite. C’est Driss, inadapté à cette vie rangée où règne la bienséance, qui concentre le ridicule de toutes les situations et qui bouscule également les habitudes de l’hôtel particulier où se situe la majeure partie de l’action du film.

Mais le film ne s’arrête pas au comique de situation et met également en avant les difficultés intimes des personnages à vivre leur propre vie. Le rythme général est parfaitement équilibré entre des séquences drôles et d’autres plus touchantes, sans pour autant tomber dans le pathétique. La légèreté reste le maître-mot de ce film. La bande-originale est d’ailleurs à l’image de tout le reste du film en reprenant un savant mélange de musique classique, de soul et de compositions originales principalement au piano : profonde, festive et légère.

Rares ont été les occasions dans ma vie de cinéphile de voir une salle applaudir à la fin de la projection, mais il est bon de constater qu’à l’ère des effets numériques superflus et des scenarii minimalistes le public sait encore reconnaître un vrai bon film.

25 septembre 2011

Mac OS X Lion

“Un bond en avant phénoménal pour le Mac.” Voilà comment Mac OS X Lion est présenté sur le site français d’Apple. Mais est-ce véritablement le cas ? Ou est-ce que cette nouvelle version 10.7 de Mac OS X n’est pas une simple évolution du système d’exploitation d’Apple. Plutôt que de me précipiter dans une critique à chaud quelques jours après sa sortie le 20 juillet 2011, j’ai préféré attendre quelques mois pour avoir un retour concret sur son utilisation en “conditions réelles”. Cet article va reprendre une par une les 10 avancées soi-disant majeures mises en avant par Apple et je vous ferai part de mon expérience personnelle dans chacun des cas.

1. Les Gestes Multi-Touch

Apple l’aura assez répété pendant la longue campagne de promotion de OS X Lion (à partir de cette version, Mac OS X perd sa dénomination “Mac”), ce système a été conçu pour rapproché le système des ordinateurs portables et de bureau de la marque d’iOS qui équipe les iPod Touch, iPhone et iPad. Les gestes multi-touch (comprendre à plusieurs doigts) avaient déjà été introduits depuis Mac OS X Leopard, puis améliorés dans Mac OS X Snow Leopard, mais n’étaient que peu utilisés au sein même du système (à moins de posséder une Magic Mouse ou un Magic Trackpad). Cela restait donc assez marginal.

Avec OS X Lion, les gestes multi-touch sont véritablement mis en avant et les ordinateurs portables donc les trackpads autorisent le multi-touch permettent de s’en servir. Si vous utilisez régulièrement un portable en déplacement, ces nouveaux gestes se révèleront relativement pratiques, notamment pour passer d’un espace de travail à un autre. Cependant, si, comme moi, vous utilisez votre ordinateur avec un clavier “classique” et une souris, les gestes multi-touch ne vous seront pas d’une grande utilité. Basculer d’un espace de travail à un autre peut se faire grâce aux touches directionnelles associées à la touche Contrôle et l’accès à Exposé et disponible très simplement depuis une touche du clavier depuis déjà 3 versions du système.

2. Des Apps Plein Ecran

Autre fonctionnalité martelée pendant les keynotes de présentation, la fonction Plein Ecran. Son concept est assez intéressant puisque, lorsque les applications le permettent, une fenêtre passée en “Plein écran” (en cliquant sur la double flèche en haut à droite des applications qui supportent la fonctionnalité) permet de retirer le dock et la barre de menu de la surface de l’écran et place l’application dans un espace de travail spécifique. En créant un espace de travail par application, plus de problèmes de fenêtres qui se chevauchent il suffit d’un simple geste à la souris pour passer d’une application à une autre.

Sur un écran d’ordinateur portable où l’espace est réduit ou sur un ordinateur ne disposant que d’un seul écran, cette fonctionnalité se révèle très utile en retirant tout parasite de notre vue. Mais sur un ordinateur avec plusieurs écrans (comme un ordinateur portable avec un moniteur auxiliaire), cette fonctionnalité est tout bonnement inutile. En effet, une application “Plein écran” crée un espace de travail spécifique où seule sa fenêtre principale peut apparaître sur l’écran principal. Impossible de placer la fenêtre de l’application sur l’écran auxiliaire, souvent bien plus grand. De même, impossible de travailler sur un écran avec une application en plein écran et ses fenêtes “normales” sur son autre écran. Dommage, cela perd en efficacité.

3. Mission Control

Les habitués de Mac OS X connaissent certainement Exposé (apparu dans Mac OS X 10.3 Panther) et Spaces (apparu dans Mac OS X 10.5 Leopard). Le premier permet d’afficher de manière réduite l’ensemble des fenêtres affichées à l’écran pour sélectionner celle qui vous intéresse. Le deuxième permet de créer plusieurs espaces de travail distincts et ainsi mieux répartir vos applications selon votre convenance. Depuis Mac OS X Panther, Exposé a subi plusieurs améliorations. Spaces, plus récent, n’avait pas changé d’un pouce dans Mac OS X 10.6 Snow Leopard. OS X Lion propose de fusionner ces deux concepts en un seul : Mission Control.

Voilà pour moi la plus grande réussite d’OS X Lion à ce jour. Mission Control prend le meilleur des deux outils précédents et crée un véritable tableau de bord de l’activité du système. Très ergonomique, il affiche en haut de l’écran tous les espaces de travail (qui désormais ne peuvent plus être organisés qu’horizontalement) en incluant les applications en plein écran et sur le reste de l’écran toutes les fenêtres visibles de l’espace de travail courant réparties par application et par écran. C’est alors un jeu d’enfant d’aller activer la fenêtre ou l’application qui nous intéresse. Mission Control conserve également tout ce qui avait fait le succès d’Exposé en permettant d’afficher uniquement les fenêtres de l’application en cours ou de dégager les fenêtres de l’écran pour laisser apparaître le bureau.

Malgré quelques défauts de jeunesse (notamment une répartition parfois étrange sur plusieurs écrans), Mission Control est une vraie nouveauté à l’ergonomie parfaite qui crée un gain d’efficacité énorme.

4. Mac App Store

Inauguré avec la mise à jour 10.6.6 de Mac OS X Snow Leopard, le Mac App Store est l’équivalent en bureautique de l’App Store présent sur les iPod Touch, iPhone et iPad : un kiosque de téléchargement d’applications gratuites ou payantes. Plate-forme de diffusion privilégiée pour le Mac, le Mac App Store n’est pas exempt de défauts, mais il présente deux fonctionnalités intéressantes depuis OS X Lion.

La première, c’est que le système permet de rechercher directement dans le Mac App Store une application susceptible d’ouvrir un fichier dont le type ne serait pas connu. Sympathique pour s’éviter d’éventuelles longues heures de galère.

La deuxième, c’est son intégration directe dans le dock qui permet en un clin d’œil de voir si une ou plusieurs de ses applications a bénéficié d’une mise à jour, et le cas échéant de pouvoir l’actualiser en presque un seul clic.

Chose importante pour les personnes comme moi qui possèdent plusieurs Mac, les application achetées via le Mac App Store peuvent être installées sur n’importe quel Mac, autant de fois que vous le souhaitez (à partir du moment où vous utilisez votre Apple ID pour les télécharger).

5. Launchpad

Launchpad est le nom de l’écran d’accueil d’iOS, là où se trouvent toutes les icônes des applications sur les iPod Touch, iPhone et iPad. OS X Lion a directement récupéré cet outil pour le transposer dans le monde de la bureautique.

Autant le dire tout de suite, Launchpad ne sert à rien. Lorsque Mac OS X 10.5 Leopard a inauguré les Piles (Stacks) dans le dock, on a pu intégrer la pile des applications, des téléchargements, etc… au dock et tous restent accessibles en permanence et sans couper notre flux de travail. Et tout était très bien comme ça. Je me suis personnellement posé la question du pourquoi de Launchpad. Je n’ai toujours pas trouvé la réponse. Effectivement, Launchpad propose de retrouver toutes les applications disponibles sur le système, et pas seulement celles du dossier Applications. Mais, c’est peut-être sa seule qualité.

Launchpad a hérité des mêmes qualités que son grand frère du monde mobile : lisibilité, esthétique, ergonomie, possibilité d’organiser les icônes à sa guise. Mais sa filiation ne s’est pas faite sans mal. Lorsque sur un appareil nomade, il apparaît relativement normal de ne pas avoir des centaines d’applications, cela n’est plus vrai sur un ordinateur professionnel. Sur iOS, il est possible des créer des groupes d’applications. Chaque groupe prenant la forme d’une icône d’application composée des icônes des applications du groupe. Sur iOS encore, la taille de l’écran n’autorise pas d’imbriquer des groupes dans des groupes. Mais cela aurait été très intéressant de pouvoir le faire sur un ordinateur de bureau où l’on est habitué à hiérarchiser ses informations et/ou ses applications.

Pire, Launchpad sur mobile permet de supprimer une application alors que la version bureautique ne le permet que pour les applications achetées via le Mac App Store (impossible de supprimer une application installée “à l’ancienne”). On est à nouveau obligé de passer par le dossier où est stockée l’application pour faire le ménage. Vraiment dommage. Un raté sur toute la ligne !

6. Reprise

Autre fonctionnalité très intéressante. Reprise permet de restaurer au démarrage les applications dans l’état où elles se trouvaient (y compris la disposition des fenêtres) au moment où vous avez éteint votre ordinateur (ou lorsque vous quittez l’application concernée). Idéal pour commencer la journée. Mieux, le système peut restaurer les applications dans certains cas quand le système subit un des rares plantages existants.

Il est à noter que cette fonctionnalité ne nécessite pas de mise à jour spécifique des applications développées pour les versions précédentes de Mac OS X, ce qui est un plus appréciable (que l’on aurait bien vu de pareille façon pour les applications Plein écran). A l’heure actuelle, j’ai rencontré quelques comportements étranges sur des applications comme Photoshop ou Word qui réouvrent des fichiers clos juste avant la fermeture de l’application. Cela est probablement dû à une période d’actualisation trop longue pour les sauvegardes des états des applications.

7. Auto Save

Comme son nom l’indique, Auto Save permet une sauvegarde régulière et automatique des fichiers. Je n’ai pour l’instant pas pu tester cette fonctionnalité car le nombre d’applications le permettant est très restreint. Mais si elle tient ses promesses, cela va constituer une arme redoutable contre les pertes d’information.

8. Versions

Comme pour Auto Save, peu d’applications intègrent un support de Versions. Je n’ai donc pas pu tester pour le moment. Il s’agit d’une fonctionnalité proche de Time Machine (disponible depuis Mac OS X 10.5 Leopard) et qui permet de “remonter dans le temps” directement au sein d’un document pour en parcourir les différentes versions précédentes et retrouver éventuellement des informations perdues (ou revenir à une version antérieure après s’être trompé de direction). Versions est la fonctionnalité que j’attendais le plus. J’espère la voir fonctionner sur beaucoup d’applications très bientôt.

9. AirDrop

AirDrop permet l’échange de fichiers entre ordinateurs équipés d’OS X Lion et dont le module Wifi est activé, sans avoir besoin de se connecter à un réseau spécifique, mais en étant à moins de 10 mètres l’un de l’autre. Pour l’avoir expérimenté plusieurs fois, c’est un outil très pratique qui évite d’avoir à passer par une clé USB pour échanger des fichiers. Les débits en Wifi sont cependant très aléatoires, bien que tous les fichiers transférés soient toujours arrivés entiers à destination.

10. Mail

Véritable refonte de l’application Apple de courrier électronique, Mail passe pour l’occasion en version 5 et bénéficie de nombreuses améliorations, dont la vue des emails sous forme de conversation. Il intègre également un nouveau moteur de recherche très performant bien qu’un peu complexe à prendre en main au début.

Conclusion

Vous l’aurez compris, OS X Lion est une mise à jour du système de demi-teintes. D’un côté, on a de magnifiques ratés (Launchpad, les apps Plein écran). De l’autre, de petites merveilles (AirDrop, la refonte de Mail, Mission Control, Reprise). OS X Lion permet aussi au Mac de rattraper son retard sur ses concurrents à différents niveaux (possibilité de redimensionner les fenêtes par n’importe quel côté, …). Et, au milieu de tout ça, nous avons des concepts très avant-gardistes comme Auto Save ou Versions qui donneront probablement ses lettres de noblesses à Lion dans les prochains mois ou les prochaines années.

Mais alors, au final, la convergence Mac OS X / iOS est elle vraiment entamée. En dehors des gestes multi-touch et de Launchpad, Mac OS X reste lui-même, mais en mieux pour l’essentiel. Certes, OS X Lion est un peu plus gourmand en mémoire, mais quelques réglages plus tard, cela n’y paraîtra plus. Globalement, il s’agit d’un bon système, mais les nouveautés qu’il propose ne justifient pas encore de passer le pas. Mac OS X 10.6.8 Snow Leopard est un système très stable et tant que Auto Save, Versions et les autres fonctionnalités exclusives ne seront pas plus répandues dans le parc application, passer à OS X Lion sera superflu.

18 juillet 2011

PHP – Jongler avec les dates

Lors de mes recherches pour une modification de WordPress, je suis tombé par hasard dans la documentation de PHP sur la fonction date_parse_from_format(). Cette fonction propose de décomposer une date à partir de sa représentation en chaîne de caractères. Cependant, à la différence de strtotime(), il est possible de passer en paramètre le format de la date à décomposer. Il est donc désormais possible de retrouver les éléments constitutifs d’une date (heure incluse) plus facilement qu’auparavant.

Exemple

Avant lorsque l’on souhaitait transposer une date SQL en date “française”, on pouvait procéder comme suit :

$maDateSQL = '2011-07-18';
preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $maDateSQL, $regs);
$maDateFr = sprintf('%d/%d%d', $regs[3], $regs[2], $regs[1]);

Avec date_parse_from_format(), le code est tout de suite plus agréable à lire (de plus, certaines vérifications plus poussées sont effectuées au passage car le code ci-dessus ne vérifie que la présence de chiffres et pas leur cohérence) :

$maDateSQL = '2011-07-18';
$arr = date_parse_from_format('Y-m-d', $maDateSQL);
$maDateFr = sprintf('%d/%d/%d', $arr['day'], $arr['month'], $arr['year']);

Problème

Je disais précédemment qu’il était “désormais possible” d’utiliser cette fonction. A vrai dire, pas tout à fait. date_parse_from_format() n’est disponible qu’à partir de PHP 5.3 !

A vrai dire, lorsque l’on a la maîtrise de son hébergement, il s’agit d’un détail. Mais le passage à PHP 5.3 a des conséquences si l’on migre depuis la version 5.2 et tout le monde n’y est pas encore passé. De plus, lorsque l’on travaille avec un logiciel comme WordPress, massivement utilisé dans le monde, il faut pouvoir s’adapter au plus grand nombre et ne pas se limiter au haut du panier.

Résolution

Du coup, j’ai recodé la fonction directement en PHP et elle rend à peu près les mêmes résultats que la fonction native.

Le code source est disponible sous licence GPL version 2 et téléchargeable ici (requiert PHP 4.0.6 ou version ultérieure, c’est-à-dire à peu près tout le monde).

17 juillet 2011

L’Open source ou la Vie

L’Open source donne un accès libre et illimité au code source d’un programme, avec la possibilité de le modifier, de le compléter et de le diffuser à sa guise. Cette approche diffère bien évidemment des choix propriétaires qui ont prédominé pendant les années 80 avec la domination notoire de Microsoft et de son Windows. La diffusion de logiciels libres a également profité de l’émergence d’internet dans les foyers et qui a permis de partager beaucoup plus vite des informations.

Cependant, contrairement à la pensée actuelle, l’Open source et la notion de code source partagé ont précédé les grandes sociétés de logiciels propriétaires puisque dès les années 1950, IBM fournissait le code source de ses logiciels aux clients qui investissait dans un ordinateur de la marque.

Deux visions s’opposent donc : la vision capitaliste (ou égoïste) ou la vision communautaire (ou altruiste).

La Vision Capitaliste

Les bases de cette approche sont simples : un développeur engage du temps, de l’argent et des ressources pour développer un logiciel. Celui-ci supporte donc l’ensemble des coûts tant financiers qu’humains de la création dudit logiciel et fait donc payer son client pour obtenir le droit d’utiliser son logiciel, avec pour objectif évident de vendre plus que ce que le développement aura coûté.

Dans le meilleur de cas, l’argent ainsi récolté sera réinvesti dans le logiciel lui-même pour lui assurer un avenir et un bon support tout en enrichissant ses propriétaires. Dans le pire des cas, l’avenir et le support seront oubliés.

Rappelons une chose importante à ce sujet. Lorsque vous acheté une boîte d’un logiciel (quel qu’il soit, logiciel bureautique ou même logiciel de jeu vidéo), vous ne devenez pas propriétaire du logiciel mais d’une licence vous autorisant à vous en servir. Le logiciel reste la propriété de son créateur, ou d’une entité physique ou morale qui en aura fait l’acquisition à un moment donné.

La notion de “propriétaire vendeur” induit nécessairement une notion de “client acheteur”. Une obligation de résultat du logiciel est également induite et si un logiciel propriétaire entraîne une perte avérée d’informations dommageable pour son utilisateur, le “client” peut éventuellement se retourner contre le “vendeur” pour réparation.

La Vision Communautaire

A l’opposée de la vision centrique capitaliste se situe la vision excentrique communautaire. La principale différence vient de la position du développeur par rapport au logiciel qu’il a créé. Ici aussi, un développeur décide d’investir du temps et des ressources (et donc de l’argent) pour créer un logiciel. Cependant, ce logiciel n’est pas nécessairement terminé ou débogué lorsqu’il est fourni au public sous une forme libre. En ouvrant son logiciel au monde, le développeur initial peut potentiellement créer une communauté d’autres développeurs si son concept intéresse du monde.

La chose la plus importante dans le monde de l’Open source est similaire au monde propriétaire. Il s’agit de la notion de licence. Un code libre ne veut pas dire qu’il n’y a aucun encadrement. Une des licences les plus connues, la General Public Licence (ou GPL) inclut dans ses clauses une propriété fondamentale pour l’essor du logiciel libre. Toute modification apportée à un code source libre doit être partagée selon les mêmes termes, et donc rendue libre également. Ce qui permet l’avancée de tous.

Mais alors comment gagne-t-on de l’argent dans le monde libre ? Plusieurs possibilités existent à ce niveau-là :

  • Vendre son logiciel libre
    La General Public Licence est une des rares (sinon la seule) licences à autoriser le diffuseur à vendre ou à revendre son code source libre. Mais comme le code source vendu doit être libre et que la licence autorise la rediffusion de façon gratuite, les sources d’accès payantes n’ont qu’un potentiel très limité. Pourquoi payer si l’on peut avoir un accès légal gratuit identique ?
  • Publier son code source selon plusieurs licences
    En tant que créateur ou originel, il est possible de publier son code source selon plusieurs licences différentes, comme par exemple une licence Open source (qui requiert donc que le logiciel qui sera déployé au final soit Open source lui aussi) et une licence commerciale (qui autorise les développeurs du logiciel suivant à ne pas diffuser leurs sources). C’est le cas notamment du framework Qt, actuellement propriété de Nokia, et utilisé notamment par le gestionnaire de bureau libre KDE.
  • Faire payer le support ou des services
    La notion d’Open source ne porte que sur la liberté d’accès au code source. Rien n’interdit le créateur de faire payer des services connexes comme le support technique pour faciliter l’intégration des outils. On retrouve dans ce cas des sociétés comme Canonical (créateurs d’Ubuntu) ou Red Hat.
  • Offrir un service amélioré
    Nous entrons aujourd’hui dans l’ère du “cloud“, autrement dit des services hébergés sur des sites internet plutôt que des applications installées directement sur nos ordinateurs. Différentes sociétés du monde Open source ont décidé d’embrasser ce mouvement en proposant des services gratuits utilisant leur propre logiciel mais avec des portions payantes pour les utilisateurs désirant aller plus loin. Dans ce cas, on ne paye pas le logiciel, mais simplement l’accessibilité à une partie du service hébergé. Un des exemples de réussite les plus récents reste la plate-forme WordPress.com sur laquelle est hébergée ce blog.
  • Les donations directes

Un Logiciel Libre doit-il rester Gratuit pour ses Utilisateurs ?

La question est large, mais la réponse est oui. La gratuité est la meilleure forme d’égalité et permet l’accès à tous aux mêmes services. Cela garantit donc en partie la neutralité que l’on commence à exiger aujourd’hui d’internet.

Cependant, que penser du fait que des sociétés gagnent de l’argent en utilisant des logiciels libres sans reverser quoi que ce soit aux créateurs originaux ? Cela fait partie du jeu du logiciel libre. Diffuser son code source sous cette forme implique que n’importe qui pourra s’en servir sans compensation.

Il existe cependant des moyens de remercier les auteurs de logiciels libres sans pour autant systématiquement parler d’argent. Voici la liste des actions que j’ai personnellement entamées sur différents projets :

  • depuis plusieurs années, je contribue à la traduction française de TortoiseSVN
  • j’ai effectué une donation pour le logiciel CyberDuck
  • j’aide à la résolution de bugs sur différents plugins WordPress

Cet article a été motivé par ma décision récente d’intégrer la communauté WordPress encore plus activement en tentant de corriger des bugs du logiciel principal et en proposant de nouvelles fonctionnalités.

Tous les projets auxquels j’ai contribué sont tous des logiciels que j’utilise intensivement dans mon travail et/ou dans mes loisirs. Après plusieurs années d’utilisation à sens unique, il m’est apparu important de renvoyer la balle et j’engage tous les développeurs et créateurs motivés à en faire de même pour ces projets et bien sûr pour d’autres

2 juillet 2011

Benchmarking PHP – Partie 2

Voici la suite du premier article de cette série sur les performances de PHP.

Je me suis intéressé cette fois-ci à un autre “côté pervers” des langages de scripting tels que PHP, à savoir leur aspect faiblement typé.

En programmation, deux tendances s’opposent : le typage fort (ou typage strict) et le typage faible. Comme son nom le laisse entendre, le typage se rapporte aux types de données utilisés couramment : nombre entiers, nombres réels, chaînes de caractères, etc…

Dans un langage fortement typé, les fonctions ne peuvent être appelées qu’avec les types de données pour lesquels elles ont été conçues. Si une fonction requiert que son premier paramètre soit en entier, vous obtiendrez une erreur de compilation si vous essayez de lui envoyer une chaîne de caractères.

La plupart des langage de scripting sont, quant à eux, faiblement typés, c’est-à-dire, qu’il est possible d’appeler des fonctions avec un autre type de données que celui avec lequel elles ont été conçues. Dans certains cas, comme JavaScript ou PHP avant sa version 5, les paramètres de fonction n’ont même pas de type, uniquement un nom. Cela simplifie la programmation mais complique le débogage dans certains cas, notamment avec les objets. Avec l’arrivée de PHP 5, il est possible d’appliquer un typage fort sur certains paramètres de fonction. La raison principale de ce comportement est que les langages de scripting sont compilés au moment de leur exécution.

Etat des lieux

Dans le cas de PHP, c’est à sa capacité à traiter des chaînes de caractères comme des nombres que j’ai choisi de m’intéresser.

Le code suivant est parfaitement légal en PHP :

$a = 3;
$b = '4';
$c = $a + $b;

Le résultat sera bien 7.

Mais travailler avec des chaînes de caractères comme avec des entiers n’est-il pas plus long que de travailler directement avec des entiers ?
La réponse théorique est évidente, mais dans la pratique, certains éléments font que les choses ne sont pas si simples.

Le protocole de test

Pour ce test, j’ai choisi d’effectuer 1000 fois l’addition de tableaux d’entiers contenant :

  1. 100 000 entiers aléatoires natifs
  2. 100 000 entiers aléatoires sous forme de chaînes de caractères
  3. 100 000 entiers aléatoires sous forme de chaînes de caractères qui seront convertis “manuellement” au moment du traitement

Tous les entiers aléatoires sont compris entre 0 et 100 inclus.

Résultats

Les résultats sont évidents :

Somme de 100 000 entiers natifs (1000 itérations) : 2.017847 s
Somme de 100 000 entiers sous forme de strings (1000 itérations) : 9.314373 s
Somme de 100 000 entiers sous forme de strings convertis en natifs (1000 itérations) : 57.042635 s

Les entiers natifs sont les grands vainqueurs, avec un calcul plus de 4x plus rapide que les entiers sous forme de chaîne de caractères.

J’ai poussé les tests avec des entiers compris entre 0 et 1 000 000. Les résultats montrent que la longueur des chaînes de caractères (plus le nombre est grand, plus la chaîne est longue) influent sur les performances globales. Dans le cas présent, les entiers natifs sont presque 6x plus rapide que les chaînes de caractères.

Somme de 100 000 entiers natifs (1000 itérations) : 2.561392 s
Somme de 100 000 entiers sous forme de strings (1000 itérations) : 12.046772 s
Somme de 100 000 entiers sous forme de strings convertis en natifs (1000 itérations) : 55.341405 s

PHP incite-t-il à l’usage des chaînes de caractères ?

A vrai dire, cela n’est pas le cas. Le typage faible de PHP permet cette utilisation aberrante des chaînes de caractères, mais rien dans son fonctionnement ne force à aller dans ce sens. En revanche, l’utilisation de PHP avec MySQL incite fortement à ce comportement.

Les extensions de PHP qui permettent de communiquer avec MySQL présentent une étrangeté. Toutes les valeurs retournées par MySQL lors d’une requête (exceptée NULL) sont des chaînes de caractères, que le champ original contienne un entier ou bien tout à fait autre chose. Du coup, ce que montre ce test, c’est que nous gagnerions beaucoup à ce que MySQL permette de renvoyer à PHP les types natifs de ses champs, mais aujourd’hui aucune possibilité à ma connaissance n’est proposée dans ce sens (que ce soit du côté de MySQL ou de PHP).

Mais alors pourquoi vouloir utiliser des entiers natifs ?

Il y a quelques cas que j’ai rencontrés personnellement, récemment, où l’utilisation d’entiers natifs a son avantage. Le plus courant est l’encodage JSON, qui permet de faire transiter de manière simplifiée des données.

Considérons les deux alternatives que sont un tableau d’entiers sous forme de chaînes de caractères (A) et le même tableau sous forme d’entiers (B), voilà ce qui ressort en JSON :

A = ["1","2","3","4","5"]
B = [1,2,3,4,5]

Vous pourrez constater deux choses :

  1. les nombres sont entourés de guillemets (“) pour indiquer à JSON qu’il s’agit de chaînes de caractères et donc le résultat encodé en JSON est plus long
  2. lorsque ces informations encodées en JSON vont être décodées de l’autre côté, ce sont des chaînes de caractères qui vont être générées. Si le destinataire est un langage faiblement typé, tout va bien, mais s’il s’agit d’un langage fortement typé comme Java, attention aux dégâts.

Astuce : convertir des chaînes en entiers

Voilà un petit code source très sommaire mais qui résume à lui seul la méthode à employer pour convertir un tableau d’entiers sous forme de chaînes de caractères en tableau d’entiers natifs :

$tableau = array('1', '2', '3');
$tableau_natifs = array_map('intval', $tableau);

Code du test

<?php
    header('Content-type: text/plain; charset=UTF-8');
    set_time_limit(0);

    // Construction du tableau d'entiers natifs
    $intArray = array();
    for ($i = 0; $i < 100000; $i++)
        $intArray[] = mt_rand(0, 1000000);

    // Construction du tableau d'entiers sous forme de strings
    $strArray = array_map('strval', $intArray);

    // Temps de calcul avec le tableau d'entiers natifs
    $debut = microtime(true);
    for ($i = 0; $i < 1000; $i++)
        array_sum($intArray);
    $elapsed = microtime(true) - $debut;
    printf("Somme de 100 000 floats natifs (1000 itérations) : %f s\n\n", $elapsed);

    // Temps de calcul avec le tableau d'entiers sous forme de strings
    $debut = microtime(true);
    for ($i = 0; $i < 1000; $i++)
        array_sum($strArray);
    $elapsed = microtime(true) - $debut;
    printf("Somme de 100 000 floats sous forme de strings (1000 itérations) : %f s\n\n", $elapsed);

    // Temps de calcul avec le tableau d'entiers sous forme de strings avec conversion vers entiers natifs
    $debut = microtime(true);
    for ($i = 0; $i < 1000; $i++)
        array_sum(array_map('intval', $strArray));
    $elapsed = microtime(true) - $debut;
    printf("Somme de 100 000 floats sous forme de strings convertis en natifs (1000 itérations) : %f s\n\n", $elapsed);
?>
12 juin 2011

Benchmarking PHP – Partie 1

Pour ceux qui ne connaîtrait pas encore PHP, je vous laisse découvrir sa définition sur le site officiel.

Comme tous les langages de scripting, PHP est un outil très permissif et configurable à volonté qui facilite grandement le travail des développeurs.
Cependant, la permissivité des outils est parfois source de mauvaises habitudes pour les développeurs et ce qui peut apparaître comme étant une fonctionnalité intéressante pour gagner du temps, s’avère en fait être un problème en terme de performance au final.

Le premier benchmark de cette série porte sur les différentes façons d’accéder à une entrée de tableau associatif sans vérifier son existence au préalable ou, au contraire, en vérifiant son éligibilité selon plusieurs méthodes.

Protocole de test

Pour tester les performances de chacun des cas suivants, nous tentons d’accéder une entrée inexistante ‘id’ du tableau associatif $_GET et vérifions que sa valeur est différente de 0. Pour faire apparaître d’éventuelles différences dans nos tests, ils seront effectués sur un million d’itérations.

Voici, les différents tests qui seront effectués dans ce benchmark :

1. Aucune protection

Dans le premier test, nous n’effectuons aucun test d’existence de l’entrée dans le tableau. Le code se résume donc à :

if ($_GET['id'] != 0)

2. Protection avec array_key_exists() :

Dans le deuxième test, nous vérifions que la clé ‘id’ existe au sein du tableau $_GET grâce à la fonction array_key_exists(). Le code se résume cette fois-ci par :

if (array_key_exists('id', $_GET) && $_GET['id'] != 0)

3. Protection avec isset() :

Dans le troisième test, nous vérifions simplement si $_GET['id'] a été défini avant de tester sa valeur grâce à la fonction isset(). Le code est cette fois-ci :

if (isset($_GET['id']) && $_GET['id'] != 0)

4. Test avec empty() :

Dans le dernier test, nous vérifions uniquement si la variable $_GET['id'] est vide ou non grâce à la fonction empty(). Le code du test est donc :

if (!empty($_GET['id']))

Résultats

Voilà les résultats de l’exécution des tests :

Nombre d'itérations : 1000000

Aucune protection : 0.652613162994 ms
Protection avec array_key_exists() : 0.448069095612 ms
Protection avec isset() : 0.246340990067 ms
Protection avec empty() : 0.248647928238 ms

Nos grands gagnants sont donc isset() et empty().

Comme pouvait le laisser supposer l’introduction de cet article, ne pas protéger ses tests de variable est permis par PHP mais entraîne une réduction de performances. Le surcoût de vouloir accéder à une variable qui n’existe pas est que PHP déclenche une erreur de type E_NOTICE. Le réglage par défaut de PHP induit que cette erreur ne sera pas reportée à l’écran pour l’utilisateur via un message d’erreur, mais le déclenchement de cette erreur est bien réel.

Le cheminement de PHP dans ce cas-là est le suivant (qu’il s’agisse du gestionnaire d’erreur par défaut ou non) :

  1. Utilisation d’une entrée de tableau associatif qui n’existe pas
  2. Déclenchement d’une erreur
  3. Récupération de l’erreur par le gestionnaire d’erreur
  4. Test du niveau de reporting actuel via error_reporting()
  5. Affichage ou non d’un message d’erreur

On constate donc que ce chemin est certes le plus court pour le développeur, mais est relativement long pour PHP.

Certes, l’exécution d’un million d’itérations dure moins d’une seconde, il est donc tout à fait légitime de négliger cet aspect, mais gardons à l’esprit qu’un simple !empty($_GET['id']) est trois fois plus rapide pour PHP, pour une longueur de code similaire et pour le même résultat.

En changeant cette habitude permissive, nous devrions pouvoir améliorer les performances générales de nos codes sources. Même si cela ne constitue qu’un infime gain, sur un environnement concurrentiel à très forte demande, cela peut contribuer à une meilleure qualité de service.

Note : comme le montre le code ci-dessous, les tests originaux ont été effectués sur un tableau vide. Les mêmes tests ont été effectués sur un tableau de 100000 entrées (ne contenant toujours pas l’entrée recherchée) et les valeurs sont similaires.

Code du test

<?php
    header('Content-type: text/plain; charset=UTF-8');
    set_time_limit(0);
    error_reporting(E_ALL ^ E_NOTICE);

    define('ITERATION_COUNT', 1000000);
    printf("Nombre d'itérations : %d\n\n", ITERATION_COUNT);

    $start = microtime(true);
    for ($i = 0; $i < ITERATION_COUNT; $i++) {
        if ($_GET['id'] != 0)
            echo 'ok';
    }
    $elapsed = microtime(true) - $start;
    echo "Aucune protection : {$elapsed} ms\n";

    $start = microtime(true);
    for ($i = 0; $i < ITERATION_COUNT; $i++) {
        if (array_key_exists('id', $_GET) && $_GET['id'] != 0)
            echo 'ok';
    }
    $elapsed = microtime(true) - $start;
    echo "Protection avec array_key_exists() : {$elapsed} ms\n";

    $start = microtime(true);
    for ($i = 0; $i < ITERATION_COUNT; $i++) {
        if (isset($_GET['id']) && $_GET['id'] != 0)
            echo 'ok';
    }
    $elapsed = microtime(true) - $start;
    echo "Protection avec isset() : {$elapsed} ms\n";

    $start = microtime(true);
    for ($i = 0; $i < ITERATION_COUNT; $i++) {
        if (!empty($_GET['id']))
            echo 'ok';
    }
    $elapsed = microtime(true) - $start;
    echo "Protection avec empty() : {$elapsed} ms\n";
?>
18 avril 2011

Skyline

On pourrait résumer Skyline par “un film tout bleu mais sans James Cameron“. Plus clairement, et pour ne pas tourner autour du pot, Skyline est un film qui a autant d’effets de spéciaux de qualité qu’il a peu de scénario recherché. Le pitch est simple : une bande d’extra-terrestres débarquent sur Terre pour éradiquer la race humaine.

Histoire

Terry et Jordan sont deux amis d’enfance qui se retrouvent à Los Angeles pour fêter l’anniversaire de Terry. Après une soirée bien arrosée, tout le monde dort dans le spacieux appartement de Terry au dernier étage d’un immeuble flambant neuf. C’est le moment que choisit une race extra-terrestre belliqueuse pour venir semer le trouble. D’étranges lumières bleues atterrissent dans les rues de la ville et commencent à capturer les humains à proximité en prenant le contrôle de leur esprit. Terry, Jordan et trois autres personnages en réchappent par magie, quasiment seuls au monde après la première attaque. Comment vont-ils s’en sortir ?

A vrai dire, qu’ils s’en sortent ou pas n’a que peu d’intérêt dès les premières minutes du film. On comprend très vite qu’il ne faudra pas compter sur les personnages aussi caricaturaux que faibles pour apporter un réel contenu au film. On finit très rapidement par se lasser des tirades héroïques poussives et des concepts hasardeux comme la thématique de la femme enceinte qui ne parvient pas à accrocher la sympathie du public, le personnage d’Elaine (Scottie Thompson) étant aussi glacial que la lumière bleue des extra-terrestre.

Conclusion

Les frères Strause ne sont pas reconnus pour leur finesse cinématographique avec à leur actif le deuxième volet d’Aliens vs Predator : Requiem. Ils le prouvent une nouvelle fois avec Skyline, film emblématique de la politique marketing hollywoodienne : une campagne de pub tous supports pour occuper le terrain et attirer un maximum de monde dans les salles, des effets spéciaux tape-à-l’œil et un scénario inexistant. Rien à voir avec d’autres titres comme le récent Monsters, qui, sans pour autant défrayer la chronique, apporte son lot d’originalités. A éviter donc !

7 avril 2011

Unstoppable

Imaginez un train de marchandises de 900 mètres, soit à peu près 5 000 tonnes, et 20 000 litres de carburants lancés à 110 km/h sur une voie de transit bordée par de grandes agglomérations, le tout sans mécanicien aux commandes et vous obtiendrez le cocktail détonant d’Unstoppable.

Sorti le 10 novembre 2010, ce film est arrivé récemment sur les services de VOD avec comme acteurs principaux Denzel Washington (Philadelphia), Chris Pine (Star Trek) et Rosario Dawson (Sin City). Après le visionnage, je le classerais volontiers dans la catégorie bonne pioche. Ce long métrage tiré d’une histoire vraie réussit l’audacieux pari de combiner action effrénée et suspens insoutenable sans un seul coup de feu en direction d’un humain (quelques balles sont tout de même tirées par des policiers pour tenter d’arrêter le convoi).

A voir !

27 mars 2011

Lara Croft and the Guardian of Light

En surfant sur le PlaystationStore il y a quelques jours, je suis tombé par hasard sur la démo du dernier titre issu de la longue liste des jeux Tomb Raider, à savoir Lara Croft and the Guardian of Light. Sorti à la fin de l’été 2010, ce jeu était pour ma part passé totalement inaperçu, mais la démo disponible sur le PlaystationNetwork (PSN) m’a permis de rattraper mon retard en la matière.

Héritage

Grand fan des trois premiers Tomb Raider, j’ai voulu tout de suite en savoir plus. Tomb Raider III étant sorti en Novembre 1998, 12 ans séparent donc le dernier Tomb Raider auquel j’avais pu jouer de ce tout nouveau Lara Croft. Autant dire que techniquement, rien n’est plus pareil. J’éviterais donc les comparaisons évidentes. Mais que reste-t-il tout de même dans ce jeu des premiers volets des aventures de Lara ?

Aventures et Enigmes

La version d’évaluation disponible sur le PSN permet de jouer intégralement le premier niveau du jeu. On pourrait croire difficile de se faire une idée du jeu final avec un si court aperçu (environ 20 minutes), mais il n’en est rien. Le niveau est découpé en phase de combats, d’action intense et de réflexion. Dans la mesure où ce nouvel épisode est décliné sur les consoles XBox 360 et PS3, le jeu ne se destine pas uniquement à un public de joueurs confirmés (même si la difficulté semble être relativement haute). Ainsi, les phases de réflexion et d’énigmes propres à tout bon Tomb-Raider-like sont parfois placées dans des mini-donjons facultatifs. Libre donc aux joueurs pressés de ne pas les finir, ce qui les fera passer à côté d’un certain nombre de bonus bien utiles. Cependant, cela permet de proposer un jeu à plusieurs vitesse où le joueur choisit lui-même son rythme sans nuire à la narration.

Tout est une Question de Point de Vue

Ces dernières années n’ont malheureusement pas été marquées par la moindre sortie flamboyante d’un Tomb Raider sans défaut majeur et cela a nuit et continue à nuire considérablement à la licence. Cela a aussi permis à d’autres de s’insérer dans ce créneau laissé vacant. C’est le cas de la très bonne série des Uncharted de Naughty Dog sur PS3 qui a repris avec brio tous les codes établis par son ancêtre et les a amené à un autre niveau en terme de gameplay, tant dans les phases de combat que dans les phases d’exploration. Les derniers épisodes parus de Tomb Raider n’ont pas su relever la barre, c’est probablement là une des raisons qui ont poussé un changement d’angle de vue pour ce nouveau titre. Fini la vue à la troisième personne, Lara Croft and the Guardian of Light se joue en vue de dessus en 3D isométrique. Difficile d’ailleurs de ne pas voir un parallèle graphique avec le futur best-seller annoncé de Blizzard : Diablo 3. Eidos et Square Enix tenteraient-ils de surfer sur cette nouvelle vague avant l’heure ?

Nouveau Look, Nouvelle Identité

Avec le changement de gameplay mentionné ci-dessus, il apparaît évident que ce nouveau titre n’a plus grand chose à voir avec les précédents volets de la sage Tomb Raider et il était temps pour la licence de changer son identité en tirant les leçons de ses concurrents. Une des forces d’Uncharted est le charisme de son personnage principal, Nathan Drake. La plus grande force de Tomb Raider reste encore son héroïne : Lara Croft. Exit donc la dénomination Tomb Raider. Il y a fort à parier que le nom de Lara Croft sera désormais présent sur tous les futurs titres à paraître, comme cela fut le cas pour les films issus des jeux, même si un nouveau Tomb Raider a été annoncé fin 2010 (sans titre officiel pour le moment). Les premières captures de cinématiques laissent d’ailleurs entrevoir une ressemblance frappante avec les ambiances d’Uncharted 2 : Among Thieves.

Le Jeu

Pour en revenir précisément à ce Lara Croft and the Guardian of Light, le premier niveau laisse donc entrevoir des perspectives très intéressantes avec un rythme de jeu très soutenu. Mais ce qui a également attiré mon attention, c’est la présence d’un mode coopératif comme le montre la vidéo ci-dessous. Encore une fois, à la façon d’un Diablo, vous pourrez jouer avec un de vos amis chez vous ou via le PSN pour terminer le jeu ensemble. C’est constitue une raison de plus à l’utilisation de la 3D isométrique et donne une dimension sociale au jeu particulièrement attrayante.

La presse et les joueurs semblent avoir très bien accueilli ce nouveau volet de la vie de Lara Croft grâce à un gameplay original pour la série et une difficulté à la hauteur des attentes. Gageons qu’il y aura prochainement une suite.

Suivre

Get every new post delivered to your Inbox.