Mise à jour du blog en Go

12/04/2015

Si vous connaissiez mon blog, vous avez remarqué qu’à partir d’aujourd’hui sa tête a changé. Je me suis décidé à refondre la totalité du site, ce qui va apporter son lot de soucis car tester le tout est pas simple du tout. Mais dans l’ensemble ça va aller vachement mieux. Le blog fonctionne maintenant en Go (Golang), dans un conteneur Docker et avec mon framework (kwiscale). Je vous raconte ?

Il y a des mois de cela, j’avais sauté le pas depuis PHP (sous Copix) et NodeJS (avec un framework maison nommé Knotter). Pour le coup j’étais super content. Et puis au fil des semaines et des mois les soucis se sont accumulés. Commentaires en double, voir plus de commentaire du tout, runtime node qui tombait (car je tentais de gérer de l’interprocess), et j’avais accumulé du code franchement pas beau. Bon clairement j’ai pas été bon sur le coup. Javascript étant très permissif, j’ai vraiment mal codé certaines parties et j’ai eut du mal à corriger l’ensemble. Coder des systèmes asynchrones est, certes, génialissime en terme de concept, mais très compliqué à maintenir si, pour N raisons, vous avez une coquille dans l’architecture logicielle.

Je vais calmer le jeu tout de suite: j’adore NodeJS. Mon mini framework marchait, le principe était pas mauvais. Le souci c’est que j’aime coder de manière “modulaire” et avoir des couches de séparation entre mes structures fonctionnelles. Et malheureusement le concept de mon code de gestionnaire de blog était trop éparpillé pour un tel framework sur cette technologie.

Autre souci, et pas des moindres, je ne maitrisais pas bien MongoDB. Depuis j’ai énormément lut et testé et je me suis rendu compte que j’avais vraiment fait n’importe quoi sur le blog.

Aujourd’hui je sais assurer une écriture viable ou une modification de document dans la base. Et ça change la vie.

Mongo, j’en parlerai dans un prochain ticket. Il y a des problèmes qu’un débutant peut rencontrer, ne pas savoir ou simplement imaginer de mauvais concepts. J’ai d’ailleurs utilisé une chose que j’avais laissé de coté sur Mongo: la recherche full-text.

Technos utilisées

J’en parle depuis un moment au boulot, j’adore Go (ou Golang). Ce langage apporte tellement de plaisirs à coder que me suis lancé dans la création d’un vrai framework nommé kwiscale. Ce qui m’a étonné en codant ce framework, c’est que la langage pousse à faire en sorte que tout se passe bien. Si si, vraiment. Pas moyen de faire “n’importe quoi n’importe comment”. On est proche du C, sans en avoir la complexité. On s’étonne à utiliser des pointeurs partout et sans en avoir peur. On s’impressionne à réussir à lancer et synchroniser des “goroutines” (ou coroutine, c’est à dire des tâches parallèles) sans se taper les neuronnes dans le fond du crâne. En clair, ce langage est un pied d’enfer pour un développeur qui cherche à maitriser une grosse batterie modulaire.

A l’inverse de mon framework “maison” nommé “Knotter” en NodeJS, je savais très bien où j’allais, comment j’allais amener la configuration, comment le rendre modulaire.

Je me répète mais… j’adore NodeJS et je ne crache pas sur PHP. J’ai codé près de 10 ans sur PHP et j’ai toujours défendu ce langage. L’idée c’est que Go m’apporte un peu plus de contôle, de maitrise, de bonnes performances et une gestion de la concurrence plus abordable et maitrisable. Je n’ai plus à me poser des questions sur l’implémentation, je me penche quasi essentiellement sur l’algo. Ça change la vie.

Développer ce blog sur le framework Kwiscale m’a pris 3 soirées. Sachant que je gère:

  • la détection de spam via un filtre bayésien et gestion de demande de modération
  • envoit de mails
  • traitement des drafts (pour les tickets)
  • page statique (ficheri markdown)
  • ticket en base Mongo (format markdown)
  • sitemaps
  • flux RSS (au passage j’ai abandonné Feedburner)

et j’en passe… Je reparlerais de Kwiscale dans un autre ticket, le jour où je releaserai une version stable (disons en fin Avril 2015 si tout se passe bien).

Ce qui m’a éclaté c’est la facilité à générer du XML ou du JSON avec ce que Go propose en built-in. Du coup, les flux RSS ou encore les sitemap m’ont pris 10-15 minutes à les réaliser. Un bonheur je vous dis.

Bref, j’utilise Kwiscale et le plugin que j’ai créé pour utiliser le moteur de template Pongo2. Ce moteur m’apporte la possibilité de traiter du markdown très facilement dans les templates, la syntaxe est proche de Jinja2. Pour un développeur comme moi qui a usé Python dans toutes les directions, c’est un gain de temps d’apprentissage non négligeable. Les développeurs PHP/Syfony connaissent aussi cette syntaxe via Twig.

