Développement d’applications sur Windows Phone 7

L’année dernière, pendant mon année d’alternance, j’ai travaillé sur la plateforme Windows Phone 7. Je vais essayer de partager avec vous mon expérience sur cette plateforme mobile qui reste un peu méconnue du grand public, tout en essayant d’avoir un esprit critique sur le sujet.

Dès mon arrivée en septembre 2010, j ‘ai eu la chance  de manipuler des terminaux qui n’étaient pas encore commercialisés (date officielle de sortie : le 21 octobre 2010). Voici les réactions immédiates qui me sont venues concernant le hardware. Côté design rien d’impressionnant,   les téléphones sont assez sobres mais ce qui m’a surpris ce sont les performances : une rapidité d’exécution pouvant faire pâlir certains de ses concurrents et des écrans de très bonne qualité. La gamme des téléphones est assez homogène (caractéristiques techniques moyennes : processeur 1Ghz, 512MB de RAM, capacité entre 8 et 16Go, écran 800x480pixels, APN 5mégapixels avec Flash).

Au niveau de l’OS, le premier démarrage donne vite un brin de déception : on trouve un premier bureau avec les applications épinglées (grosses icônes carrées) et un autre avec « une grosse liste horizontale de toutes les applications », autant dire qu’il ne faut pas avoir peur de slider lorsqu’on a une grosse liste d’applications… On retrouve donc une interface Metro assez basique et on se rend vite compte que, mis à part la couleur des icônes et l’épinglage d’applications, rien n’est modifiable. En ce qui concerne les applications natives, on retrouve les classiques  (« Téléphone», « Contacts », « Photos », « Musiques + Vidéos », « Internet Explorer 8 » et « Jeux » qui correspond au Xbox Live),  la suite Microsoft Office Mobile et le moteur de recherche Bing accessible à tout moment (grâce à la touche recherche). Enfin, on a le Windows Phone MarketPlace, sur lequel, j’ai pu me rendre compte tout au long de l’année, qu’on retrouve petit à petit les grands classiques des autres markets (pour n’en citer aucun).

Maintenant, que le tour de l’utilisateur lambda est fait, passons à la partie un peu plus technique.

Le développement d’application WP7 repose sur une version de Silverlight « adaptée ». En plus du framework traditionnel, on trouvera toutes les APIS spécifiques aux SmartPhones : accéléromètre,  géolocalisation, caméra, tâches : téléphoner, envoyer un message, lancer le marketplace, et d’autres encore. On trouve aussi les 2 modes de navigation propres aux applications WP7 que sont le panorama et le pivot ; dans le cadre de mon projet l’accent était mis sur l’utilisation du panorama pour garder l’authenticité de WP7 et ne pas essayer de copier la navigation par onglets des autres plateformes mobiles. Toutefois, on observe une certaine amputation au niveau des composants classiques qui composent Silverlight et celle-ci s’avère vite handicapante.

Qui dit Silverlight, dit pattern MVVM (Model View ViewModel)… Ces deux notions étaient pour moi totalement inconnues et mes premiers pas furent hésitants, mais une fois les grands principes compris, on devient très vite adepte du concept.  Pour faire simple, et sans rentrer dans les détails voici un petit schéma  qui explique le pattern:

MVVM est basé sur le principe de « Databinding » qui permet de synchroniser une propriété du ViewModel avec une propriété d’un composant graphique de la View (y compris les événements : click, changement de sélection,…).  Cette technique devient très vite appréciable : code minimal, rafraichissement  automatique  dans les 2 sens entre la View et ViewModel.

