Catégorie : Développement web

  • Flysys­tem – accès aux systèmes de fichier au PHP

    Petite décou­verte récente et sympa : Flysys­tem. Une biblio­thèque de code PHP qui présente une abstrac­tion assez simple et sympa autour des systèmes de fichier locaux, S3, drop­box, FTP, …

  • Docu­men­ta­tion PHP

    Quelques (nombreux) écrans de présen­ta­tion de Willian Durand à propos de PHP

    Je ne sais pas à qui est destiné cette docu­men­ta­tion, mais c’est un boulot énorme et très bien fait de collecte, analyse et présen­ta­tion des bonnes pratiques. Vous devriez passer dessus et prendre du temps à lire même si vous travaillez déjà avec PHP au jour le jour.

    Pour m’être frotté à ce genre d’exer­cice, j’ai rare­ment vu un résul­tat aussi bon.

    Il y a une version pour la suite qui parle plus parti­cu­liè­re­ment de Symfony, mais moins essen­tielle à mon avis.

  • Lien vers du Javas­cript

    Problé­ma­tique du jour : Inter­cep­ter l’ap­pel à des liens via Javas­cript.

    Mon cas d’usage : J’ai des conte­nus (images, vidéos, audio, polices de carac­tères) stockés côté client (indexedDB, webSQL ou DOMS­to­rage) que je souhaite insé­rer dans mes pages.

    (billet mis à jour au fur et à mesure des réponses)

    Quelques solu­tions :

    Data:URI

    Je récu­père ma donnée, je la trans­forme en base64, et je remplace le lien stan­dard par un lien en data:uri.

    Deux défauts : Je stocke N fois la donnée dans le DOM où N est le nombre d’ap­pa­ri­tion de l’image ou de la ressource dans mes pages HTML/CSS. Pour ne rien gâcher, on stocke en base64 donc avec 30% de poids en plus. De plus, même si je n’ai pas de test à montrer, on s’est déjà pris les pieds dans le tapis à cause de très mauvaises perfor­mances de pages avec beau­coup de data:uri, spécia­le­ment sur Fire­fox (proba­ble­ment sur les polices de carac­tères)

    Blob + crea­teObjectURL

    Je récu­père ma donnée, je créé un Blob à partir de cette donnée, je passe par URL.crea­teObjectURL pour créer une URL dédiée et j’uti­lise cette dernière quand je réfé­rence ma ressource.

    On résout les problèmes du data:uri mais on se coupe de IE 9, IE mobile et iOS 5. Pas gravis­sime mais j’au­rai préféré éviter.

    Par contre la solu­tion ne fonc­tion­nera de toutes façons pas pour les images ou polices de carac­tères réfé­ren­cées depuis les CSS (sauf à construire les CSS via Javas­cript mais là on entre dans des usines à gaz).

    Cas spéci­fique des vidéo et audio

    Les deux solu­tions me posent de toutes façons un sérieux problème pour les vidéo et les audio, qui peuvent être de gros volume. Je me vois mal sortir d’in­dexedDB des dizaines de méga­oc­tets (au mieux) pour construire un blob juste et avoir une URL dans ma balise HTML sans même savoir si l’uti­li­sa­teur tentera effec­ti­ve­ment de lire la vidéo ou le fichier audio.

    Pour les vidéos et les audio (mais unique­ment ces deux types de contenu) je peux réflé­chir à mettre un lien vers une vidéo de taille quasi nulle et le chan­ger dès que la vidéo est acti­vée. J’ai toute­fois un peu peur des effets de bords. Il va falloir aussi bosser en amont pour que la première image s’af­fiche bien dans le lecteur vidéo malgré l’ab­sence de la vidéo complète.

    Bidouille

    Pour l’ins­tant ma solu­tion serait :

    • Pour les images et polices de carac­tères dans les CSS : data:uri. En espé­rant que la CSS ne contient pas trop de ressources inutiles ou trop de liens vers la même ressource.
      • Au pire : Géné­rer la CSS en Javas­cript avec des liens obte­nus par crea­teObjectUrl, l’in­sé­rer dans le DOM manuel­le­ment
    • Pour les images dans le code HTML : crea­teObjectURL si possible.
      • Véri­fier tout de même si le data:uri n’est pas plus simple. La diffé­rence entre les deux sera assez faible si les images ne sont pas répé­tées plusieurs fois.
    • Pour les audio et vidéo : Désac­ti­ver le preload, rensei­gner le lien via crea­teObjectURL qu’au lance­ment de la vidéo. Pour les vidéo, penser à créer une image d’at­tente avec l’at­tri­but poster.

    Ça reste fran­che­ment du brico­lage je trouve, et ça va néces­si­ter plein de javas­cript pour géné­rer tout ça.

    Dans mon monde idéal

    Dans l’idéal j’au­rai bien aimé avoir une sorte de faux serveur web en javas­cript depuis le navi­ga­teur. Genre toute url en « local-js://xxxxx » fait appel à un objet Javas­cript qui répond ensuite ce qu’il veut.

    À défaut, un URL.createObjectURL( 'text/html', function() { return bindata; } ) serait bien pratique : Le navi­ga­teur n’ap­pe­lant la fonc­tion pour récu­pé­rer le contenu que quand il cherche à accé­der au dit contenu, au lieu de lui donner tout le contenu par avance au cas où il en aurait besoin.

    Quelqu’un a des pistes pour moi ?

  • Please stop preten­ding PHP is a good language

    The first step to fixing a problem is admit­ting that there is one.

    Bon, des critiques de PHP ce n’est pas ce qui manque mais pour une raison incon­nue je m’étais dit que ça partait bien quand j’ai lu la première ligne. Sauf qu’au final

    • It’s not ok that you can’t relia­bly get the first element of an array using less than 4 lines of code without causing side effects.*[1]
    • It’s not ok that the output of echo 5/3 might depend on the coun­try you live in if you don’t know the fine details of confi­gu­ring PHP.
    • It’s not ok that you won’t be able can’t call array_map” or just “$itera­tor->reduce” on an itera­tor in 2014.
    • It’s not ok to ignore the simple fact that most of the PHP world currently relies on parsing func­tion and class comments for it’s code to func­tion because people can’t get their shit toge­ther on mailing lists.
    • It’s not ok to run around shou­ting “type hinting for lite­rals would mean that passing an int to float hint would fatal PHP” and calling that an reaso­nable argu­ment while people just write $x = (float)$x; in the cases where it actually does matter anyways.
    • It’s not ok to be not able to talk to 2 back end data sources in paral­lel, using “promises” or whate­ver, in a language that has “pull stuff out of data­base and put it into the inter­net” as a proclai­med core compe­tency.
    • It’s not ok that echo 0.000001; produces 1.0E-6 and that casting it to string doesn’t help but putting quotes around it does.
    • It’s not ok that you have to clear the error buffer by gene­ra­ting a suppres­sed unde­fi­ned variable error just to be able to sanely use token_get_all().

    Au final la moitié des items ressemblent juste à « ça ne fait pas ce que j’es­père ». Alors pour ceux qui m’ont fait suivre le lien :

    Pour le premier item il existe plusieurs solu­tions, dont un simple array_values($tab)[0]. Bref, rien d’ex­cep­tion­nel pour aller itérer sur un diction­naire.

    Pour le second, si on demande expli­ci­te­ment au niveau du système à affi­cher les résul­tats suivant les conven­tions d’un pays spéci­fique, PHP s’y conforme. C’est le cas de la plupart des langages, y compris la ligne de commande de base. Diffi­cile d’avan­cer que c’est un problème, d’au­tant qu’il est bien évidem­ment possible d’igno­rer la confi­gu­ra­tion du système pour forcer une locale au niveau du langage.

    Quant à savoir comment affi­cher 0.000001 ou 1E-6, comme le langage n’a aucun moyen de savoir comment a été tapé la valeur initiale dans le code source (rien de spéci­fique à PHP, à ma connais­sance aucun ne le fait), il faut bien qu’il choi­sisse une forme arbi­trai­re­ment à la sortie. Si l’au­teur veut forcer autre chose, il a tous les outils pour ça.

    Pour le dernier item j’ai la flemme de véri­fier les cas limites mais à priori c’est juste que l’au­teur n’a pas eu le courage d’al­ler créer un gestion­naire d’er­reur pour gérer ses erreurs.

    Bref, tout ça c’est bien joli mais à première vue une bonne partie n’est qu’un problème de déve­lop­peur frus­tré, pas un problème de langage.

    Ce qui me frustre moi c’est que des problèmes de langages il y en a plein, et que pous­ser des faux problèmes décré­di­bi­lise ceux qui essayent de corri­ger les problèmes réels.

  • Bomber­man massi­ve­ment multijoueur

    Un bomber­man-like massi­ve­ment multijoueur ? Je ne suis pas convaincu par l’in­té­rêt ludique. Ne pas jouer avec ses amis, ne pas tisser de liens, avoir une inter­ac­tion limi­tée à quelques minutes et faite au hasard, j’ai peur que ça ne remplisse pas de promesses sur le long terme.

    Tech­nique­ment par contre c’est inté­res­sant, pas forcé­ment si complexe que ça, mais sacré­ment inté­res­sant. Le jeu dans le navi­ga­teur n’est qu’à ses débuts.

  • Je veux chan­ger ça, et ça, et ça

    Je pense que je ne suis pas le seul à imagi­ner régu­liè­re­ment comment créer un nouveau langage ou modi­fier les exis­tants à ma conve­nance. Sans aller jusque là, en croi­sant ce qui se fait dans les diffé­rents langages, on trouve toujours des point inté­res­sants qu’on aime­rait voir copiés.

    Voilà donc quelques unes de mes frus­tra­tions, parce que les expri­mer permet de s’en débar­ras­ser un peu et de se concen­trer sur l’im­por­tant : ce qu’on fait avec le langage.

    Persis­tance du code en PHP

    Chaque requête web recharge entiè­re­ment l’ap­pli­ca­tif PHP. APC apporte une béquille indis­pen­sable mais ça reste au niveau de la béquille. Toute l’ini­tia­li­sa­tion est à refaire à chaque fois. Ça fonc­tionne, mais j’ai­me­rai vrai­ment un mode de PHP ou un frame­work web PHP qui permette de commen­cer direc­te­ment au trai­te­ment des requêtes sans avoir à tout refaire de zéro.

    Acces­seurs en PHP

    Toujours côté PHP j’at­tends depuis bien long­temps l’ap­pa­ri­tion d’ac­ces­seurs trans­pa­rents pour les attri­buts des objets. Ruby, Python et Javas­cript ont chacun leur façon de faire. Là il ne s’agit pas de repiquer une syntaxe au langage voisin mais bien de combler un manque.
    Sérieu­se­ment, je n’en peux plus de ces getX() et setX(). C’est encore plus pénible à l’uti­li­sa­tion qu’à la créa­tion.

    Espaces de noms

    Fut un temps je râlais beau­coup contre PHP mais ce dernier une bonne partie du retard qu’il avait. Mieux : Arrivé en dernier il s’est permis de parfois faire les choses plus intel­li­gem­ment.

    Dites, pourquoi n’ai-je pas d’es­paces de nom en Javas­cript ?

    Les « use » de PHP me manquent aussi en Ruby. Ils présentent une solu­tion élégante et pour donner des noms courts en local à des classes qui viennent d’autres espaces de noms, mais ils permettent aussi les alias pour chan­ger faci­le­ment une implé­men­ta­tion par une autre sans impac­ter le code.

    Pendant qu’on y est, pourquoi pas d’auto-char­ge­ment en Ruby ? Si je charge X::Y::Z, j’ai­me­rai bien que le langage se charge tout seul d’al­ler cher­cher le fichier X/Y/Z.rb. Ça fonc­tionne dans quasi­ment tous les autres langages mais Ruby conti­nue de faire du spaghetti d’in­clu­sion manuelle de fichiers.

    Blocs et ferme­tures lexi­cales

    Les blocs sont *la* fonc­tion­na­lité qui me fait utili­ser Ruby. On peut certes faire beau­coup de choses simi­laires avec des fonc­tions anonymes en Javas­cript ou en PHP mais c’est juste moins élégant (et ça compte beau­coup pour se sentir à l’aise).

    Par contre, sérieu­se­ment, la récep­tion des para­mètres dans les blocs est vrai­ment peu lisible. Le choix de la barre verti­cale comme déli­mi­teur est juste illi­sible.

    Le pire arrive avec les ferme­tures lexi­cales. Ruby laisse bien trop faci­le­ment utili­ser par erreur une variable venant de la portée parente. La syntaxe pour forcer une variable comme locale ajoute encore plus au côté non lisible. |x, y=3; z| ? sérieu­se­ment ?

    À côté de ça PHP et Python proposent des variables en lecture seule, ce qui limite la casse. PHP impose même de décla­rer expli­ci­te­ment les variables à impor­ter de la portée parente au lieu de décla­rer les variables locales. Diffi­cile à imagi­ner en monde Ruby mais assez confor­table au final.

    Et vous ? qu’est-ce que vous chan­ge­riez en premier ?

  • La lame de fond nodejs

    En ce moment côté star­tup et inno­va­teurs, les déve­lop­peurs javas­cript ont le vent en poupe. Pour autant, je ne crois pas que Javas­cript côté serveur soit le rouleau compres­seur qu’on veut nous faire croire.

    La syntaxe du langage est honnête, mais a large­ment autant de points néga­tifs que de points posi­tifs par rapport à l’exis­tant ailleurs.

    Si je résume, on me dit que Javas­cript a

    • Une grosse base de déve­lop­peurs à cause de son utili­sa­tion dans les pages web
    • Un runtime exis­tant sur quasi­ment toutes les machines
    • La possi­bi­lité d’avoir un seul langage côté client et côté serveur
    • Un système de proto­type
    • Un système d’event loop, api asyn­chrones et call­backs sur nodejs

    La base d’uti­li­sa­teur est un facteur très impor­tant, mais sur ceux ci une frange très mineure peut se récla­mer d’avoir une bonne connais­sance de Javas­cript. Le niveau moyen est même presque pire que sur PHP. Si on se contente de ceux qui font plus de quelques lignes et qui pour­raient passer côté serveur, la base utili­sa­teur n’est plus si fantas­tique que cela. PHP ou Java en ont proba­ble­ment autant si ce n’est plus.

    On trouve de quoi exécu­ter Javas­cript même sous Windows, mais au final on va instal­ler une machine virtuelle dédiée. Encore une fois, si on parle de côté serveur, Linux et autres BSD sont une bien meilleure cible et là Python ou Ruby sont par défaut, PHP est déployable faci­le­ment, Java est presque partout. Je n’ai jamais entendu dire que l’un des trois premiers souf­frait d’un frein à cause de la néces­sité d’ins­tal­la­tion sur telle ou telle machine.

    La possi­bi­lité d’avoir un seul langage n’est pas à négli­ger, mais au final coder du Javas­cript pour une page web dans le navi­ga­teur n’est pas comme coder du Javas­cript pour nodejs : Les API, les perfor­mances, les besoins, tout ça est diffé­rent. Même sans ça, les partages de code entre client et serveurs reste­ront anec­do­tique, Java en a fait l’ex­pé­rience il y a long­temps. Reste la syntaxe qui est la même, et évite un nouvel appren­tis­sage, mais c’est assez faible. L’ex­per­tise dans un langage est prin­ci­pa­le­ment liée à l’API et à ses impli­ca­tions, la syntaxe de base s’ap­prend rapi­de­ment.

    Le système de proto­type est effec­ti­ve­ment une des spéci­fi­ci­tés de Javas­cript par rapport aux langages courants. Ceci dit c’est un point incom­pris par quasi­ment tous les déve­lop­peurs au point que tous essayent de recréer arti­fi­ciel­le­ment un système de classe au dessus du système de proto­type. Le résul­tat est d’ailleurs un peu bancal. En théo­rie le système de proto­type ça peut être génial. Dans la réalité, sauf pour une petite mino­rité, c’est un gros point noir. Diffi­cile de consi­dé­rer ça comme un avan­tage.

    Il reste un point, parti­cu­lier : Tout l’en­vi­ron­ne­ment Javas­cript côté serveur s’est construit autour d’un système asyn­chrone bourré de call­back. S’il est facile d’y faire de la program­ma­tion spaghetti, c’est aussi une grande force et la plus grande spéci­fi­cité du langage.

    Avoir un système d’évent loop avec des accès asyn­chrones c’est réali­sable sur les autres langages, mais ça prend du temps. Il faut refaire tout un jeu de biblio­thèques. Les quelques essais actuels sont limi­tés, complexes à mettre en oeuvre, et surtout n’ont pas eu le coup de projec­teur qui a lancé nodejs.

    Et c’est un peu ça l’idée : Rien n’em­pêche Ruby, Python ou Java de créer une biblio­thèque équi­va­lente à nodejs. S’il y a une vraie valeur ajou­tée, alors ça se fera. À ce moment là, à part le coup de projec­teur, Javas­cript n’aura plus de quoi prétendre être en avance. Ça restera un bon langage, avec une excel­lente machine virtuelle, qui méri­tera proba­ble­ment d’être côté serveur, mais pas plus que les autres. Je ne vois pas ce qui justi­fiera la lame de fond que certains imaginent.

  • Acces­seurs

    Je déteste avoir à program­mer ou utili­ser des acces­seurs. Voilà, c’est dit.

    Sérieu­se­ment, qui a eu l’idée de faire des méthodes getX() et setX() ? Dans le meilleur des cas c’est pénible a écrire et diffi­cile à lire.

    Qu’on ne me parle pas d’en­cap­su­la­tion, ces méthodes arti­fi­cielles sont tout sauf un besoin d’en­cap­su­la­tion. C’est même exac­te­ment le contraire de l’en­cap­su­la­tion : C’est parce que je n’ai pas à savoir si un attri­but est en accès direct ou non que je n’ai pas à utili­ser d’ac­ces­seurs.

    Il n’est pas besoin d’im­pac­ter la manière dont on appelle les attri­buts d’un objet pour diffé­ren­cier l’in­ter­face publique et les données internes. De nombreux langages on trouvé une manière élégante de gérer les acces­seurs au niveau du langage au lieu de faire faire des pirouettes à l’uti­li­sa­teur. Un des gros avan­tages c’est qu’on ne commence à défi­nir des méthodes d’ac­ces­seur que quand on en a vrai­ment l’uti­lité, pas « partout, au cas où pour plus tard ».

    Donc, quand il s’agit de migrer un attri­but autre­fois en accès direct, en Javas­cript :

    A = { 
      get b() { return this._b; },
      set b(val) { return this._b = val;} 
    };
    // ou 
    
    A.__defineGetter__("b", function() { return this._b; };
    A.__defineSetter__("b", function(val) { return this._b = val; };

    en Ruby :

    class A
      def b
        @b
      end
      def b=(val)
        @b = val
      end
    end

    en Python :

    class X(object):
      def getb(self):
        return self._b
      def setb(self, val):
        self._b = val
      b = property(getb, setb)
    
    # ou mieux :
    
    class X(object):
      @property
      def b(self):
        return self._b
      @b.setter
      def b(self, val):
        self._b = val

    Sérieu­se­ment, c’est moins de complexité pour démar­rer du code (pas besoin de déve­lop­per des acces­seurs passe-plat au cas où on en aurait besoin plus tard, on peut s’en occu­per unique­ment quand le besoin arrive), et c’est plus de clarté pour tout ce qui utilise notre code (et là le gain est immense même si ça semble juste quelques carac­tères). Je n’ima­gine pas de m’en passer dans les langages où ça existe.

    Si vous utili­sez des getter et setter passes-plat, c’est soit votre code qui est mauvais, soit votre langage qui est bridé (soit que vous utili­sez consciem­ment un langage bas niveau). Dans les deux premiers cas il y a quelque chose à repen­ser.

    Bien entendu PHP reste à la traine, sous prétexte de simpli­cité (allez comprendre).

  • Évolu­tion de PHP – acces­seurs

    Il y a matière à se réjouir : Le déve­lop­pe­ment et l’évo­lu­tion du langage PHP a repris. Nous avons eu les fonc­tions anonymes, les espaces de nom, et quelques nouveau­tés bien­ve­nues, souvent atten­dues de trèèèèès longue date.

    Bref, ça bouge, bien. Nous avons  cepen­dant encore deux courants très oppo­sés au niveau du langage : L’un qui souhaite le garder simple et « comme il est », avec souvent un histo­rique quick’n dirty, et qui au final freine quasi­ment toutes les évolu­tions. L’autre qui souhaite le voir profon­dé­ment changé, et reprendre les bonnes idées des autres langages, au risque de trop vouloir copier ces autres langages.

    Si je devais cari­ca­tu­rer je dirai qu’une majo­rité des déve­lop­peurs de PHP (surtout les histo­riques) sont ceux qui freinent, et qu’une majo­rité des utili­sa­teurs actifs de PHP sont ceux qui poussent. Si ça bouge depuis PHP 5.3, c’est que l’ex­cès du « on ne touche rien » a provoqué un trop grand ras-le-bol, et les déve­lop­peurs de PHP ont été forcés de mettre de l’eau dans leur vin.

    Malheu­reu­se­ment les deux courants existent toujours et rien n’a été tran­ché. On le voit très bien sur la RFC concer­nant les acces­seurs : Une bonne partie des « contre » sont ceux que je quali­fie de « déve­lop­peurs histo­riques du langage », et une partie des « pour » sont ceux que je quali­fie de « utili­sa­teurs actifs dans le langage ».

    Il est plus que temps de déci­der où l’on va, sinon nous allons conti­nuer à avoir un Fran­ken­stein.

  • Paliers de respon­sive design

    Et si nous dépas­sions les posi­tions de prin­cipe ?

    Pour faire une mise en page web « respon­sive », des gens biens me décon­seillent de me servir des tailles des diffé­rents appa­reils pour imagi­ner les paliers sur lesquels modi­fier l’agen­ce­ment. L’idée est de travailler sur le contenu et d’ima­gi­ner ce qui est le plus perti­nent pour le contenu, indé­pen­dam­ment des appa­reils sur le marché, qui vont de toutes façons évoluer.

    Oui, ok, en théo­rie. Main­te­nant il est temps de travailler la pratique.

    Je peux faire une opti­mi­sa­tion ou un nouvel agen­ce­ment à chaque fois que l’es­pace dispo­nible me permet d’ap­por­ter un peu de valeur ajou­tée. Je fini­rai avec une multi­tude de paliers diffé­rents. Certains me deman­de­ront du temps, peut être beau­coup, alors qu’ils ne repré­sentent quasi­ment aucun visi­teur. Autant dire que j’au­rai perdu du temps.

    À l’in­verse, je peux prévoir unique­ment quelques paliers prin­ci­paux et lais­ser les marges ou tailles s’adap­ter parce que mon contenu le permet. Ce sera correct et lisible partout mais peut être que tel ou tel type d’ap­pa­reil repré­sente beau­coup de visi­teurs et qu’un palier ou qu’une opti­mi­sa­tion supplé­men­taire aurait apporté un retour sur inves­tis­se­ment signi­fi­ca­tif.

    Au final je vais devoir faire des choix de palier non seule­ment en fonc­tion de mon contenu, de l’er­go­no­mie visée et du temps dispo­nible, mais aussi en fonc­tion des visi­teurs et de leur maté­riel. C’est une clas­sique ques­tion de retour sur inves­tis­se­ment, de ratio entre la valeur ajou­tée et l’in­ves­tis­se­ment néces­saire : Je veux que ce soit correct partout, mais je veux concen­ter mes efforts supplé­men­taires là où c’est le plus utile et visible.

    Même sans toucher au nombre de paliers, l’er­go­no­mie et les conte­nus ne dictent pas toujours un palier très précis. Je peux fina­le­ment viser un peu plus tôt ou un peu plus tard sans que ça ne change grand chose, j’ap­por­te­rai juste une solu­tion légè­re­ment diffé­rente. Tel ou tel appa­reil risque de se retrou­ver proche d’un palier et avoir connais­sance de cette proxi­mité me permet un quick-win au niveau de la valeur ajou­tée qu’il serait dommage de rater.

    Bien évidem­ment c’est une réflexion qui dépend en partie des appa­reils, de la répar­ti­tion des utili­sa­teurs et des prévi­sions tels que nous en dispo­sons aujourd’­hui. Cela peut chan­ger, et cela chan­gera. Si je prends correc­te­ment en compte le design et l’er­go­no­mie alors le rendu restera correct. Peut être pas autant opti­misé qu’au départ, mais pas moins bon que si je ne prends pas du tout en compte les appa­reils et utili­sa­teurs au départ.