Exile on Keyboard St. - Blog sur Linux et Debian

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

lundi 6 août 2018

Java: Bien utiliser le Builder pattern

Quand on maintient du code Java, on tombe malheureusement assez souvent sur des méthodes aux signatures complexes comme celle-ci:

public int myMethod(String id, String name, Boolean secure, Object obj, Object backupObj, boolean restart)

Et il n'est pas rare d'avoir encore plus de paramètres !

La situation se dégrade encore quand pour "simplifier", on surcharge la méthode précédente en:

public int myMethod(String id, String name, Boolean secure, Object obj, Object backupObj)

quand restart vaut false puis en:

public int myMethod(String id, String name, Boolean secure, Object obj)

quand en plus backupObj est null.

On peut avoir ainsi 3 à 5 signatures différentes pour la même méthode. Et cela devient vite unsupportable quand on veut refactorer ces méthodes, parce qu'elles sont référencées n fois dans le code de production et également dans les tests.

Si le développeur qui a créé la première méthode avait créé un object et l'avait passé en paramètre de sa méthode, on n'en serait pas là !

Imaginons maintenant la méthode suivante qui permet de créer un utilisateur:

public long create(final String firstName, final String name, final int age)

Elle retourne l'identifiant de l'utilisateur créé. Supposons que l'age n'est pas obligatoire et que l'on souhaite anticiper l'ajout de nouveaux champs pour créer un utilisateur.

On va alors plutôt procéder comme suit:

public long create(final User user)

La classe User commencera comme ceci:

public class User
{
    private long id;
    private String firstName;
    private String lastName;
    private int age;
}

Mais pour créer un utilisateur à passer en paramètre de la méthode create, on va créer un Builder pour construire l'objet User.

Pour cela, on peut installer le Plugin Builder Generator. Un autre plugin est également disponible: Inner Builder.

Après redémarrage d'IDEA, un clic-droit puis Generate propose maintenant l'option "Builder" et on a alors la boite de dialogue suivante:

Capture-CreateBuilder.png

Ici on a choisi un "innerBuilder" afin que le Builder soit une classe interne de l'objet lui même.

On choisit ensuite la liste des champs à inclure, on ne prends pas l'id puisqu'il ne sera pas calculé par l'appelant de la méthode create mais bien par celle-ci:

Capture-Select_Fields_to_Be_Available_in_Builder.png

Et on obtient:


    public static final class UserBuilder
    {
        private String firstName;
        private String lastName;
        private int age;

        private UserBuilder()
        {
        }

        public static UserBuilder anUser()
        {
            return new UserBuilder();
        }

        public UserBuilder withFirstName(String firstName)
        {
            this.firstName = firstName;
            return this;
        }

        public UserBuilder withLastName(String lastName)
        {
            this.lastName = lastName;
            return this;
        }

        public UserBuilder withAge(int age)
        {
            this.age = age;
            return this;
        }

        public User build()
        {
            User user = new User();
            user.lastName = this.lastName;
            user.age = this.age;
            user.firstName = this.firstName;
            return user;
        }
    }

On crée ensuite notre User comme suit:

        final User user = UserBuilder
                    .anUser()
                    .withFirstName("Brian")
                    .withLastName("Kernighan")
                    .build();

Cette façon de faire permet:

  • de faire évoluer l'objet User en changeant un minimum de code
  • de valider les différents champs dans la méthode build

Et les signatures des méthodes ne changent pas.

On peut même éviter de dupliquer les champs de la classe User dans la classe UserBuilder en procédant comme ceci:

public static final class UserBuilder
    {
        private User user;

        private UserBuilder()
        {
            user = new User();
        }

        public static UserBuilder anUser()
        {
            return new UserBuilder();
        }

        public UserBuilder withFirstName(String firstName)
        {
            this.user.firstName = firstName;
            return this;
        }

        public UserBuilder withLastName(String lastName)
        {
            this.user.lastName = lastName;
            return this;
        }

        public UserBuilder withAge(int age)
        {
            this.user.age = age;
            return this;
        }

        public User build()
        {
            return user;
        }
    }

Mais notre générateur ne sait pas le faire :-(

samedi 2 juin 2018

Chercher dans des fichiers de log avec lnav

Quand on développe, on passe beaucoup de temps à consulter et à chercher des informations dans les fichiers de logs des produits ou du système.

J'ai longtemps utilisé glogg et maintenant il me parait lourd et peu efficace.

lnav que je vais vous présenter maintenant est plus léger et s'avère très performant grâce à de nombreux raccourcis clavier.

Au lancement, on obtient le résultat suivant:

lnav.png

Vous constatez qu'on est au début du fichier. Pour naviguer dans le fichier, on peut utiliser:

  • g pour aller au début
  • G pour aller à la fin
  • Page up ou Backspace/ Page down ou Espace pour naviguer de page en page

Mais ce qu'il y a de commode, c'est que lnav permet d'aller à la prochaine erreur, en tappant 'e' ou au prochain warning en tappant 'w'.

De la même façon, 'E' vous positionne sur l'erreur précédente et 'W' sur le warning précédent.

On peut également naviguer dans le temps, c'est à dire que la touche 'o' vous fait avancer de 24h dans le fichier et 'O' le fait dans le sens inverse. Si l'intervalle recherché est de 24h, il faut utiliser respectivement 'd' ou 'D'.

lnav vous autorise aussi à rechercher un motif en tappant /<regexp>, les regular expressions acceptées étant les PCRE (Perl-Compatible Regular Expressions).

Autre fonctionnalité intéressante, on peut marquer une ligne pour la retrouver plus tard avec la touche 'm'. Ensuite l'appui sur les touches 'u' et 'U' permet de naviguer d'une ligne marquée à l'autre. C'est très utile pour débugger.

Bref, lnav devient rapidement un outil indispensable du quotidien du développeur, et le fait qu'il soit utilisable directement dans un terminal est un atout non négligeable.

Je n'ai évidemment pas décrit ici tout ce qu'on faire avec, pour découvrir d'autres fonctionnalités, vous pouvez utiliser la touche '?' au démarrage de lnav.

dimanche 24 septembre 2017

Sublime Text en version 3 et avec le dépôt Debian

L'éditeur de texte Sublime Text est sorti récemment en version 3.

Ce build 3143 est le build final de la version 3 et aussi la première mise à jour depuis le build 3126 qui datait quand même du 23 septembre 2016 !

C'est donc l'occasion de mettre à jour votre éditeur préféré. Pour cela, il existe maintenant un dépôt pour les principales distributions Linux.

Sur Debian, on procèdera comme suit:

Ajout de la clé GPG:

user@machine:~$ wget -qO - https://download.sublimetext.com/sublimehq-pub.gpg | sudo apt-key add -
[sudo] password for user: 
OK

Ajout du dépôt:

user@machine:~$ echo "deb https://download.sublimetext.com/ apt/stable/" | sudo tee /etc/apt/sources.list.d/sublime-text.list

Puis:

user@machine:~$ sudo apt-get install sublime-text

Si Sublime Text n'était pas déjà installé, il sera mis à jour:

user@machine:~$ subl --version
Sublime Text Build 3143

Les commandes précédentes installent la version stable de l'éditeur. Pour disposer de la version de développement, il faut acheter une license.

Chose intéressante, une license personnelle donne le droit d'utiliser Sublime Text au travail ! Des fois que votre employeur soit quelque peu radin ...