Comment stocker les configurations d'accès aux environnements de façon sécurisée

icon Tags de l'article : , , ,

Septembre 13, 2019
Bonjour à tous et toutes,

Aujourd'hui on va parler fichiers de configuration, variables d'environnement, stockage, sécurité et contrôleur de source.

Quand je parle de variables d'environnement, je parle par exemple des identifiants pour se connecter à la BDD, des clefs analytics, ou encore d'autres identifiants critiques.
Il s'agit en général de variables que les développeurs doivent posséder pour les environnements intermédiaires (développement, qualification, préproduction) mais pas pour certains environnements (production, analytics, BI, etc.).
Ces variables sont, en général, stockées dans un gros fichier de configuration qui sera utilisé par le logiciel pour ses différentes connexions.

Du coup la question qui revient à CHAQUE fois : comment stocker de façon sécurisée quelque part ces variables, afin que les développeurs puissent y avoir accès facilement, sans pour autant les rendre récupérables par n'importe qui de passage dans la société ?
Exit donc la feuille collée au mur avec les mots de passe.

Dans ces 5 dernières années, je suis passé par plusieurs solutions :
  • Le service production/exploitation qui s'occupe lui-même de renseigner les clefs de production dans le fichier de configuration. Avantage : sécurité, inconvénient : mise à jour des clefs de configuration ultra complexe. (on doit spécifier à chaque fois les champs ajoutés, les champs modifiés, les champs supprimés, etc. et les fails arrivent souvent)
  • Les développeurs ont toutes les clefs de tous les environnements, et ils les remplacent eux-même pour faire des builds en production. Avantage : simple, inconvénient : sécurité très faible.
  • Les fichiers de configuration sont archivés avec la solution. Avantage : ultra simple, inconvénient : aucune sécurité, n'importe qui ayant accès aux sources a accès à tous les environnements.
  • Les clefs sont enregistrés dans un keepass archivé avec la solution, et seules les personnes concernées connaissent son mot de passe. Avantage : sécurité, inconvénient : très chiant à modifier et saisie constante du mot de passe.

Afin de simplifier les choses sur le projet sur lequel je suis, j'ai proposé la solution suivante :
1) Nous avons un fichier config.zip archivé et chiffré avec mot de passe à la racine du projet
2) Nous avons développé un script nommé init.sh, qui a pour mission d'initialiser le projet.
3) Lorsqu'on lance le script init.sh, il va se charger :
  • De vérifier les versions des packages globaux installés (par exemple les versions de NPM, d'Ionic, de Cordova, ...)
  • De demander le mot de passe du fichier config.zip
  • De dézipper le fichier config.zip grâce au mot de passe renseigné, pour récupérer le fichier de configuration .config
  • De supprimer tous les dossiers générés (nodes_modules, www, plugins, etc.)
  • De lancer les commandes nécessaires à l'initialisation du projet (npm i par exemple)
4) Nous avons ajouté une commande "zip:config" qui sert à chiffrer notre fichier de configuration (en saisissant à nouveau le mot de passe)
5) Nous avons ajouté dans le gitignore notre fichier de configuration.

Ainsi, nous pouvons archiver le fichier config.zip qui n'est dézippable qu'avec le mot de passe.
Dès qu'une personne doit mettre à jour le fichier de configuration, elle fait un "npm run zip:config", tape le mot de passe, et archive ensuite le nouveau fichier config.zip.
Dès qu'une personne change de branche ou merge la branche principale dans sa branche, elle a juste à faire un "npm run init", puis de saisir le mot de passe.

Cette solution nous permet de garder un process très simple sans pour autant sacrifier la sécurité du projet !

Voici le fichier init.sh que nous utilisons :

#!/usr/bin/env bash
expectedIonicVersion="5.2."
expectedCordovaVersion="9.0."

echo "Config file password (ask your colleagues):"
read -s password

ionicVersion="$(ionic -v)"

if [[ "$ionicVersion" != "$expectedIonicVersion"* ]]; then
    echo "Wrong Ionic version, you need to install the $expectedIonicVersion"
    exit;
else
    echo Ionic version OK"
fi

cordovaVersion="$(cordova -v | cut -c-5)"

