Les controleurs de version

Le contrôleur de version

Introduction

Bonjour,

J’utilise des contrôleurs de versions depuis quelques années déjà.

  • CVS en 2004 jusqu’à 2006
  • SVN de 2006 à ce jour
  • GIT de 2015 à ce jour

Celui que je maîtrise le plus est bien entendu SVN, vu que je l’ai utilisé plus de 10 ans, et oui j’ai sauté dans le train Git en retard.

Il serais intéressant de discuter de la façon dont j’utilise le controleur de version.

Le contrôleur de version ce n’est pas :

Je vais commencer par dire ce que ce n’est pas fait pour : Sauvegarder ses données.

Il faut absolument mettre Git ou Svn sous une gestion de sauvegarde (appelé communément backup). Mettre son code source sous contrôle de version ne le sécurise pas. Même si c’est sur un site comme github ou bitbucket. Il faut faire une sauvegarde régulière sur au moins un environnement que vous maîtrisez (non, l’ordinateur portable n’est pas un environnement maîtrisé). Je devrais songer à faire un billet sur les sauvegardes.

Alors, c’est quoi le contrôle de version ?

Gestion des conflits

La chose la plus importante pour moi, c’est la gestion des conflits. Il est loin, mais toujours présent dans mon esprit, le temps où travailler à 2 sur un même projet impliquait écrasement des changements d’autrui par mégarde. Les corrections mineures perdues d’une mise en production à une autre parce qu’on écrase tous les fichiers.

Le contrôle de version, est la pour dire « Attention, le fichier que tu veux écraser a été modifié, prend le temps de regarder ». Plus aucun changement n’est perdu de façon involontaire. On vérifie, on gère les changements des autres avec les notres et ça roule.

Gestion des tâches

Le 2ème problème que le contrôleur de version corrige, c’est les copies pour chaque tâche. On commence une tâche, on ne la finit pas qu’il y en a une autre plus urgente. On copie le répertoire original, on commence la 2ème tâche, et une 3ème urgence, etc…

On se retrouve avec une dizaine de copies, et on ne sais plus laquelle est la plus à jour. Avec le contrôleur de version, on fais une branche par tâche et on garde trace des dates, des changements déjà effectués etc.

Pour ne pas se perdre, il faut garder une structure propre, c’est à dire supprimer les branches qui ne sont plus actives (après avoir fusionné son contenu dans la branche principale).

Gestion de l’historique

Certains pensent que c’est la chose la plus importante, pour moi, elle vient en 3ème position. Le code source versionné c’est un historique de son évolution. Soyons francs, personne ne visite le code pour en connaître le cheminement.

Là où cette fonctionnalité devient utile, c’est lorsqu’on a l’impression qu’un bug réapparaît alors qu’on est sûr de l’avoir corrigé.

On regarde la dernière version qui ne contient pas le bug et on regarde comment la correction à été écrasée. On récupère le patch et on l’applique à la version courante.

Autre utilisation

Une utilisation intéressante du contrôleur de version est pour les bases de connaissance.

J’ai un fichier qui s’appelle symfony.txt, il contient tout ce que je sais sur symfony : Installation, cheat sheet, problèmes principaux, etc.

Pour gérer les différentes versions de symfony, je pourrais faire des paragraphes dans le même fichier. Le problème c’est qu’il ne fera que se rallonger et il y aura beaucoup de duplication.

Une autre solution, serait d’avoir un fichier par version de symfony. Le problème des fichiers à rallonge est réglé, mais je vais surpeupler mon répertoire, en plus, il faudra modifier tous les fichiers si un problème touche plusieurs versions.

La solution que j’utilise c’est avec le contrôleur de version. Je met un tag par version principale du fichier. Je remonte dans la bonne version grâce aux tags. Je n’ai qu’un fichier, et aucune redondance. Quand une nouvelle version de symfony sort, je met un tag.

La difficulté viens si j’ai une correction sur une version qui n’est pas la dernière. Je vais sur la version concernée. J’applique les changements et je les propage sur toutes les versions ultérieures. Si la solution n’est plus pertinente sur une autre version, j’y vais et corrige et repropage.

Ainsi j’ai une base de connaissances qui est simple à utiliser.

Bien sur, un outil dédié aux bases de connaissances serait plus adapté, mais j’utilise cette méthode et elle fonctionne bien. Laissez un commentaire si vous avez des suggestions.

Conclusion

Même quand on travaille seul, il est indispensable d’utiliser un contrôleur de version. Sur mon ordinateur, j’ai un serveur svn qui gère la plupart de mes travaux. Les plus récents sont sous git.

