Blog // Exirel.me

Tu ne routeras point comme un cochon

Par Florian Strzelecki - 19:57 - 11.04.2012

Tags : Framework, Web, Documentation, Bonne pratique, PHP, loldev, Technique

Ces derniers jours, j'ai un problème avec les URLs. Plus spécifiquement, avec certaines URLs, qui sont gérées par certains mécanismes de "routage d'url" (et de réécriture d'url).

Il y a les bons routages et les mauvais routages.

Les bons routages d'URLs considèrent un format type (à base d'expressions régulières par exemple), et permettent d'associer une URL concrète à ce format, et d'en tirer une représentation à usage interne pour l'application. Les mauvais routages d'URLs considèrent un format type (à base d'expressions régulières par exemple), et permettent d'associer une URL concrète à ce format, et d'en tirer une représentation à usage interne pour l'application. Sauf que c'est un mauvais routages d'URL.

Trêve de blagues (et faisons plutôt la paix) (...) (ok j'arrête) voici le vrai problème que j'ai en ce moment : lorsque / et /home/default produisent exactement le même résultat, c'est à dire, pointent finalement sur la même "ressource". Autant c'est bien gentil de vouloir de jolies urls, et d'avoir des mécanismes simples pour gérer automatiquement un tas de cas, mais ce n'est quand même pas très RESTFull au final (je hais la duplication de contenu).

Car il s'agit bien d'un problème de "comment", et pas de "quoi" : réécrire des URLs à usage interne, et adapter le routage en conséquence, c'est tout à fait normal - ce n'est pas sale. Mais autant le faire bien, s'il vous plait. Ce problème n'est malheureusement que rarement traité, même si lors de mes recherches, j'ai été agréable surpris par les documentations de Symfony 2 et CakePHP.

Faisons un petit tour d'horizon de ce que nous proposent certains frameworks "à la mode" du monde PHP, puisque c'est majoritairement chez eux que j'ai rencontré ce problème, que chaque développeur devrait connaître et savoir gérer. Je veux dire, en commençant par reconnaître le problème quand ils l'ont devant leurs yeux.

Zend Framework

Allez, on commence avec du lourd, du sale qui tache : ce bon vieux Zend Framework. Après toutes ces années, je ne sais pas pourquoi je dis encore "ce bon", parce que je le trouve tout sauf bon, et même si ce n'est pas le sujet, encore une fois, ce framework montre des faiblesses de conception.

Dans sa documentation concernant le système de routage d'URL, vous pouvez tomber sur Zend Framework: Default Routes, section qui vous explique ceci :

Zend_Controller_Router_Rewrite comes preconfigured with a default route, which will match URIs in the shape of controller/action.

Ah, donc non seulement c'est le routeur par défaut, mais en plus il a pile le comportement qu'on ne veut pas avoir. Heureusement qu'à la fin de cette section il est ajouté qu'on peut supprimer cette route par défaut... bien que, par expérience, les résultats sont plutôt hasardeux (du genre vraiment, et pénible avec ça).

Cela dit, ce n'est pas encore terminé, sur la partie Dispatcher vous pouvez lire ceci :

If any of the module, controller, or action are not found, it will use default values for them.

Et pour revenir sur mes expériences : oui, ça peut devenir un problème, puisque le mécanisme qui utilise les routes d'URLs a déjà sa façon de voir les choses, et ce n'est pas toujours à votre avantage. Rien que d'y penser... non, je n'ai pas envie d'y penser.

CakePHP : presque !

Je ne connais pas bien CakePHP, et de ce que j'en ai lu, ce n'est pas trop mal - mais bon, mon avis ne vaut pas grand chose, testez plutôt vous-même. Que nous dit la documentation de CakePHP : Default Routing ?

You can access an action directly via the URL by putting its name in the request.

Brrr... ok, la même chose que pour Zend-Framework (mais avec une documentation plus sympa cela dit), ce qui n'est pas vraiment une bonne chose. D'autant que la suite n'est pas mieux, puisqu'on retrouve même des conseils sur comment faire de mauvaises choses automatiquement :

The keys of the array should be named after the route elements in the URL, or the default elements: :controller, :action, and :plugin. The values in the array are the default values for those keys.

Erm... je reviens, je vais boire une litre ou deux de ice-tea, pour me calmer. Ah moins que... CakePHP : Disabling the default routes : en voilà deux paragraphes intéressants !

Dommage qu'ils ne prennent pas beaucoup de place, mais ils ont le mérite d'être là. Je retiens plus particulièrement ceci, qu'il faudrait peut-être mettre en gras, en gros, avec des néons et des balises <blink></blink> tout autour (non, je déconne, les néons c'est en trop) :

If you have fully customized all your routes, and want to avoid any possible duplicate content penalties from search engines [...]

Bon, d'accord, la raison mise en avant, c'est pour faire plaisir aux moteurs de recherches : en attendant, c'est déjà une mise en garde sur les dangers d'un routage un peu trop permissif et automatique. Un bon point, au moins (et puis la doc a vraiment une jolie tête).

Symfony : le 1, et puis le 2 ensuite

J'ai connu une version de la branche 1.x de Symfony, et si le framework ne m'a pas marqué plus que ça, je me souviens très bien de son système de routes, qui est relativement facile à configurer (notez que je ne parle jamais de performance ici). Cette fois je peux nuancer plus facilement mon discours.

Tout d'abord, il est parfaitement possible de se passer d'une route par défaut avec Symfony 1.x, et je le conseille même vivement. Le soucis, c'est que la documentation section 9 ne précise pas forcément très bien cet aspect là. Je reprends cet exemple de code fourni :

# generic rules
# please, remove them by adding more specific rules
default_index:
  url:   /:module
  param: { action: index }
default:
   url:   /:module/:action/*

Alors, oui, il y a un commentaire, mais c'est à peu près la seule remarque sur le sujet, et j'ai vu bien des développeurs l'ignorer complètement, l'oubliant, et reléguant cette ligne au fin fond des poubelles de l'histoire de leur framework favori.

D'ailleurs, un exemple de code un peu plus loin ne reprend déjà plus le commentaire, c'est dire... bref, là encore, Symfony rejoint la liste des frameworks qui permettent des choses bien crades, et qui en plus ne documentent pas bien la chose. Pas cool.

Symfony 2.x : de bonnes inspirations ?

N'ayant pas travaillé avec Symfony 2, j'ai du faire un peu plus de recherches, et j'ai été agréablement surpris par une documentation bien plus claire, et plus encore, par le système de routage.

Ce derniers ne propose pas (de manière documentée explicitement en tout cas), un mécanisme "générique" pour des urls qui peuvent correspondre automatiquement à une représentation interne (du genre :controller/:action comme dans la version 1.x). En cherchant un peu, j'ai trouvé que c'était tout à fait possible de mal faire les choses quand même, mais cela me semble moins grave, du fait d'une information qui n'est pas mise en avant du tout (là encore, contrairement à la version précédente).

Bref, bon point pour Symfony 2.x, qui propose un mécanisme de routage d'URLs relativement intelligent. Le point bonus : il propose même un système d’annotations, comme les décorateurs en Python, pour gérer ses URLs... un peu à la manière de Pyramid (un framework web minimaliste en python).

TL;DR: Tu ne routeras point comme un cochon

Vous l'aurez compris aux travers de ces exemples, je ne critique pas le principe de routage d'URLs en lui-même, mais seulement son implémentation, sa documentation, et les conseils fournis aux développeurs. Il y a dans la conception de ces outils une mauvaise compréhension des contraintes posées par les URLs et les bonnes pratiques. Les solutions apportées, bien que facile d'utilisation (et encore...), ne me semblent pas bien répondre aux problématiques posées, ou alors, seulement en partie, alors que toutes les parties sont importantes.

Je compare ces problèmes de conceptions à d'autres implémentations : celles de Django et de Pyramid, deux frameworks web en python. Ni l'un, ni l'autre, ne permettent simplement d'instaurer un tel mécanisme, mais proposent à la place une grande souplesse et une grande réutilisabilité.

Comme quoi, c'est un problème de conception, pas de fonctionnalité.

Sinon, une dernière blague pour la route ? Essayons de ne pas nous fâcher en si bon chemin !

Faire des trucs

Par Florian Strzelecki - 20:27 - 10.04.2012

Tags : Web, Ma vie, Lecture, Citation, doing things

Aujourd'hui, j'ai envie de partager une certaine coïncidence entre mes réflexions personnelles, un lien ou deux, et quelques discussions avec des amis. Cette concomitance (au sens large de faits, incluant les idées, les réflexions, et les faits en eux-même) est tout à fait bienheureuse et positive, et je ne peux m'empêcher de la partager avec vous. Au passage, c'est un bout de réflexions et de "trucs", et je prétends n'avoir qu'un avis personnel, peut-être naïf, peut-être faux, incorrect, ou tout simplement ridicule. Non, je n'ai pas peur, j'ai seulement envie d'écrire un peu.

doing things

Cela commence - enfin non, je commence plutôt - par une affiche où se lisait ceci :

We have a 'strategic' plan. It's called doing things.

A quote from Herb Kelleher.

Je n'ai pas la moindre idée - dans mon ignorance - de la véracité de cette citation, ni de son exactitude, ni de son origine, n'ayant rien trouvé sur le sujet ou sur la personne de Herb Kelleher (mais je n'ai pas beaucoup cherché, je vous en laisse tout le soin).

Mais, il se trouve que cette phrase me plait, ce concept de simplement "faire des choses" et de se laisser guider par nos réalisations a quelque chose de particulièrement séduisant pour moi. Non, je ne sais pas bien dire pourquoi, là, comme ça.

getting things done

Et puis, il y a cette expression anglaise tout à fait charmante : "getting things done". Je dis "charmante", mais ce n'est pas toujours le cas : dans la bouche de certaines personnes avec qui je ne souhaite plus avoir à faire, c'est une façon stupide et écœurante d'instaurer une pression malhonnête sur une équipe de travail - j'ai d'ailleurs eu quelques soucis avec cette expression dans ce cadre là, ce qui m'amena souvent à la considérer avec circonspection.

Or donc aujourd'hui je la trouve "charmante", comme "il y a quelque chose à en retenir de bon". En quelque sorte, c'est un "rappel" constant des objectifs : il faut savoir "faire les choses". Non seulement les commencer, les continuer, mais aussi les finir : les "faire", dans leur ensemble, et pas seulement sur quelques points.

"prier pour une avancée"

Beaucoup plus récent, je lisais cet article par @LeReilly "1268 - Envy" qui faisait, d'une certaine façon, écho à mes réflexions personnelles du moment.

Il dit ceci :

Tu ne peux à la fois dépenser de l’énergie pour t'élever et en dépenser pour descendre les autres.

Et aussi ceci :

Parce que dans tous les domaines qui soient, je ne fais que prier pour une avancée. Tout autre schéma de pensée, de l’immobilisme jusqu’à la rétrogradation, me foutent la trouille.

Ce qu'il y a d'amusant, c'est qu'aujourd'hui même je discutais avec un ami et ancien collègue (comme quoi, je me fais des amis dans le monde du travail, pour de vrai) à propos de nos projets, des choses qui avancent, de ces choses dans le monde du travail qui nous dégoutent et nous déplaisent... et j'ai trouvé qu'il y avait un lien entre notre discussion et l'idée de cet article.

Je le livre donc à votre réflexion, puisqu'il alimente la mienne.

Et moi donc ?

Bref, j'en arrive à la fin de ce petit billet, de cette note entre l'humeur, la réflexion, et le partage. Je retire de toutes mes expériences, de mes rencontres, cette même impression : mon temps est précieux, mon énergie aussi, il faut que je les dépense bien ou correctement - même si j'ai du mal à définir ce qui est "bien" et/ou "correct" (ce qui donne lieux à de passionnante discussion entre moi-même, volant parfois mes heures de repos durement acquises la journée).

Je réfléchis sur le sujet, parfois digressant, parfois oubliant, parfois animé d'une passion dévorante que mes amis connaissent bien (mes amis venant souvent de mes passions, le contraire serait pour le moins surprenant).

Mais il me faut aussi agir quand je le peux, quand j'estime cela nécessaire, ou simplement, quand "je le dois". Dernier sujet en date : écrire des tutoriels autour de l'utilisation du framework python Django. C'est un sujet comme un autre dans la longue liste des choses à faire.

Ladite longue liste ayant, au passage, déjà maigrie plusieurs fois sous la coupe franche de mes conclusions : "aujourd'hui, je fais un truc, je le termine, et ce sera bien".

Sur ce, je vous laisse à vos propres réflexions et idées, et si vous avez quelque chose à partager sur le sujet, mon @ mail est toujours disponible. À vos idées.

UnicodeEncodeError : fichiers, formulaires, django et gunicorn

Par Florian Strzelecki - 17:17 - 09.03.2012

Tags : Django, Python, Programmation, Développement, Charset, Problème, Technique

L'erreur bête et très frustrante du jour vient d'un petit formulaire qui permet de téléverser un fichier quelconque sur le serveur. Vous me direz, c'est la base du formulaire web avec des fichiers, et il ne devrait pas y avoir de soucis particuliers... sauf lorsque lesdits fichiers ont des accents dans le nom de fichier, et qu'une erreur aussi frustrante que difficile à analyser débarque avec ses gros sabots.

Alors, premier réflexe : chercher sur le net, entre Stack Overflow et le tracker de bug de django. Vous pourrez tomber sur ce genre de discussions : UnicodeEncodeError: 'ascii' codec can't encode character.

Cela donne déjà un premier aperçu d'où vient le problème, à savoir, une configuration de locale sur l'environnement serveur. Pour vous en dire plus, voici les symptômes auxquels j'ai été moi-même confrontés :

La première "solution" qui est proposée, c'est que l'environnement serveur soit correctement configuré, avec, entre autre, une modification du fichier /etc/apache2/envvars. Personnellement, j'ai essayé, mais cela ne fonctionne pas.

Bref, que faire dans ces cas là ?

Comprendre et analyser le problème

Je ne suis pas un expert, mais voici ma démarche pour comprendre puis résoudre ce problème.

Tout d'abords, j'ai regardé la locale de la machine à l'aide de la commande locale, et j'ai obtenu ceci :

LANG=fr_FR.UTF-8
LANGUAGE=
LC_CTYPE="fr_FR.UTF-8"
LC_NUMERIC="fr_FR.UTF-8"
LC_TIME="fr_FR.UTF-8"
LC_COLLATE="fr_FR.UTF-8"
LC_MONETARY="fr_FR.UTF-8"
LC_MESSAGES="fr_FR.UTF-8"
LC_PAPER="fr_FR.UTF-8"
LC_NAME="fr_FR.UTF-8"
LC_ADDRESS="fr_FR.UTF-8"
LC_TELEPHONE="fr_FR.UTF-8"
LC_MEASUREMENT="fr_FR.UTF-8"
LC_IDENTIFICATION="fr_FR.UTF-8"
LC_ALL=

Ensuite, j'ai lancé l'interpréteur python, pour en savoir plus :

>>> import locale
>>> locale.getlocale()
(None, None)
>>> locale.getdefaultlocale()
('fr_FR', 'UTF-8')

Bon, je remercie ici mYk et linova sur IRC de m'avoir fait chercher dans ces directions, et de m'avoir proposé ensuite de vérifier la valeur de ces informations là dans le contexte de mon application django. J'ai donc affiché ces valeurs dans un template et voici les valeurs que j'ai obtenues avec le serveur de dev de django :

loc: (None, None)
loc_def: ('fr_FR', 'UTF-8')

Puis la même chose, mais avec gunicorn :

loc: (None, None)
loc_def: (None, None)

À partir de là, j'ai pu enfin comprendre le problème, et comment le résoudre. Merci à linova pour l'idée sur IRC.

Merci encore une fois au chan #djangocong sur freenode !

Résoudre le problème

J'utilise runnit pour gérer mes différentes applications servies par gunicorn, et j'ai donc des petits scripts (comme pour init.d), dans lesquels j'ai ajouté ceci :

export LC_ALL=fr_FR.UTF8

Et c'est tout. Oui, tout à fait, c'était juste ça : la locale n'était pas définie dans ce contexte très particulier, et pas dans un autre, ce qui explique tout mon problème avec ces foutus fichiers. J'ai redémarré les différentes applications, et je n'ai plus constaté de problèmes.

Alors, si vous aussi vous avez ce problème, je vous conseille de suivre la même démarche que moi : vérifiez vos locales, vérifiez vos locales via l'interpréteur python d'une part, puis dans le contexte de votre application plus spécifiquement.

Enfin, allez voir du côté du script de votre serveur, et voyez s'il n'y a pas quelque chose à faire avec.

Python-epub : un projet sous licence libre pour le format epub

Par Florian Strzelecki - 18:05 - 08.03.2012

Tags : Python, Programmation, Format ouvert, Développement, Livre numérique, epub, Technique

Ce n'est pas sans une certain appréhension que je publie ce billet, où je souhaite vous parler de mon travail actuel : la bibliothèque python-epub, placée sous licence libre (LGPL), et disponible officiellement sur pypi.

De l'appréhension, car je n'ai pas la prétention d'être un maître dans l'art du code python d'une part, pas plus qu'être le plus grand expert du format epub d'autre part. Et puis, surtout, c'est la première fois que je publie vraiment du code sous licence libre !

Mais, passons mes états d'âme pour aller au cœur du sujet.

Téléchargement et installation

Tout d'abords, si vous cherchez directement comment l'installer, et avoir une documentation technique, vous pouvez aller sur le site officiel du projet : http://epub.exirel.me. Il est à jour et documente la dernière version publiée (et pas la version en cours de développement).

Pour faire simple : utilisez pip install epub. Si vous voulez la version de développement (je ne garantis pas la stabilité dudit code), vous pouvez faire un clone des sources disponibles en ligne : https://bitbucket.org/exirel/epub.

À quoi ça sert ?

En premier lieu, à ouvrir des fichiers au format epub, dans la version 2 de la spécification (la 3 restant encore trop jeune et trop peu utilisée pour le moment). Qu'est-ce que le format epub ? Il s'agit d'un format ouvert de livre numérique. Il est utilisé de manière majoritaire dans l'édition numérique, et peut être lu par des applications sur mobiles et tablettes, et surtout, sur des liseuses à écran à encre numérique (de type Kobo ou Cybook Odyssey). Je n'entre pas ici dans la polémique autour des autres formats, ce n'est pas le sujet (mais vous pouvez toujours me poser des questions par email, ou via twitter et g+).

Le format Epub 2

Le principe d'un fichier epub, c'est d'avoir un fichier compressé au format Zip, qui contient plusieurs fichiers importants :

Les autres fichiers composent le "vrai" contenu du fichier epub et sont référencés de plusieurs façons, tant par le fichier OPF qui en fait une liste exhaustive, que par le fichier de navigation NCX qui propose une navigation pour l'utilisateur (comme une table des matières, des illustrations, etc.).

Le code python

De son côté, la bibliothèque python-epub permet de représenter les données d'un fichier epub : fichier OPF, fichier NCX, et le contenu du fichier. Elle est même découpée en trois parties :

Ce découpage logique permet une grande souplesse dans l'utilisation de cette bibliothèque. De prime abord, elle ne permet (pas encore) de générer un fichier epub, mais certains éléments sont déjà manipulables en dehors d'un fichier epub pur : c'est le cas pour le format OPF et le format NCX, dont les modules dédiés permettent d'une part de lire ces formats, mais aussi de générer des fichiers dans ces formats.

Le projet

Licence libre : LGPL

Le projet est placé sous la licence libre LGPL : elle correspond à ma volonté, en tant qu'auteur, de rendre libre le fruit de mon travail pour les utilisateurs. Si d'autres développeurs souhaitent utiliser mon travail (avec ou sans modification) ils n'auront pour seule obligation que de donner les mêmes droits sur cette partie là de leur travail (par exemple, dans le cas d'une application, seule ma bibliothèque devra être sous une licence libre compatible, pas l'ensemble de l'application).

Je pense d'ailleurs que c'est la seule chose pour laquelle je n'envisage pas de changement, contrairement au code en lui-même.

Les évolutions à apporter et celles envisagées

Pour le reste – le code concret, mais aussi la documentation – j'envisage beaucoup d'évolutions, et certaines dont je ne suis pas encore sûr de la façon de les implémenter. Tout d'abords, pouvoir créer et modifier des fichiers epub : il est plutôt simple de lire un fichier epub, mais l'écriture pose beaucoup d'autres questions.

En vrac, j'ai listé les améliorations/évolutions suivantes :

Il y a encore beaucoup à faire pour que je sois pleinement fier de ce projet, mais j'avance correctement, je fais attention à la qualité du code, aux tests unitaires, et à la documentation. Je pense donc que ça va dans le bon sens.

Appel à contribution

Pour le moment, je suis le seul développeur sur ce projet, que j'ai initié en début d'année, mais si j'ai choisi une licence libre, c'est bien pour laisser la place à d'autres personnes.

Ce que je cherche ? Les bonnes volontés : contributions au code, des retours d'expérience, des demandes d'ajouts de fonctionnalités, des rapports de bugs, pourquoi pas des traductions de la documentation ?

Comme je le disais en début de billet : je ne suis pas un maître pythoniste, et au vu de mon expérience, je ne doute pas un instant qu'il me reste beaucoup à apprendre. Je prends donc toutes les remarques et critiques constructives, les avis, les optimisations, les conseils... tout !

Migration vers Django 1.3

Par Florian Strzelecki - 19:41 - 07.03.2012

Tags : Django, Python, Web, Programmation, Développement, Optimisation, Technique

Sur ma liste des choses à faire, il y avait cette migration concrète de mon site&blog vers Django 1.3. Il faut savoir que j'ai développé à l'origine avec la version 1.1, en ajoutant à l'occasion quelques petites choses de Django 1.2 lorsque j'ai mis à jour mon serveur.

Aujourd'hui, mes dernières applications sont développées avec Django 1.3, et il y a quelques petites choses en plus que j'apprécie bien. Je vous propose donc un retour d'expérience, avec un tour d'horizon de ce que j'ai modifié et eu à modifier.

Nommer les urls

Je n'avais pas touché à mon fichier urls.py depuis longtemps, et j'ai donc commencé par là : remettre certains trucs à plat, et rendre le tout plus propre et plus facile à maintenir.

Premier truc : utiliser la fonction url, qui permet entre autre chose de nommer ses urls, ce qui est très pratiques pour la suite, comme, par exemple, ne pas s'embêter à écrire des urls en dur dans les templates.

Exemple de template (avec Django 1.3) :

{% load url from future %}
<p>Lire l'article : <a href="{% url 'entry' entry.url %}">{{entry.title}}</a></p>

Vous noterez l'usage de {% load url from future %}, car le template-tag url a un comportement modifié pour les futures version de Django.

Du côté de la view, cela permet aussi de se simplifier la vie :

def redirect_to_tag(request, section_url):
    """Section now redirect to tag."""
    return redirect('tag', permanent=True, tag_url=section_url)

J'ai simplement nommé l'une de mes urls "tag", et la fonction redirect s'occupe du reste. Si je change la forme des url des tags, je n'aurai pas à changer le code de cette view.

Séparer media et static

Apparu avec Django 1.3, la gestion des fichiers "statiques" a été grandement amélioré par l'intégration de django-staticfiles directement dans le projet Django en tant que django.contrib.staticfiles.

J'ai pu découvrir son fonctionnement avec mon dernier projet (un truc secret pour le moment...), et c'est vraiment très pratique. Le principe ? Au lieu d'avoir un répertoire de médias, intégrant les fichiers de l'application (css, js, etc.) et les fichiers téléversés par les utilisateurs, il y a maintenant deux espaces différents.

Je ne vais pas détailler ici tout ce que j'ai eu à faire mais voici un rapide résumé :

Ensuite, pour lancer la collecte, la commande suivante fonctionne très bien :

python manage.py collectstatic

Au passage, j'ai aussi simplifié un peu ma configuration Apache, mais ça, c'est un autre sujet.

Et d'autres petites choses...

S'il n'y avait que ça, ce serait trop facile. Et bien, en réalité : il n'y avait que ça.

J'avais déjà fait une première passe pour simplifier grandement le code, faire le ménage, et retirer ce qui n'était pas bien fait et/ou bien pensé (avec un code qui a presque deux ans, c'est normal, j'ai beaucoup appris pendant ce temps). Du coup, une migration assez simple, avec, au déploiement, pas un seul soucis.

J'ajoute, au passage, que c'est une bonne expérience, qui permet de revenir sur ce qui a été fait avant, et sur ce que je fais aujourd'hui - et donc, de pouvoir mesurer l'écart.

Envie de changement sur le blog

Par Florian Strzelecki - 17:03 - 22.02.2012

Tags : Ma vie, Divers

Depuis que je tiens ce blog, j'ai écrit un tas de trucs, et c'est un peu devenu le bordel - si vous me permettez l'expression.

Pour commencer, je pense virer les commentaires. Pourquoi ? C'est une réflexion un peu plus globale à propos de la publication en ligne, sur le contenu qui doit primer sur le contenant, et sur cet aspect "social" des blogs qui peut s'exprimer différemment.

Finalement, les commentaires, ce n'est pas vraiment l'échange que je cherche à avoir avec les autres : il vaut mieux un échange de mail, ou de tweet, de statut sur G+ ou bien mieux encore une réponse via un billet de blog. Bref, sans doute une question de contrôle de l'espace de diffusion - et des responsabilités des auteurs.

La forme aussi, le "design" de ce blog ne me convient qu'à moitié. Finalement, il reprend les codes classiques de ce que l'on attend d'un blog... mais ça ne m'intéresse pas (plus ?) non plus. Finalement, l'idée d'une suite de document me plait beaucoup plus que toutes les fioritures.

Cela implique une suppression des catégories, au profit de tags associés, avec un changement de flux RSS, et des remaniements d'urls (des choses très simple, pas de soucis).

Il faut aussi que je travaille sur une certaine façon d'aborder le contenu. Rien de forcément très original au passage : mon but, c'est aussi de faire un truc bien qui marche.

Enfin, cela implique une disparition du menu en haut, il me faut trouver une autre forme. Je vais aussi chercher d'autres typographies qui correspondent mieux à ce que j'attends.

Alors, côté technique, même si ça ne parle pas à grand monde, je vais regarder du côté de reStructuredText et Mercurial pour la publication. On verra bien ce que ça va donner.

Bref. Attendez vous à des changements futurs.

GGJ 2012 : Aux quatre coin coin

Par Florian Strzelecki - 12:27 - 01.02.2012

Tags : J'aime, Jeux vidéo, Ma vie, Jeu, Global Game Jam, GGJ12, Ludique

Le WE dernier avait lieu la Global Game Jam 2012, un peu partout dans le monde, et notamment à Rennes. Plus précisément, cette édition a été représentée à Rennes aux Jardins Modernes par l'association 3hitcombo (tout cela fait un bon paquet de liens...).

C'est un truc un peu fou dans l'idée : réunir un tas de gens autour de la création de jeux (vidéos entre autre, mais pas que) en 48h. Commencée le vendredi à 15h, terminée le dimanche à 15h, j'ai pu participer à cette édition 2012, dans un groupe de joyeux compagnons - et à l'origine, de parfaits inconnus.

C'est un défi complètement fou, un concept déjà développé dans différentes manifestations, et je m'étais toujours dit que ce serait une expérience intéressante. Oh, pas forcément très productive, ou très réussie (pour moi), mais je peux désormais balayer ce "léger" manque de confiance en moi face à l'inconnu : heh, en fait, je suis même plutôt bon dans de telles conditions.

Je pense que je ne suis pas le seul à avoir cette impression, tant le principe de "dépassement de soi" m'a semblé être l'expérience principale de ces deux jours.

Aujourd'hui, je suis très fier d'avoir participé à cet événement, et tout aussi fier du travail accompli par l'ensemble de l'équipe. Mention spéciale au travail des 3 graphistes, dont la dessinatrice qui a réalisé un sublime plateau de jeu, à la main, et en couleur !

Je ne vais pas vous faire un compte-rendu détaillé, je n'ai pas une assez bonne mémoire pour ce genre de chose trois jours après ! Mais revenons un peu sur ce WE de créativité.

GGJ 2012 - Aux quatre coin coin (prototype)

Image : GGJ 2012 - Aux quatre coin coin (prototype) - Florian Strzelecki - Creative Common By-NC-SA

Mon premier coworking à la Cantine de Rennes

Par Florian Strzelecki - 00:29 - 09.12.2011

Tags : Premier, J'aime, Ma vie, Rennes, Geek

Le mois dernier (en Novembre donc), j'ai changé un peu mon orientation pour quitter le salariat et me diriger vers l'indépendance. Pour l'instant, cela se traduit par beaucoup de temps sur des projets personnels (Tapcaz en PHP, et JdrPost.it en Python/Django), et un statut d'auto-entrepreneur - statut que j'escompte bien faire évoluer vers autre chose, que ce soit une entreprise ou un statut d'indépendant, ou... on verra bien.

Cela va faire un an que je connais la Cantine Numérique Rennaise, que je la fréquente de temps en temps, au gré entre autre des Ateliers 46 animés par @nookeff, de conférences sur Wikipedia, de Twunch rennais, et j'ai même contribué à organiser l'événement annuel python - la Pycon France 2011 - à la Cantine.

Mais aujourd'hui, j'ai franchi un nouveau cap dans ma relation avec ce lieu très particulier : j'ai passé ma première journée de coworking.

Diantre. Qu'est-ce que cet anglicisme ? Heh, le "travail coopératif", c'est un principe très simple, qui repose sur le fait que ça fait du bien de sortir de chez soi pour travailler, et que pouvoir rencontrer des gens différents ne peut qu'être bénéfique.

Et c'est le cas. En une journée, j'ai organisé mon travail différemment (plus de lecture et moins de dispersion), mais surtout, j'ai pu discuter un peu au hasard avec d'autres personnes : sur le livre numérique notamment (sujet qui me passionne beaucoup en ce moment), mais aussi sur des livres, sur de la photo, et sur des initiatives communautaires (ça me fait penser au groupe python Rennes).

Bref, j'ai pris beaucoup de plaisir à être là dans cet espace ouvert, avec mon PC portable et mes pensées, à côté d'autres gens faisant à peu près la même chose que moi : pas juste leur travail, mais aussi des échanges.

Je crois que je vais revenir. D'ailleurs, j'ai pris un abonnement. Hé hé hé.

DjangoCong 2012 à Montpellier, en face de la mer !

Par Florian Strzelecki - 17:14 - 29.11.2011

Tags : Django, Python, Framework, Web, J'aime, Djangocong, Technique

J'étais à la DjangoCong 2011, c'était à Marseille, et c'était super. Et ça tombe bien, parce que pour l'édition 2012, j'assiste les organisateurs dans cet évènement, qui a été pris en main par une équipe locale... à Montpellier !

Plus exactement à Carnon-Montpellier, devant une immense étendue de sable chaud et la mer Méditerranée.

Quand ? Le 14 et 15 Avril 2012. Prévoyez vos billets de train !

Où ? À Carnon-Montpellier, dans le Sud de la France. Il y a une gare TGV et tout le confort sur place (la mer, et on l'espère tous du Soleil).

Le lieu ? Dans la journée, ce sera à la Maison Familiale EAGA, et le soir au Gédéon. Oui, ça vend du rêve en barre (j'ai hâte).

Les inscriptions ne sont pas encore ouvertes : elles le seront lorsque l'appel à conférences sera clôturé, c'est à dire aux environs du 13 - 15 Janvier 2012. Donc, si tu as quelque chose à proposer, il est temps de le faire !

La mer devant Carnon-Montpellier

Image : La mer devant Carnon-Montpellier - DjangoCong - DR

Multi-Db avec Zend

Par Florian Strzelecki - 20:20 - 07.10.2011

Tags : loldev, Framework, Web, Zend Framework, Technique, Documentation, Programmation, SQL, PHP

Depuis que je travaille avec le Zend Framework (et ce n'est définitivement pas par passion ni envie), je ne passe pas une semaine sans avoir besoin d'aller voir dans le code source du framework pour comprendre ce qu'il fait, pourquoi, comment, et en quel honneur.

Et généralement, je me marre - enfin pas vraiment, mais faites comme si.

Cette semaine pour le #loldev du vendredi, c'est la documentation qui m'a donné l'info qui me manquait pour résoudre un problème qui n'est pas trivial à l'origine, mais qui devrait l'être avec un framework web digne de ce nom : comment gérer une application qui doit se connecter à différentes bases de données ?

En voilà une question intéressante... voici ma réponse.

Pages and pages of source code.

Image : Pages and pages of source code. - Neil Crosby (http://www.flickr.com/photos/thevoicewithin/) - Creative-Common By-NC-SA

Dédoublonner un tableau de tableau en php

Par Florian Strzelecki - 16:01 - 30.09.2011

Tags : Documentation, Programmation, PHP, Optimisation, loldev, Technique

Halala... le array_unique est définitivement une fonction trompeuse de php. Pourquoi ? Parce que son mode de dédoublonnage par défaut est SORT_STRING, et pas SORT_REGULAR. D'ailleurs, c'est d'autant plus un problème que ce fut le cas en PHP 5.2.9, puis retour arrière en PHP 5.2.10.

Note : documentation php de array_unique.

Le #loldev du vendredi nous vient donc de cette petite fonction. En voici l'exemple :

$res = array(
        array('id' => 2),
        array('id' => 3907),
        array('id' => 7814),
        array('id' => 2),
    );
$unique = array_unique($res);
var_dump($unique);

// Résultat :
// array(0 => array('id' => 2));

Ce qui est un problème, puisque le but, c'est seulement de virer la deuxième ligne, comme il a été fait dans l'exemple suivant :

$id = array();
foreach ($res as $idRes) {
    $id[] = $idRes['id'];
}
$id = array_values(array_unique($id));

Donc, oui, cela fonctionne et on obtient bien un tableau dédoublonné par la valeur de la clé 'id' de chaque tableau. Heureusement, il y a mieux aujourd'hui.

Ce code provient d'une application pré-5.2.9, où le flag "SORT..." n'existait tout simplement pas. Ce n'est donc pas la faute du pauvre développeur qui a dû trouver à l'époque une solution qui fonctionne ! Je n'aurais pas aimer être à sa place.

Car aujourd'hui, il suffit d'écrire ceci :

$res = array_unique($res, SORT_REGULAR);

Pour dédoublonner le tableau. Simple, efficace. Mais il aura fallu attendre PHP 5.2.9 pour pouvoir le faire !

Remarque : suite à des remarques, voici le pourquoi du comment SORT_STRING pose problème :

Par défaut array_unique transforme en string le contenu de chaque élément du tableau, donc (string) array(...) ça donne "Array". Donc il trouve que le tableau de tableau, c'est un array de 'Array', 'Array', 'Array', ... qui sont donc des éléments identiques, et ne retourne que le premier élément.

Logique, imparable, mais particulièrement pénible.

Ugly code

Par Florian Strzelecki - 01:56 - 28.09.2011

Tags : Framework, Programmation, Bonne pratique, Chaton, Optimisation, Problème, loldev, Technique

Il est parfois difficile de dire d'un code qu'il est bon ou mauvais, qu'il est moche ou élégant. Parfois, les deux se confondent dans un doute profond sur la nature d'une idée, et sur son implémentation.

Beautiful is better than ugly.

Heureusement, parfois, il y a du code php/java/python/javascript/ruby/perl/autre bien sale et c'est très facile à repérer.

Notez l'effort pour ne pas troller toujours sur le même langage.

Retour sur la Pycon Fr 2011

Par Florian Strzelecki - 18:02 - 24.09.2011

Tags : Django, Python, J'aime, Ma vie, Informatique, Rennes, Pycon, Technique

C'était à Rennes, c'était les 17 et 18 Septembre dernier, et j'y étais en tant qu'organisateur local (en gros, cela veut dire aider l'équipe des organisateurs avec mes connaissances du terrain, et les avantages de la proximité).

Dans l'ensemble, ça s'est très bien passé : du monde, des gens contents, de belles rencontres, quelques soucis techniques avec un câble HDMI et une prise capricieuse, des centaines de croissants, des litres de cocas, de cafés et de jus d'orange.

Mais ce n'était pas juste un WE pour moi, puisque j'ai pu participer à son organisation depuis quelques mois déjà. Petit retour d'expérience sur cette édition 2011 de la Pycon Fr.

Awesome Fontstacks : oh la belle typo !

Par Florian Strzelecki - 21:49 - 23.08.2011

Tags : Web, Programmation, Typographie, Technique

Comment souvent je surf sur le grand Internet qu'il est plein de belles images, et je traîne mon curseur du côté du dossier "design & typo" de mon lecteur de flux rss. Tiens, un site qui propose... des ensembles de polices de caractères pour son site web ? Intéressant...

Il s'agit du site Awesome Fontstacks, et j'ai décidé de tester tout un tas de ensembles divers et variés... et c'est vrai que les résultats finaux sont plutôt très réussis !

Le concept : vous choisissez une police de caractères pour le titre, le sous-titre, le corps de texte, le texte à mettre en exergue, et pour le code source ; mais pas n'importe comment, car le site vous aide dans cette démarche.

En correspondance avec la première police choisie, il vous propose un ensemble de polices "qui se marient bien avec la première police choisie", et ainsi de suite pour chaque partie. Le résultat final est donc un ensemble de polices cohérent, et il faut le dire, qui sont plutôt élégantes.

Il ne reste alors plus qu'à récupérer les fichiers des polices qui vous intéresse, puis à faire un tour sur Font Squirrel pour générer les fichiers de polices pour le web, avec, en prime, le code CSS "font-face" qui va bien !

Le service est pratique, agréable, et le résultat est une réussite. Je regrette néanmoins qu'en fonction de vos choix, vous risquez de vous retrouver avec les mêmes ensembles pour le corps de texte / le code source. Pourtant, il y a déjà pas mal de choix : à tester !

Du coup, j'en ai profité pour ajouter la police "Incosolata" pour l'affichage des blocs "pre" de ce blog... et c'est vrai que c'est plus sympa comme ça.

Svn Id dans un template

Par Florian Strzelecki - 13:11 - 19.08.2011

Tags : Web, Documentation, Programmation, Bonne pratique, Technique

Parfois j'y pense (et parfois j'oublie) : utiliser la propriété svn "svn:keywords" sur les fichiers, en utilisant tout particulièrement Id, et de temps en temps Author et Date (mais cela dépend du projet et des conventions de l'équipe).

Pour ceux qui ne connaissent pas, il s'agit d'une propriété que l'on peut mettre sur un fichier versionné avec svn (et pas un répertoire), de cette façon là :

svn propset svn:keywords "Id" fichier

Ensuite, dans le fichier, n'importe où (de préférence en entête du fichier, dans les commentaires), il suffit d'écrire ceci :

$Id$

Au commit du fichier, ceci sera remplacé par quelque chose comme :

$Id: Fichier 7814 2011-08-19 07:49:47Z Exirel $

En général, je pense à le mettre sur des fichiers de code, mais pratiquement jamais sur mes templates. Pourtant, c'est tout aussi pratique, surtout lorsque le template a plus d'importance que la façon de récupérer les données (ce qui est parfois une opération tout à fait triviale).

Du coup, au début de tous mes fichiers de template avec php, je mets ceci :

<?php /* @version $Id$ */ ?>

Avec smarty, je mets ceci :

{* @version $Id$ *}

Et avec django, je mets ceci :

{% comment %}
(...)
  - Version : $Id$
(...)
{% endcomment %}

Parfois, je me demande encore comment je peux oublier ça. Peut-être parce que je devrais l'automatiser, et plus le faire à la main ? Je dois être trop nostalgique de la ligne de commande...