De plus, du fait de sa faible dépendance entre les interfaces graphiques et le code métier, MVVM facilite les tests de code et la séparation des taches des développeurs et des designers. J’en profite pour faire un petit point sur les outils mis à disposition. Tout d’abord, on trouve l’incontournable IDE pour les technologies Microsoft, Visual Studio auquel est associé le Windows Phone Developer Tools (SDKs + Emulateur). Pour moi, l’environnement s’est avéré être très complet : parmi les choses appréciables, on trouve un petit éditeur d’interfaces graphiques, le déploiement sur l’émulateur ou sur un device, un débuggeur pas à pas (dans les 2 cas de déploiement). Il est possible d’effectuer tout le développement dans Visual Studio, toutefois, dans le cadre d’un projet où un designer a un rôle à part entière à jouer, il peut utiliser l’outil Microsoft Expression Blend pour créer les interfaces graphiques sans se soucier du code métier qui tournera derrière. Pour ma part, je pense que Blend est un « jouet de luxe » et qu’on peut rapidement s’en passer.

Voici un petite liste des concepts que j’ai pu utiliser et qu’il est judicieux d’évoquer :

  • L’ IsolatedStorage est un espace de stockage de données propres à chaque application et qui est abstrait du reste de système de fichiers et facile d’utilisation.
  • L’application possède plusieurs points d’entrées (launched ou actived) et de sorties (closed et deactivated) dans lequel on peut faire des traitements différents selon que l’utilisateur ferme ou mette en background l’application. On trouve aussi  une méthode Application_UnhandledException qui permet d’effectuer des actions importantes (sauvegarde du contexte par exemple) avant que l’application se ferme dans le cas d’une exception non traitée (donc crash) et cela s’avère très utile.
  • Dans l’attente de la gestion du multitâches, le développeur doit gérer la sauvegarde du contexte de l’application lors de sa « mise en background » et le rétablissement de ce contexte lors de la réactivation de l’application. Ce procédé appelé le tomstoning est assez fastidieux puisqu’il faut sauvegarder unitairement toutes les données nécessaires, mais il est toutefois inévitable dès lors que l’application possède des données persistantes. Dans le cadre de mon projet, c’était un point essentiel à respecter et une grande partie des tests y était consacrée.

Avec tout cela, on peut donc réaliser des applications avec des interfaces graphiques très riches sans produire beaucoup de code car le pattern MVVM très puissant quand on a compris les bonnes pratiques. J’ai pu aussi m’appuyer sur un MSDN très complet et plutôt bien présenté.

Pour moi, le principal aspect négatif est que le framework manque parfois de composants graphiques ou de propriétés dans les composants existants. Cela a entraîné que j’ai vite eu le besoin de créer des composants « custom ». Un des autres faits est que la plateforme manque encore de contributeurs. J’ai été confronté à quelques problèmes techniques qui n’ont pas trouvé de réponse sur les forums appropriés.  Enfin, j’ai pu constater qu’on obtenait vite de mauvaises performances  si l’application est mal architecturée ou si on ne se soucie pas de décharger un maximum le thread principal.

Après une  expérience de 3 mois sur un projet WPF et un peu de recul, le MVVM que j’ai pratiqué sur WP7 n’était pas optimal (trop de code behind). Il s’avère que, à l’heure actuelle, le framework Silverlight pour WP7 n’est pas complet pour pratiquer un bon MVVM et que si l’on souhaite mettre en place une vraie architecture MVVM, il faut utiliser l’outil MVVM Light Toolkit et complexifier un peu son code.

En conclusion, et pour donner un avis tout à fait personnel, le développement d’applications sur Windows Phone 7 s’appuie sur de bonnes bases (Silverlight pour des interfaces interactives riches, MVVM pattern, environnement de développement complet et pratique),  mais laisse rapidement transparaitre une grosse lacune : le framework WP7 n’est pas assez riche par rapport à ces aînés (Silverlight et .NET). Beaucoup de personnes pourront vite être repoussé par l’étiquette Microsoft, mais pour moi, le développement d’applications sur WP7 est aussi intéressant que le développement sous Android (pour avoir pratiquer les 2). Microsoft doit toutefois, selon moi,  enrichir son framework et l’interface de son OS car elle présente un excès de sobriété.

