Archive

Articles de Pierre-Yves RICAU

Son site web : http://blog.piwai.info

Mieux le connaître


Vous pouvez me retrouver sur Twitter, me suivre sur mon blog, et découvrir mon parcours sur LinkedIn.

GWT = Google Won’t Throw ?

Connaissez-vous l’histoire de l’exception dont on a perdu trace ?

Vous le savez probablement, chaque service GWT-RPC est en réalité une servlet. Petit rappel :

  • les appels Ajax GWT-RPC sont réalisés en POST,
  • le nom de la méthode du service à appeler est spécifié dans la requête envoyée,
  • l’appel est traité dans la méthode doPost(HttpServletRequest request, HttpServletResponse response), qui se charge de désérialiser les paramètres, faire appel à la bonne méthode du service par réflexion, puis sérialiser la réponse.

Que se passe t’il lorsque la méthode du service jette une exception ? Deux possibilités :

  • soit l’exception est déclarée dans l’interface du service, et celle-ci sera sérialisée jusqu’au client, qui pourra la traiter correctement,
  • soit ce n’est pas le cas (y compris pour les RuntimeException), et le client recevra une erreur 500, et le tristement célèbre :

    The call failed on the server; see server log for details

Lire la suite…

Share

GWT : Big Fat deRPC

Le framework GWT met à disposition du développeur plusieurs API pour communiquer avec un serveur en HTTP.

L’une des possibilités offertes est l’utilisation du framework deRPC, présent depuis GWT 2.0. Cette nouvelle implémentation de GWT RPC est top moumoute, à tel point que Sami Jaber, dans son (très bon) livre Programmation GWT 2, considère l’ancienne API comme dépréciée et invite à utiliser uniquement deRPC.

Alors, faut-il adopter deRPC les yeux fermés ? Attention malheureux ! DeRPC peut considérablement augmenter la taille de vos requêtes HTTP.

Au cours d’une mission, j’ai ainsi découvert la multiplication par 50 de la taille d’une requête, de 200 Ko à 10 Mo.

Lire la suite…

Share

Clean Android Code : I CAN HAZ INT IDS?

Disclaimer : cet article contient des switch, et pourrait donc heurter la sensibilité d’un public non averti. Je tiens à décliner toute responsabilité en cas de switchite aiguë consécutive à une pratique trop assidue d’Android.

Développeurs Android, avez-vous remarqué à quel point votre code utilise des int comme identifiant à tout bout de champ ?
Il n’est pas rare de devoir écrire le code suivant :


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class MyActivity extends Activity {

    private static final int WARNING_DIALOG = 0;
    private static final int DOWNLOAD_PROGRESS_DIALOG = 1;
    private static final int CONFIRM_LOGOUT_DIALOG = 2;

    public void iCanHasCheezburger() {
        showDialog(WARNING_DIALOG);
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        switch (id) {
        case WARNING_DIALOG:
            return createWarningDialog();
        case DOWNLOAD_PROGRESS_DIALOG:
            return createDownloadProgressDialog();
        case CONFIRM_LOGOUT_DIALOG:
            return createConfirmLogoutDialog();
        default:
            return null;
        }
    }
    // [...]
}

Cette manière de faire est d’ailleurs recommandée par le guide de développement Android officiel.

Papy Android réalisé avec Androidify : http://markoi.de/HIy


Lire la suite…

Share

La SCJP, c’est pas de la menthe à l’eau

Les JDuchess françaises ont récemment décidé d’organiser un groupe de travail pour les personnes souhaitant passer la certification SCJP.  Après avoir donné mon retour d’expérience sur la mailing list dédiée, je me suis dit qu’il serait intéressant d’en faire un article.

Lire la suite…

Share

Refactoring par la pratique

Dans cet article, nous allons procéder à un refactoring sur un exemple concret, afin de mettre en exergue quelques bonnes pratiques.

Défi : comprendre du code inélégant*

*Edit : j’avais initialement écrit “imb*table”, mais il paraît que ça ne fait pas très sérieux :-P

Êtes-vous capable de comprendre ce que fait la méthode computeConvexHull() en moins de 3 minutes ?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
public List<GeoPoint> computeConvexHull(Set<GeoPoint> points) {

    // Path list
    ArrayList<GeoPoint> path = new ArrayList<GeoPoint>();

    // Pick the min longitude point as first
    GeoPoint first = null;
    for (GeoPoint point : points) {
        if (first == null || point.getLongitude() < first.getLongitude()) {
            first = point;
        }
    }

    if (first != null) {
        path.add(first);
    } else {
        throw new IllegalArgumentException("Can't retrieve the western point");
    }

    boolean right = true;
    boolean loop = true;

    while (loop) {

        GeoPoint current = path.get(path.size() - 1);

        GeoPoint next = null;
        double nextLatitudeDiff = 0;
        double nextLongitudeDiff = 0;
        boolean recordNext = false;
        for (GeoPoint point : points) {
            if (!point.equals(current)) {
                double latitudeDiff = point.getLatitude() - current.getLatitude();
                double longitudeDiff = point.getLongitude() - current.getLongitude();
                if (longitudeDiff == 0 || longitudeDiff > 0 == right) {
                    if (next == null) {
                        recordNext = true;
                    } else {
                        // Compare the 'a' in the linear equation Y = a.X
                        // that correspond to the line slope.
                        boolean negativeSlope = latitudeDiff * nextLongitudeDiff - nextLatitudeDiff * longitudeDiff < 0;

                        if (negativeSlope) {
                            recordNext = true;
                        }
                    }

                    if (recordNext) {
                        recordNext = false;
                        next = point;
                        nextLatitudeDiff = latitudeDiff;
                        nextLongitudeDiff = longitudeDiff;
                    }
                }
            }
        }

        if (next != null) {

            // Check abnormal case
            if (path.size() > points.size() + 1) {
                throw new RuntimeException("Convex hull computation failed");
            }

            path.add(next);

            /*
             * If we are not back to the first point, let's continue finding
             * the path.
             *
             * Otherwise, do nothing => going back from the stack, this is
             * actually the end point of the recursive algorithm.
             */


            if (path.get(0) == next) {
                loop = false;
            }

        } else {
            // We have reached the point on the right, let's go back!
            right = !right;
        }
    }

    return path;
}

Alors ? Checkstyle lui donne une complexité cyclomatique de 16. Plutôt difficile d’y voir clair. Moi en tout cas, je n’en suis pas capable.
Et pourtant, j’en suis l’auteur :-). Critique de code bien ordonnée commence par soi-même ! Lire la suite…

Share