Développer en Go sans recompilation

Go demande une compilation de votre projet (tout comme C/C++ ou Java). L’intérêt est qu’il compile très vite, le temps est quasi négligeable (de l’ordre de la centaine de miliseconde). Du coup Go propose une commande go run ... qui exécute le programme juste après la compilation. Ça donne l’impression d’utiliser un langage interprété, sans en avoir l’arrière gout.

Le souci, c’est qu’il aurait fallut que je relance la commande go run à chaque modification de code.

Gin justement nous affranchit de cette contrainte. C’est un programme en Go qui permet de détecter et relancer la compilation au moindre changement de code. Il agit comme un proxy et transmet les connexions au programme que vous développez. C’est tout bête et ça marche bien.

Il ne me restait que la base Mongo à installer, configurer… mais non, j’ai utilisé Docker !

Je vais pas trop développer le sujet dans ce ticket, mais j’ai trouvé un trio gagnant pour développer sans prise de tête un site en Go:

  • Godep - gère les dépendances Go dans un workspace
  • Gin - un outil qui relance votre code lors d’une modification qui sait utiliser Godep
  • Docker-compose - anciennement “Fig”

En gros, j’ai créé un fichier docker-compose.yml qui lance:

  • un serveur nginx avec la conf montée dans le répertoire /etc/nginx/conf.d
  • la base mongo (avec les data sauvé localement sur l’hôte)
  • une image golang (de base) qui utilise un makefile qui installe ce qu’il faut (2 packages) et lance une commande gin avec l’option qui demande à utiliser Godep.

Toutes les dépendances étant enregistrées via Godep depuis mon host, et ayant “monté” mon répertoire de travail dans le conteneur, le conteneur Go n’avait besoin que de Gin et Godep. Godep se servant du répertoire Godep qui se crée en tapant godep save (je ferai un autre ticket pour ce sujet, patience). Seulement deux pacakges à installer via le Makefile, rien de méchant donc… et pas la peine de le modifier si j’utilise un nouveau paquet dans mon projet. Godep se charge de tout.

Arrivée en production, j’utilise un second docker-compose.yml nommé “docker-compose-prod.yml” qui, lui, n’instancie pas nginx (car j’en ai un sur le serveur qui tape sur d’autres services web) et surtout qui n’utilise plus Gin, juste Godep. Effectivement en production je n’ai pas besoin d’écouter les modifications de code.

Cette fois, il utilise une autre directive du makefile qui ne lance que les commandes:

go get github.com/tools/godep
godep go run main.go

La commande “godep” va simplement spécifier GOPATH au compilateur “go”. c’est à dire le réperoire “Godep” livré avec mon projet. Donc, pour être clair:

  • je déploie depuis ma machine le code + le workspace Godep (qui contient tous les packages nécessaires) avec rsync
  • docker-compose lance les deux instances (mongo et golang)
  • le conteneur golang lance “make prod”
  • le makefile installe godep puis lance le service en utilisant le workspace Gedep via la commande godep go run main.go

Promis, je ferai un ticket sur le sujet. Car je pense que mon modèle est loin d’être mauvais et peut être réutilisé. Je me la pète un peu non ? si… tant pis… soyons fier de ce qu’on réalise parfois !

Comprennez juste que je suis “certain” que ce qui tourne sur mon poste va tourner de la même manière en production.

Et ça, c’est vraiment une révolution

-- ® S.Jobs

Spam

Mon site est fortement spammé. J’ai donc utilisé 2 bloquages:

  • le premier est tout bête, le formulaire de commentaire a plein de champs inutiles qui, s’ils sont remplis, le sont à coup sûr par un robot - le CSS les cache, donc vous, vous ne les voyez pas
  • un filtre bayésien que j’ai codé en 15 minutes - il charge un index de mot depuis les commentaires que j’ai classé en spam et en “commentaire sûr”.

Ce filtre bayésien est sensible, car comme je vous le disais, mon blog à énormément de messages de spam. Du coup, si vous commentez vous avez de forte chance de vous retouver classé en tant que spammeur. Mais pas de panique, Si vous le premier filtre est passé (donc vous n’êtes pas un robot qui a rempli des champs interdits) alors je vous propose sur une page de cliquer sur un bouton pour me signaler l’erreur. C’est automatique, ça m’envoit un mail, et j’ai plus qu’à valider votre commentaire.

