Sur la route d'Oxiane digressions diverses

LeBlog OXiane

8 avr
2011

Redirection mobile d’un site web

une redirection apache - Illustration © OXiane Studio

Voilà donc le retour du site mobile !

Problème : gérer la redirection de son site vers une version mobile. Les stratégies sont multiples aujourd’hui et pour ainsi dire, complémentaires.

Gestion par CSS3

Vous pouvez profiter des capacités des media queries CSS3 pour adapter votre layout HTML au device de votre visiteur ! C’est très efficace, démonstratif, et facile à mettre en oeuvre. Bien sûr les problèmes sont nombreux : les CSS3 ne sont pas gérés par encore une majorité des navigateurs, mais le sont à priori par les navigateurs mobiles (n’oublions pas que c’est la cible). Problème beaucoup plus important : comment faire si mon visiteur veut retourner sur la version « normale de mon site internet ? Je ne sais pas pour vous, mais moi je déteste qu’on m’impose des trucs de ce genre … d’autant plus quand je sais pertinemment :

  • 1. que le site complet existe et
  • 2. que mon navigateur mobile est très capable de l’afficher … et
  • 3. que visiblement il y a des parties du site normal qui ne sont pas présentes sur le site mobile et que j’aimerais consulter… etc etc.

Exemple de media queries CSS3

@media all and (orientation:portrait) { … }
@media all and (orientation:landscape) { … }

Redirection serveur

Sur un serveur type Apache, on peut facilement créer des règles de redirection. Les directives de type Rewrite permettent de gérer le UserAgent (le navigateur pour faire simple) afin de rediriger toute requête entrante vers ma version mobile. Encore une fois c’est facile à mettre en oeuvre, mais je suis incapable de désactiver cette configuration quand je le veux.
Exemple de gestion du UserAgent :

RewriteCond %{HTTP_USER_AGENT} ipod|iphone|ipad|android|palm [NC]

Solution Javascript

Pour moi la plus élégante est donc une solution mixte : un layout dédié mobile, et pourquoi pas développé en JQuery Mobile, et une gestion fine des options en Javascript. Ce dernier me permet également de connaitre le UserAgent, et il me permet également de faire une redirection. Mais en plus il me permet de gérer les éventuels choix de l’utilisateur. Historiquement, ces informations étaient stockées dans les cookies, mais l’interface HTML5 Web Storage, en particulier SessionStorage, me permet de gérer des données nettement plus intéressantes. Autre avantage, c’est un objet purement de session, il disparaitra toujours à la fermeture du navigateur, je n’ai pas à gérer la durée de vie du cookie ou que sais-je encore. C’est une solution de ce type que nous avons utilisé sur www.oxiane.com, et en particulier, l’implémentation très simple de http://sebarmeli.com. C’est un fichier javascript qui permet de gérer différents types de redirection :

  • par répertoire ( vers /mobile /mobile_jquery comme chez oxiane )
  • par domaine (de www.site.com vers m.site.com ou mobile.site.com)

