Je suis développeur web freelance et propose des formations à Symfony2 ! Contactez-moi pour en discuter.

Nous sommes aujourd’hui le premier décembre. Comme tous les ans, c’est le premier jour des calendriers de l’avent. Sur le web, de nombreux calendriers virtuels en profitent pour parler du web sur un principe simple : un jour = un article. Les articles sont généralement écrits par des auteurs de tous bord, et c’est l’occasion de découvrir de nombreux sujets.

Voici une petite liste des calendriers que je connais, et qui parlent de développement web, de prêt ou de loin :

24joursdeweb est le seul que je connaisse. Il parle du web en général, pas d’une techno en particulier. Tous les sujets sont abordés : développement, intégration, UX, accessibilité, bonnes pratiques…

24ways est son pendant en anglais. Même style d’articles, mais en anglais.

UXmas propose des articles sur le thème de l’UX (User eXperience).

24pullrequests fonctionne un peu différement. Il propose aux utilisateurs de contribuer à un projet open source différent chaque jour, en fournissant une plateforme qui incite à faire une pull request par jour.

Plus décalé, The Avengifs propose tous les jours un Gif rigolo.

Si vous connaissez un calendrier qui manque à cette liste, n’hésitez pas à le dire dans les commentaires !

Retours sur le ForumPHP 2014

27 octobre, 2014

Le Forum PHP, c’était la semaine dernière et c’était super bien. Petit compte rendu pour les absents, les liens ramènent vers la page joind.in des conférences.

La théorie, une vision de l’avenir du web

Plusieurs conférences étaient un peu théoriques, dans le sens où elles présentaient une vision du développement et des pratiques qui gravitent autour de manière idéale. Même si le monde réel est plus mitigé, celles auxquelles j’ai pu assister valaient le coup, et je vous les recommande.
Sebastian Bergman (créateur, entre autres, de phpunit), expliquait qu’il y a 4 grands problèmes à faire des applications : la présentation, la persistance, les problématiques bas niveau, et la logique métier. Aujourd’hui, on gère à peu prêt correctement les 3 premiers grâce -entre autre- aux framework, il y a maintenant plein de choses à faire mieux pour améliorer et rendre pérenne la plus importante, la logique métier. Même si la conférence en elle même était un peu passe partout, j’ai trouvé le rappel d’idées qu’on considère implicites pertinent.
William Durand et son analyse des pratiques de tests automatisés m’a mis sur le cul. Thésard sur la question, son état de l’art et sa vision d’où les tests se dirigent et doivent se diriger donnaient vraiment envie de mieux maîtriser la question. Sa présentation contient un paquet de mots-clés et de librairies qui devraient gagner en popularité.
Francois Zaninotto, dans un discours façon homme politique (une idée originale bien menée) présentait une vision selon laquelle les framework full stack vont décliner pour laisser place à plus de micro framework, de micro services, d’API. L’idée, à terme, étant de se rapprocher d’une philosophie à la unix (faire des applications/services ayant un but unique mais le faisant très bien). L’avenir n’est plus à des mono-technologies, mais à l’usage de techno adaptées à des besoins précis : CMS en PHP, api en node, applis mobiles qui consomme ces API. Ce sera entre autre possible grâce à l’interopérabilité permise par l’utilisation d’HTTP, et des groupes de discussion comme php-fig.

Je vous encourage à regarder les conférences lorsqu’elles seront disponibles car il est bien évidemment très difficile de résumer en quelques mots ces conférences riches en idées.

La pratique, c’est à dire la théorie avec du retard et du pragmatisme

J’ai beaucoup apprécié la vision théorique de ces présentations, mais j’ai aussi beaucoup apprécié les retours d’expérience de plusieurs boites présentes. Cela permet de situer l’état de l’industrie par rapport aux visions théoriques, et car cela m’a permis de voir que ce nous faisons dans ma boite tient autant la route que ce qui se fait ailleurs. Au delà du côté « c’est bon pour l’ego », cela m’a surtout permis de voir que où nous n’avons pas de réponses, d’autres sont tout autant dans le brouillard que nous.

La conclusion ? En théorie, on sait faire beaucoup de choses depuis longtemps. En pratique, le temps que les choses soient intégrées dans l’industrie il faut beaucoup de temps, et pas mal de compromis (« The only sure thing about computer science: everything is a tradeoff« , comme le disent certains, et qui se généralise probablement très bien).

Maison du monde parlait des problèmes de régression de leur site e-commerce. Intégrer l’automatisation de la qualité par des tests ne s’est pas fait sans mal, pose de vrais questions d’organisation et est, chez eux, un enjeu permanent.

Les développeurs de L’express expliquaient l’état de leurs recherches sur l’automatisation de déploiement d’environnement de développements grâce à puppet, chef et amazon. Ces outils permettent de gagner en automatisation, et ont une forte valeur ajoutée, mais laisse encore des questions et ont chez eux un coup d’adoption élevé. Répliquer la configuration exacte de prod est compliqué (notamment quand on souhaite également répliquer la base de données quand elle est conséquente, pour reproduire des bugs complexes sans avoir à le faire directement en prod par exemple). Ils n’ont pas de solution pour reproduire les problèmes d’assets (images, uploads) dans les environnements de développement de manière systématique sans avoir à dire « t’inquiète, ça marchera en prod ».

Maxime Valette, fondateur de Viedemerde, expliquait comment ils ont (sur)vécu à l’explosion de viedemerde.fr à ses débuts, à cheval entre les besoins de communication pour répondre aux journalistes, et les besoins démentiels d’infrastructure auxquels ils n’étaient pas du tout préparé (en pour lesquels le temps possible de mise en place d’une solution se chiffrait en heures). Bref ça a plus parlé de survie que de qualité, mais cela montrait clairement que la qualité de code n’empêche pas du tout un site de survivre à des très gros volumes de visite (comme le dit Jeff Atwood, hardware is cheap).

Les vieux de la vieille

C’est assez inévitable avec un langage qui a plus de 15 ans et qui est le plus déployé dans le monde, des présentations sur les CMS les plus répandus présentaient leur situation courante et l’avenir.
Je ne suis pas utilisateur, mais ça a permis de voir que là où EzPublish et Drupal ont récemment fait le choix de la refonte pour tenir dans le temps, WordPress préfère conserver la rétrocompatibilité en ne touchant pas au core. On verra bien ce que cela donnera dans les années à venir : wordpress a le volume, les autres ont maintenant une meilleure qualité de code, mais ça n’est pas forcément pertinent et nécessaire pour mieux pénétrer le marché…

