insideIT.fr : le blog des architectes IT de SFEIR

Aller au contenu | Aller au menu | Aller à la recherche

mercredi 15 décembre 2010

gwt-table-to-excel

Présentation d’un nouveau projet Open Source.

Lire la suite...

samedi 9 octobre 2010

Fastcall Android

A Sfeir, nous aimons la technologie, et Android en fait évidement parti.

J'ai développé avec mon collègue Clément Griffoin une application basée sur une idée de celui qui est à la fois notre directeur technique et notre directeur des opérations : Didier Girard. Lorsqu'on a beaucoup de contacts dans son répertoire, il devient fastidieux de retrouver celui que l'on veut : que de mouvements de pouces de bas en haut pour faire défiler sa liste.

Fastcall vous propose d'en écomiser !

Confucius disait qu'une image vaut mille mots, je vous épargne un long discours pour vous en expliquer le principe :

            

Et voilà, en 3 coups de pouces, nous pouvons appeler notre ami Blaise Lucas bien qu'il soit l'un de nos 1000 contacts téléphoniques.

Si vous souhaitez tester notre application :

Puisque nous aimons et croyons en l'open source, cette application est bien sûr soumise à ce principe :

http://code.google.com/p/fastcall-android/

Nous sommes donc à l'écoute de vos propositions, problèmes rencontrés, ...

Et pour les twittos, suivez .

samedi 18 septembre 2010

Mvp avec mvp4g

Depuis la conférence Google I/O 2009, le pattern architectural MVP fait parler de lui à un point où un grand nombre de framework open source s’est répandu, chacun proposant son implémentation plus ou moins élaborée. Tous contiennent au moins la gestion du présenteur et ensuite on y trouve ou non un event bus, une gestion de l’historique, injection de dépendances, pattern action, ....

C’est sur google code que j’ai découvert Mvp4g  qui couvre une bonne partie de ses fonctionnalités.

Pour vous le faire découvrir, nous allons reprendre le code de l’application de gestion de contacts de l’article de google sur le mvp : http://code.google.com/intl/fr/webtoolkit/articles/mvp-architecture.html

Pour cet exercice, nous prendrons la dernière version de mvp4g qui vient l’être releasée ainsi que de ses dépendances :

  • mvp4g-1.2.0

  • commons-lang 2.4

  • commons-configuration 1.6

  • gin 1.0

  • guice 2.0

  • aop-alliance.

Comme pour n’importe quel bibliothèque gwt, il faut la déclarer dans notre fichier gwt.xml :


<inherits name='com.mvp4g.Mvp4gModule' />


Maintenant, faisons un tour d’horizon des modifications que nous allons devoir apporter :

  • La partie Model ne changera pas : Mvp4g ne couvrant pas l’Action pattern, nous ferons appel au méthodes exposée en rpc tout comme dans le code original.

  • La partie Presenter, elle sera une des parties qui changera le plus : nous devrons étendre une classe du framework et répondre à son contrat.

  • La partie View ne changera que très peu : nous n’aurons qu’à changer l’interface implémentée.

  • L’Event Bus : un des autres gros changement. Mvp4g propose en effet son propre modèle avec un système d’évènements haut niveau assez souple.

  • La gestion de l’historique, là aussi tout est à refaire.

  • L’Entry Point : Avec mvp4g, nous n’avons pas forcément besoin d’en écrire un ...

A cela, nous rajouterons une injection de dépendances via gin qui n’est pas dans le code original. C’est aussi dans cet esprit que se configure mvp4g. Que ce soit pour lier les différents composants ou spécifier le comportement dus bus ou de l’historique. Elle peut être soit réalisée en xml ou par annotations. J’ai préféré l’utilisation des annotations.

J’imagine que le point sur l’entry point, vous a laissé perplexe mais attention ce n’est pas parce que nous n’allons pas en écrire un que nous n’en aurons pas. C’est justement parce que l’application s’assemble en fonction des annotations que cette partie peut devenir générique. Nous utiliserons donc celui que nous propose mvp4g en incluant cette ligne dans le gwt.xml :


<entry-point class='com.mvp4g.client.Mvp4gEntryPoint' />