Nouvelles versions

  • Actuellement, on trouve la version de l’OS 7.5 « Mango » : Multitâches complet, IE9, copier-coller, … et la version 7.1 du SDK Windows Phone.
  • A venir, l’OS nom de code « Tango » (date inconnue) avec certainement un nouveau SDK.

Les liens utiles

HTML5 : quels enjeux pour la mobilité et le RIA ?

3 nouveaux séminaires techniques organisés et animés par Objet Direct, en juin :
« HTML5 : quels enjeux pour la mobilité et le RIA ? ».

Etat des lieux du marché, retours d’expérience et démonstrations au cours de ces séminaires Objet Direct, avec le témoignage de Speedinfo : Venez découvrir les nouveaux usages et les perspectives ouvertes par les applications HTML5 mobiles.

=> le 16 juin à Grenoble, le 23 juin à Lyon, le 28 juin à Paris, 9h-11h (accueil petit déjeuner)
Evénements gratuits, sur réservation ferme.
En savoir plus et s’inscrire en ligne sur le site d’Objet Direct.

HTML5 ou Silverlight, Microsoft va t-il choisir ?

Microsoft s’est fortement engagé en faveur d’HTML5 sur IE9 comme le prouve les résultats des premiers tests de conformité publiés par le W3C (résultats qui naturellement font controverse par exemple ici ).

Pour autant, Bob Muglia (le président de la division Serveur et Outil de Microsoft) a jugé utile de rappeler que Silverlight ne serait pas abandonné et a clarifié la stratégie Microsoft autour de Silverlight.

Et vous vous en pensez quoi ?

En bonus, voici un lien pour tester la compatibilité de votre navigateur actuel vis à vis d’HTML5, et savoir quelles sont les caractéristiques qu’il supporte.

Charger une association dans WCF RIA Services

Je l’avais annoncé ici : .NET RIA services est devenu WCF RIA Services.

Rappels

L’objectif de ce projet est de simplifier le développement d’applications RIA.

Le principe général est assez simple :
Je développe des services de domaine (CRUD + Queries) en utilisant des conventions de nommage côté serveur.

Par exemple, la méthode Sprint LoadSprint(int sprintId) renvoie un sprint d’une application Scrum à partir de son identifiant.

WCF RIA Services projette ce code côté client dans des classes de type DomainContext.

Dans notre exemple, j’obtiens une classe ScrumDomainContext avec une méthode EntityQuery<Sprint> LoadSprintQuery(int sprintId)

Projection de code
Projection de code

Les associations

La version beta est disponible depuis le mois de Novembre. On trouve sur le Web quelques introductions, notamment celles de Brad Abrams. En revanche, on trouve très peu de choses sur comment charger une association dans notre application cliente Silverlight.

Dans mon exemple, je veux afficher une vue Master/Details qui présente un sprint et la liste de ses tâches.

Le modèle

Sprint association
Sprint association

La déclaration de l’association

Je dois ensuite décrire à WCF Ria services les associations entre mes entités. Pour cela, je décore les propriétés Tasks de la classe Sprint, et Sprint de la classe Task avec l’annotation AssociationAttribute. Il faut indiquer un nom pour cette association, par exemple Sprint_Tasks et préciser les clés étrangères de chacune de ses relations. Dans le sens Sprint -> Task, la clé c’est le champ Id de la classe Sprint et la clé étrangère c’est le champ SprintId de la classe Task.


public class Sprint{
[Key]
public virtual int Id { get; set; }

[Association(« Sprint_Task », « Id », « SprintId »)]
public virtual ICollection Tasks { get; set; }
}

Quelques remarques :

  1. Les habitués de NHibernate vont déplorer le fait d’avoir à décrire l’association à l’aide des clés étrangères. Cela nécessite par ailleurs d’avoir une propriété SprintId dans la classe Task en plus de la propriété Sprint 🙁
  2. La décoration est automatique avec l’utilisation de LinqToSql ou d’Entities Framework