if [[ "$cordovaVersion" != "$expectedCordovaVersion"* ]]; then
    echo "Wrong Cordova version, you need to install the $expectedCordovaVersion"
    exit;
else
    echo "Cordova version OK"
fi

unzip -o -P "$password" config.zip > /dev/null
if [[ $? == 0 ]]; then
  echo "Successfully unzipped the .env file"
else
  echo "Wrong Password for env file"
  exit;
fi

echo "Now removing generated folders..."

rm -rf ./node_modules/
echo "nodes_modules folder removed"

rm -rf ./plugins/
echo "plugins folder removed"

rm -rf ./platforms/
echo "platforms folder removed"

rm -rf ./www/
echo "www folder removed"

npm i

Enfin, voici les commandes qu'on peut trouver dans notre package.json :
{
  "scripts": {
    "zip:config": "zip -o -re config.zip .config",
    "init": "./build-scripts/init.sh"
  }
}

A noter :
  • zip -o -re target origin permet de zipper un fichier de façon chiffrée en demandant un mot de passe
  • read -s password dans le fichier .sh permet de lire un texte saisi sans qu'il s'affiche à l'écran
  • unzip -o -P "$password" config.zip > /dev/null permet de décompresser et déchiffrer le fichier config.zip à l'aide du mot de passe récupéré préalablement
  • Si vous voulez gérer plusieurs fichiers de configuration, par exemple pour l'environnement dev & l'environnement de production, vous pouvez avoir un fichier dev.config.zip et prod.config.zip, et deux scripts d'initialisation, chaque zip ayant son propre mot de passe. Ainsi seules les personnes habilitées pourront dézipper le fichier prod.config.zip :)

En espérant que ça vous soit utile, bon dev à tous et toutes !

Exposition d'un jeu, AMOUR, au Numerik Games d'Yverdon

icon Tags de l'article : , , ,

Septembre 06, 2019
Hello tout le monde,

Une fois n'est pas coutume, j'avais envie de communiquer sur un évènement ultra cool auquel j'ai pu participer ce weekend : le Numerik Games d'Yverdon !

Il y a 2 mois j'ai participé à une Game Jam (un genre de hackathon sur le thème du jeu vidéo) à Neuchâtel : l'Epic Game Jam.
Avec un collègue et 2 connaissances à lui, on a développé (via Unity3D) un petit jeu de combat basé sur des formes.
Une sorte de Pierre Papier Ciseaux meets Smash Bros jouable à quatre.

L'idée était d'avoir 3 formes, carré, triangle & rond, et que ces formes correspondent aux boutons de la manette de Playstation. Chaque forme était destinée à absorber la suivante (le carré absorbe le triangle, le triangle absorbe le rond, et le rond absorbe le carré).
Le thème de l'Epic Game Jam était en effet que les jeux ne devaient pas contenir de notion de "mort". Et quoi de mieux qu'une fusion des joueurs pour symboliser ça ?
Nous avions donc nommé le jeu AMOUR.

Du coup quelques caractéristiques :
  • L'objectif du jeu était de créer un jeu de combat simple, auquel on peut jouer à 2, 3, 4 et où tout le monde peut s'amuser et gagner
  • Même vaincu, un joueur n'arrête pas de jouer. En effet, à 3/4 joueurs, si le joueur qui vous a absorbé se fait absorber à son tour, il vous "recrache" au passage !
  • L'idée des formes qui match avec les boutons des manettes de Playstation avait pour objectif de simplifier l'assimilation des contrôles.
  • Le jeu peut vite virer en chaos en sans nom, surtout à 4, mais il reste très fun et parfois un joueur gagne sans le vouloir en mode euh il s'est passé quoi ?
  • Le changement de forme a un cooldown de 2 secondes, rendant le joueur vulnérable (si on change en triangle pour manger un rond, un carré qui arrive dans notre dos peut nous avoir)
  • Le jeu est aussi fun en duel, car tout se joue à la forme choisie au moment du contact... du coup il faut anticiper, calculer, choisir si on fonce ou si on esquive, etc.

Voici le jeu à la fin :


Il faut maintenant savoir qu'un des prix de cette Epic Game Jam était que le jeu qui s'y prêterait le plus serait exposé au Numerik Games d'Yverdon, projeté sur un immeuble !