Les API à l’honneur

Les micro services et API avaient le vent en poupe lors du forum. Plusieurs conférences en parlaient et il y a notamment eu 2 retours d’expérience sur le sujet, l’une faite par les gens d’Elao expliquant tous les problèmes qu’ils ont eu et auquel on peut s’attendre d’être confrontés un jour ou l’autre lorsqu’on cherche à mettre en place une architecture d’api orientée micro services. La présentation était assez macro, et présentait les problématiques de communication, d’infrastructure, de sécurité, de monitoring, de cache…
L’autre, présentée par quelqu’un de l’équipe d’Arte rentrait plus dans les détails, avec quelques bouts de code sur comment ils avaient pu résoudre certains problèmes. Les deux donnaient des idées à des niveaux différents et sont complémentaires.

De nouveaux usages

Les conférences parlaient aussi de « nouveaux » usages, des usages pas encore tout à fait répandus dans la communauté.

Je parle beaucoup d’API, quelqu’un de chez Lemonde est venu expliquer comment ils ont intégré du nodeJS dans leur pile applicative lors de la refonte de leur CMS, notamment pour exposer une API consommé par une application javascript monopage.

J’ai beaucoup aimé sa remarque « Considérez vous comme des développeurs avant d’être des développeurs PHP ». Merci ! Il faudrait l’imprimer en immense et l’afficher dans toutes les boites. Ca marche également avec « vous êtes des développeurs avant d’être des développeurs web ». Cette idée a l’air simple mais en pratique, c’est parce que des gens ont regardé ce qu’il se faisait ailleurs, notamment dans les applis clients lourd, que les bonnes pratiques du génie logiciel (tests automatisés, injection de dépendances par exemple) ont fini par arriver dans le monde du PHP. Ca a toutefois mis beaucoup de temps et PHP (et le web en général) continue d’avoir du retard. Bref, cette conférence était l’application directe de l’idée de Francois Zaninotto, selon laquelle nous arrivions sur plus d’interopérabilité grâce à HTTP, et à l’utilisateur d’outils spécifiques pour des besoins précis.

Une autre série d’outils que j’ai pu découvrir, ce sont les outils d’analyse de code. Scrutinizer, ainsi que qu’Insight de SensioLabs permettent de voir le code qui ne respecte pas des règles élémentaires (le passage de paramètres get directement dans les requêtes SQL, donc source d’injection par exemple), même dans des configurations complexes. Leur force, c’est leur utilisation en SaaS, intégrée avec Github, qui ouvre des perspectives intéressantes.

Une conférence présentait également une idée assez intéressante: l’utilisation de diffbot pour concevoir des API pour ses propres besoins. Basé sur du scraping de page intelligent, on peut se créer sa propre API pour des sites qui n’en proposent pas, par exemple pour sortir de manière automatique la liste des articles publiés par une personne sur un site éditorial, pour par la suite automatiser des tâches (en faisant des graphes de fréquence de publication) de suivi.

J’ai eu l’impression que ça n’a pas intéressé grand monde, peut-être l’intérêt pour les développeurs est moins immédiat que dans d’autres sujet. C’est pourtant hyper disruptif et je suis convaincu que ça va gagner en popularité d’ici peu avec les avancées et les nouveaux besoins amenés par le big data (ça y est, moi aussi je me mets à parler comme un chef de projet d’agence digitale).

La conférence en elle même

La conférence a bien marché, l’organisation était top. Les speakers, pour beaucoup très connus dans la communauté étaient évidemment très compétents. Les sujets étaient généralement pointus, ce qui permet de ramener plusieurs idées et pas mal de motivation pour faire mieux chez soi…

Une seule conférence m’a franchement déçue, celle de Dayle Reese. Il devait parler de Laravel, mais après avoir parlé 15mn de lui s’est trouvé à court de temps. J’y suis allé pour découvrir la philosophie de ce framework controversé (et, ironiquement, qui semble pratiquer le culte de la personnalité derrière son gourou, Taylor Otwell), je ne suis pas plus avancé, et n’ai aucune envie de creuser plus la question, dommage.

Au niveau du fonctionnement, il y avait simultanément deux conférences, ce qui permettait de choisir les thématiques qui nous intéressaient (ou, parfois, de devoir faire un choix terrible !). L’horloge était bien gérée par l’équipe d’organisation, il n’y a presque pas eu de retards et c’était vraiment bien pour ne pas louper de présentation. Une gestion rigoureuse du temps n’est pas la norme dans les conférences alors que c’est pourtant essentiel, c’était donc cool d’avoir bien géré ça.

Le seul bémol, c’est le manque de places parfois pour certaines conférences. Il fallait arriver en avance pour certaines conférence afin d’avoir une place assise, pour des histoires de sécurité, le personnel du beffroi était intransigeant sur la question. C’est d’autant plus dommage pour la table ronde finale, seul événement à ce moment là… il n’y avait pas de places pour tout le monde, et arrivant parmi les derniers, l’accès à la salle m’a été refusé car il ne restait plus de places assises. Dommage pour moi. Même si c’est un signe positif pour l’événement qui marche très bien et pour la communauté qui n’a pas fini de faire des trucs sympa, vu le prix des places c’est pas super cool.

Evidemment, cet article bien trop long met de côté la moitié des conférences, et ne parle pas des ateliers vu que je n’ai participé à aucun d’entre eux. Et si le sujet des API m’a marqué car il m’intéresse, il est probable que chacun soit revenu avec des idées différentes. Quoi qu’il en soit, c’était très chouette et si vous n’y étiez pas, je vous conseille de regarder les slides des présentations. Si vous n’en pouvez plus d’attendre les vidéos officielles, rabattez vous sur la video officieuse du karaoké slideshow 🙂

Quelques astuces testées sur le terrain pour débugguer une application angularJS sans quitter le navigateur.

Dans chrome, on ouvre la console avec F12 ou ctrl+maj+j. Couplé au fait que l’on peut modifier le code et le faire rejouer directement depuis les outils pour développeurs, cela permet de débugger/corriger rapidement son code sans avoir à recharger la page systématiquement, ce qui est parfois très pratique.

Récupérer un service

Des fois un service en cours de développement ne marche pas comme il faut et c’est pas toujours marrant de devoir recharger la page à chaque modification pour déclencher à nouveau l’appel en question et le débugger. Par contre, on peut récupérer le service avec la méthode ci-dessous, modifier en direct la méthode depuis l’onglet « sources » de chrome dev tools, et lancer l’exécution à la main de la méthode réticente.

