22 février 2012

JAX-RS et CDI sont dans un bateau...


Ceux qui ont eu la chance (?) de bosser avec moi savent que, en termes d'architecture des applications Java, je défends le concept de modèle métier riche, par opposition au Anemic Model Domain.

L'idée part d'un constat simple : on a souvent un beau modèle objet du domaine métier, bien adapté pour accueillir les données de l'application, et on déporte toute la logique de leur gestion dans des classes techniques spécialisées, qu'on appelle des "services" parce que c'est un mot qui peut dire tout et n'importe quoi alors pourquoi se priver ?

On se retrouve donc avec un modèle métier qui ne fait rien, noyé dans des couches de services métier, de services web, de services techniques (celui-là je l'adore) et de DAO (qu'on a pas appelé service pour une fois).

Avec JPA et ses annotations, on peut rapidement réduire la couche DAO à peu de choses, voir l'éliminer purement et simplement comme je l'ai fait avec Fonzie (un jour, promis, je reprendrai le développement ce projet ... quand j'aurais le temps). JPA étant déjà une abstraction de la persistance, je ne vois aucun intérêt à rajouter une couche DAO pour faire une requête JPA. En quoi se faire injecter un DAO est plus "propre" que se faire injecter un PersistenceContext et utiliser des NamedQueries ?

Pour aller plus loin, c'est à dire faire que nos objets métier portent eux-même la logique métier, on est rapidement confronté à un problème : nos objets ont besoin de faire appel à d'autres objets "collaborateurs" pour faire autre chose que de la conversion franc-euro. Spring propose depuis 2006 une solution via l'annotation @Configurable et l'instrumentation par AspectJ. Pour l'avoir utilisé sur un gros projet qui se reconnaitra, ça marche bien mais c'est un peu encombrant pour les développeurs (oui, AJDT, je pense à toi). Depuis, Java EE 6 est sorti et propose CDI.

Pour des besoins internes, j'ai développé une application d'intégration de services REST déployée sur RUN@Cloud. N'en déplaise à mes collègues, pas de Scala, d'Erlang ou de Ruby ici, mais du Java EE 6 brut de spécification, histoire de vérifier si Antonio raconte des bobards pendant ses conférences.

J'ai un objet métier Ticket, que je veux exposer avec JAX-RS :

@Path("/ticket/{id}")
public class Ticket {

    private int id;

    public Ticket(@PathParam("id") int it) {
        this.id = id;
        // Load data from id;
    }
}

Cela fonctionne très bien tant qu'il s'agit de faire un System.out, maintenant j'aimerais faire des choses plus concrètes, nécessitant l'utilisation d'un autre composant.

Après quelques errements, et avec l'aide de Paul, j'ai compris comment activer CDI pour obtenir l'injection de mes dépendances. Comme j'ai peur de ne pas m'en souvenir pour la prochaine fois, et que ça peut servir à d'autres, voici la recette : d'abord placer le fameux fichier bean.xml vide sous WEB-INF, puis modifier mon code pour CDI-fier ma classe JAX-RS :

@Path("/ticket/{id}")
@RequestScoped
public class Ticket {

    @PathParam("id")
    private int id;

    @Inject
    private AnotherComponent foobar;

    @PostConstruct
    public void load() throws IOException {
        // Load data from id;
    }

    @POST
    @Produces("text/plain")
    public String notify() throws Exception {
        foobar.sendNotification(id, getEmail());
        return "ok";
    } 
}



petite explication :
Dans un premier temps j'avais utilisé un constructeur prenant en paramètre l'ID du chemin REST et chargeant les données. Couplé avec CDI, je dois annoter ce constructeur @Inject pour qu'il soit utilisé à la place du constructeur par défaut, mais CDI dans ce cas cherche à m'injecter l'ID. Je ne sais pas si c'est un bug de RestEasy-cdi dans JBoss, toujours est-il que j'ai du suivre le plan B.


Je récupère donc l'ID par injection d'attribut depuis la requête REST. L'initialisation du bean est confiée à un @PostConstruct, ce qui en termes de gestion du cycle de vie est nettement plus explicite que de tout mettre dans le constructeur.


Et voila, mon Ticket est désormais un objet de mon domaine métier, exposé comme service REST, qui sur un POST gère un traitement métier via des composants avec qui il collabore et qu'il obtient par injection de dépendance. Pas besoin de TicketService, TicketResource ou autre classe purement artificielle juste introduite pour respecter un joli modèle en couches.

20 février 2012

La fin de Moore

La loi de Moore, tout la monde la connait sans la connaitre. On la cite souvent en disant que la puissance des processeur double tous les 18 mois, alors qu'elle concerne la densité de transistors sur une puce de silicium.

(source : wikipedia)

Cela a longtemps été équivalent, mais vous savez que la fréquence de nos puces se heurte à des limites physiques (depuis ~2004 déjà), et que la solution est le "scaling out" : multiplier le nombre d'unités de calcul plutôt que d'en avoir des plus rapides, voie même avoir beaucoup de "coeurs" de (relativement) faible complexité  et consommation (donc dissipation thermique). Même sur une machine grand public, il est courant d'avoir 4 ou 8 coeurs, et les CPU de serveurs en affichent parfois 128, sans parler de ce que les labs nous préparent, et cela arrive aujourd'hui également dans les appareils portatifs que sont nos smartphones (le savez-vous ? on peut même téléphoner avec !).

Twitter attire ce matin mon attention sur cet article, qui présente un transistor réalisé en labo avec un seul atome. Si cette technologie va mettre un peu de temps à arriver sur le PC de Mme Michu, c'est la première fois que l'industrie du silicium va se heurter à une limite physique infranchissable. Pendant des années, malgré les difficultés techniques et les effets de l'ultra-miniaturisation, ils ont réussi à descendre toujours plus sous le nanomètre. Cette fois-ci, il n'y aura pas d'échappatoire, et la loi de Moore s'arrêtera brutalement sur un palier définitif.



Je vous laisse imaginer la complexité de réalisation et le niveau de traitement des impuretés qui sont nécessaires à une telle réalisation ...

Note :
Définitif ... peut être pas, car les fondeurs ont plus d'un atout dans leur manche ! Mettre les pistes sur la tranche ou empiler les couches de transistors sur une même puce, à l'assault de la troisième dimension, en prévoyant soigneusement des "canaux" de dissipation des calories produites.

Et le transistor quantique ? Il pourrait prendre le relais, mais nécessite pas conception un traitement parallèle pour être utile (et sans doute tout un tas d'autres "détails" algorithmiques).

Quoi qu'il en soit, on y échappera pas, il va falloir apprendre à coder "concurrent", et ce n'est pas faute de vous avoir prévenu. Et que faisons nous, encore et toujours : du code purement séquentiel.

Le Cloud (désolé, je baigne un peu dedans en ce moment) n'échappe pas à cette règle : faire du scale-out sur des machines relativement peu puissantes / peu couteuses est très efficace si le problème est correctement pris en charge lors de la conception. Prennes l'exemple de Facebook qui a envisagé de construire un DataCenter basé sur des processeurs ARM, dont le principal intérêt est la très faible consommation.

Fork-join en Java 7, Concurrent collections prévues dans Java 8, Akka nous apporte le paradigme d'acteur pour une nouvelle conception, certains langages alternatifs intègrent de base ces concepts de parallélisme pour une plus grande efficacité.


Et vous ? Avez-vous déjà codé au moins une fois un algorithme de traitement non-séquentiel ? Pour ma part, en regardant en arrière 15 années de développement, ça a été rarissime, et je suis souvent passé pour un dangereux geek en évoquant cette option (peut être aussi pour d'autres raisons). Faites moi part de votre expérience !