Et c'est notre jeu qui a été choisi au final !

Nous avons donc pu continuer de travailler sur le jeu (en retravaillant les couleurs et en faisant des tests) afin de le rendre le plus adapté à cet évènement.

Voici le résultat final :


Et enfin, projeté sur un batiment au Numerik Games :


Quelques photos en plus :


Avant l'installation


Les bornes d'arcade derrière nous


Les premiers testeurs


Avec des transats, c'est mieux !


VICTOIRE !


Quand les gens n'osaient pas demander, les transats étaient tristes.

C'était une véritable expérience, d'abord la Game Jam, puis tout ce qui a suivi, le rush pour finaliser le jeu, le modifier pour qu'il s'adapte au support, faire fonctionner les nouvelles manettes (à 18h les manettes ne marchaient pas... alors qu'à 21h le jeu devait être installé et jouable !).

J'espère avoir l'occasion de continuer sur ce jeu, mais aussi à travailler sur d'autres jeux. Je commence à me débrouiller pas mal sur Unity ;)

Encore un grand merci à David Javet et aux organisateurs de l'Epic Game Jam !

Je ferai sûrement un autre article à l'occasion pour parler un peu plus de tout ce qu'implique ce genre de projet, de ce qu'on a réussi, ce qui a été difficile, les pièges dans lesquels il faut éviter de tomber, etc.

A suivre,

Bon dev à tous et toutes !

(A noter que c'est article n'est pas sponsorisé, évidemment)

Journée de travail, ou journée au travail ?

icon Tags de l'article :

Février 25, 2019
It's story time !

Je vais vous raconter une petite histoire, en écho à cet article qui explique qu'un employé anglais ne travaille en moyenne que 2h53 par jour.

Contexte : j'étais dans mon entreprise depuis 3 ans. Chef de projet technique, je manageais une équipe de 4 développeurs sur le même projet depuis 2 ans et demi.
Nous travaillions en SCRUM, et notre vélocité oscillait entre 37 points et 42 points par sprint. Elle était donc assez stable.
Mon équipe travaillait, elle, 8h par jour. De 9h30 à 12h, et de 13h à 18h30.
Nous partagions un grand openspace avec 2 autres équipes. Openspace d'environ 60/70m² où nous étions 16/18 selon les jours (autant vous dire qu'on se marchait dessus, et qu'on avait très souvent le casque sur les oreilles).

Sauf que voilà, un jour, on a dû changer de locaux. Comme on était sur un projet un peu à part, et comme la place manquait, on s'est retrouvés dans un bâtiment à l'écart.
Mais on était bien mieux ! Openspace de 70/80m² juste pour notre équipe de 8 (avec le nouveau manager et la personne du marketing qui nous ont rejoint).
Une salle de réunion rien qu'à nous (elle n'était pas sur le système info, et on la réservait avec des post-its).
Et la salle CE à côté de nous, avec la Playstation 4 en libre accès.

Autant vous dire qu'on a pris nos aises.
L'équipe a commencé à faire de plus grosses pauses le midi. A aller jouer à Fifa entre midi et deux. A retourner jour à la console à 18h00 pile.
On a même commencé à jouer au ping pong dans la salle de réunion le midi (vive le filet Artengo). On a même parfois fait du Minecraft, du Don't Starve Together ou du Smash Bros sur la TV de la salle de réunion !
Du coup, l'équipe ne travaillait plus 8h par jour, mais 6h30 (9h30/12h, 14h/18h).

Là vous vous dites : mais merde, tu permettais ça ? Et personne n'est venu gueuler ?
Bien évidemment que si...

Un des directeurs, qu'on n'avait plus vu depuis des mois (un manager intermédiaire avait été installé) est venu nous faire un grand discours sur l'investissement et les horaires (déguisé, comme souvent, en : "je compte sur vous pour partir une fois le travail fait, pas quand la cloche sonne").
On se prenait régulièrement des piques, des remarques, des commentaires d'autres personnes.
Mais le nouveau manager du projet (qui commençait à en avoir marre de notre rythme "pépère" de travail) ne pouvait pas faire grand chose, car nous ne dépendions pas de lui, mais de la direction technique de la société.