1
2
var service = angular.element('body').injector().get('myService');
service.maMethodeARelancer("plop");

A mettre entre toutes les mains. Depuis que j’ai découvert ça, je ne peux plus m’en passer.

Récupérer un scope local

Des fois on a besoin de récupérer le scope sous un contrôleur, que ce soit pour voir le contenu d’une variable à un instant particulier. Pour ce cas d’usage, la plupart du temps le débuggueur est plus pratique.
Par contre, quand on veut appeler une action de controlleur présente dans le scope, c’est très pratique.

Il faut connaitre le sélecteur DOM de l’élément du DOM dans lequel se trouve le scope auquel ou souhaite accéder.

1
var scope = angular.element('[ui-view=panel-communication]').scope()

Ensuite, on peut accéder aux propriétés accessibles dans ce scope, et appeler les méthodes que l’on souhaite.

1
2
scope.unMethodeARelancer("pouet")
scope.UnAttributQueJePeuxRegarderPlusFacilementDansLeDebuggueur

Débugger les directives

Il est parfois d’accéder au scope local à la directive, qui ont un don assez fou pour ne pas contenir les valeurs que l’on croit, les rendant particulièrement pénibles à débugger.

1
var localScope = angular.element('[ui-view=panel-communication]').localScope()

Certains directives ont un contrôleur, auquel on peut accéder, ce qui est un luxe qui peut vous faire gagner pas mal de temps et vous économiser nombre de dolipranes.

1
var controller = angular.element('[ui-view=panel-communication]').controller()

Bon courage !

terminatorIl y a quelques semaines, mon collègue tilap écrivait un article sur l’utilisation de screen partager un terminal en plusieurs.

Screen est plus largement répandu, et permet de partager un terminal sans installation préalable lors d’une connection SSH. Par contre au quotidien je préfère utiliser terminator, qui est quand même plus simple et convivial. Voici donc un petit guide de survie.

Installation

L’installation sur Ubuntu 14.04 se fait via :

1
apt-get install terminator

Les raccourcis essentiels

4 raccourcis servent à faire la plupart des choses :

  • ctrl+maj+o = ouvre un terminal dans le répertoire actuel, une barre horizontale sépare alors les 2 terminaux
  • ctrl+maj+e = ouvre un terminal dans le répertoire actuel, une barre verticale sépare alors les 2 terminaux
  • ctrl+maj+w = ferme le terminal sélectionné
  • ctrl+maj+x = fait disparaitre les autres terminaux, en ouvrant le terminal sélectionné en grand. ctrl+maj+x permet de revenir aux autres écrans

Pour ceux qui aiment naviguer au clavier, on peut se déplacer entre les terminaux rapidement assez rapidement avec quelques
ctrl+tab permet de naviguer vers le terminal suivant (ctrl+maj+tab pour obtenir le précédent)
ctrl+maj+gauche/droite/haut/bas permet déplacer les séparateurs entre les différents terminaux

La configuration de terminator est stockée dans ~/.config/terminator/config. Voici quelques paramètres que je trouve bien pour donner à terminator l’apparence d’un gnome shell :

1
2
3
4
5
6
7
8
9
[global_config]
  suppress_multiple_term_dialog = True
[profiles]
  [[default]]
    background_image = None
    background_color = "#2c001e"
    split_to_group = True
    show_titlebar = False
    foreground_color = "#ffffff"

Cela permet d’avoir la couleur de fond d’ubuntu et masque les titres ajoutés par terminator, donnant ainsi aux terminaux le même aspect qu’un gnome-terminal, mais en ayant plus de possibilités.

I wrote this article a while ago. Instead of letting it sink on my hard drive, the release of docker 1.0 is a good opportunity to let people know how easy getting started is. There might be some better solutions for many things, since stuff have evolved a lot in the last months, but you can see this article as an introduction to what docker is and how it works.

A few months ago, I talked about how to use Vagrant in order to deploy virtual machines on DigitalOcean. More recently, I’ve been playing with Docker, which is a kind of git for virtual machines.

With this tool, one can create virtual machines. The philosophy is not to ease machine creation (stuff that you would find with Vagrant + Puppet or Chef). The magic idea is that after every modification on the system (setup, file creation, script execution…), it is possible to save the state of the machine. This is so similar to ‘git commit’ that the command is… ‘docker commit’.
With such a philosophy, it is possible to navigate between the states, publish a machine like you would publish a repository on github, update a set of already-running machines efficiently, and so on.

I’ll get through the first steps to create a small machine that can be used in order to execute sandboxed php code : the php code will run inside the machine, and we’ll get the result. This could be used for a PaaS (Platform as a Service), like jsbin or codepen, but for languages whose functionnalities could pose security threats if it was executed on the main machine (php, python, ruby…).

Installing docker

I won’t get much into the details about how to install docker actually, everything you need is up to date in the <a href= »http://docs.docker.io/en/latest/ »>documentation</a>. There are some requirements about the version of your kernel, so if you can’t install, a solution is to run it inside a vagrant virtual machine. The source code contains a Vagrantfile already setup, so nothing could be easier :

Now that we have our new toy, we can start creating an image.

Open a terminal and start an instance using the base image :

1
sudo docker run -i -t base /bin/bash

This will launch you into a shell inside the machine. We can now start customizing the image. We won’t do much in this tutorial, we will simply install php, but of course you can do everything you would do with any virtual machine.

Installing php

Inside the shell, run :

1
2
apt-get update
apt-get install php5

Saving of a machine

Now that we have a machine with PHP installed, we want to save it, in order to be able to reuse it afterwards. We have made modifications on the system but if we exit the shell right now, since they have not been saved, we’ll have to install php again the next time we run our image.

Leave the current terminal open, and open another terminal. In order to save our image we need its identifier, so run :

1
 sudo docker ps

It will show the ID of the running container in the other terminal. We can save our image with the name ‘clem/php’ by running the commit command :

1
sudo docker commit clem/php

The name looks like the conventions on github (user/repository). Even though here there are no obligations, it’s good to keep good habits.

If all went well, your images ‘clem/php’ will appear in the list of available images :

1
sudo docker images

Images are similar to git branches of the base image. The next time you want to create a machine, if you want to install php and mysql, you can :

  • run the base image, install php and mysql
  • run the clem/php, and install mysql