Le chargement explicite

Il reste enfin à indiquer explicitement que l’on souhaite sérialiser les tâches avec le sprint. Pour cela, nous devons définir une classe de méta données relative à la classe métier. Dans notre exemple, ce sera une classe SprintMetaData définissant un champ Tasks que l’on décore avec l’annotation IncludeAttribute.


public class SprintMetaData {
[Include]
public EntitySet Tasks;
}

Je vous laisse regarder le blog de Brad Adams ou un ancien billet pour les détails de la classe de méta données.

Personnellement je trouve dommage d’avoir à définir une stratégie de chargement dans un fichier de méta données. L’idée générale n’est pas mauvaise, mais présente un inconvénient majeur : la stratégie est valable pour tous les cas d’utilisation. Or il est probable que l’application ne nécessite à la fois le sprint et ses tâches que dans certains écrans …

Outils de mapping objet/relationnel

Si vous utilisez un ORM, n’oubliez pas de récupérer la collection de tâches dans votre requête.

Avec LinqToEntities, ça donne :


public Sprint LoadSprint(int sprintId){
return this.Context.Sprints
.Include("Tasks")
.Where(sprint=>sprint.Id == sprintId);
}

Avec LinqToNhibernate, ça donne:


public Sprint LoadSprint(int sprintId)
{
var result = this.Session.Linq().Expand("Tasks")
.Where(x => x.Id == sprintId)
.ToList().First();
return result;
}

Conclusion

Nous avons vu en détail comment charger une association entre deux entités dans une application WCF Ria Services. Une partie de ces détails est masquée par l’outillage fourni par Microsoft et nous ferait presque oublier la complexité qui ne manquera pas de ressortir si vous souhaitez utiliser cette pile en association avec des outils tel que NHibernate

Référencement d’une application Silverlight

Je l’avais rapidement évoqué dans ce billet. David Rousset le détaille ici.

Si vous cherchez dans Bing avec la requête suivante http://www.bing.com/search?q=pizza+ind%C3%A9cis&filt=all ou dans Google avec http://www.google.fr/search?q=pizza+ind%E9cis, vous allez probablement trouver l’application de David déployée dans le Cloud : http://cloudypizza.cloudapp.net/Pizza.aspx?Name=Pizza+des+indecis#/Pizzas

Si votre navigateur ne supporte pas Silverlight, vous obtiendrez une version Web. Sinon vous obtiendrez grâce au deep-linking une page Silverlight présentant la pizza des indécis.

En fait, c’est très simple: la page Web qui est indexée fournit des informations au PlugIn Silverlight en lui demandant de charger telle ou telle page.

White : un framework de test intéressant ?

Pour situer le contexte, je réitère l’animation d’un séminaire à l’Université de Savoie sur le même thème que l’an passé : les tests automatisés et l’intégration continue. L’intervention aura lieu le 18 novembre prochain. Je suis donc en pleine phase de revue des différents framewoks de test abordés.

Ma bête noire c’est le test automatisé d’une application de type client lourd, écrite en Winforms, WPF ou plus léger Silverlight. Les solutions open source (et gratuites) sont soit inexistantes soit très pauvres.

Pour peut-être enfin répondre à ce besoin, je regarde actuellement le framework white qui me semble très prometteur: white encapsule la couche UI Automation, l’API d’accessibilité de Microsoft. Quelle que soit la technologie utilisée, on pourrait partir du principe qu’une application accessible est une application testable !

Les premiers tests sur une application école Winform sont assez concluants. Le prochain objectif est clairement d’éprouver cette solution sur une application grandeur nature.

RIA : Silverlight 3 disponible

La version finale de Silverlight 3 est disponible. Scott Guthrie l’a annoncé ce matin.