Du coup, de mon côté, je laissais faire. Je voulais voir les résultats en chiffres. Voir l'évolution de notre vélocité.
Et puis l'ambiance était largement meilleure. Ne pas être les uns sur les autres. Pouvoir faire de vraies pauses le midi, prendre notre temps...
Egalement, j'avais remarqué que si l'équipe faisait de grosses pauses, en général ils compensaient en bossant à fond une fois la pause terminée.

Du coup, j'ai laissé faire. J'ai observé.

Jusqu'au jour où ma manager a demandé à me voir.
Elle m'a expliqué qu'on renvoyait une mauvaise image, que l'équipe clairement bossait moins qu'avant et qu'ils pouvaient faire bien plus, s'investir plus... etc.
Et là, j'ai sorti les chiffres. En travaillant 1h30 de moins par jour, la vélocité de l'équipe n'avait pas bougé. Elle oscillait toujours entre 37 et 42 points par sprint.
L'équipe était tout aussi productive en travaillant 6h30 par jour, qu'en travaillant 8h par jour !

L'équipe avait même tendance à culpabiliser de prendre de telles pauses, et compensait en travaillant parfois plus longtemps ou plus intensément.

Alors oui, on se dit toujours : si l'équipe arrive à faire tout ça en 6h30, ils peuvent faire plus en 8h.
Ben la preuve que non. L'équipe travaillait en 8h avant, et elle ne produisait pas plus.

Ma manager a finit par accepter mes arguments. Evidemment avec le "si la vélocité baisse, il faudra changer ça".
Mais on a pu continuer l'expérience. Et les résultats étaient toujours là.

D'ailleurs, 1 an plus tard, on est repassés dans un openspace partagé avec d'autres équipes. A l'étage de la direction.
Du coup l'équipe est repassée sur un format de journées de 8h.

Et bien vous savez quoi ? La vélocité n'a, à nouveau, pas bougé.. Toujours 37/42 points.
En repassant à 8h par jour, l'équipe produisait autant qu'avant, en travaillant 6h30 par jour !

Voilà pourquoi je pense vraiment que le cadre, le confort, les règles, les méthodos de travail... sont plus importantes que la durée de travail.
Un cadre sain, assez d'espace pour chacun, un focus sur la qualité, des méthodos carrées et strictes (vrai SCRUM = AC, DoR et DoD) et des petites journées... seront, pour moi, plus efficaces sur le rendement long terme. Bien plus que de forcer l'équipe à travailler 45/50h par semaine.
Car qui dit pression et mauvais cadre de travail, dit turn-over, fatigue, lassitude, maladies, ... et bugs ! Je vous rappelle qu'au delà de 40h par semaine, on produit plus de bugs que de code utile !

On a trop souvent tendance à se concentrer sur les heures. Sur le rendement par heure. Sur le temps passé derrière un écran (quitte à somnoler en mode "il me reste 1 heure à tirer"...) ou dans les locaux (coucou les gens qui font des pauses aux toilettes !).

Après tout, l'objectif d'une entreprise ne devrait-il pas être de créer un environnement de travail tellement cool que les employés se voient y rester jusqu'à leur retraite ?

A réfléchir.

Manipuler une collection de sous-objets dans une vue ASP.Net MVC

icon Tags de l'article : , , ,

Aout 13, 2018
Hello les devs !

Aujourd'hui on va parler d'une problématique assez commune : envoyer des sous-objets au serveur depuis une vue CSHTML.

En effet, quand on développe un site avec ASP.Net MVC, il peut arriver qu'on ait besoin, dans notre vue, de manipuler des objets qui sont en fait... une collection d'objets liés à notre objet principal.

Exemple : ma classe Guerrier qui a une propriété "Inventaire" contenant une collection d'"Objet".

Dans ma vue, j'aimerais donc pouvoir voir les objets dans l'inventaire, et si besoin... en ajouter/supprimer.

Comment faire ça ?

Et bien en fait c'est ultra simple : le moteur d'ASP.Net MVC sait tout à fait mapper des sous-objets à partir de nommages façon "tableau".

Exemple : <input type="text" name="Guerrier.Inventaire[0].Nom" value="Epée des mille vérités" />