Toutes les options sont décrites sur la page de l’article et dans le code lui-même. (en cas de non support de HTML5, un cookie valable 2 heures est créé, on peut bien sûr modifier ce comportement.

On peut donc facilement naviguer du site mobile vers le site complet, et à ma première visite, je peux sans problème « imposer » à mon visiteur la version mobile.

Alain

Alain Boudard

aboudard

6 avr
2011

Adobe sur la route de JQuery

Aujourd’hui nous commençons l’ère du HTML 5, la spec est toujours à l’état de draft, mais les gros navigateurs pour PC ont emboité le pas de ceux embarqués sur mobiles pour implémenter toujours plus des fonctionnalités décrites. Android 3 propose d’ailleurs une interface vers la Device API, ce qu’on appelle le media capture, c’est une petite révolution. Toujours sur Android, la possiblité est offerte de jouer avec les complexes transformations CSS 3D.

La convergence développement mobile et développement web est très actuelle, il suffit de voir le nombre de frameworks qui fleurissent en version beta, RC ou alpha 0.01 qui proposent un package plus ou moins abouti, testé et compatible sur les différents navigateurs : un ensemble de conventions de code HTML à l’aide d’attributs HTML5, un cadre CSS3 de base pour la présentation et une API javascript unifiée et si possible adaptée aux interfaces tactiles.

Dans ce domaine, celui qui me plait le plus est sans conteste JQuery Mobile. Cet outil sortait il y a peu une Aplha 4 qui m’a permis de tester une pré-migration de pré-version ! (oui, passer le la alpha 2 à la alpha 4 nécessite quelques adaptations, surtout si on s’est amusé à customiser à droite à gauche). Basé sur JQuery, ce framework est simple et efficace, j’en avais déjà parlé pour présenter le catalogue mobile qui devient peu à peu une version mobile du site internet OXiane. Les widgets sont assez robustes même si ils ne sont pas forcément très nombreux. On peut toujours expérimenter une intégration avec JQuery UI si on reste raisonnable, j’ai par exemple intégré les Tabs avec succès, mais il ne faudrait sans doute pas pousser trop l’idée, les deux outils n’ont pas pour l’instant vocation à travailler en commun, UI étant bien sûr très axé événements « souris ».

La gestion des événements est bien entendu la problématique centrale, puisqu’on en parle, dans un framework Javascript, et à ce sujet, l’implication d’Adobe dans le HTML5 est éloquente, et son interêt pour JQuery ne l’est pas moins. Adobe s’implique non seulement dans l’API mobile, mais dans la roadmap des nouvelles interfaces de UI, ce qui devrait rassurer les développeurs qui se demandent si tel ou tel framework a de l’avenir, mais surtout si il va implémenter les dernières nouveautés de l’API native HTML5.

Tout ceci est motivant, comme l’était il y a quelques mois la présentation Adobe de son produit Edge qui sera certainement, si il voit le jour, une killer-app si on peut dire. Avant gout de ce produit, encore un joli nom : Wallaby ! Cet outil permet de traduire une animation Flash disons basique en son équivalent HTML5 CSS3 ! Pas mal, et sans doute également révélateur des orientations d’Adobe dans le web.

Je termine ce tour d’horizon avec Rails. Ce papa du développement web MVC tient toujours la forme avec la version 3 qui intègre désormais JQuery en tant qu’API Javascript, disons que ce n’est pas par défaut, mais c’est possible.

HTML 5 nous ouvre la porte de belles heures de codage forcené pour faire tourner des chats par exemple ;)

Alain Boudard

aboudard

6 avr
2011

Sur la route du Padawan

Episode I

@MenaceFantoche

Bonjour à tous,
je me présente : Manu, padawan sur la planète Oxiane.
Durant mes premiers entraînements programmatiques, nécessaires à tous ceux qui souhaitent maîtriser la Force, j’ai pu découvrir (et redécouvrir) des notions qui méritent un peu d’attention. Certaines seront bien connues de nombre d’entre vous et peut être depuis longtemps mais l’apprentissage d’un padawan est semé d’ignorance et d’incertitudes qu’il comblera à Force de persévérance et de curiosité.

C’est pourquoi, je vous donnerai rendez-vous chaque mois pour partager ces (re)découvertes et ce sera, j’espère, l’occasion pour vous de nous faire part de votre expérience et de vos réflexions en la matière.

Ce mois-ci, j’aimerais vous parler des annotations.
(Tadaaaaaaaaaaaaa ! non ? ouah le bide, bon… )

Dans une galaxie lointaine, très lointaine…

« Oui… ça va on connait… : @Deprecated, @Override,… «  me direz-vous,
bah moi aussi je connais, calmos hein !

Non, je voulais dire les autres, les « vraies », celles que je ne connaissais pas quoi.

« Hein quoi !!!?? Y en a d’autres ??? Oracle (ou Sun pour les nostalgiques) m’a pas appelé pour me le dire ! Y en a combien ? C’est bien ? C’est cher ? »

Je vois que ça aiguise votre curiosité alors avançons.
Franchement, je savais que ça existait quelque part mais je voyais pas trop l’utilité de la chose… jusqu’à ce que je fasse le TP de Maître Jeff !

« C’est quoi une annotation ? »

Et bien c’est un marqueur, ça se déclare comme ceci :

public @interface Force{
}

« Ah ok… comme une interface quoi. Aller, merci salut. »

Mais non, attends ! Revenez ! C’est bien plus que ça, on peut marquer des classes, des méthodes, des variables d’instances,… :