Pour les plus curieux, voici le code qui y correspond :


Mvp4gModule module = (Mvp4gModule)GWT.create( Mvp4gModule.class );

module.createAndStartModule();

RootPanel.get().add( (Widget)module.getStartView() );

Et c’est tout. Le code étant assez simple, il se comprend de lui même. Tant que nous n’aurons qu’un seul module gwt, il nous sera suffisant.

Passons maintenant au centre névralgique de notre application : le bus évènementiel. Dans une application mvp4g, il est indispensable. C’est bien sûr par lui va passer la distribution des événements haut niveau mais aussi quelques autres notions liées comme la gestion de l’historique et surtout l’action “start”.

A 3ème ligne de l’entry point, vous aviez sans doute remarque le getStartView. Il n’y a rien de magique, c’est par la configuration du bus que nous la connaîtrons.

Allez, mettons nous en route , pour coder notre bus. En fait, nous n’aurions rien à implémenter puisqu’il s’agit d’une interface. Elle devra néanmoins étendre l’interface EventBus de mvp4g et être annotée :


@Events( startView = RootView.class)

public interface   ContactsEventBus extends EventBus {

}


C’est sur l’annotation @Events que nous définissons RootView en tant que vue chargée s’affichant au démarrage. Fidèle à son nom, elle sera notre vue racine. Mvp4g conseille de disposer d’une telle vue qui servira de container aux autres vues. Comme toute vue dans un modèle MPV, elle sera statique et sera associée à un présenteur. L’interface qui servira de contart avec le présenteur sera celle ci :

public interface RootViewInterface {

     Panel getBody();

}

et l’implémentation sera la suivante :


public class RootView extends  Composite  implements  RootViewInterface {

private  SimplePanel body = new SimplePanel();

      public RootView() {

            VerticalPanel mainPanel = new VerticalPanel();

            mainPanel.add(body);

            initWidget(mainPanel);

      }

      @Override

      public Panel getBody() {

            return body;

      }

}


Le présenteur quant à lui sera de la forme suivante :


@Presenter( view = RootView.class )

public class RootPresenter  extends  BasePresenter<RootViewInterface, ContactsEventBus>


Là encore, nous avons du code assez simple à comprendre . Nous annotons le présenteur pour qu’il puisse être détecté par mvp4g et étendons la classe BasePresenter<V, E extends EventBus> pour nous permettre d’interagir avec la vue mais aussi avec notre bus. De la même manière, nous aurons : un ContactsPresenter et un EditContactPresenter avec des vue telle qu’on les a dans le code original.

Nous avons déjà la base de notre application mais pour l’instant, elle ne fait rien. Dans notre cas, nous voudrions qu’au lancement, la liste des contacts soit affiché. Tiens, nous tenons un évènement haut niveau et nous voudrions qu’il soit lancé au lancement... C’est encore une fois le bus qui va s’en occuper, encore un fois par une simple annotation.

Puisque nous voulons lister, nous allons créer un évènement “list” tout simplement. A la différence du mvp proposé par google dans l’article, nous n’aurons pas à créer une classe héritant de GwtEvent et de lui associer une handler. Nous allons seulement ajouter une méthode qui porte le nom de cet évènement à l’interface de notre bus :


@Start

@Event(handlers = ContactsPresenter.class)

void list();


C’est grâce à l’annotation @Start que l’évènement sera lancé au lancement client de l’application et sera délégué à notre ContactPresenter. A noter que dans notre cas, nous n’avons qu’un seul handler. Il aurait été tout à fait possible d’en avoir plusieurs en les séparant par une virgule.

Il nous reste à implémenter la réaction du présenteur face à cet évènement. Le modèle évènementiel de mvp4g repose sur une convention simple : pour un méthode XXX du bus, le présenteur devra implémenter une méthode onXXX tout simplement. Bien qu’il ne soit pas possible à s’assurer de la concordance entre l’évènement est sa méthode réceptrice lors de la compilation java, ce contrôle est réalisé lors de la phase de compilation gwt.

Revenons à notre cas, nous aurons donc une méthode onList() dans notre ContactsPresenter :


