Blog // Exirel.me

Retrouvez tous les articles liés au tag Programmation via le flux rss dédié à ce tag.

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.

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.

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...

(bool) $flag

Par Florian Strzelecki - 13:00 - 08.08.2011

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

Je suis toujours autant amusé par ce que je peux trouver dans le code-source du Zend Framework. Oh, rien de grave, cela fonctionne très bien de cette façon là :

public function setNoRender($flag = true)
{
    $this->_noRender = ($flag) ? true : false;
    return $this;
}

Il s'agit d'une méthode de la classe Zend_Controller_Action_Helper_ViewRenderer, qui effectue un traitement fort simple et basique, mais d'une façon que je trouve "inutile".

Je veux dire... si j'analyse ce bout de code d'un coup d'oeil, je peux voir qu'un cast implicite en booléen est effectué, pour ensuite... affecter cette même valeur (mais écrit "explicitement"). En gros, ce bout de code est strictement équivalent au suivant :

$this->_noRender = (bool) $flag;

Pourquoi faire plus compliqué ? Pourquoi s'embêter à écrire explicitement "true" et "false" ?

Oui, c'est du pinaillage. Mais j'aime bien pinailler sur ce genre de choses.

Algorithme en if mineur

Par Florian Strzelecki - 11:47 - 18.07.2011

Tags : Programmation, Bonne pratique, PHP, loldev, Technique

Un petit truc auquel je viens de penser, en regardant du code trouvé sur Internet dans l'une de mes recherches :

$ok = $database->query($sql);

if ($ok !== false) {
    $ok = $this->doSomething();
}
if ($ok) {
    $ok = $this->doItAgain();
}
return $ok;

Ce petit bout de code, nous allons (je vais) l'optimiser. Comment ? En réduisant les instructions inutiles, et en le rendant un brin plus "lisible" - en tout cas, moi, les if à la chaîne, ça me file des boutons.

if (false !== $database->query($sql)) {
    return $this->doSomething() && $this->doItAgain();
} else {
    // Ne faudrait-il pas lever une exception ?
    // Ou au moins traiter l'erreur ?
}
return false;

Le principe est simple : lorsqu'une expression booléenne est forcément fausse ou vrai, elle n'est pas évaluée jusqu'au bout. Dans notre cas, si $this->doSomething() retourne false, alors $this->doItAgain() ne sera jamais évalué.

Simple, efficace. J'aurais pu éviter le premier if d'ailleurs, mais je me dis que traiter l'erreur c'est un peu mieux que simplement retourner false et laisser le reste s'en charger.

Moins de code, plus de fonctionnalité

Par Florian Strzelecki - 21:17 - 10.06.2011

Tags : Framework, Programmation, Bonne pratique, Optimisation, Technique

