Je me souviens assez bien de mon premier cours de conduite. Je venais de passer le code, j’avais 16 ans.
Top 10 other things every TFS Administrator should do
This post follows Rene’s top 10 list post:
Continue reading
Pas de build? Et vous, quelle est votre excuse?
La build est la clé de voute du processus d’industrialisation de vos développements. Sans build vous êtes à la merci de la compilation hasardeuse de votre logiciel sur un poste de développeur. En gros ne pas faire de build est un pari perdu.
Alors pourquoi ne pas faire de build? Il y a beaucoup de raisons. Voici certaines que j’ai croisées et qui reviennent souvent:
Je ne sais pas ce que c’est qu’une build et on m’a appris à livrer mon logiciel par mail ou dans un zip (ou les deux)
Corolaire: on ne m’a pas appris du tout à livrer mon logiciel. Donc je l’envoie par email.
De ce que je me souviens de mes études, l’ALM et encore moins la build était au programme. Mais on a changé de siècle depuis, il faut évoluer avec son temps!
J’ai des gens pour ça: interne, presta, etc…
L’éternel combat de la machine contre l’humain. Mais cette fois-ci la machine gagne. Demandez à un gars de lancer la compilation à 3h du mat, de déployer les binaires et de lancer des tests pendant 1h: vous verrez.
Ça coute trop cher, c’est une perte de temps.
Généralement ça ne coute pas plus de temps que de configurer un poste de développement. C’est également le bon timing pour décrite la procédure d’installation d’un poste de développeur où d’une build.
J’en ai une, elle est cassée, personne ne la répare donc on l’a laissé tomber.
C’est qui le chef?
C’est trop compliqué.
C’est souvent aussi compliqué que de compiler le logiciel sur un nouveau poste. C’est surtout le signal d’alarme qu’il y a quelque sorte qui ne va pas et qu’il faut corriger.
C’est pas la priorité, la build ça sera quand il n’y aura plus de problèmes.
Au contraire la build permet de rapidement et de façon fiable un logiciel près à tester. Ça serait dommage de s’en passer quand cela ne va pas.
Pour compléter ma liste: quelles excuses avez vous eu ?
@+
[FR] Début d’une nouvelle aventure: bonjour Cellenza
Je viens de rejoindre Cellenza pour me concentrer sur l’industrialisation du cycle de développement autour des méthodologies Agiles sur la plateforme Microsoft. Tout un programme!
@+
Nant Episode 1 – Présentation
NAnt est un langage de script adapté à la compilation de projets. les scripts NAnt sont simplement des fichiers XML. NAnt possède 3 concepts de base:
- les “targets” (cible): les targets rassemblent des ensembles de tâches. On peut dire très naïvement que ce sont les “méthodes” du script. La “target” lancée au démarrage est soit la target par défaut, soit celle définie lors du lancement (il peut aussi y en avoir plusieurs à lancer)
- les taches
- les propriétés: elles peuvent être définies en dehors du script lors du lancement
Tous ces éléments se retrouvent sous un noeud principal, le projet.
Si l’on s’arrète à cela, NAnt ressemble trait pour trait à MSBuild. Nous allons voir que non. Nant se détache de MSBuild sur plusieurs points. En particulier:
- On peut imbriquer les tâches dans des tâches, pour par exemple reproduire un graphe d’appel et pas seulement une séquence.
- la gestion des erreurs est plus simple
- la syntaxe des expression est très puissante et très extensible
On peut lancer un script via la ligne de commande de NAnt, ou embarquer nant dans une application (nous verrons plus tard comment et pourquoi).
NAnt est écrit en .Net, et vient de Ant son frère de Java. Toutes les tâches NAnt sont écrites en .Net est NAnt doc est très extensible.
Commençons par un script simple:
<?xml version="1.0" encoding="utf-8"?>
<project name="hello" default="main_target">
<target name="main_target">
<echo message="Hello from nant" />
</target>
<target name="other_target">
<echo message="Hello from nant (other)" />
</target>
</project>
La ligne de commande est la suivante: nant -buildfile:HelloFromNAnt_1.build
Changeons un peu la ligne de commande: nant -buildfile:HelloFromNAnt_1.build other_target
La cible a changé, par défaut le script pointe sur “main_target”, mais il est possible de choisir.
On peut aussi appeller une cible d’une autre cible:
<?xml version="1.0" encoding="utf-8"?>
<project name="hello" default="main_target">
<target name="main_target">
<echo message="Hello from nant" />
<call target="other_target" />
</target>
<target name="other_target">
<echo message="Hello from nant (other)" />
</target>
</project>
Lançons ce script:
Le prochain script montre une partie de la puissance de NAnt: les propriétés
<?xml version="1.0" encoding="utf-8"?>
<project name="hello" default="main_target">
<target name="main_target">
<echo message="Hello from nant" />
<call target="Target_${cible}" />
</target>
<target name="Target_A">
<echo message="Hello from A" />
</target>
<target name="Target_B">
<echo message="Hello from B" />
</target>
</project>
j’ai créé une propriété via la ligne de commande “cible”. et j’ai appellé la target “Target_${cible}” la syntaxe ${} permet d’executer une expresssion et pas seulement lire une variable. la chaîne résultante est devenue Target_B d’où le résultat.
Dans le prochain billet nous verrons les tâches les plus interessantes de NAnt.
[FR] Champs “Public const”: comment les trouver avec ndepend
Comme on l’a vu précedemment il faut éviter d’avoir des champs const visibles à l’extérieur d’une assembly. Comme le problème est assez subtil, cela peut arriver à tout le monde. Une constante “internal” peut très vite se retrouver publique lors d’un refactoring. Alors comment les retrouver? Ma réponse la plus rapide est NDepend.
Premièrement, il suffit d’ouvrir, puis de créer un nouveau projet et de cliquer sur “Add Assemblies of VS Solutions”:
C’est tout bète, mais ultra pratique: NDepend affiche les solutions ouvertes récemment dans visual studio (toutes versions confondues).
Une fois la solution ouverte j’ajoute une nouvelle requète cqlinq:
// < ;Name>;Public const fields< ;/Name>;
warnif count >; 0 ;from f in JustMyCode.Fields ; ; where
f.IsLiteral && f.IsPubliclyVisible
select f
Et j’obtiens ma réponse:
@+
[FR] public const … Fausse bonne idée?
Prenons un exemple simple, un projet avec 2 composants:
- une dll avec des API et des constantes
- et une console (notre super app)
Les API contiennent souvent des déclarations de constantes, certaines informatives, d’autres plus sensibles comme des limites de fonctionnement des algorithmes.
Voici le code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace APILib
{
public class MetaData
{
public const string PROG_TITLE=&quot;Mon super prog&quot;;
public const int VERSION_MAJOR=1;
public const int VERSION_MINOR=2;
public const int MaxProcessedValue = 1000;
}
}
J’ai mis ce code dans une dll (APILib) et je l’appelle ensuite dans une simple application console (ConsoleApp) :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(&quot;{0} Version {1}.{2}&quot;, APILib.MetaData.PROG_TITLE, APILib.MetaData.VERSION_MAJOR, APILib.MetaData.VERSION_MINOR);
Console.ReadLine();
}
}
}
Dans reflector, on obtient le résultat suivant:
2 remarques sur le fonctionnement du compilateur:
- il n’y a aucune référence à notre API!
- les constantes ont été remplacées dans le code par les valeurs associées
Imaginons le scénario suivant: je dois faire une modification de l’API et cette modification change le numéro de version et je ne relivre que l’API. Dans ce cas, le numéro de version reste le même. Si cela ne touche qu’un numéro de version, ce n’est pas très grave, mais très souvent les constantes contiennent les limites utilisations de nos programmes! Si ces limitations changent, aucun des clients de cette API – si ils ne sont pas recompilés avec la dernière version – ne verront les changements. Le bug est d’autant plus difficile à trouver que si le developpeur n’utilise pas les symboles de debug de prod pour debugguer mais qu’il reouvre la solution dans visual studio, même si il travaille sur les sources de prod, il n’aura pas le bug car il aura recompilé en local tout le code et donc changé la valeur limite dans les clients!
Voila pourquoi je n’aime pas les public const et pourquoi il est aussi important d’avoir des symboles de debug pour la prod !
@+
[EN] Visual Studio 12 RC: error/warning/message list filter
[EN] Sql Server Data Tools a.k.a “SSDT” is released
You can find the announcement on the SSDT blog. SSDT is an evolution of the database projects on VS 2010. I use VS database tools since Datadude in VS2005 and SSDT is a step forward in database programming with Visual Studio.
My top features:
- LocalDB: you don’t need an sql instance to test your base
- Designers: you can now write directly the code in an editor or modify the structure in the designer: They are synced to each other
@+
[FR] Regular Expression Denial Of Service (REDOS)
Bien qu’elles soient pratiques, les expressions régulières ne sont pas toujours nos amies. Lorsqu’elles deviennent trop complexes, elles peuvent devenir une faille dans la sécurité de nos applications. Tout l’inverse de ce que l’on voulait en faire.
L’une des premières utilisations des expressions régulière est la validation des saisies utilisateurs. Par exemple une adresse mail. Prenons cette expression:
“^([a-zA-Z0-9])(([\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$”
D’un seul bloc, c’est complètement illisible et incompréhensible. Coupons là en plusieurs morceaux:
- ([a-zA-Z0-9])
- (([\-.]|[_]+)?([a-zA-Z0-9]+))*
- (@)
- [a-z0-9]+[.]{1}
- (([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))
Si je prends cet email: john.doe@toto.com. Voila ce qui est validé pour chacun des 5 blocs:
- john
- .doe
- @
- toto.
- com
C’est plus clair maintenant?
Forcement pas tout le monde sait écrire des expressions régulières. Car personne n’en a vraiment envie (sauf ceux qui sont succombés au Perl). Alors, lorsque l’on doit valider une entrée utilisateur, et bien on se retourne sur internet et on prend la première expression qui passe (et qui marche presque). Jouons un peu avec cette expression pour lui faire valider des emails…. mais pas que…
- ‘toto@toto.com’: 0,0068746 seconds
- ‘aaaaaaaaaaaaaaaa!’: 0,0121044 seconds
- ‘aaaaaaaaaaaaaaaaa!’: 0,0254051 seconds
- ‘aaaaaaaaaaaaaaaaaa!’: 0,0495118 seconds
- ‘aaaaaaaaaaaaaaaaaaa!’: 0,0979562 seconds
- ‘aaaaaaaaaaaaaaaaaaaa!’: 0,1938863 seconds
- ‘aaaaaaaaaaaaaaaaaaaaa!’: 0,390627 seconds
- ‘aaaaaaaaaaaaaaaaaaaaaa!’: 0,788265 seconds
- ‘aaaaaaaaaaaaaaaaaaaaaaa!’: 1,5697939 seconds
- ‘aaaaaaaaaaaaaaaaaaaaaaaa!’: 3,1256698 seconds
- ‘aaaaaaaaaaaaaaaaaaaaaaaaa!’: 6,2264587 seconds
- ‘aaaaaaaaaaaaaaaaaaaaaaaaaa!’: 21,9357298 seconds
Que se passe-t-il? à chaque ‘a’ ajoutée, le temps de calcul double au moins. Je ne vais pas rentrer dans les explications ici, mon seul but est de montrer qu’exposer une expression régulière ne limite pas forcément la surface d’attaque d’un programme. Avec cette expression régulière par exemple, nous avons empêché la saisie de mauvaises données, mais nous avons surtout donné la possibilité à un attaquant de bloquer le site (si l’application c’est sur un site web) avec une seule saisie (par exemple aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!) qui vampiriserait tout le CPU: c’est notre “Regular Expression Denial Of Service” ou “REDOS”.
Alors comment faire pour éviter cela:
- éviter de prendre n’importe laquelle des expressions régulières
- éviter celles avec 2 boucles de backtracking imbriquées: c’est ce que l’on a ici dans la clause 2: ([a-zA-Z0-9]+))* avec le + et le *
- Si vous pouvez passer au Framework 4.5, il y a maintenant la possibilité de configurer une durée maximale d’analyse. Avec un timeout de 1 seconde cela donne:
Voici le code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace RegexDemo
{
class Program
{
static Regex _regex;
static void TestEmail(string pattern)
{
var sw = new Stopwatch();
sw.Start();
try
{
var match = _regex.Match(pattern);
Console.WriteLine(match.Success ? "OK" : "Failed");
}
catch (RegexMatchTimeoutException)
{
Console.WriteLine("Timeout");
}
finally
{
sw.Stop();
}
Console.WriteLine("'{0}': {1} seconds", pattern, sw.Elapsed.TotalSeconds);
}
static void Main(string[] args)
{
#if true
_regex = new Regex(@"^([a-zA-Z0-9])(([\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$",
RegexOptions.Compiled,
TimeSpan.FromSeconds(1));
#else
_regex = new Regex(@"^([a-zA-Z0-9])(([\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$",
RegexOptions.Compiled);
#endif
TestEmail("toto@toto.com");
TestEmail("aaaaaaaaaaaaaaaa!");
TestEmail("aaaaaaaaaaaaaaaaa!");
TestEmail("aaaaaaaaaaaaaaaaaa!");
TestEmail("aaaaaaaaaaaaaaaaaaa!");
TestEmail("aaaaaaaaaaaaaaaaaaaa!");
TestEmail("aaaaaaaaaaaaaaaaaaaaa!");
TestEmail("aaaaaaaaaaaaaaaaaaaaaa!");
TestEmail("aaaaaaaaaaaaaaaaaaaaaaa!");
TestEmail("aaaaaaaaaaaaaaaaaaaaaaaa!");
TestEmail("aaaaaaaaaaaaaaaaaaaaaaaaa!");
TestEmail("aaaaaaaaaaaaaaaaaaaaaaaaaa!");
TestEmail("aaaaaaaaaaaaaaaaaaaaaaaaaaa!");
TestEmail("aaaaaaaaaaaaaaaaaaaaaaaaaaaa!");
TestEmail("aaaaaaaaaaaaaaaaaaaaaaaaaaaaa!");
TestEmail("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!");
TestEmail("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!");
Console.ReadLine();
}
}
}
Pour terminer quelques liens sur le sujet:
@+