Le commentaire devenant “sûr”, il entre dans le jeu de données “message non spam” (qu’on appelle “ham”). La prochaine fois, qu’un commentaire arrive, votre commentaire est aussi utilisé pour la vérification. C’est le principe de Bayes, la probabilité “à posteriori”. Ça marche pas mal.

Plus vous commentez, plus le filtre est fiable.

Reprise de contenu, le cauchemard

Par contre, la reprise de contenu m’a pris une bonne semaine… et le pire c’est que c’est toujours pas bon.

La base utilisée est toujours “Mongo”. J’ai implémenter un moteur de recherche full text en partant de ce que propose MongoDB. Dans les prochains jours je parlerai de quelques aspects de MongoDB souvent négligés, voir des erreurs de base qu’on peut faire (et que j’avais fait avec mon ancien système de blog)

Finalement, ce qui m’a pris le plus de temps, c’est de récupérer le contenu du site “ancienne version”. Et je dois bien avoué que j’ai baissé les bras à un moment donné. En effet, sous Copix j’utilisais une syntaxe “wiki” spéciale qui est très compliqué à transformer en Markdown. Du coup, les vieux messages ont de sérieux soucis… pour ceux tapés en RST ça a été plus simple (merci à Pandoc).

J’ai corrigé les tickets les plus lut… mais je sais qu’une passe complète ne sera jamais possible. Tant pis…

Les anciennes URL

Restait un point qui me faisait grogner, j’ai modifié la forme d’url et la forme du slug (le titre rendu lisible dans l’url). Avant, la date du ticket apparaissaient dans l’url et j’ai décidé (à tort peut-être) de m’en passer. D’abord parce que je trouve pas ça beau, que la date apparait dans la page et enfin parce que j’ai utilisé un truc pour ne pas avoir de doublon de slug. Donc, inutile à mon gout.

Mais voilà… certains ont bookmarké quelques unes de mes pages. Il y a même quelqu’un qui a référencé un de mes tickets dans Wikipedia (pour Gstreamer), et la forme d’url a changé. Google va se plaindre, ça m’embêtait vraiment. La solution a été finalement simple. Ne sachant pas reproduire les vieux slug, j’ai décidé de ruser.

Je prend un slug, je vire les tirets: ça me donne une liste de mots. Je lance une recherche full-text dans Mongo. Sachant que le titre correspond au slug, et que le titre a un poids important dans mon indexation (par rapport au contenu), je suis sûr à 99% que le premier résultat que me retournera la recherche est le ticket initial. Une réponse “HTTP Permanent Redirect (301)” et le tour est joué.

Style CSS, en avant flexbox !

Exit Bootstrap ou Skeleton. Non pas que je ne les aime pas, mais ce blog est là pour que je teste des technos et que je donne des idées, des solutions et des méthodes. Bootstrap est génial, Skeleton est vraiment cool, mais CSS apporte depuis quelques temps la gestion de “boites flexibles” qui permet de réduire le travail.

Du coup, j’ai tenté le coup. À mon grand étonnement, j’ai put sortir ce que je voulais: un design responsive en 205 lignes de CSS tout compris.

Ok, Internet Explorer < 10 va me taper une gueulante, mais IE ne représente que 4% de mon auditoir. Par contre, ça marche bien sur Android (tablette et mobile).

Question couleur, j’adore les couleurs “sombres”. J’ai utilisé la couleur du gopher (en haut à droite du site) pour les liens (merci à mon épouse pour l’idée) et je pense que ça reste sobre, lisible et pas aggressif.

Bilan

Golang est vraiment un langage prêt pour la production. Kwiscale approche de son but et mon blog fonctionne largement mieux qu’avant.

Je suis plutôt content du résultat et je vais pouvoir réécrire des tickets plus régulièrement.

Ça peut vous intéresser aussi


Go-Pipe, streamez à la unix/like en Go

Vous connaissiez les “pipelines” de Gulp, et bien voici celles ...


Créer une API en GO avec Gorilla

Bon, on va parler Go ou Golang (faudra me dire ...


JWT en Go

Vous avez envie de gérer l’autorisation de vos API ...


Golang, comment définir un destructeur

Si vous avez un peu bourlingué sur Go, vous savez ...

Merci de m'aider à financer mes services

Si vous avez apprécié cet article, je vous serai reconnaissant de m'aider à me payer une petite bière :)

Si vous voulez en savoir plus sur l'utilisation de flattr sur mon blog, lisez cette page: Ayez pitié de moi

Commentaires

Ajouter un commentaire

Ajouter un commentaire

(*) Votre e-mail ne sera ni revendu, ni rendu public, ni utilisé pour vous proposer des mails commerciaux. Il n'est utilisé que pour vous contacter en cas de souci avec le contenu du commentaire, ou pour vous prévenir d'un nouveau commentaire si vous avez coché la case prévue à cet effet.