public void  onList(){

      contactsService.getContactDetails(newAsyncCallback<ArrayList<ContactDetails>>() {

            @Override

            public void  onSuccess(ArrayList<ContactDetails> result) {

                  doList(result);

            }

            @Override

            public void  onFailure(Throwable caught) {

                  eventBus.errorMessage(ErrorMessages.RPC_CALL_FAILED);

            }

      });

      eventBus.changeBody(view.asWidget());

}

Pour déclencher un évènement haut niveau, il suffit d’appeler la méthode associée du bus.C’est ce que nous faisons par exemple avec le changeBody qui permet à la vue ContactView de devenir active.

Nous pouvons aussi transmettre une valeur ou plusieurs valeurs lors du déclenchement de l’évènement. Nous rencontrons ce cas pour l’édition :


@Event(handlers = EditContactPresenter.class)

void  edit(String id);

Vous avez aussi sûrement remarqué, l’appel au service rpc. Sa déclaration est très simple, nous utiliserons l’injection GIN par une simple annotation sur son setter :


@Inject

public void setContactsService(ContactsServiceAsync contactsService) {

      this.contactsService = contactsService;

}

Quant à la phase de binding des événements bas niveau par les présenteurs, elle est est analogue à celle du code original : nous n’aurons qu’à implémenter la méthode bind().

Nous aurons par exemple :


view.getAddButton().addClickHandler(new ClickHandler() {

      public void  onClick(ClickEvent event) {

            eventBus.add();

      }

});

Si vous avez peur de ne pas savoir où vont vos évènements, l’annotation @Debug sur le bus vous aidera en loggant en console ce qui se passe autour du bus. Il existe 2 modes de LogLevel : SIMPLE et DETAILLED, par défaut ce sera la première valeur. Regardons ce qui se passe dans les 2 modes sur un évènement edit .

Tout d’abord en mode simple :

16:47:05.355 [INFO] [contactsmvp4g] Module: Mvp4gModule || event: edit || param(s): 18

16:47:06.551 [INFO] [contactsmvp4g] Module: Mvp4gModule || event: changeBody || param(s): [...plein de html...]

et en mode détaillé :

16:50:53.187 [INFO] [contactsmvp4g] Module: Mvp4gModule || event: edit || param(s): 18

16:50:53.751 [INFO] [contactsmvp4g] com.sfeir.contacts.client.presenter.EditContactPresenter@640782 handles edit

16:50:54.052 [INFO] [contactsmvp4g] Module: Mvp4gModule || event: changeBody || param(s): [...plein de html...]

16:50:54.058 [INFO] [contactsmvp4g] com.sfeir.contacts.client.presenter.RootPresenter@16e4f00 handles changeBody

Intéressons nous maintenant à l’historique. Mvp4g utilise la notion de convertisseur d’historique. Ce qui signifie que nous devrons implémenter la façon dont les évènements seront convertis en url et vice et versa. Nous allons devoir implémenter l’interface HistoryConverter<E extends EventBus> et comme toujours l’annoter. Notre application étant relativement simple, nous n’en aurons qu’un seul mais sachez qu’il est tout à faire possible d’en avoir plusieurs. Pour répondre à son contrat, nous devrons implémenter les 2 méthodes suivantes :

  • convertFromToken( String eventType, String param, E eventBus ) : réaction lors d’une url tokenisée.
  • isCrawlable() : indique si le l’url sera crawlable en renvoyant un booléen.

La gestion de l’historique viendra se greffer sur le bus événementiel. Pour gérer l’historique, nous rajouterons :


@Events( startView = RootView.class, historyOnStart = true)


Réfléchissons d’abord un peu. Sur quoi aimerions nous avoir une historique avec des urls identifiables ? J’en vois 3 :

  • La liste des contact

  • Ajout d’un contact

  • Edition d’un contact. Idéalement, il serait intéressant d’avoir un paramètre permettant d’identifier le contact que nous éditons.

Le modèle d’historique de mvp4g utilise un token situé après un "#" dans l’url. Ce token correspond tout simplement au nom de l’évènement. Nous avons aussi la possibilité d’assigner un valeur à ce dernière en le placant derrière un "?".