@Weapon
public void lightSaber(){
           ...
}

@Force
public Class Padawan{
          ...
}

Je vous laisse le bonheur de découvrir tout ce qui est annotable.

De plus, on peut les utiliser à la compilation et à l’exécution et là c’est génial avec l’introspection !

« Bon d’ac, je reste »

Ouf.

Choisissez vos armes !

(je prends le sabre laser)

Je laisse de côté les annotations standards/communes  (sachez qu’il y en a 8 ) car celles qui nous concernent sont les annotations personnalisées – Il y a en a également dans javax.annotation.

Continuons avec les méta-annotations ou les annotations d’annotations.
Ces petites choses, situées dans java.lang.annotation, sont indispensables puisqu’elles permettent de définir le comportement de nos annotations et répondent à des problèmes particuliers :

  • – annoter un certain type d’élément (classe, interface, méthode, champs, constructeur, package,…) —-> @Target
    ex: @Target(ElementType.METHOD)
  • – définir leur durée de vie (disponibles à l’exécution, conservée dans le code source et ignorée par le compilateur, conservée dans le code source et le bytecode —-> @Retention
    ex: @Retention(RetentionPolicy.RUNTIME)
  • – indiquer si l’annotation est héritée dans les sous classes —-> @Inherited
  • – conserver l’annotation dans la javadoc —-> @Documented

« Mais c’est dingue, on peut faire plein de combinaisons avec ça ! »

Et oui, c’est ce que je me suis dit aussi.
Poursuivons, ce qu’il y a de bien avec les annotations personnalisées c’est qu’elles peuvent avoir un ou plusieurs attributs (ou zéro évidemment).

« Ah ouais super… c’est quoi un attribut d’annotation ? »

Bah, m’enfin… Euh oui, un attribut au sens d’une annotation c’est en fait un membre, c’est à dire soit une méthode soit un champs initialisé. Illustrons ce propos :

@Target(ElementType.METHOD)
public @interface Weapon{
    public enum Type {BLASTER, LIGHTSABER, HEAD} ;
    Type type() default Type.BLASTER;
    String calibre() default "none";
    int kill();
}

@Inherited
public @interface Force{
    String type() default "good side";
    public enum Niveau {YOUNGLING, PADAWAN, MASTER} ;
    Niveau niveau() default Niveau.PADAWAN;
}

@Force("dark side") // un attribut avec default est optionnel, ça tombe bien j'ai annoté une classe Padawan !
public class Padawan{
    ...
    @Weapon(type=Type.HEAD, kill=0)
    public void attack(){
    }
}

NB: Lorsqu’on a un unique attribut dont l’annotation est explicite, on peut le nommer value() ce qui évite de ré-écrire  son nom.

Les types de ces membres sont soumis à contrainte, je laisse Eclipse (ou votre IDE préféré vous le montrer, essayez de mettre un peu tout ce que vous connaissez comme type… )

Un certain point de vue

« Ouais super et l’utilité du machin ? »

On peut imaginer apporter des extensions au compilateur et ce grâce au PAP (Pluggable Annotation Processing, désolé le jeu de mot était trop tentant) du style : vérifier que toutes les classes Padawan annotées par @Trainable dispose d’une méthode train().
On voit assez bien la puissance du mécanisme : une vérification d’un comportement d’un code, grâce à l’interface Processor du PAP donnant accès à l’AST (Abstract Syntax Tree, la représentation interne du programme avant génération du code) en train d’être compilé, et de plus la possibilité de générer du code.
Pour notre exemple, supposons que nous avons des classes Jedi (possédant une méthode teach()), Padawan et Formation.
A chaque instance de Formation sont associés une instance de Jedi et des instances de Padawan, la méthode teach() est appelée pour pouvoir dispenser son enseignement à ses Padawan.
Malheureusement la classe Gredin, qui étend Jedi, c’est « glissée » dans certaines Formation et a remplacé le Jedi d’origine à la compilation à cause d’une mauvaise manip’ de génération de code avec le PAP (;-D) :

Le but de la classe Gredin est d’exécuter sa méthode gredine() contenue dans sa méthode teach() afin de pervertir ses padawans.

public class Gredin extends Jedi{

@Gredinable
public void teach(){
    gredine();
}

private void gredine(){
    //des choses pas bien genre des gredineries
}

----------- ------------ ----------- ------------

public class Formation{
    private Map<Jedi,List<Padawan>> formations;

    //je vous laisse imaginer la suite ?
    ...
    //un peu plus loin donc
public void teaching(){
    Set<Jedi> jediSet = formations.keySet();
    for (Jedi j : jediSet) {
        Method[] methods = Jedi.class.getMethods();
        for (Method method : methods) {
            if (method.isAnnotationPresent(Gredinable.class)){
                formations.remove(j);
            }
        }
    }
}
    //je vous laisse imaginer la suite ?
    ...
}

On peut, à l’exécution, contrôler qui est le gredin grâce à une annotation @Gredinable par exemple (décorant sa méthode teach() contenant gredine() ) et dans quelle instance de Formation il s’est mis et ainsi lui faire exécuter le bon code afin qu’il forme ses padawans au lieu de « grediner » et de les faire passer du côté obscur…

Comme me l’a soufflé Maître Jef, un exemple simple des annotations pourrait être @ReadOnly et @ReadWrite pour indiquer que des attributs ont uniquement un getter ou également un setter et vérifier cela.

Une autre annotation toute simple et bien utile pour la relecture et la compréhension du code (ou des erreurs) est @OrNull qui indique qu’une méthode peut retourner null et qu’on est prévenu !

On perçoit donc bien une autre facette de la programmation par contrat avec ses avantages (plus de sémantique, meilleure conception,…) et ses inconvénients (demande plus de ressource mémoire, pas exempt de bug, assez complexe à mettre en oeuvre pour la génération de code) mais l’annotation en elle-même ne fait rien, c’est en quelque sorte un commentaire un peu typé et ce sera autre chose qui l’utilisera ou pas.

On peut tout de même s’interroger sur le degré de pratique et d’utilisation des annotations chez les développeurs même si elles sont très présentes dans Hibernate ou Spring en alternative au fichier de configuration.

On peut d’ailleurs imaginer un métalangage complet qui pourrait annoter n’importe quel langage, un standard en somme qui établirai des règles de conception et de génération de code automatique. A méditer pour l’intérêt et la lourdeur d’apprentissage en plus des langages existant déjà bien fourni en frameworks et autres gredineries.

Pour ma part, j’ai été quand même plus qu’enchanté d’approfondir cette partie de Java que l’on entrevoit peu dans les cursus universitaires sauf lors de la mise en place de tests avec JUnit 4 ou lorsqu’ un prof s’y intéresse. Comme toujours est-ce plus important que d’apprendre les fondements de la POO et les mécanismes de base du langage ? Non, certes mais au moins une ouverture permet d’imaginer de nouvelles possibilités de développement.
J’ai entendu parler de certains hacks de javac permettant de modifier le code avant compilation (officiellement, on ne peut pour le moment que générer des fichiers à ma connaissance) et en fouinant un peu, j’ai même touvé un projet (http://projectlombok.org/) qui ouvre la voie et répond à une idée de Maître Jef : pourquoi pas ne plus implémenter les accesseurs et annoter directement les attributs ?
A chaque fois qu’on en apprend un peu plus, on se dit encore que tout reste à faire…

Voilà, si vous avez des remarques ou des questions, n’hésitez pas à commenter !

« Oui moi, j’ai une question et je voudrais dire plein de trucs, de choses et de machins… »

Bah, tu commentes ! Non mais, gredin…

Merci pour votre lecture et merci à Maîtres Jef et Stef.

PS: Cette année évidemment un de mes anciens prof a intégré les annotations dans son cours et parle d’un langage d’annotation développé et soutenu en grande partie par des universitaires : JML (Java Modeling Language), des outils de vérification et de certification existent déjà comme Krakratoa (INRIA)

Manuel François

tHeFeaTuReDMaN

24 mar
2011

C’est quoi un Objet ?

Nos échanges internes, souvent passionnés (et parfois alcoolisés) du soir nous ramènent souvent à la question fondamentale « c’est quoi un objet (en informatique) ? »
et autres sous-question du genre « c’est quoi la différence entre le sous-typage et l’héritage ? » ou « c’est quoi un type ? »

Sur l’objet, un dessin vaut mieux qu’un grand discours …

La réponse un peu mieux expliquée …

Les vrais fondements

1/ l’encapsulation
Les données internes et privée de l’objet (à ne pas confondre avec l’agrégation ou la composition comme malheureusement je le vois avec horreur dans certaines réponses à nos tests d’évaluation)

2/ l’envoi de message
Les objets sont sollicités par envoi de message et ce sont eux qui déterminent le traitement à effectuer

Le reste n’est pas fondamental mais en découle plus ou moins :

3/ le polymorphisme
Un objet peut être remplacé par un autre qui sait répondre aux messages attendus
Conséquence du 2 (le même message peut être envoyé à des objets différents et c’est l’objet receveur qui détermine la méthode à exécuter)

4/ le mécanisme d’héritage
Consiste à éviter de recopier les mêmes méthodes dans des objets différents.
Les langages à base de classe (ndr: comme Java, smalltalk, php) proposent une relation d’héritage entre classes (les méthodes sont portées par les classes et les objets sont instances de ces classes)
Les langages à base de prototype (ndr: comme javascript) font porter les méthodes par les objets directement mais les objets font références à des prototypes (la recherche de méthodes est déléguée au prototype lorsque l’objet ne trouve pas la méthode correspondant au message reçu).

Qu’en est-il du typage ?
Le typage n’est pas une notion objet. C’est une notion de compilation.
Ce qu’on type, ce sont des variables, paramètres et retours de traitements (fonction, méthode, procédure)
Dans un système objet à base de classes, les classes servent généralement aussi de type.
Et la relation d’héritage correspond un peu à la notion de sous-type.

Par abus de langage, on parle parfois de typage dynamique dans les langages à objets non typés.
Java a formalisé le concept d’interface (qui correspond à la notion de type abstrait)
ce qui dissocie un peu plus encore le typage de l’héritage.

Article honteusement inspiré d’échanges sur la mailing liste interne et d’une réponse synthétique de Jean-François

Stéphane Liétard

slietard

31 jan
2011

Organiser les accès aux données sous Android

En réalisant une application « Cave à vins » sous Android, je me suis trouvé face à un problème de taille: comment faire passer mes objets métiers d’une Activity à l’autre en gardant un code maintenable?

Tout dans les Intents!

Ma toute première approche a été de tout envoyer dans les Intents, à chaque changement de vue, j’ai envoyé des ArrayLists d’objets métier entiers. Je me suis vite rendu compte que ça devenait rapidement ingérable. Il faut traiter trop de cas différents dans chaque page: que se passe-t-il avec mes données si l’utilisateur clique sur « back »?
Intent i = new Intent(DisplayDetail.this, MarkedMap.class);
ArrayList<Marker> mm = new ArrayList<Marker>();
mm.add(new Marker(1, 2, 3));
i.putParcelableArrayListExtra("markers", mm);
startActivityForResult(i, CODE_REQ_MARKER);

Avec un ContentProvider

Ma seconde approche fut d’utiliser un Content Provider, puisque son nom dit qu’il fournit des données, ça devrait être ce que je veux. Ca a l’air super, y’a une méthode « managedQuery » qu’on peut appeler de n’importe quelle Activity. Le souci, c’est qu’il fournit des objets de type Cursor. Et là, si on a besoin dans deux Activity de la liste des Personnes, on doit écrire deux fois la boucle sur le Cursor:
Cursor cur = managedQuery(myPerson, null, null, null, null);
if (cur.moveToFirst()) {

        String name;
        String phoneNumber;
        int nameColumn = cur.getColumnIndex(People.NAME);
        int phoneColumn = cur.getColumnIndex(People.NUMBER);
        String imagePath;

        do {
            // Get the field values
            name = cur.getString(nameColumn);
            phoneNumber = cur.getString(phoneColumn);

            // Do something with the values.
            ... 

        } while (cur.moveToNext());

    }

(exemple pris sur developer.android.com)

Et ça, c’est terrible. Si un jour on change le modèle métier des Personnes, faut réécrire ce code dans CHAQUE Activity.

L’héritage, tout simplement

Vous me direz, mais pourquoi ne pas avoir une superclass qui s’occupe de tout ça et qui renvoie des objets métiers comme on veut? Ca semble être une super idée, on a une classe qui contient un ensemble de méthodes pour récupérer, lister, modifier nos objets Personne. Et puis toutes les Activity qu’on crée qui ont besoin de ces Personnes héritent de notre superclasse. Si on veut faire les choses bien, on peut même envisager que la super classe est abstraite et qu’on a une flopée de classes du style « DAOimpl » qui vont aller chercher les données dans un flux xml, la base de donnée interne SQLite ou encore un webservice ou que sais-je?
C’est une bonne idée, à un détail près: sous Android, quand on passe d’une Activity à l’autre, ce n’est pas le développeur qui appelle explicitement le constructeur de l’Activity. C’est géré de façon interne (et obscure à mes yeux!), avec un classloader. Le développeur ne fait qu’appeler « startActivity(Intent i…) » ou encore « startActivityForResult(Intent i….) » et c’est à peu près tout ce qu’on peut contrôler sur l’instanciation de l’Activity.
Et donc si dans la superclasse on gère une collection de Personne, on risque fortement (pour ne pas dire inévitablement) d’avoir plusieurs collections de Personne qui se baladent en mémoire de façon parallèle! Et donc éventuellement une des instances de la collection qui sera modifiée par une Activity, une autre instance de la collection de Personne par une deuxième Activity…
Enfer et damnation, ce n’est donc toujours pas la bonne solution.
La solution, c’est d’utiliser un service. Le service Android, c’est comme un thread qui tourne en parallèle de votre application, qui peut soit être lancé et s’arrêter en même temps que chaque Activity, soit tourner indéfiniment, jusqu’à ce qu’on lui dise explicitement de s’arrêter.
Donc, l’idée, c’est que chaque vue qui a besoin des Personnes se connecte au service:
Intent dbServiceIntent = new Intent("com.oxiane.service.DBService");
ServiceConnection conn = new ServiceConnection() {
			@Override
			public void onServiceConnected(ComponentName name,IBinder service) {
				Log.d("dbService", callingClassName + " Connected");
				dbService = ((DBService.MyServiceBinder) service).getService();
				serviceConnectionIsReady();
			}

			@Override
			public void onServiceDisconnected(ComponentName name) {
				Log.d("dbService", callingClassName + " Disconnected");
			}
		};
bindService(dbServiceIntent, conn, Context.BIND_AUTO_CREATE);

Note: la méthode serviceConnectionIsReady() est une méthode que j’ai mise en abstraite dans la superclass de mes Activity. Chaque Activity va donc devoir l’implémenter. Un bon exemple d’utilisation est, par exemple, d’afficher une barre de progression « Loading… » puis, dans la méthode serviceConnectionIsReady(), vous avec accès à vos données, donc vous pouvez afficher votre vue avec les données.

Il reste encore un souci: dans ce cas d’utilisation, chaque Activity qui appelle ce bout de code va lancer le service et l’arrêter quand l’Activity meurt. Ce qu’on veut, nous, c’est que le service soit lancé tout le temps, et que chaque Activity puisse à sa guise, se connecter ou non au service.

On pourrait faire simplement un « startService » dans un coin, sur la première Activity de l’application. Mais ce serait trop simple, non? Et on risque d’oublier que c’est dans telle ou telle Activity que le service est démarré. Et il faudrait changer de place ce code si on décide que c’est finalement une autre Activity qui se lance en premier…

Au lieu de ça, il suffit de vérifier si notre service « com.oxiane.service.DBService » est lancé ou non:

Lister les services qui tournent sur votre machine

Il y’a justement un service Android qui est fait pour ça! Le service ACTIVITY_SERVICE:

final ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
final List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);

Et voilà, plus qu’à parcourir cette liste, et on peut lancer le service s’il n’existe pas, ou s’y connecter s’il existe!

for (int i = 0; i < services.size(); i++) {
if ("com.oxiane.service.DBService".equals(services.get(i).service.getClassName())) {
isServiceFound = true;
break;
}
}
if(isServiceFound)
{
Log.d("oxianeService", "Service trouvé, je me connecte!");
bindService(dbServiceIntent, conn, Context.BIND_AUTO_CREATE);
}
else
{
Log.d("oxianeService", "Service NON trouvé, je le crée puis je me connecte");
startService(dbServiceIntent);
}
Johann Hilbold

jhilbold