Our basic jsbin like for PHP

Remember, we want to do something similar to jsbin, but for executing php in a sandbox. Our image clem/php will be the sandbox, because we don’t want to restrict the functionnalities of the language, what if someone executed some shell code from PHP in order to erase the whole system. We can use docker to start a machine, execute any phpcode, return us the result, and quit. Since we won’t save the machine, every execution will provide us with a brand new machine. If someone destroys it in anyway, we couldn’t care less.

We need to create a file on the host, that will be executed in docker. Create test.php, and write something like :

1
<?php echo 'Hello World !'.PHP_EOL;

Run some code inside your new sandbox
The first idea I came up with was this one :

1
cat test.php | sudo docker run -i clem/php /bin/bash -c "cat &gt; test.php; php test.php"

Basically, to manually copy the content of the file thanks to cat inside docker. Then we run it thanks to bash, with a 2 command script : « cat > test.php; php test.php », or ‘dump the content to test.php then run test.php’.

There is a better solution : using a mounting point. We can share a folder on the host machine to docker.
/home/vagrant/test.php will be the file on the host machine
/home/docker.php is the file we want to have on the docker machine.
the ‘-v’ option tells docker to create a mounting point between the two files.
This time, instead of running bash, we can directly run PHP.

1
docker run -v /home/vagrant/test.php:/home/docker.php php /home/docker.php

Awesome, huh ?

J’ai assisté cette semaine au meetup ParisRb. J’ai fait plusieurs meetups récemment (j’aime voir l’évolution du web depuis des angles différents), et j’ai beaucoup aimé celui-ci. Des sujets variés (certains techniques, d’autres moins), un endroit sympa (dans les locaux de Google) et pas mal de monde (dans les 250 personnes). Ha, et tout meetuper vous le dira : le buffet, ça compte, et celui-ci était sympa. Et les présentations ? Dans une première partie plusieurs lightning talks, puis on mange/discute, puis 3 conférences de 20 minutes. Bref un format sympa qui fait qu’on ne s’ennuie pas trop quand un talk spécifique ne nous intéresse absolument pas, qui permet de voir des choses variées et de rentrer quand même dans les détails tout en rencontrant pas mal de monde. Bref, même si je ne fais pas de ruby, c’est un meetup où je reviendrais !