Si vous utilisez de façon intéressante les contrôleurs de versioin, n’hésitez pas à commenter.

Utiliser plusieurs versions de jQuery simultanément

Bonjour,

Aujourd’hui encore, beaucoup de projets utilisent jQuery.

Malheureusement, jQuery ne garde pas une compatibilité ascendente, on peut donc avoir des projets qui ne marchent qu’avec une version précise.

Bien sûr, si j’en parle, c’est que j’en ai fais les frais.

Eh bien, j’ai du utiliser 2 composants qui dépendaient de 2 versions incompatibles de jQuery.

Après quelques recherches, j’ai trouvé la solution :

On peut renommer sur pour une des 2 la variable ‘$’.

var $j = jQuery.noConflict(true);
$j(function() {
   $j('.datepicker').datepicker({
      onSelect: function() {
         update(this);
      }
   });
});

La commande noConflict, ordonne à jQuery de ne plus utiliser l’alias $.

C’est la dernière instance chargée qui est effacée. On récupère l’instance dans une variable que l’on peut utiliser en place de ‘$’ ou ‘jQuery’.

La première instance est celle qui peut utiliser ‘$’ et ‘jQuery’.

Avec cette méthode, on peut utiliser autant de versions de jQuery que l’on veut. Il faut juste faire attention à l’ordre de chargement des scripts.

Idée sur les sites multilingues

Bonjour,

La traduction d’un site est un casse tête. Différents frameworks proposent différentes solutions.

Et si je devais construire un module de traduction sans me soucier de ce qui existe déjà ? Comment je verrais la chose ?

Voici mon idée :

Je mettrais en place une structure de base de données qui permet d’avoir autant de langues que l’on veut. Aucune langue n’est obligatoire ni aucune par défaut. C’est l’application qui fera un choix en « requêtant » la base de données.

La clé pour un texte ressemble a une variable et non a un texte.

Voici un exemple de chaque :

echo trad("client.lister");
echo trad("Lister les clients");

La fonction trad fait la traduction et rapporte les manques :

Si une clé n’existe pas dans la base de données, on la crée et on ne lui donne aucune traduction.

Si une clé existe mais pas de traduction dans la langue courante, l’application décidera quoi faire : Afficher la clé, une erreur ou le texte dans une autre langue. De plus, un flag dans la base de données est positionné afin de savoir qu’une traduction manque.

Pour accélérer la traduction, on peut exporter la base de données dans plusieurs fichiers PHP (un par langue) contenant un tableau des traductions.

Enfin, un portail admin permet de voir les clés demandées sans traduction et de les traiter. Quand on valide toutes les traductions, les fichiers PHP (si l’accélération est activée) sont re-générés.

Voilà pour les grandes lignes. Si vous avez aussi des idées sur une implémentation plus aboutie, mettez les en commentaire.

Les chemins vers les fichiers en php

Bonjour,

Voici un sujet qui me donne pas mal de soucis quand je veux faire une application web.

Comment écrire ses chemins ?

Il y a plusieurs façons de procéder et je vais donner mon avis sur chacune d’elles.

Contexte

Il faut d’abord savoir dans quel contexte on est. Le contexte dans ce cas est l’environnement qui va résoudre le chemin.

On peut distinguer 3 contextes différents :

Le contexte php : C’est PHP sur le serveur qui va résoudre le chemin et consommer le fichier.

Le contexte http de la page : C’est le navigateur qui va demander le fichier et il connaît l’url en cours.

Le contexte externe : On ne connaît rien sur l’adresse du fichier à atteindre. Quand on est dans un mail par exemple.

Invocation

Dans le contexte de PHP

On peut invoquer un fichier de plusieurs façons :

! J’ai choisis la commande include, mais toutes les autres invocations marchent de la même façon pour les autres types d’inclusion

Chemin aléatoire
include "../chemin/fichier.php";

C’est une inclusion relative au chemin courant.

Cette méthode marche mais on ne sais pas toujours quel fichier est utilisé à cause de sa méthode de résolution cf doc.

On se met à dupliquer les fichiers pour être sûr de l’inclure sans se prendre la tête à comprendre la résolution de PHP.

Chemin relatif
include __DIR__."/../chemin/fichier.php";

On donne ici le chemin absolu dans l’arborescence du serveur, mais dans notre tête, c’est un chemin relatif au fichier courant.

C’est la méthode que je privilégie car il devient simple de retrouver son chemin 🙂

Chemin absolu
define("_ROOT", __DIR__."/../cheminVersRoot");
include _ROOT."/cheminDepuisRoot/fichier.php";

