Techdays 2009 : jour 2

Publié le 11 février 2009 par Olivier Duval

Ce 2ème jour aura été consacré à seulement 3 sessions.

C# et Linq avancé

Présentée par Mitsu. Ici encore, Mitsu nous a épaté par ses idées du côté de Linq et des méthodes d'extension, le tout dans une application Winforms. Ses démonstrations sont en générale bien réussies, et il n'a pas dérogé à la règle.

Virtualisation de données avec Linq

Sur la problématique du binding dans des applications windows, avec comme modèle, la liste des fichiers sous l'explorateur : les fichiers apparaissent au fur et à mesure du scrolling, et ne sont donc pas tous chargés en une seule fois.

La démonstration se basait sur un exemple en Linq to SQL. Les méthodes d'extension Skip et Take permettent une pagination de facto des résultats ramenés par la requête Linq To SQL. La requête SQL générée est optimisée, en utilisant notamment le mot clé TOP de SQL (voir un exemple du MSDN).

Code exemple avec du Linq to SQL sur la base Northwind :

var db = new NorthwindDataContext();
db.Log = Console.Out;
var q = from c in db.Orders 
              select c;
datagridview.DataSource = q.Skip(pagen*pagesize).Take(pagesize).ToList();

on aimerait avoir directement la possibilité d'écrire

datagridview.DataSource = q.ToPagesBindingList(pagesize);

Pour cela, Mitsu utilise l'interface IBindingList, ce qui correspond à implémenter un proxy : référence IList, ICollection, IEnumerable + les notifications des modifications (évènements) pour gérer automatiquement la pagination lors du scrolling dans l'application.

Création d'une méthode d'extension (sur le résultat de la requête linq, de type IQueryable) ToPagedBindingList(int pagesize) afin de charger au fur et à mesure du scrolling dans l'application, il chargera au fur et à mesure les données.

Méthode à implémenter pour le scrolling dans la classe : thisint index qui renvoie uniquement les éléments de la pagination (la IList contenant les éléments de n à p) : Skip.Take + count

Belle démonstration de ce que l'on peut faire avec du Linq To SQL, et surtout l'utilité des méthodes d'extension dans ce type de cas, économise énormément de code, et participe à plus de clarté.

CompiledQuery container

Dans une requête normale, à chaque fois, Linq to SQL analyse la requête Linq et construit le SQL associé, il n'y a pas de cache pour le SQL généré. Ce qui serait mieux c'est d'avoir une requête compilée (déjà analysée et construite).

Au lieu de ce code

var q = from c in ctx.Customers 
              select c

on aimerait avoir

var q1 = CompiledQuery.Compile( 
     (NorthwindDataContext ctx) => 
                             from c in ctx.Customers 
                             select c);

ou avec des paramètres comme arguments de la requête Linq :

var q2 = CompiledQuery.Compile( 
    (NorthwindDataContext ctx,string city) => 
                                       from c in ctx.Customers 
                                       where c.City==city  
                                       select c);

Par exemple, pour déclarer q2 en donnée membre cela donnerait

private Func<DataContext, string, IQueryable<Customer>> q2;

Il n'y a aucune inférence de type, et cela reste laborieux au niveau de la déclaration.

ou en plus simple :

Delegate q1;

mais dans ce cas il faudra tout de même caster datagridview.DataSource = (Func<...>) q1(db,"London").ToList();, on ne résout pas la question de la lisibilité.

Comment faire pour éviter ça : créer une classe dictionnaire pour conserver les requêtes, selon le modèle suivant :

public static class MyQueries
{
   private static Dictionary<string,Delegate> compiledQueries = new Dictionary<string, Delegate()>();
 
   private Func<TArg0, TResult> Get<TArg0, TResult>(string key, Expression<Func<TArg0, TResult>> queryProvider) : where TArg0 : DataContext
   private Func<TArg0, TResult> Get<TArg0, TArg1, TResult>(string key, Expression<Func<TArg0, TArg1, TResult>> queryProvider) : where TArg0 : DataContext
 
   //...
}

afin d'obtenir à la fin une ligne de code de ce type, où customer est la clé du dictionnaire, afin de stocker la requête Linq :

MyQueries.Get("customer", ((NorthWindDataContext ctx),city) => 
                            from c in ctx.Customers 
                            where c.City==city 
                            select c);

TreeSelector

On a les collections pour parcourir des entités, des collections, ...mais aucune pour les arbres.

Cela permettra le chaînage des méthodes de la façon suivante :

var cust = Data.CreateCustomer();
var ts = TreeSelector.Create<Customer>(cust)
            .Add(c=>c.CustomerID)
            .Add(c=>c.Adress,
                   ad=>ad
                   .Add(a=>a.City)
                   .Add(a=>a.Country));
             .Add(c=>c.Order);

qui permet de sélectionner uniquement les éléments que l'on souhaite dans l'arbre afin de les réordonnancer par exemple.