Exemple : #token?value

Cette solution convient à notre exigeance de mieux marquer l’url lors de l’édition d’un contact. Pour lier, un évènement à notre convertisseur d’historique, il suffit de lui assigner sur le bus :


@Start

@InitHistory

@Event(handlers = ContactsPresenter.class, historyConverter=ContactHistoryConverter.class)

void  list();


L’annotation @InitHistory sert à marquer quand l’historique doit être initialisé. Celle est obligatoire si vous voulez utiliser l’historique. Revenons à notre convertisseur :


@History

public class  ContactHistoryConverter implements HistoryConverter<ContactsEventBus> {

      @Override

      public void convertFromToken(String  eventType, String param, ContactsEventBus eventBus) {

            if(“edit”.equals(eventType)){

                  eventBus.edit(param);

            } else if(“add”.ADD.equals(eventType)){

                  eventBus.add();

            } else if(“list”.equals(eventType)){

                  eventBus.list();

            }

      }

      @Override

      public boolean isCrawlable() {

            return  true;

      }

}


La première méthode est assez claire : nous appelons la méthode correspondante au token avec une particularité pour edit où nous nous servirons de la valeur en paramètre du token comme paramètre edit.

Même si l’IDE ne signale aucune erreur, la compilation gwt en provoquera. Il nous faut la réciproque de la méthode convertFromToken : c’est à dire indiquer quelle sera la valeur du paramètre d’un token. Ainsi, pour chaque évènement XXX historisé,il nous faudra une méthode onXXX qui renvoi une valeur sous forme de chaîne de caractères. Nous aurons ainsi par exemple :


public String  onEdit(String id){

      return id;

}

public String  onList(){

      return "";

}


Un reproche possible à faire à mvp4g est

Un des reproches possible à faire est l’assemble dynamique et instanciation des composants. Nous n’avons pas toujours besoin d’en disposer au moment au l’ont accède à l’application. Dans notre cas, nous n’avons pas besoin d’édition d’un contact tant que n’a pas cliqué sur un contact. Rassurez vous, la construction paresseuse est là. Pour cela, nous allons changer la super classe pour LazyPresenter<V extends LazyView, E extends EventBus>. En plus de cela, notre interface de vue devra étendre l’interface LazyView. Cela va perturber un peu notre code et des erreurs de compilation vont s’inviter. Avant de les corriger, intéressons nous à la classe LazyPresenter et en particulier sa méthode bind()


final public void bind() {

      view.createView();

      createPresenter();

      bindView();

}


Voilà la clé de nos corrections :

  • Les constucteurs de vue et de présenteur deviendront respectivement createView() et createPresenter()

  • La méthode bind() du présenteur deviendra bindView()

Personnellement, j’ai remarqué qu’après ses modifications, le lancement était plus rapide.

Le principal avantage d’un découpage mvp est la testabilité. Notre présenteur étant décorélé de problématique d’affichage, il sera alors plus simple de le tester. En effet, en mockant la vue, les services et le bus, nous pourrons nous concentrer nos tests sur la logique métier. De plus avec le système évènementiel haut niveau de mvp4g, il est simple de tester la réception d’un événement.

Un aspect qui peu rebuter les plus intégriste du modèle mvp est la gestion évènement de haut niveau spécifique de mvp4g et principalement ses performances. Quelles sont elles ? Le wiki du projet répond à cette question :

http://code.google.com/p/mvp4g/wiki/Mvp4gPerformances

Les performances semble honorables. Bien sûr, tout produit vante ses performances, mais bon joueur les tests sont disponibles.

La question à se poser avant tout est de savoir ce que l’on teste exactement. En observant le code, on voit qu’un évènement est lancé est attrapé par son réceptacle. Rien de plus. Pour éviter un conflit entre les deux, un test se fait en temps : d’abord mgp4g puis gwtEvent.

Pour la partie benchmarking, j’ai réalisé depuis le lien appspot les même tests sous 3 navigateurs dans leur version courante :

  • Chrome 6

  • Internet Explorer 8

  • Firefox 3.6