J’ai testé quelques fonctionnalités dans la version beta qui manquaient cruellement dans la version 2:

  1. Des contrôles (classiques) de saisie pour les applications de gestion de données avec un bon support pour la validation des données et la notification des erreurs de saisie (c’était possible dans la version 2 mais cela demandait un peu plus de travail)
  2. Un framework de navigation permettant entre autres le deep-linking et donc la possibilité de référencer une page de l’application

On peut également noter la possibilité d’utiliser .NET Ria Services.

Avec ces nouveautés, Silverlight devient une vraie alternative à Adobe Flex.

API REST en .NET

Suite à mon dernier article sur le RIA et la formation en soirée que j’ai animée, j’ai eu quelques questions sur comment exposer un modèle relationnel dans un mode REST en .NET et plus particulièrement pour un client RIA genre Silverlight.

Je vais donc vous proposer une série d’articles sur le sujet.

Le premier présentera ADO.NET Data Services, le framework de Microsoft qui à partir d’un provider LINQ peut exposer votre modèle d’entité sur HTTP dans un mode REST.

A titre d’exemple, je vais utiliser le prototype que j’ai réalisé pour une application traitant de la traçabilité des produits sanguins au CHU de Grenoble. J’ai donc le modèle d’entités suivant:

Modèle d'entités
Modèle d'entités

Depuis Visual Studio, j’ai créé un service ADO.NET Data Services. Je lui ai indiqué mon modèle d’entités et j’ai ajusté les autorisations. La ligne suivante indique que les entités Etat sont accessibles en lecture seule.

config.SetEntitySetAccessRule(« Etat », EntitySetRights.AllRead);

Mon modèle est maintenant accessible sur HTTP. Je peux regarder sa description à l’URI suivante : http://mondomaine.com/DTI.svc/

Le modèle REST exposé par ADO.NET Data Services
Le modèle REST exposé par ADO.NET Data Services

Les connaisseurs noteront que la description de notre API utilise Atom Publishing Protocol et Atom Syndication Format.

Je peux maintenant interroger mon modèle en requêtant directement avec mon navigateur. Par exemple, pour avoir toutes les poches, je vais utiliser l’URI http://localhost:2427/DTI.svc/Poche

Personnellement, pour vérifier mes requêtes j’utilise Fiddler. Par défaut, on obtient un feed Atom contenant une collection de poches. ADO.NET Data Services supporte également le format JSON. Si dans Fiddler, vous modifiez le header HTTP Accept avec application/json vous obtiendrez un flux JSON:

Une collection de poches au format JSON
Une collection de poches au format JSON

ADO.NET Data Services ne se limite pas à récupérer une collection d’entités. On peut filtrer les entités sur certains critères. Par exemple l’URI http://localhost:2427/DTI.svc/Poche?$filter=NumDon%20%eq%20%12345678 me permet de récupérer la/les poches dont le champ NumDon vaut 12345678. On peut également récupérer les entités associées aux poches. L’URI http://localhost:2427/DTI.svc/Poche?$expand=Tracabilite récupère les poches avec leurs traçabilité sachant qu’une poche peut avoir plusieurs traçabilités.

Les principales fonctionnalités de requêtage sont disponibles: filtre, tri, pagination. Le format des URI est décrit ici

Dans les applications de gestion de données, on ne se limite pas à afficher des données. On souhaite aussi ajouter, modifier, supprimer. Dans le monde REST, on utilise pour cela le verbe HTTP. Par défaut, lorsque vous saisissez une URI dans votre navigateur, c’est le verbe GET qui est utilisé. Mais on peut aussi utiliser les verbes POST, PUT ou DELETE si les conditions d’accès que nous avons définies sur le serveur le permettent.

On peut noter que toute cette API repose sur des standards reconnus: HTTP, Atom, JSON. Elle peut donc être interrogée par n’importe quel client qui supporte ces standards.

Dans le prochain article, j’expliquerai comment interroger cette API à partir d’un client Silverlight et de LINQ For ADO.NET Data Services.