En ce moment, je répète souvent à mes collègues (et à d'autres personnes) la maxime suivante :

Moins de code, plus de fonctionnalité.

C'est devenu mon leitmotiv en ces jours sombres où je dois travailler avec des gens qui n'ont pas encore acquis toutes les compétences nécessaires sur le projet. Et vu mon niveau d'exigence, autant dire que c'est vaguement difficile à gérer pour moi (mais je me soigne).

Pour paraphraser cette pensée, je dirais qu'il ne sert à rien d'écrire beaucoup de lignes de code pour apporter de nombreuses fonctionnalités.

L'important, notamment et surtout dans le cas d'utilisation de framework, c'est de proposer un code simple, facile à étendre, et qui s'intègre bien à son environnement. C'est ma façon à moi de rappeler les principes KISS et DRY : Keep It Simple & Stupid, Don't Repeat Yourself.

Je parle du cas où l'utilisation d'un framework est obligatoire (parce qu'il s'impose de lui-même ou parce qu'il a été arbitrairement imposé), car c'est exactement dans ces moments là qu'il faut rester vigilant.

Dans le cas d'un framework, écrire "moins de code" ne veut pas dire littéralement écrire moins de code, mais plutôt "intégrer parfaitement le moindre code dans le contexte du framework".

Si le framework impose d'écrire une classe, ou plusieurs, pour écrire un "plugin", alors il vaut mieux le faire, plutôt que d'écrire quelque part codé en dur dans le code, la modification voulue.

C'est peut-être paradoxal, mais cela fonctionne mieux. C'est peut-être frustrant, mais cela évite bien d'autres frustrations.

Croyez-moi, il vaut mieux que tout fonctionne toujours parfaitement avec le framework, que tout fonctionne maintenant comme vous le voulez contre le framework.

Parce que le framework lui, il a déjà écrit beaucoup, beaucoup, beaucoup de lignes de code.

data.decode('UTF8')

Par Florian Strzelecki - 18:00 - 19.05.2011

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

Gérer du texte est parfois (souvent) un véritable casse-tête quand des problèmes d'encodage de caractères pointent le bout de leur nez. Alors, pour avoir perdu bien trop de temps, je m'écris un article "marque-page" pour me rappeler que, bordel, voilà comment récupérer les données d'un fichier en UTF-8, les traiter avec Markdown, puis écrire le tout dans un fichier.

import markdown

f = open('fichier.txt', 'r')
data = f.read()
f.close()

html = markdown.markdown(data.decode('UTF8'))

h = open('fichier.html', 'w')
h.write(html.encode('UTF8'))
h.close()

L'idée, c'est de "décoder" la chaîne qui est à l'origine en UTF-8 vers de l'Unicode, puis la traiter comme je le souhaite (ici avec Markdown), puis de l'encoder en UTF-8 pour l'écrire dans un fichier. Voilà.

Simple, efficace, mais il faut y faire scrupuleusement attention, sous peine de se prendre ce genre d'erreur :

UnicodeEncodeError: 'ascii' codec can't encode character

Je développe donc j'écris des tests unitaires.

Par Florian Strzelecki - 02:07 - 18.05.2011

Tags : J'aime, Programmation, Bonne pratique, Développement, Unit Testing, Technique

Suite à mon article sur PHPUnit, il m'a été posé la question, fort simple dans sa forme, de "Mais pourquoi faire des tests ?".

Après tout, cette question, je me la suis aussi posé avant de faire des tests, ainsi qu'à mon premier apprentissage, et encore aujourd'hui quand j'écris tel ou tel morceau de code, je me demande à quoi servent les tests que je vais écrire, ou que j'ai déjà écrit.

Je vais essayer de faire rapide, car expliquer "pourquoi faut-il faire des tests" n'est pas mon but premier : tout un tas de gens ont écrit tout un tas de choses sur le pourquoi comment, avec études théoriques et pratiques. Non, moi, je vais me contenter de vous exposer, de manière très subjective, pourquoi je fais des tests unitaires.

À la découverte de PHPUnit

Par Florian Strzelecki - 19:40 - 10.05.2011

Tags : Programmation, Bonne pratique, PHP, Unit Testing, Technique

Les tests unitaires, je connais depuis que je fais du python, et je sais qu'il est possible d'en faire avec php, mais je n'avais jamais vraiment essayer avec ce langage. Il faut dire que mes dernières expériences professionnelles n'étaient pas vraiment portées sur la qualité du code (ce qui est dommage, et particulièrement frustrant pour moi).

Mais ce matin, j'ai relevé ma motivation pour m'intéresser de plus près aux tests unitaires avec php. Je suis tombé sur PHPUnit, et j'ai donc passé la matinée à l'installer, l'utiliser, et à me poser des questions.

Cet article traite donc de mon exploration (très récente) de PHPUnit, de sa phase d'installation puis d'utilisation. Le contexte est un petit projet de carte en 2D gérée par Tile (2D-tile based system) avec un algorithme de shadowcasting recursif et tout un tas d'autres détails.

D'ailleurs, ce petit projet sera l'occasion d'un autre article après la publication d'une première version stable (probablement sur bitbucket) avec sa documentation. Oui, c'est du teasing, c'est mal, mais je parle d'abords des tests unitaires. Si je veux.

Boucle et SQL (et ORM) : la petite erreur à éviter

Par Florian Strzelecki - 18:51 - 11.04.2011

Tags : Programmation, Bonne pratique, PHP, Optimisation, ORM, SQL, Technique

Petite précaution avant d'entamer la lecture de cet article : il est technique, certes, mais ne concerne pas spécifiquement ni symfony ni doctrine. Le sujet de l'article est un problème technique très concret, qui se retrouve dans tous les langages, et avec n'importe quelle base de données.

En lisant le livre "Pratical symfony", plus spécifiquement le chapitre 6, je suis tombé sur un cas très classique : afficher une liste d'élément par catégorie, comme dans l'exemple qui suit.

L'approche ici - mais j'ai déjà vu ça ailleurs très souvent - est de récupérer la liste des catégories, puis, pour chaque catégorie, de récupérer la liste des offres de ladite catégorie.

Sauf qu'il y a un problème : voyez-vous lequel ?

Documenter ses applications

Par Florian Strzelecki - 19:18 - 23.11.2009

Tags : Python, Documentation, Programmation, Bonne pratique, Technique, autodoc

Le pouvoir de la documentation est immense, et mésestimé par beaucoup trop de monde, parfois même par ceux à qui elle serait le plus utile, les développeurs.

Une documentation peut faire gagner du temps aux développeurs, mais c'est bien plus que ça. Le fait de documenter ses applications va au-delà du fait de gagner du temps, ou de gagner en compréhension : c'est un signe de qualité.

Pour ma part, je considère que documenter mes applications est un devoir, et un gage de qualité. Avec une bonne documentation, je montre que mon application a été pensée et imaginée dans le bon sens.

Une bonne documentation, évidement, car une mauvaise est peut-être pire que tout finalement.

La documentation de Django

Image : La documentation de Django