Mes résultats diffèrent, mais attention cela ne signifie pas les résultats sur la page mvp4g sont faux. En effet, pour avoir reproduit ces même tests sur différentes machines possédant le même navigateur, j’obtenais des résultats avec une différence assez importante (jusqu’à x 10 entre un bon pc fixe et un simple netbook) :

Voici mes résultats pour 1000 évènements lancé :



mvp4g

gwt

Chrome 6

31

122

Internet Explorer 8

477

3609

Firefox 3.6

206

312

Ces résultats vont dans le même sens, c’est à dire que le modèle événementiel de mvp4g est plus rapide que celui de gwt.

Bien sûr, GWT 2.1 va arriver avec son modèle MVP intégré. Quand il sortira, on pourra re-comparer les temps de réaction événementielle. En attendant, sa sortie vous pouvez vous amuser au mpv avec mpv4g, qui propose bien d’autres fonctionnalités encore comme les filtres d’évènements, la gestion du multi-module, ....


Le code source complet est joint à cet article.

mercredi 8 octobre 2008

VS 2010 et .Net 4.0 surfent sur la vague des plateformes Next gen

die_hard_4_1 Si vous vous souvenez (ce dont je doute), nous avions ici même annoncé un 1 avril la sortie imminente du framework 4.0. Le canular était gros ? La réalité le dépasse. Un certain "Rosario", nom de code de la future version de Visual Studio s'annonce tonitruant. Son optique est plus que jamais de faciliter l'interaction entre architectes, designers d'applications, programmeurs, testeurs, chefs de projets et commerciaux, de briser les silos. Et pour cela qu'offre-t-il ?

- Un outil de gestion du cycle de vie des applications (ALM pour Application Life-cycle Management).

- Des interfaces graphiques de design métier et système à base d'UML et de DSL: les "modeling tools". Ce n'est donc pas un hasard si Microsoft a rejoint l'OMG il y a peu.

- Un vrai effort a été fait du côté des outils de tests (qui manquaient un peu jusque là) pour apporter enfin une alternative aux sempiternels tests manuels.

- Une plus forte adhérence aux méthodes agiles avec TFS (le Team Foundation Server) qui devient un vrai Hub de collaboration entre acteurs du projet.

- Des outils permettant de travailler sur les bugs non reproductibles.

Cette nouvelle version est la confirmation d'une nouvelle stratégie entamée dans le passage de la version 2005 vers 2008 qui est celle d'un dialogue réel avec les utilisateurs de Visual Studio. Et l'ouverture à l'open source qui se confirme comme pour l'intégration de jQuery, le framework javascript open source pour l'AJAX.

Qu'apporte le framework 4.0 de son côté ? Il surfe sur le Cloud Computing, vise plus que jamais le "developer delight", confirme la percée du parallel computing, des traitements distribués, de l'exploitation des processeurs multi-coeur, il améliore la partie SOA (notamment avec REST pour WCF), augmente les interactions entre WF et WCF. Et ce n'est qu'un début. Le reste sera annoncé à la PDC (Professional Developers Conference), à suivre donc.

Maintenant, pour désamorcer les moqueries que l'on sent déjà venir sur la vitesse des sorties de nouveau framework, rappelons que depuis le Framework 2.0, chaque nouvel opus vient compléter le précédent et non le remplacer. Donc pas de panique. Pas la peine de tout remettre en cause dans les applications existantes, votre plan d'action visant à convaincre votre chef de projet de la nécessité de passer au framework 3.5 (et qui vous promet déjà de longs débats) ne vole pas en éclat.

Je préfère laisser la conclusion au Senior Vice President de la division développeurs de Microsoft, S. Somasegar :

"With Visual Studio 2010 and the .NET Framework 4.0, we are focussed on the core pillars of developer experience, support for the latest platforms spanning client, server, services and devices, targeted experiences for specific application types, and core architecture improvements. These pillars are designed specifically to meet the needs of developers, the teams that drive the application life cycle from idea to delivery, and the customers that demand the highest quality applications across multiple platforms. You can expect to hear a lot more about Visual Studio 2010 and the .NET Framework 4.0 in the coming months."