! Les 2 lignes ci-dessus sont dans 2 fichiers différents, généralement config.php pour la 1ère.

Ici aussi on donne un chemin absolu sur le serveur à PHP, mais dans notre tête, on donne un chemin absolu depuis la racine du projet.

C’est une solution qui fonctionne bien et qui avait son avantage à l’époque où on avait l’url qui reflétait la structure des fichiers.

Dans le contexte HTTP de la page

Pour illustrer ce contexte, j’utiliserais une balise img (et sans les attributs obligatoires).

Chemin relatif
<img src="../chemin/fichier.png">

C’est un chemin relatif, ça marchait à l’époque où le fichier php avait le même chemin que l’url pour y accéder. Depuis la réécriture d’url, c’est une technique qui ne fonctionnera pas sans y laisser ses cheveux.

Chemin absolu
<img src="/chemin/fichier.png">

C’est la méthode que j’utilise, elle a l’avantage de donner un chemin absolu par rapport à la racine du projet.

Chemin externe
<img src="http://www.domaine.com/chemin/fichier.png">

Le travail et la maintenance deviennent un vrai casse tête, il faut être certain d’avoir modifié les chemins du serveur local avant l’envoi etc.

Chemin externe aidé par PHP
define("_HTTP_ROOT", "http://www.domaine.com");
ou (pire) define("_HTTP_ROOT", $_SERVER["HTTP_HOST"]);
<img src="<?= _HTTP_ROOT ?>/chemin/fichier.png">

! Les 2 lignes ci-dessus sont censées être dans 2 fichiers différents
! J’ai choisi HTTP_HOST mais SERVER_NAME marche tout aussi bien, mais il faut faire attention avec ces variables

On essaie de pallier au problème ci-dessus en n’ayant qu’une constante à modifier, mais il faut quand même penser à la modifier avant l’envoi.

Dans le contexte externe

La meilleure solution est le chemin externe décrit ci-dessus.

On peut néanmoins avec quelques précautions utiliser les variables dans $_SERVER.

Conclusion

Les chemins sont toujours un casse tête en PHP. Avec un peu de rigueur et en utilisant la bonne forme, on peut s’en sortir.

Je n’ai pas mis tous les dérivés de chemins que j’ai pu utiliser mais seulement un échantillon. Si vous avez une suggestion intéressante que j’aurais oublié n’hésitez pas à la mettre en commentaire.

Principe DTF (don’t fear typing)

Bonjour,

Aujourd’hui je vais parler d’une règle que je m’impose et que j’ai appelé DTF (don’t fear typing).

Copier-coller

Il y a beaucoup de cas où on est tenté d’utiliser le copier-coller. C’est une très mauvaise habitude et pratiquement tous les bugs viennent de là.

La tentation est très grande. On a un bloc qui fait presque le boulot ailleurs. Il suffit juste de le copier et de l’adapter.

Bien sûr, on le fait et on est sûr que tout c’est bien passé car il n’y avait que 4 occurence d’une variable à changer. On pousse directement en production.

C’est la catastrophe, le script marche une fois sur 2.

Si on est tenté de copier un bloc, il vaut mieux le retaper et se refaire l’algorithme dans sa tête au fur et à mesure de sa reconstruction. Investir un peu plus de temps en développement, c’est éviter d’en perdre en débogage.

Commentaires

Un autre cas de DTF arrive quand il faut commenter une section. On ne prend pas la peine de décrire le fonctionnement. Quelques jours plus tard, on ne peut plus modifier ce code car on ne se souvient plus de son fonctionnement et qu’il est trop compliqué pour s’en refaire une idée en simple lecture.

Quelques commentaires qui décrivent l’idée générale d’une fonction peut aider à la maintenance du code.

Attention, la pire chose que de ne pas commenter c’est d’avoir un commentaire faux.
Il faut maintenir les commentaires. Quand on modifie le code, on met à jour le commentaire !

Nommage

Le nom des fonctions et des variables n’ont pas de limite restrictive. On peut donc avoir des fonction de plus de 30 caractères. Si toutes les fonctions et variables ont un nom à rallonge, ça ne va pas aider à la lisibilité. Cependant, mettre que des noms courts n’aide pas non plus.

Il faut viser le juste milieu en ayant une combinaison de 3 mots tout au plus qui définissent au mieux la fonction ou la variable.

Il ne faut pas avoir peur de transgresser la règle pour avoir une meilleure lisibilité. On peut très bien avoir une boucle très courte avec « i » comme variable d’itération.

Conclusion