Grâce à la syntaxe "Inventaire[0].Nom", le moteur d'ASP.Net va comprendre de lui-même qu'il s'agit du premier objet dans la liste "Inventaire" et va essayer de le créer et mapper ses propriétés.

Quelques choses à noter tout de même :
  • Attention à la numérotation, si vous avez juste un sous-objet numéroté [1], il ne sera pas mappé et récupéré.
  • Côté serveur vous ne récupérerez que ce qui a été envoyé par le client. S'il s'agit de données à sauvegarder, vous devrez faire une comparaison entre ce que vous avez en base et ce que l'utilisateur a envoyé.
  • Si vous n'avez pas de valeurs, vous n'aurez pas d'objets.
  • Si vous n'avez pas d'objets, vous ne récupérerez pas une collection vide, mais null.
  • Si jamais les champs sont disabled, ils ne seront ni récupérés, ni mappés (pratique pour activer/désactiver un objet en javascript).

Voilà,

Bonne semaine et bon dev à tous/toutes !

Bug avec bootstrap-datepicker dans sa version v4.17.45

icon Tags de l'article : , , ,

Aout 10, 2018
Hello,

Juste un micro article pour vous prévenir d'un bug dans la version 4.17.45 du bootstrap-datepicker...

Si vous êtes comme moi et que vous passez par des packages nugets, méfiez-vous : la dernière version en Nuget est la 4.17.45 qui contient des bugs.

(Dont un très chiant : si vous faites une sélection particulière en fonction du format, par exemple une sélection par mois uniquement, au 2eme clic le mode de sélection aura disparu).

Les bugs sont corrigés sur la dernière version en ligne : la 4.17.47.

N'hésitez pas à mettre à jour manuellement votre code, étant donné que le package Nuget est à la masse :(

Bon dev à tous/toutes.

Chiffrer / déchiffrer très facilement des données avec la classe MachineKey en .Net 4.5

icon Tags de l'article : ,

Mai 17, 2018
Salut à tous,

Aujourd'hui on va parler chiffrement. Et depuis .Net 4.5, c'est fichtrement simple (je vous épargnerai l'historique complet du "pourquoi c'est plus simple et mieux" depuis .Net 4.5, mais vous pouvez le trouver ici).

En effet, pour chiffrer/déchiffrer du texte, vous aurez besoin de 2 choses :
  • une entrée MachineKey dans votre app.config ou web.config.
  • la classe MachineKey

Première étape donc, vous devez ajouter une ligne dans votre fichier de config, avec vos clefs de chiffrement. Exemple :
<machineKey validationKey="78BEF3A7DF5611DF7D5A4ABF373C539B6A9E7323B13103D5F66A38653686543C084D7574F6D180C9F17AE7F4E4D72C7CD47725946589788C5A8EC916223A9E9B" decryptionKey="A8B2C28F08ADB2D18DAC0E5A642AA90B8BF6A5864499A88ADB7C459D96B885B9" validation="SHA1" decryption="AES" /> 

Vous pouvez générer ce genre d'entrée très facilement grâce à ce site : http://www.allkeysgenerator.com/Random/ASP-Net-MachineKey-Generator.aspx
(ou encore directement via IIS)

Par défaut l'algorithme sera AES, mais vous pouvez changer pour DES ou 3DES si vous préférez (même si je vous conseillerai plutôt de garder AES).

Ensuite, niveau C#... ben rien de plus simple. Vous n'avez plus qu'à appeler la classe MachineKey du namespace System.Web.Security, et ses méthodes Protect et Unprotect :

// ici on va chiffrer notre chaine de caractères
string purpose = "USER_ID"; 
byte[] bytesToEncrypt = Encoding.UTF8.GetBytes(stringToEncrypt);

byte[] encryptedBytes = MachineKey.Protect(bytesToEncrypt, purpose);
string encryptedString = Convert.ToBase64String(encryptedBytes);

// [...]
// ici on va déchiffrer notre chaine de caractères
string purpose = "USER_ID";
byte[] encryptedBytes = Convert.FromBase64String(encryptedData);

string decryptedBytes = MachineKey.Unprotect(encryptedBytes, purpose);
string decryptedString = null;

if (decryptedBytes != null)
{
    decryptedString = Encoding.UTF8.GetString(decryptedBytes);
}

Dernière précision : l'attribut purpose correspond à un tableau de chaines de caractères qui servent à décrire les raisons pour lesquelles on chiffre ces données (comme une sorte de rôle). Cet attribut, s'il est passé au chiffrement, doit être passé également au déchiffrement.
En bref : on met une string propre à la donnée ou au composant, afin de s'assurer que lui seul arrivera à déchiffrer cette donnée, et pas d'autres composants / morceaux de l'application.

Voilà, c'est tout pour moi, bonne journée et bon dev à tous et toutes !

Quelques outils que tout bon développeur .Net devrait utiliser sur ses projets

icon Tags de l'article : , , , ,

Mai 15, 2018
J'ai entendu dire, il y a longtemps, que Bill Gates avait dit :



Et c'est vrai. Quelqu'un qui n'aime pas travailler inutilement trouvera toujours des voies pour travailler plus efficacement et supprimer les tâches chiantes inutiles.

Au fil des années, je me suis rendu compte que trop peu de développeurs se posaient une question pourtant évidente : quelle tâche quotidienne et contraignante pourrais-je simplifier dans mon process de développement/test ?

La réponse est souvent : ben merde y'en a plein en fait !!!

Qu'il s'agisse de purger la base de données, de créer un compte utilisateur, de remplir la BDD avec de fausses données... il y a souvent énormément de tâches qu'un développeur pourrait automatiser pour vite gagner un maximum de temps. Et si en plus ce développement est mutualisé entre les développeurs... ben c'est un gain énorme pour toute l'équipe.

Pour ça, je voulais partager avec vous les outils que tout bon développeur .Net devrait utiliser pour ça.

1) Une extension Visual Studio