Mitsu a étendu le principe en mettant en place une méthode d'extension ToXElement(this INodeValueSelector) pour sérialiser le graphe directement en XML, ce qui est pratique et concis.

Dernière fonctionnalité : ajout de la possibilité d'ajouter des tags aux éléments :

TreeValueSelector<string>.Create<Customer>(cust).Add("Id", c=>c.CustomerID)...

Conclusion

J'espère que Mitsu mettra en ligne ses exemples de codes, cela pourra nous permettre de pousser un peu plus loin notre connaissance des points suivants :

  • l'inférence de type et comment l'exploiter (comme la réalisation du chaînage),
  • les Func<A,R>,
  • et les Expressions

WCF dans .NET 4.0

Présentée par Pascal Belaud.

La session était très orienté "remoting", et assez peu Web.

Parmi les nouveautés de la 4.0 : les bindings et behaviours peuvent maintenant prendre les valeurs par défaut, en utilisant "" dans l'attribut de chacun des types de binding ou behaviour (attribut name).

REST : REST Starter kit sur codeplex, sera intégré en partie dans la 4.0 : apport du cache (attribut [WebCache]), d'une page d'aide (attribut [WebHelp]) en ajoutant /help à la fin de l'URL, et des templates de projets : POX (Plain-Old XML), AtomPub, REST Singleton / Collection service, Atom Feed Service

Il est à noter que depuis le SP1, il n'y a plus besoin de décorer les classes avec DataContract et DataMember, fonctionne donc avec des POCO non décorés.

Astuce : mettre le namespace dans le XML lors d'un POST ou PUT (démo effectuée grâce au fameux Fiddler)

Non REST : nouveaux protocoles supportés : WS-I Basic Profile (BP) 1.2, implémentation de WP-Discovery au travers d'UDP (utile pour des logiciels de chat qui font client et serveur)

Démonstration pour le discovery : un MSN light avec les channels (channelFactory), orienté remoting.

<services><service behhaviorConfiguration="canalComm"></service></services>
<endpoint name="udpDiscoverypt" kind="udpDiscoveryEndpoint"/>
<behavior name="canalComm"><serviceDiscovry/></>

Session intéressante, ainsi que la démonstration, malgré la séance du code un peu longue. Au niveau Web (REST), rien de bien nouveau dans la 4.0, mis à part l'intégration du starter kit, mais c'était prévisible.

Comment ne pas reste un informaticien incompris

Gérard Berry est un chercheur, on pourra retrouver ses séminaires sur le site du collège de France . Il est le créateur du langage Esterel. Il a collaboré au projet Airbus via sa société Esterel Techno.

On sent bien le chercheur qui s'exprime, c'est à dire - sans aucune méchanceté - le côté un peu barré du personnage. Il aurait pu être l'auteur de ce livre, pour ceux qui l'ont lu. Personnellement, je me suis arrêté en chemin, difficile d'appréhender vers quoi il veut tendre, et quelque part, trop loin d'un bon roman

Je ne sais pas si c'est lié au sujet qui était en rapport à la sociologie [de l'informaticien], mais il y avait un peu plus de femmes dans l'assistance, ce qui était plutôt une bonne chose (dit-il).

Difficile de résumer une séance de ce type, malgré le talent de l'orateur qui nous a fait bien rire avec ses anecdotes.

J'aurais au moins conforter la définition d'un informaticien pour la personne lambda : "qui sait réparer un PC et qui utilise des mots totalement abscons", au moins, nous sommes d'accord sur ce fait presque quotidien. Qui n'a jamais entendu ça "toi qui est dans l'informatique, tu voudrais pas me réparer mon imprimante ?".

Dans les grandes lignes, pour ne plus être incompris, il faut communiquer et savoir expliquer ou vulgariser (par des analogies ?) notre domaine aux êtres les plus profanes. Mais ça, on le savait déjà Al Khuwarizmi (8è siècle) : naissance de l'algorithmique

  • Circuits : l'industrie la plus lourde du monde, 1 usine = 2 milliards $. L'augmentation du nombre de transistors peut continuer, le principal problème actuel, est le coût économique qu'engendre la fabrication des µprocesseurs, et cela va s'amplifier avec la crise économique. 850 M $ pour la conception d'une puce, progression concomitante du coût des usines (> 2 Mds $)
  • méthode formelle pour l'Airbus, selon un modèle qui produit du C
  • BUG : défaillance du concepteur, coût annuel global : 100 milliards de $ / an. Exemple couteux: ariane 5 : causé par un overflow dans un code inutile. Pour éviter ça : utiliser les méthodes formelles (théorie et sémantique de la programmation, preuves de programme, langage formel, et ça m'a rappelé ma jeunesse à l'université...sic...et dire que ça peut servir).
  • Conclusion : saurons-nous contrôler un jour les bugs ? probablement jamais (et là on se demande à quoi sert le TDD).