Il ne faut pas avoir peur du clavier, taper quelques caractères en plus peut faire gagner beaucoup de temps dans le long terme. Commenter quand c’est nécessaire, choisir le nom de ses fonctions et variables et ne jamais copier-coller.

Détecter l’environnement de php

Bonjour,

J’ai eu besoin de connaître l’environnement de Php. C’est à dire savoir si c’est en environnement web, en ligne de commande directe, ssh ou via cron.

Je n’avais pas besoin de plus de détail, mais il fallait que ce soit fiable.

Comme d’habitude, une recherche sur stackoverflow donne plusieurs réponses. Je fais le tri et ne trouve rien qui marche bien pour mon cas. Mais une bonne piste que j’ai creusé.

Je me retrouve donc avec ceci :

php_sapi_name()=="cli"?(isset($_SERVER["TERM"])?"cli":(isset($_SERVER["SSH_CLIENT"])?"ssh":"cron")):"web";

Ce one-liner renvoie :

  • « web » en environnement web
  • « cli » en ligne de commande directe
  • « ssh » via ssh
  • « cron » quand il est lancé via cron

Ce script m’a été très utile et marche bien dans un environnement linux. Si vous avez l’occasion de le tester sur un autre système, n’hésitez pas à commenter sur votre expérience.

Utiliser screen

Bonjour,

Quand j’utilise ssh, ma hantise c’est de perdre la connexion. En effet, les processus sont attachés à la session ssh, donc toutes les tâches en cours sont stoppées par le système dès que la console ne répond plus.

Une solution simple est screen. C’est une application qui abstrait la console. On peut donc se détacher et se rattacher sans que les tâches ne soient perturbées.

On peut se rattacher à une console screen depuis n’importe où. Pas besoin d’être sur le même ordinateur que celui qui a créé l’instance.

Voici un petit exemple d’utilisation de screen.

Créer une instance :

screen -S moninstance

moninstance est un identifiant comme le prenom, on peut créer une instance sans préciser l’identifiant mais on obtiendra un identifiant numérique difficile à retenir et qui peut prêter à confusion si on est plusieurs à utiliser screen.

Se détacher quand on est dedans :

<ctrl> a d

on peut aussi fermer la fenêtre du terminal pour se détacher 🙂

Lister les instances :

screen -ls

Détacher une instance attachée à un terminal :
Il est préférable de détacher une instance qu’on sait attachée à un terminal fantôme, sinon on expulsera l’utilisateur en cours.

screen -d moninstance

Se rattacher à une instance qui n’est attachée à personne :

screen -r moninstance

On peut combiner les flags :

screen -dr moninstance

La commande ci dessus, détache moninstance et la rattache a mon terminal.

Voilà les bases de l’utilisation de screen. J’ai parlé de ssh mais on peut utiliser screen sur un terminal local. Ca évite de garder une fenêtre ouverte sur le bureau. On peut lancer une tâche en local puis vérifier qu’elle tourne toujours via ssh.

Utiliser Mysql en tant que back-end pour libreoffice base

Bonjour,

Ms access est la solution qui me vient à l’esprit quand je dois faire une base de données que je serais seul à utiliser. Parmi les points forts, on peut citer :

  • Transportable
  • On peut l’ouvrir sur quasiment tous les ordinateurs Windows
  • Facile à utiliser

On peut faire tout ce que l’on veut quand on a appris à contourner certains bugs.

Malheureusement, depuis plusieurs années, je suis sous Linux et je m’interdit d’utiliser wine car il pollue les fonctionnalités natives de l’environnement de travail.

Il reste les machines virtuelles quand je dois utiliser Windows. C’est stable, rapide et on peut transférer les fichiers entre la machine hôte et la machine invitée.
Mais, c’est une solution très gourmande en RAM et HDD. C’est pourquoi, j’ai cherché une alternative.

Mes exigences pour un remplaçant sont assez faibles :

  • Gérer les tables
  • Gérer les vues
  • Faire des formulaires
  • Faire des états
  • Intégrer un langage de script
  • Comprend SQL

C’est tout. Il ne doit pas être compatible avec quelqu’autre logiciel, ni importer ou exporter dans un format particulier.

Libreoffice base est le candidat idéal. Il a tout ce qu’il faut.

Les premiers essais sont concluants et je décide de faire ma base de données avec.

Au bout de quelques jours, la base de données est corrompue, le fichier ne veut pas s’ouvrir. Heureusement que je sauve tous mes travaux personnels dans un repository svn. Un petit retour en arrière, on réinsert les données et ça roule.

Rebelotte, quelques jours après, nouvelle corruption. C’est la cata, libreoffice correspond à mes besoins mais son système de stockage est trop fragile.