Coder sa propre extension Visual Studio n'est pas forcément évident... mais ça peut vous permettre de gagner un maximum de temps en ajoutant directement dans VS les choses chiantes que vous devez faire régulièrement.

Quelques exemples (dont certains tirés de l'extension VS de mon poste actuel) :
  • purger la base de données
  • créer un compte utilisateur de test
  • démarrer le noeud Selenium
  • tuer tous les process Chrome Selenium qui restent
  • changer la configuration de la BDD (local / tests de perfs / preprod)
  • etc.

Avoir ces options directement dans votre Visual Studio peut vous faire gagner un temps précieux. Car même juste 2 minutes par jour, sur une année ça représente une journée entière de travail...

2) Le #if DEBUG

En local, on a parfois besoin d'avoir des fonctionnements différents du fonctionnement en production. Que ce soit à cause du cache, de la quantité de données, ou même de l'initialisation de la base de données... on a parfois envie d'avoir un fonctionnement différent, pour se simplifier la vie.

Voici quelques exemples d'actions que j'ai pu automatiser par le passé, grâce au #if DEBUG :
  • au lieu d'aller chercher le catalogue complet de données en BDD (ce qui prenait 2 minutes à chaque lancement de l'application), on le stocke sérialisé sur le disque dur et on l'utilise comme tel (bim, 10 secondes de chargement au lieu de 2 minutes)
  • création automatique d'un compte par défaut si aucun compte n'existe déjà
  • connexion automatique au compte par défaut
  • extraction, anonymisation et stockage sérialisé dans des fichiers de données venant de la production, afin de pouvoir faire des calculs statistiques sans avoir à requêter directement la BDD de prod
  • forcer la connexion à la BDD locale

3) Un dossier de ressources

Là on est dans l'évidence, mais parfois ça ne fait pas de mal de rappeler les évidences : prenez des notes.

Vous galérez à trouver une procédure spécifique ? Notez là quand vous avez enfin trouvé.
Un collègue vous montre une procédure compliquée pour faire quelque chose ? Notez là.
Vous découvrez gadget super cool que vous pourriez avoir à utiliser plus tard ? Mettez le de côté.

Quand on développe, il faut aussi savoir prendre des notes. Personnellement, j'ai toujours un dossier de ressources (personnelles) chiffré.