Mais si j’écris cet article, c’est surtout pour parler de la conférence qui m’avait poussé à m’inscrire, celle de Thibaut Barrère. Nous avions déjà discuté de freelancing il y a quelques temps ensemble et échangé plusieurs mails, et aujourd’hui il venait présenter un retour d’expérience sur le bootstrapping d’un produit, financé par son activité de freelance. Il est derrière WiseCashHQ (https://www.wisecashhq.com/), une application de prévision de trésorerie, pour les indépendants et entrepreneurs. Ce post contient quelques unes de mes notes, et les slides de la présentation sont sur speakerdeck :

Pour ceux qui ne connaissent pas, bootstrapper un produit, c’est lancer un produit sans apport de capitaux extérieurs.

Son idée ? Travailler en freelance auprès de quelques clients, et développer une application en parallèle (Mais pas sur le temps qu’il facture à ses clients bien sûr), application qui va lui apporter des revenus récurrents.

En freelance, il ne travaille qu’avec 2 clients récurrents. Gérer et développer une application SaaS prend du temps, et il souhaite en avoir à consacrer à sa famille. Son temps est donc divisé en 4 (pas nécessairement à part égales, mais symboliquement). Il fournit à ses deux clients son emploi du temps à environ trois mois, pour qu’ils aient de la visibilité sur ses disponibilités, et qu’il puisse s’en dégager pour son projet sans que cela n’impacte sa vie de famille.

La formation d’Amy Hoy (le style peut rebuter) lui a permis de tester une méthodologie qui n’est pas basée sur l’itération autour d’un produit (comme on le présente souvent dans les méthodes type Lean Startup), mais plutôt autour d’une audience et de recherches concrètes sur internet.
Ces 10 étapes sont, en gros (simplifiées par Thibaut, le process n’est pas formellement celui-ci) :

  • Trouver une audience à qui l’on sait s’adresser, ou avec laquelle on se sent à l’aise de communiquer
  • Safari : Faire des recherches sur les problèmes que cette audience a, et qu’elle serait prête à payer pour voir résolus
  • Trouver 10-15 pitchs de produits, sur des problèmes différents
  • Itérer pour n’en garder qu’un (ranking)
  • Copywriting
  • Landing page, qui présente les points de souffrance qui sont résolus, et sert à capter des emails
  • Construction d’un produit minimal (« Atome créatif », équivalent d’un MVP)
  • Lancement
  • eBombs, des campagnes sociales ciblées (articles éducatifs visant l’audience, promotion, articles invités…)

Une fois le projet trouvé, la vie d’une appli SaaS a 3 phases (cette fois selon Rob Walling):

  • Construire : la partie où l’on conçoit et code l’application
  • Apprendre : celle où le revenu progresse mais lentement et où on apprend à communiquer et vendre son produit
  • Grandir : celle où l’on a plus de clients, plus de machines, plus de fonctionnalités

Thibaut a fait le choix de construire son produit (ce qui a pris du temps), et une fois lancé, de basculer dans la phase « apprendre » de façon assumée, c’est à dire ne pas viser à développer de nouvelles fonctionnalités lourdes (durant cette phase en tout cas), mais plutôt de développer la façon de vendre (l’application évolue tout de même mais à vitesse lente).

Pour les techniques, la tentation est grande de rester concentré uniquement sur la technique justement, mais le risque d’essoufflement est grand. On peut se retrouver « entre deux », assez d’utilisateurs pour générer du support et des coûts, et pas assez de revenu pour en vivre. Thibaut cherche donc à mitiger ce risque en apprenant à mieux vendre durant cette phase.

Durant cette deuxième phase, le focus est largement sur le marketing, la gestion de newsletter, la diffusion de contenu éducatif, le copywriting. C’est celle où l’on apprend par exemple que parler de bénéfices (« Dormez tranquille ! ») plutôt que de fonctionnalités (« Calcul automatique des échéances des impots ») permet de mieux faire comprendre à l’acheteur potentiel ce qu’il a à gagner. Une phase donc où l’on travaille de nombreux axes pour améliorer son produit, mais en se focalisant essentiellement sur les ventes (et du code associé à cela).

A retenir également : le SaaS, c’est long. Même si on peut et doit adresser la « pente des ventes », il faut considérer que le développement prendra du temps, et s’armer financièrement (le mix avec le freelance d’une part, et le prévisionnel de trésorerie d’autre part aident à tenir la distance).

On peut aller plus vite en livrant plus vite (avec moins de choses) et plus tôt, et en utilisant des outils externes (MailChimp, librairies open source) plutôt que tout recoder soi même, mais la croissance du produit restera longue. « Get used to it ».

Bref, une conférence très intéressante sur un sujet peu traité en français, et qui donne envie de s’y mettre.

Même si les bases de données NoSQL ont la côte en ce moment, les bases de données SQL ont encore de beaux jours à vivre devant eux. En effet, dans beaucoup de situations, il est assez facile de sortir des statistiques avec quelques lignes de SQL. Voici quelques astuces que j’ai découvert il y a quelques temps, et qui sont très pratiques pour sortir des chiffres.

Assez rapidement, lorsqu’on fait du SQL, on a besoin de récupérer le nombre d’éléments dans la base qui correspondent à un certain critère. Pour faire des statistiques, comme par exemple extraire le nombre d’utilisateurs enregistrés dans la base par exemple. La réponse est classique :

1
2
3
4
SELECT
    COUNT(u.id) AS total
FROM
    users u

Ok, c’était facile. Et si on veut le nombre d’utilisateurs qui ont été créés chaque mois ?

On peut utiliser un « group by date_trunc »

L’astuce, c’est d’utiliser date_trunc. date_trunc permet de ne conserver, dans une date, que la partie de la date qui nous intéresse. Si notre date est le 4 janvier 1981 à 17h23, lorsqu’on tronque au mois, date_trunc nous renverra le 1 janvier 1981 à 00h00. En combinant cela avec un group by, on peut obtenir le nombre d’utilisateur qui a été créé mois par mois :

1
2
3
4
5
6
7
SELECT
    COUNT(u.id) AS total,
    date_trunc ('months', u.created_at) AS considered_month
FROM
    users u
GROUP BY date_trunc ('months', u.created_at)
ORDER BY date_trunc ('months', u.created_at)

Comme vous l’avez compris, le premier paramètre de date_trunc permet de définir où tronquer. En tronquant au jour ou bien à l’heure on obtient une granularité plus fine, mais également plus de données, ce qui n’est pas toujours ce dont on a besoin.

On obtient des résultats de ce genre, en supposant que nous ayons des utilisateurs entre avril et novembre 2013 :

total considered_month
3956 « 2013-04-01 00:00:00 »
3965 « 2013-05-01 00:00:00 »
3549 « 2013-06-01 00:00:00 »
3728 « 2013-07-01 00:00:00 »
8311 « 2013-08-01 00:00:00 »
6041 « 2013-09-01 00:00:00 »
6381 « 2013-10-01 00:00:00 »
3784 « 2013-11-01 00:00:00 »

En fait, maintenant, on aimerait bien connaitre, pour chaque mois, le pourcentage d’utilisateurs qui s’est connecté au moins 3 fois, par rapport au nombre total d’utilisateurs créés durant le mois. Ok, c’est un exemple tordu, mais c’est pour expliquer comment peut faire un pourcentage sur le nombre d’éléments d’un sous-ensemble de données d’un mois concerné par rapport au nombre d’éléments de l’ensemble de départ.

La structure sum (case …)

L’idée, c’est d’utiliser une structure avec SUM (case … ) pour gérer un compteur « à la main ». Dans l’exemple ci-dessous, vous pouvez voir qu’on compte le nombre d’éléments total avec count, et qu’on compte le nombre d’utisateurs ayant 3 connections en incrémentant un compteur nous même via SUM (case … ). Enfin, à la troisième ligne du select on calcule le pourcentage correspondant.

1
2
3
4
5
6
7
8
9
10
SELECT
    COUNT(u.id) AS total,
    SUM( CASE WHEN u.nb_connection > 3 THEN 1 ELSE 0 END) AS subset_count,
    SUM( CASE WHEN u.nb_connection > 3 THEN 1 ELSE 0 END)::FLOAT * 100/ COUNT(u.id)::FLOAT AS percentage,
    date_trunc ('months', u.created_at) AS considered_month
FROM
    users u

GROUP BY date_trunc ('months', u.created_at)
ORDER BY date_trunc ('months', u.created_at)

Dans la vraie vie, au lieu de stocker un entier correspondant au nombre de connections, on stockerait plutôt la date de connection dans une table séparée, mais c’est pour simplifier.

On obtient des résultats de ce genre :

total subset_count percentage considered_month
3956 334 8.44287158746208 « 2013-04-01 00:00:00 »
3965 343 8.65069356872636 « 2013-05-01 00:00:00 »
3549 628 17.6951253874331 « 2013-06-01 00:00:00 »
3728 456 12.2317596566524 « 2013-07-01 00:00:00 »
8311 1206 14.5108891830105 « 2013-08-01 00:00:00 »
6041 842 13.938089720245 « 2013-09-01 00:00:00 »
6381 818 12.8193073186021 « 2013-10-01 00:00:00 »
3784 800 21.1416490486258 « 2013-11-01 00:00:00 »

Il est à noter qu’avec PostgreSQL, on pourrait convertir directement le résultat de « u.nb_connection > 3 » entier pour faire la somme de manière plus concise, mais pas forcément plus simple à lire. De plus, l’exemple ci-dessus montre qu’on peut mettre plusieurs conditions (avec plusieurs « when » à l’intérieur du case), ce que la conversion d’un boolean ne montre pas forcément. Néanmoins, il est possible d’écrire la ligne qui suit :

1
2
3
4
SELECT
    COUNT(u.id) AS total,
    SUM( (u.nb_connection > 3)::INTEGER ) AS subset_count,
    ...

Bref, on a vu dans cet articles 2 structures pratiques pour extraire des chiffres à partir de votre base, en utilisant group by date_trunc et sum (case …). Ca a l’air de rien car les sommes et les moyennes sont des outils simples, mais ce sont également des outils très pratiques pour étudier l’évolution d’un business, ou anticiper les évolutions de structure à prévoir.

Bien que j’utilise git depuis un bon moment, j’ai longtemps été effrayé par l’usage de git stash, par peur de perdre du travail. A tort, car elle se révèle finalement très simple d’utilisation, et très pratique. Cette commande (to stash = réserver) permet de mettre de côté toutes les modifications en cours sans les commiter, pour pouvoir les reprendre plus tard.

Dans ma manière de travailler, c’est utile quand je travaille seul comme quand je travaille avec des collègues. Voici deux cas d’utilisation récents :

  • Je travaille sur une fonctionnalité avec un collègue. Il a besoin d’un correctif sur un bout de code que j’ai écrit avant pour pouvoir continuer à travailler. Je travaille sur une branche ‘feature’, et doit donc revenir sur la branche ‘dev’, dernière version stable de ma branche de développement, pour y apporter un correctif. Dans ma branche ‘feature’ actuelle, je suis en plein milieu d’un développement, je ne peux absolument pas lui fournir ce nouveau code à moitié terminé, ni faire un commit du code au milieu de son développement pour changer de branche. Je dois donc mettre le code sur lequel je travaille actuellement de côté, pour le reprendre par la suite.
  • Je travaille sur une fonctionnalité seul, en javascript par exemple. Lors de mon développement, je me rends compte qu’avant de pouvoir finir ce que j’ai commencé, je dois changer quelque chose ailleurs dans le code (sur la partie PHP qui va exposer une API par exemple). Comme j’aime avoir des commits unitaires et fonctionnellement séparés, je préfère avoir les modifications de l’API en PHP dans un commit, et celles du JS qui l’utilise ensuite. Comme j’ai déjà commencé à travailler sur le JS, je dois mettre mon code de côté.

Ce que j’ai longtemps fait dans ces situations, c’est de faire un commit temporaire. J’ajoutais mes fichiers modifiés, et je laissais un commentaire du type « temporary commit, edit later ». Plus tard, lorsque je revenais sur le code en question, et que le travail terminé, j’éditais mon commit via git commit –amend. Cette commande permet d’éditer le dernier commit en ajoutant/supprimer des fichiers, et en changeant le message de commit. Attention, c’est à utiliser avec soin si vous pushez/pullez du code souvent.

Plutôt que de committer du code temporaire (qui a finalement tendance à pourir l’historique avec des commits que j’oublie de nettoyer), la solution préconisée par git pour ce genre de choses, c’est git stash.

Cette commande permet de mettre de côté ses modifications pour les récupérer ultérieurement. Une fois exécutée, on peut ensuite changer de branche, faire ses modifications dans la nouvelle branche et revenir, ou bien faire ses modifications directement dans la branche où l’on a réservé les modifications, cela n’est pas un problème.

Avec un exemple d’utilisation, vous allez voir qu’il est très simple de s’en servir. Le point de départ : vous êtes en train de travailler, vous avez ajouté certains fichiers, modifiés d’autres… en vous devez mettre les modifications de côté. C’est parti, on stash.

1
2
3
git stash
Saved working directory and index state WIP on feature_branch: d9e2bb5 merged v5.3.4
HEAD is now at d9e2bb5 merged v5.3.4

Une fois que c’est fait, votre git status est vide.

1
2
3
4
5
6
[clem@clem:~/dev/currProject] git status -s
## feature_branch
# -> rien, les modifications se sont ajoutées à la pile de la réserve
[clem@clem:~/dev/currProject] git stash list
# Sur un écran à part, on peut voir que la pile
# de la réserve contient un élément: nos modifications

Vous changez de branche, faites ce que vous avez à faire, puis vient le moment où vous revenez sur la branche courante pour reprendre votre travail là où vous l’avez laissé. C’est le moment d’utiliser git stash pop.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[clem@clem:~/dev/currProject] git stash pop
# On branch feature_branch
# You are currently rebasing branch 'bh' on 'fb7b1dc'.
#   (all conflicts fixed: run "git rebase --continue")
#
# You are currently bisecting branch 'bh'.
#   (use "git bisect reset" to get back to the original branch)
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   app/Berthe/ServiceXHR/ServiceXHRQuote.php
#   modified:   lib/Evaneos/Berthe/JsonServer.php
#
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (21f9583cd4159df5627307eada103e29fe165431)
[clem@clem:~/dev/currProject] git status -s
## feature_branch
 M app/Berthe/ServiceXHR/ServiceXHRQuote.php
 M lib/Evaneos/Berthe/JsonServer.php

Comme vous pouvez le voir sur les 2 commandes ci-dessus, git stash pop enlève les modifications de la pile, les met dans la branche courante, et supprime le sommet de la pile.

Le stash fonctionnant comme une pile, il peut arriver que l’on ne veuille pas récupérer ses modifications. Pour cela, on peut supprimer le dernier élément de la pile via git stash drop. Voici à quoi cela ressemble :

1
2
3
4
5
6
7
8
9
10
11
[clem@clem:~/dev/currProject] git stash
Saved working directory and index state WIP on feature_branch: d9e2bb5 merged v5.3.4
HEAD is now at d9e2bb5 merged v5.3.4
# Je sauvegarde les modifications
[clem@clem:~/dev/currProject] git stash drop
Dropped refs/stash@{0} (befd3f17f416548c30624a01118b609ebb1bc0a8)
# Je n'en ai plus besoin, je les supprime du stash.
[clem@clem:~/dev/currProject] git status -s
## feature_branch
# Ma branche courante est vide. Dans cet exemple, c'est comme
# si j'avais fait git reset HEAD --hard.

Et voila, non seulement c’est plus élégant que des commit temporaires, mais c’est aussi très simple d’utilisation.

Depuis quelques temps, j’ai un serveur chez DigitalOcean, qui me sert principalement pour bricoler des petites applis, et jouer autour de nouvelles technos. DigitalOcean m’a séduit par le rapport pricing/résultat. Même s’il y a des choses à redire, où s’il existe des offres similaires moins chères, je suis très satisfait de pouvoir créer/détruire des machines virtuelles en 2 clics. Cela correspond en fait totalement à mon cas d’utilisation, qui consiste à monter une machine pour tester une techno, bidouiller dessus, et la détruire quand j’ai fait le tour de ce que je voulais voir.

Par contre, il est du coup un peu pénible de devoir réinstaller sa machine virtuelle à chaque fois. Installer un LAMP basique avc phpmyadmin se fait assez vite, ça tient en quelques ligne de bash :

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh
apt-get update
#install apache
apt-get install apache2
#install mysql
apt-get install mysql-server
mysql_secure_installation
#install php
apt-get install php5 php-pear php5-suhosin php5-mysql
service apache2 restart
# install phpmyadmin
apt-get install phpmyadmin
ln -s /usr/share/phpmyadmin/ /var/www

Mais dès qu’on veut faire quoi que ce soit de plus évolué, la complexité augmente rapidement. En plus d’installer des paquets il faut aller modifier des fichiers de configuration, ce qui devient rapidement chronophage, et me détourne de l’essentiel, le développement. Avec l’habitude on finit par connaitre les écueils à éviter pour aller vite, mais on y passe quand même du temps.

C’est là où Vagrant devient intéressant. Couplés à PuPHPet et DigitalOcean, j’ai personnellement atteint le nirvana de l’installation de VM en à peine 2H.

Vagrant sert à piloter des machines virtuelles. On lui file un répertoire de configuration pour définir l’environnement à installer sur une machine virtuelle. PuPHPet est une appli web qui permet de construire sa configuration pour Vagrant via une IHM, ce qui évite de devoir lire la doc. On est forcément plus limité que si on faisait tout soi même, mais dans mon cas (déployer un environnement apache ou nginx avec mysql ou postgresql, suivant l’humeur), j’ai de bonnes bases pour pouvoir faire ce qui m’intéresse sans m’embêter.

De l’intérêt de Vagrant

En fait, mon cas d’utilisation (déployer des VM kamikaze) est loin d’être le plus intéressant. Là où Vagrant prend tout son sens, c’est lorsqu’on travaille en équipe, et que l’on a le besoin de pouvoir avoir finalement de nouvelles machines identiques. Par exemple, lorsqu’un nouvel arrivant doit installer sa machine et qu’on veut une belle machine toute neuve, sans avoir à copier l’ISO de celle d’un copain, sans faire d’efforts, et sans surprises.
Et même s’il y a une valeur ajoutée à ce qu’un nouvel arrivant installe sa machine et comprenne ce qui s’y trouve, lorsqu’on plante sa bécane, on a pas forcément envie de passer du temps à tout réinstaller. De plus, une installation automatique et scénarisée permet d’assurer que tout le monde a le même environnement, ce qui n’est pas le cas d’un installation manuelle (« j’ai pas réussi à faire les choses telles qu’elles étaient décrites dans le manuel, donc j’ai googlé une alternative »), et qui peut souvent poser problème.

Autre avantage, toute la configuration de la machine à déployer tient en quelque fichiers de configuration. On peut donc la modifier, la versionner, la partager, la livrer… beaucoup plus facilement qu’on le ferait avec un manuel d’installation.

Ok, on a compris, on fait comment ?

PuPHPet vous permet de déployer des machines en local, chez DigitalOcean ou Amazon EC2.
Je vais décrire les étapes par lesquelles je suis passé pour partir de rien, et déployer une machine virtuelle sur Digital Ocean. Avoir un compte chez eux (associé à une carte bancaire) est nécessaire pour aller jusqu’au bout, mais la logique est la même si vous voulez déployer ailleurs.

Configuration de la machine locale

Nous aurons besoin d’une clé SSH pour nous authentifier par la suite, créons la.

1
2
cd ~/.ssh
ssh-keygen -t rsa -C "votre@email.com"

Je l’ai appelé digital_ocean au lieu d’id_rsa.

Il est nécessaire d’installer vagrant et virtual box. Vous pouvez récupérez les derniers paquets sur http://downloads.vagrantup.com/
https://www.virtualbox.org/wiki/Linux_Downloads

Sur Ubuntu/Debian, on installe les fichiers .deb avec sudo dpkg -i *.deb

Il également installer le plugin pour digital ocean :

1
2
vagrant plugin install vagrant-digitalocean
vagrant box add dummy https://github.com/smdahlen/vagrant-digitalocean/raw/master/box/digital_ocean.box

Créer un projet

1
mkdir vagrant_env

C’est dans ce répertoire que nous mettrons le code de configuration utilisé par vagrant. En général, on fait un vagrant init pour démarrer un nouveau fichier de configuration, mais nous allons utiliser PuPHPet qui va faire ça pour nous.

Configurer digital ocean

Enregistrez la clé SSH que vous avez créé : https://cloud.digitalocean.com/ssh_keys

Il faut ensuite récupérer votre identifiant utilisateur et votre clé API : https://cloud.digitalocean.com/generate_api_key

Notez la clé API quelquepart, car elle n est plus affichée quand on revient sur la page et le seul moyen d’en avoir une est de la regénérer.

Configurez votre machine avec PuPHPet

Je vous laisse configurer votre machine aux petits oignons avec PuPHPet. N’oubliez pas de renseigner toutes les informations sur la configuration Digitalocean (clés API), nom de la machine, et type de machine.
Vous pouvez choisir le type de serveur (apache2/nginx), postgresql ou mysql, installer ou non phpmyadmin, la configuration de PHP, les packages divers à installer… c’est très simple.

Une fois terminé, un immense bouton permet de télécharger vos fichiers de configuration. Décompressez les dans un répertoire, vous devriez avoir l’arborescence suivante :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.
├── files
│   └── dot
├── hiera.yaml
├── puppet
│   ├── hieradata
│   │   └── common.yaml
│   ├── manifests
│   │   └── default.pp
│   └── Puppetfile
├── shell
│   ├── initial-setup.sh
│   ├── librarian-puppet-vagrant.sh
│   ├── os-detect.sh
│   ├── self-promotion.txt
│   └── update-puppet.sh
└── Vagrantfile

Dans le fichier puppet/hieradata/common.yaml, vous trouverez toutes les informations que vous avez spécifiées sur comment configurer votre machine. Dans le répertoire files/dot, vous pouvez ajouter un fichier .bashrc, .vimrc… qui seront déployées lors de l’installation de votre machine.

Normalement, on est prêt à déployer sa machine :

1
vagrant up

Ca n’a pas marché pour moi (machine sous Ubuntu 12.04), il fallait encore faire quelques légères modifications. La clé ssh n’a pas été bien prise en compte lorsque je l’ai précisé dans PuPHPet, j’ai du modifier

1
config.ssh.private_key_path = "~/.ssh/digitalocean" dans le fichier VagrantFile

Il a également fallu ajouter dans mon fichier .bashrc

1
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt

puis dans le fichier VagrantFile, ajouter la ligne

1
provider.ca_path = "/etc/ssl/certs/ca-certificates.crt"

dans vm.provider

Voici donc un exemple de configuration qu’on peut avoir. Vous pouvez voir que c’est au final très simple, on dit ce dont on a besoin et comment le configurer, et vagrant se charge de l’installer pour nous. Grâce au plugin DigitalOcean, il crée même la machine pour nous.

Fichier VagrantFile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
ENV['VAGRANT_DEFAULT_PROVIDER'] = 'digital_ocean'

Vagrant.configure("2") do |config|
  config.ssh.private_key_path = "~/.ssh/digitalocean"
  config.ssh.username = "clem"

  config.vm.box = "dummy"

  config.ssh.private_key_path = "~/.ssh/digitalocean"

  config.vm.hostname = "plop"
  config.vm.provider :digital_ocean do |provider|
    provider.client_id = "id_digital_ocean_que_vous_avez_fourni"
    provider.api_key = "cle_api_digital_ocean_que_vous_avez_fourni"
    provider.image = "Debian 7.0 x64"
    provider.region = "Amsterdam 1"
    provider.size = "512MB"
    provider.ca_path = "/etc/ssl/certs/ca-certificates.crt"
  end

  config.vm.synced_folder "./", "/var/www", id: "webroot"

  config.vm.provision :shell, :path => "shell/initial-setup.sh"
  config.vm.provision :shell, :path => "shell/update-puppet.sh"
  config.vm.provision :shell, :path => "shell/librarian-puppet-vagrant.sh"
  config.vm.provision :puppet do |puppet|
    puppet.facter = {
      "ssh_username" => "clem"
    }

    puppet.manifests_path = "puppet/manifests"
    puppet.options = ["--verbose", "--hiera_config /vagrant/hiera.yaml", "--parser future"]
  end

  config.ssh.shell = "bash -l"

  config.ssh.keep_alive = true
  config.ssh.forward_agent = false
  config.ssh.forward_x11 = false
  config.vagrant.host = :detect
end

Fichier common.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
---
vagrantfile-digital_ocean:
    vm:
        box: digital_ocean
        hostname: nom_de_votre_machine
        network:
            private_network: 192.168.56.101
            forwarded_port: {  }
        provider:
            digital_ocean:
                image: 'Debian 7.0 x64'
                region: 'Amsterdam 1'
                size: 512MB
                client_id: id_digital_ocean_que_vous_avez_fourni
                api_key: cle_api_digital_ocean_que_vous_avez_fourni
        provision:
            puppet:
                manifests_path: puppet/manifests
                options:
                    - --verbose
                    - '--hiera_config /vagrant/hiera.yaml'
                    - '--parser future'
        synced_folder:
            DXt5BtQJjHh3:
                id: webroot
                source: ./
                target: /var/www
    ssh:
        host: null
        port: null
        private_key_path: ~/.ssh/digitalocean
        username: clem
        guest_port: null
        keep_alive: true
        forward_agent: false
        forward_x11: false
        shell: 'bash -l'
    vagrant:
        host: ':detect'
server:
    packages:
        - vim
        - git
    dot_files:
        -
            bash_aliases: null
    _prevent_empty: ''
nginx:
    vhosts:
        1Zbx9ZeVKOfF:
            server_name: awesome.dev
            server_aliases:
                - www.awesome.dev
            www_root: /var/www/awesome.dev
            listen_port: '80'
            index_files:
                - index.html
                - index.htm
                - index.php
            envvars:
                - 'APP_ENV dev'
php:
    version: '55'
    composer: '1'
    modules:
        php:
            - cli
            - intl
            - mcrypt
            - curl
            - common
            - gd
            - fpm
            - memcache
            - memcached
            - xcache
        pear: {  }
        pecl:
            - pecl_http
    ini:
        display_errors: On
        error_reporting: '-1'
        session.save_path: /var/lib/php/session
    timezone: Europe/Paris
xdebug:
    install: 0
    settings:
        xdebug.default_enable: '1'
        xdebug.remote_autostart: '0'
        xdebug.remote_connect_back: '1'
        xdebug.remote_enable: '1'
        xdebug.remote_handler: dbgp
        xdebug.remote_port: '9000'
mysql:
    root_password: votre_mot_de_passe_root_bdd
    phpmyadmin: '1'
    databases:
        T7hssen8Pk2a:
            grant:
                - ALL
            name: clem
            host: localhost
            user: clem
            password: votre_mot_de_passe_bdd
            sql_file: ''

Bref, j’ai vraiment été séduit par le rapport effort/résultat. Il m’aura fallu environ 1h30 pour générer cette configuration de machine que je peux redéployer à volonté, ce qui est à peine plus que le temps que ça m’aurait pris si je l’avais fait à la main. Sauf que maintenant, tous les déploiements suivants peuvent se faire via vagrant up, et que si je souhaite travailler avec des collègues sur les projets pour lesquels j’ai construit cette machine, je peux leur fournir la configuration exacte de la machine à installer.

La semaine dernière, j’ai réécrit pour Sublime Text 3 l’extension FormatSQL, qui me servait régulièrement dans la version 2, mais qui n’est plus compatible. L’objectif : prendre une chaine SQL mal formatée, et la formater de manière lisible. Le code final de mon petit plugin est sur Github.

J’ai eu étonnamment beaucoup de mal à comprendre comment démarrer. La plupart des bouts de code que j’ai trouvé sur les net, y compris sur le site officiel, ne fonctionnent que sous Sublime Text 2, et n’étaient pas compatibles.

Démarrer

Pour démarrer, c’est en fait très simple, encore faut-il le savoir : en cliquant sur Tools -> new Plugin, on obtient le code minimal d’un plugin, point de départ que je ne trouvais pas.

1
2
3
4
5
import sublime, sublime_plugin

class ExampleCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        self.view.insert(edit, 0, "Hello, World!")

C’est du python, ST3 embarque la version 3.3, d’où l’origine de conflits pour de nombreux packages, qui utilisent des librairies qui ne fonctionnent plus en python 3.3.

Exécuter le plugin

Quand on enregistre ce fichier, on est déjà positionné dans le bon répertoire (chez moi : ~/.config/sublime-text-3/Packages/User). On sauvegarde example.py, et sans redémarrer, on peut utiliser le nouveau plugin, de 2 manières :

Depuis la console :
on l’ouvre avec ctrl+`, et on tape view.run_command(‘example’). Le plugin s’exécute !
Depuis un nouveau binding :
On crée un nouveau raccourci, en allant dans Preferences -> Key bindings – User, où l’on ajoute :

1
{ "keys": ["ctrl+alt+f"], "command": "example" }

Maintenant, à chaque fois que l’on appuiera sur ctrl+alt+f, notre plugin s’executera.

Et maintenant, à vous de jouer !

Bon courage !