Plein de promesses en perspectives et pourtant c'est pas encore Noël ! Alors à votre avis, en avril prochain, on vous fait le coup du Framework 5.0 ou il faudra taper plus haut ?

lundi 17 mars 2008

Vous avez dit ALT.NET ?

Logo ALT.NETAvez-vous déjà entendu parler de "ALT.NET" ?

Derrière ce terme se trouve une partie de la communauté .Net. Elle réunit de plus en plus de personnes, notamment issues de l'Open Source, mais pas seulement.

Ce mouvement a été créé il y a environ un an. Il souhaite promouvoir une vision alternative et complémentaire à celle de Microsoft. Voici quelques-unes des idées qui sont à l'origine du mouvement :

  • Connaître et utiliser ce qui se fait actuellement, tout en gardant à l'esprit qu'on peut toujours faire mieux. Il faut pouvoir se remettre en question.
  • Ni Microsoft, ni le monde .Net n'ont le monopole des bonnes pratiques. Et celles-ci existaient bien avant l'apparition de .Net. Il existe d'autres technologies (Java, Ruby, ...) et de courants autour d'elles (Open Source, Agile, ...). Il faut savoir tirer le meilleur de tout cet écosystème.
  • Adopter et utiliser les outils qui nous forcent à mettre en place ces bonnes pratiques, sans que cela soit une contrainte. Se focaliser sur la simplicité et la maintenabilité du code, car maintenabilité signifie bonne architecture. Et une bonne architecture n'arrive pas par hasard. Elle se met en place grâce à une connaissance qui se construit sur l'expérience et sur celle des autres.

Jeremy D. Miller a publié récemment un article plus complet sur cette communauté dans MSDN magazine qui donne une très bonne vision de cette communauté. Vous pourrez le trouver ici : http://msdn2.microsoft.com/en-us/magazine/cc337902.aspx

Les logos, disponibles sous licence Creative Commons Non Commercial, ont été créés par Oren Eini, et sont disponibles ici : http://www.ayende.com/Blog/archive/2008/03/09/ALT.Net-Logo.aspx

Enfin, le site de la communauté : http://altdotnet.org

lundi 11 février 2008

[TechDays 2008 - J1] .Net et l'Open Source: Retour d'expérience

IMG_2494_10 Cette dernière présentation du symposium DNG de la journée a permis de sortir un peu du cadre strict et compassé de la technologie propriétaire. Ici on parle d'un mouvement nouveau dans le monde Microsoft mais qui devient de moins en moins marginal: l'Open Source en .Net. S'il est vrai que sur un tel sujet on passe très rapidement de l'objectif au subjectif, on se doit d'aborder cet angle d'approche d'un projet d'un point de vue rationnel et factuel. Car face à des décideurs, la seule notion de coût ne peut suffire, surtout sur de gros projets et d'autant plus que le coût réel fait souvent l'objet de débats. Débats qui masquent malheureusement l'objectif premier du choix technologique: l'efficacité.

Or malgré la jeunesse des technologies dont il est question ici, il est possible de prendre les projets existants comme autant d'éléments de comparaison avec des solutions plus classiques considérées souvent à tort comme seules envisageables.

Un cas concret et réel a servi de fil rouge à l'exposé, celui d'une application centrale, critique et volumineuse, dans un environnement projet tendu avec un timing serré. Rien qui permettait d'envisager une ouverture à de l'open source à priori. Et malgré tout, le projet, appuyé sur les frameworks Spring.Net, NHibernate et Common.Logging a été un succès à tous les niveaux. IMG_2483_10

Tout comme c'était le cas ici, il y a clairement des situations où une solution peut amener un réel avantage concurrentiel et c'est parfois une solution open-source. Mais les barrières psychologiques à franchir restent nombreuses.

Et pourtant, force est de constater la vigueur et le sérieux des projets open source en .Net qui bénéficient pour certains d'entre eux d'équipes conséquentes. C'est un nouveau paradigme, une nouvelle économie, qu'il convient d'aborder objectivement une fois passée l'utopie des débuts. On peut et on doit faire du business avec l'open source.

Il ressort de cette vision un constat: là où la communauté Java a une existence propre et une vrai légitimité, côté .Net la communauté reste à "inventer".