Qu'est ce qu'on trouve dans le mien ? Enormément de choses :
  • Les logins/mdp pour chaque compte partagé lié à notre application
  • Des scripts windows/powershell pour certaines actions (backup d'une base de données, restauration, création d'un certificat)
  • Comment faire certaines actions simples/complexes dans la solution
  • Des scripts SQL pour certaines actions BDD (purge et réindex Azure, identifier la fragmentation des index, batch de suppression des anciens logs, etc.)
  • Des rappels sur certains concepts qui ont du mal à rentrer (oui, même après plus de 15 ans de dev, ça doit être le grand âge)

Ca peut sembler idiot, car souvent en 2/3 minutes sur stackoverflow on peut retrouver la solution... mais :
1) Ca permet d'avoir du spécifique pour notre situation
2) Si nos fichiers sont bien triés et nommés, on gagne du temps même par rapport à stackoverflow
3) Ca peut vous sauver la vie si vous devez refaire une opération compliquée (prévue à l'origine comme un one-shot, vous savez, le célèbre "ne t'en fais pas, c'est juste pour cette fois" d'il y a 6 mois)

4) Les tests unitaires

Bon, je ne vais pas insister sur l'importance des tests unitaires dans un projet, mais sachez ceci : vous pouvez très bien utiliser des tests unitaires pour automatiser certaines actions de dev/debug.

Quelques exemples :
  • Tester la connectionstring du projet
  • Vérifier que toutes les procédures stockées appelées sont bien présentes dans la BDD
  • Tester une procédure stockée
  • Vérifier qu'une convention de codage est bien respectée sur le projet (quand on a des règles spécifiques)

Ou même encore : créer des données en dur en base. Après tout pourquoi pas ?

4) Un logiciel d'automatisation dans le navigateur

Lorsqu'on fait du dev web, on a souvent besoin de remplir des formulaires pour tester certaines choses. Et remplir 10 fois d'affilée les même 10 champs... ben ça fatigue très vite.

Or... il existe une solution simple : les extensions Chrome/Firefox d'automatisation. Par exemple iMacros.

Ces extensions permettent d'enregistrer un enchainement d'actions faites dans le navigateur pour les reproduire ensuite. Grâce à ça, vous pourrez créer un compte, vous logger, remplir en formulaire, etc... en un seul clic.

5) Les tests Selenium

Même si les tests Selenium sont, à la base, conçus pour tester votre application, vous pouvez les utiliser pour de nombreuses choses pas forcément évidentes à première vue :
  • Tester une API
  • Tester l'interconnexion entre 2 applications
  • Aller vérifier l'état d'un autre service en ligne
  • Créer une surcouche de monitoring (quand vous n'avez qu'un board figé de monitoring et pas d'API)
  • ...

6) Les macros de Notepad++

Si vous ne les avez jamais utilisé, sachez que Notepad++ permet d'enregistrer toutes les actions produites sur une ligne, pour ensuite les reproduire sur toutes les lignes d'un fichier.

Vous avez un fichier où le format ne va pas du tout, vous devez passer un bloc à gauche, supprimer quelques caractères et rajouter un morceau à la fin ? Record => modifications => Fin => Jouer en boucle jusqu'à la fin => terminé.

Voilà, je pense que ça fait déjà pas mal,

Je vous ai épargné les grands classiques, comme les environnements d'intégration continue, car si vous n'en avez pas déjà, il y a de fortes chances que ce soit indépendant de votre volonté (je voulais concentrer cet article sur ce que les développeurs peuvent faire eux-même, sur leur poste).

J'espère que cet article vous a plu, bonne journée et bon dev à tous et toutes !