Qu’est ce qui a fait ses preuves en matière de base de données ? Mysql.
Je décide donc de chercher un moyen d’avoir un front end libreoffice pour sa simplicité d’utilisation et son esthétique et de l’utiliser par dessus une base de données mysql pour la robustesse.

Voici donc la procédure

  • installer le connecteur mysql
sudo apt-get install libreoffice-mysql-connector
  • choisir le driver mysql
  • choisir connecter directement

Les autres options ne sont pas aussi facile à mettre en place.

Résultat, j’ai un front end plaisant avec un back end en béton.
Mais cette solution n’est pas pour moi :

  • On perd la transportabilité
    On ne peut plus enregistrer sa bdd sur clé Usb et l’ouvrir ailleurs, faire une exportation puis une importation mysql n’est pas idéal.
  • On perd la simplicité
    Il faut installer un paquet, installer un serveur de base de données, créer une base de données mysql pour chaque projet.
  • On perd l’universalité
    Ce n’est pas important pour moi, mais, on ne pas se dire qu’on a 90% de chances de trouver libreoffice + mysql sur un pc.
  • Il faut insérer le mot de passe à chaque ouverture du fichier
    Il y a surement moyen de l’enregistrer mais ce n’est pas directement avec une case à cocher lors de la création du projet.
  • On perd l’utilisation concurrente
    Mysql est fait pour une utilisation via une interface web et accepte une utilisation simultanée sur plusieurs postes. C’est un avantage qu’on ne gagne pas parce qu’on est limité par l’interface mono-utilisateur de libreoffice.
  • On ne gagne pas en stabilité
    Les fichiers ne sont plus corrompus mais ça plante trop souvent. Et ce n’est pas à cause du fichier qui grossit, vu qu’on le décharge du stockage des données.

Même si c’est une piste que j’ai pris plaisir à investiguer, je ne retiens pas libreoffice base, seul ou couplé avec un back end, comme une solution viable quel que soit le projet. En attendant d’avoir mieux, je vais créer une interface web + mysql pour tous mes projets perso.

Faire un watcher en javascript

Introduction

Bonjour,

Récemment, j’ai vu un tutoriel sur vue.js.
Il y a un concept qui m’a plu, c’est celui du binding.

En gros, on attache une variable à un contenu puis le contenu se met a jour automatiquement quand la variable change. Ce n’est pas a double sens, par exemple si le contenu est un input, la variable ne change pas quand on modifie le champ.

Je voulais recréer ce comportement en javascript et j’ai décidé d’appeler ça un watcher.

Implémentation

La syntaxe doit être simple et élégante. Voici comment j’aimerais utiliser le watcher :

<!DOCTYPE html>
<html>
 <head>
 <title>watcher</title>
 </head>
 <body>
 Exemple d'un watcher sur une variable.<br>
Tout ce qui est écrit dans ce champ sera répercuté immédiatement dans les instances dessous.<br>
 <input oninput="toto.valeur=this.value;"><br>
 Voici une instance : <span bind="toto"></span><br>
 Encore une : <span bind="toto"></span><br>
 Et une autre : <span bind="toto"></span><br>
 Allez, une dernière : <span bind="toto"></span>
 </body>
</html>

L’input sert à modifier la variable toto. un attribut bind= »toto » attachera l’élement à la variable toto.

Pour que tout se passe automatiquement, il faut utiliser get et set. Malheureusement, cela ne marche qu’a l’intérieur des objets. Il faudra donc que toto soit un objet.

Voici le script pour effectuer la magie :
On peut copier directement ce code avant </body>

 <script>
 var toto = {
 watcher : [],
 _valeur : "",
 get valeur () {
 return this._valeur;
 },
 set valeur(argValeur) {
 this._valeur = argValeur;
 for (i=0 ; i < this.watcher.length ; i++) {
 this.watcher[i].innerHTML = argValeur;
 this.watcher[i].value = argValeur;
 }
 },
 watch : function (argElement) {
 toto.watcher.push(argElement);
 }
 };
 elements = document.querySelectorAll('[bind=toto]');
 for (i=0 ; i < elements.length ; i++) {
 toto.watch(elements[i]);
 }
 </script>

Sans utiliser de champ input, on peut modifier la variable directement en javascript de la façon suivante :

toto.valeur="coucou";

Attention !

La variable toto.valeur n’est pas sanitisée, il ne faut donc pas l’utiliser directement comme ci-dessus.

Conclusion

C’était juste pour reproduire un comportement qui paraît « magique » au premier abord et d’en comprendre la mécanique.