Comment Dispose un HttpResponseMessage (et gérer l'erreur CA2000 de FxCop)

icon Tags de l'article : ,

Mars 29, 2018
Yo,

Petit souci sur lequel je suis tombé aujourd'hui : j'utilisais un using autour de mon HttpResponseMessage :

using(var response = new HttpResponseMessage(HttpStatusCode.OK);
{
     //...
     return response;
}

Evidemment... ça ne marchait pas. Le Dispose était fait avant que la requête ne parte chez l'utilisateur, et donc... ben j'essayais d'accéder à un objet disposed.

Sauf que si je retire mon using, j'ai une magnifique erreur FxCop CA2000 qui apparait...

Du coup comment faire ?

Après quelques recherches, j'ai trouvé plusieurs informations intéressantes :
  • Ce n'est, évidemment, pas obligatoire de dispose le HttpResponseMessage dans le cas où tout se passe bien. La requête sera dispose, et par conséquent l'objet HttpResponseMessage également. Le GarbageCollector est de plus là pour les restes ;)
  • Si jamais on veut planifier le Dispose pour s'assurer qu'il soit fait (sans attendre le GC), alors on peut utiliser Request.RegisterForDispose(response);
  • Dans tous les cas, l'erreur CA2000 apparaitra car dans le cas d'une exception, ben... notre HttpResponseMessage ne sera pas disposed.

Ce warning FxCop est un peu inutile quand on manipule des HttpResponseMessage dans un contexte de requêtes d'API.
Ce warning est là, normalement, pour forcer à utiliser des usings, mais là... on est dans une situation où un using ne marche pas, donc inadapté.

Ma suggestion ?
Désactiver l'erreur CA2000 pour cette méthode.

Et si vraiment vous ne pouvez/voulez pas... Vous pouvez toujours vous assurer qu'un Dispose sera fait, comme ceci :

var response = new HttpResponseMessage(HttpStatusCode.OK);
try
{
     Request.RegisterForDispose(response);
     //...
     return response;
}
catch
{
     response.Dispose();
     
     throw;
}

Bon dev et bonne journée tout le monde !

Ranger les using "System" avant les autres, dans Visual Studio

icon Tags de l'article : , ,

Mars 27, 2018
Salut,

Si vous êtes comme moi, vous aimez bien faire les choses.

Or, en C#, on sait qu'il faut toujours mettre les using "System" avant les autres. C'est une bonne pratique, ça permet de s'y retrouver plus facilement, et de gagner en clarté/lisibilité.

Sauf que voilà, sans resharper... c'est chiant d'avoir à déplacer les using pour les trier automatiquement.

Sauf que voilà... y'a pas à le faire à la main.

Visual Studio le gère automatiquement aujourd'hui. Il faut juste l'activer.

Allez donc dans Tools => Settings, puis dans C# => Advanced.

Là, vous n'avez plus qu'à cocher la case "Place 'System' directives first when sorting usings".



Et c'est fait !

Bon dev et bonne journée tout le monde !

Installer Git Extensions et Git sur Windows pour cloner un repository GitHub

icon Tags de l'article : ,

Mars 26, 2018
Bonjour à tous,

Un petit article pour bien installer Git Extensions sur son PC, afin de pouvoir l’utiliser avec un repo git (ici, Github).

Tout d’abord, vous devez télécharger Git for Windows et l’installer en administrateur.

A noter que dans les options, je choisis :
  • Notepad++ au lieu de Vim par défaut
  • Use Git and optional Unix tools from the Windows Command Prompt
  • Use OpenSSH
  • Use the OpenSSL library
  • Checkout as-is, commit as-is (évite les conversions intempestives)
  • Use Min-TTY (mieux qu’une simple console windows)
  • Enable file system caching & Enable Git Credential Manager

Ensuite, téléchargez Git Extensions et installez-le :
  • Install for all users of this machine
  • Décochez la case pour installer Git for Windows
  • Cochez l’installation de KDiff3 que si vous n’avez pas de logiciel de diff/merge d’installé
  • PuTTY comme client SSH

Lancez-ensuite Git Extensions.
Par défaut, il doit vous ouvrir la fenêtre de configuration. Si ce n’est pas le cas, ouvrez là.
Dedans, cliquez sur chaque ligne rouge et configurez là pour qu’elle passe verte (username, git path, etc.)

Une fois ça fait, vous n’avez plus qu’à récupérer le chemin de votre repository à cloner, et à l’ajouter dans votre Git Extensions pour le cloner.

S’il s’agit d’un chemin BitBucket ou Github, pensez à ajouter dans l’url votre username avant le nom de domaine, comme ceci :
https://my_account_name_or_email@github.com/HowTommy/ mycryptochat.git

Ainsi, quand vous essaierez de cloner/push un repository, une popup s'ouvrira pour vérifier votre identité.

And voilà!

En espérant que ça vous soit utile !

Bon dev et bonne semaine à tous/toutes !