Hubesco's Blog

Inside a software engineer mind

Apprendre TypeScript

Rédigé par Pao Aucun commentaire

Angular 2, Ionic 2, PrimeNG, ...

De grands frameworks se mettent à TypeScript. Il est temps de s'y mettre, avant la sortie de bêta des frameworks. TypeScript semble être l'avenir. Mais ce n'est pas simple. Il est dit que c'est un superset de JavaScript. Cependant le langage apporte des nouveautés notamment les classes, le type statique (optionnel), les interfaces, les énumérations et les modules (d'autres nouveautés ici : https://fr.wikipedia.org/wiki/TypeScript). Certes ces nouveautés ne le sont pas dans d'autres langages, mais il y a toujours des subtilités et surtout la syntaxe à apprendre.

Pour moi, on entre enfin dans l'ère du JavaScript productif. Bon OK je dis ça parce que mon langage de prédilection est Java et que j'aime le typage statique et les interfaces. Pourquoi attendre le runtime pour avoir des erreurs alors qu'on peut les avoir à la compilation. Au plus tôt l'erreur est détectée, moins chère elle coûte à corriger. Et avec ces nouveautés on va pouvoir industrialiser un peu plus et se mettre d'accord sur la façon de travailler. De packager ses apps. De structurer ses classes.

Ce qui me manque encore, c'est le bootstrap d'un projet TypeScript ou Angular 2. C'est encore trop "à la main". Je n'ai pas encore tenté les générateurs Yeoman, je m'y mettrai quand Angular 2 sera en version finale. Je rêve d'un Spring Boot en Angular.

Classé dans : software Mots clés : aucun

Le spectre du Travail en Double

Rédigé par Pao Aucun commentaire

Ce post est la continuité de mon post précédent sur Cartouche de modification du code source.

J'en rajoute une couche car je remarque que le Travail en Double nous guette en permanence. Il est là, insidieux, patient, subtil, perfide. Et il s'insinue sans même qu'on le remarque.

Un des principes du Software Engineering est Don't Repeat Yourself (DRY). Mais il est trop axé sur Software. Pas assez sur Engineering. Parce que oui, c'est dans notre travail, dans sa globalité, qu'il peut y avoir du Travail en Double.

Dans la suite je parle de système, au sens large. On travaille sur des systèmes (applications, base de données, ...) ou dans un système (méthodologie de travail, entreprise, ...).

Ses désavantages

Les désavantages du Travail en Double sont assez évidents :

  • Fastidieux
    Faire le travail une fois peut déjà être difficile. Le faire deux fois, ça en devient épuisant. Et même si la première fois est facile.
  • Source d'erreur
    Il faut en permanence penser à synchroniser les deux systèmes. Et la question n'est pas de savoir "si on va oublier de le faire" mais "quand va-t-on oublier de le faire". Le cerveau finit toujours par oublier.
    Et si les deux systèmes ne sont pas synchronisés, il y un risque de se baser sur des informations fausses.
  • Incomplet
    Quand on fait le travail la deuxième fois, on devient plus concis ou moins précis. Un des deux systèmes perd alors en pertinence. Et l'information devient incomplète.
  • Inutile
    Si deux systèmes font le même travail, c'est qu'il y en a un des deux qui est inutile.
  • Incompréhensible
    "Si je le fais une fois, pourquoi ai-je besoin de le faire une deuxième fois ?"

D'expérience, même avec toute la motivation du monde et toute la bonne volonté de l'univers, au bout de deux semaines, un des deux systèmes est finalement délaissé et n'est plus à jour. Cela génère des problèmes pour ceux qui ont besoin du système délaissé. Et donc réunion pour demander de continuer à garder à jour le système. Ca râle, démotivation, perte d'intérêt, et arrive l'incompréhension de ceux qui n'utilisent pas le système mais qui le mettent à jour .

Au final, on génère de la frustration et une perte de temps.

Là où je l'ai rencontré

  • Reporting de mon travail sur plusieurs systèmes (bug tracking, excel, application de gestion de projet, ...)
  • Documenter la structure Maven d'une application
  • Documenter un algorithme en dehors du code source
  • Faire la spécification d'un algorithme en Word et maintenir absolument à jour
  • Maintien manuel de la documentation des web services d'une application.
  • Écrire dans des documents Word des rapports de tests unitaires très proches de JUnit
  • Maintenir à jour un Scrum Board ou Kanban Board et JIRA
  • Le client devait, pour éviter une reprise des données, utiliser l'ancienne application et mettre à jour la nouvelle qui n'était pas encore tout à fait finie et donc non exploitable sans l'ancienne. La situation a duré un an.
  • Duplication de code source

Détecter le Travail en Double

Ma solution pour le détecter et l'éviter est de me poser les deux questions suivantes :

  • "Est-ce que je souhaite faire n'est pas déjà fait ailleurs ?"
  • Et si vraiment il n'y a pas le choix d'avoir deux systèmes : "N'y a-t-il pas un moyen de synchroniser automatiquement les deux systèmes ?"

Si la réponse est non dans les deux cas, méfiez-vous, c'est que le Travail en Double va arriver, ou pire encore, il est déjà là...

Classé dans : software Mots clés : aucun

Envoi d'e-mails avec une application Java EE 7, Wildfly 9 et OpenShift

Rédigé par Pao Aucun commentaire

Toujours dans l'optique d'améliorer l'application de gestion des familles d'accueil, je me suis mis en tête d'ajouter à l'application la capacité d'envoyer des e-mails, notamment pour :

  • Création d'un utilisateur, envoi d'un e-mail avec login/password
  • Reset d'un mot de passe
  • Alertes multiples
  • Envoi d'un e-mail d'information à la famille d'accueil (rappels, nouvelle inscription, ...)

Cet article décrit la façon dont j'ai procédé pour configurer les mails dans l'application.

 

Configuration Wildfly 9

Toutes les lignes de configuration qui suivent se trouvent dans le fichier standalone.xml (ou les variantes si vous avez votre propre configuration Wildfly).

  • Ajout de l'extension Java Mail (si vous n'avez pas déjà la configuration Java EE full profile) :
        <extension module="org.jboss.as.mail"/>
  • Ajout d'une session mail :
        <subsystem xmlns="urn:jboss:domain:mail:2.0">
            <!-- Other mail sessions -->
            <mail-session name="famivacMail" jndi-name="java:jboss/mail/famivac">
                <smtp-server outbound-socket-binding-ref="famivac-mail-smtp" ssl="true" username="${MAIL_SERVER_USERNAME}" password="${MAIL_SERVER_PASSWORD}"/>
            </mail-session>
        </subsystem>
  • Ajout de l'outbound socket, qui définit le host et le port du serveur de mail :
    <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
        <!-- Other sockets -->
        <outbound-socket-binding name="famivac-mail-smtp">
            <remote-destination host="ssl0.ovh.net" port="465"/>
        </outbound-socket-binding>
    </socket-binding-group>
rhc env set MAIL_SERVER_USERNAME="<Value>" MAIL_SERVER_PASSWORD="<Value2>" -a gestionnaire
  • Côté développement, j'ajoute mes variables dans les options JVM :
-DMAIL_SERVER_USERNAME="<Value>" -DMAIL_SERVER_PASSWORD="<Value2>"

 

Mail Service

Côté application, je peux maintenant utiliser la session mail déclarée et initialisée par Wildfly, grâce à son adresse JNDI :

// Imports here...
/**
 * @author paoesco
 */
@ApplicationScoped
public class MailService {

    @Resource(name = "java:jboss/mail/famivac")
    private Session mailSession;

    public void send(Mail mail) throws MailException {
        try {
            Message msg = new MimeMessage(mailSession);
            msg.setFrom(new InternetAddress(mail.getFrom()));
            msg.addRecipient(Message.RecipientType.TO, new InternetAddress(mail.getRecipient()));
            msg.setSubject(mail.getSubject());
            msg.setText(mail.getBody());
            Transport.send(msg);
        } catch (MessagingException ex) {
            Logger.getLogger(MailService.class.getName()).log(Level.SEVERE, null, ex);
            throw new MailException(ex);
        }
    }
}

 

Test d'envoi

Avec ça j'ai créé une interface graphique simple permettant de tester les envois d'e-mails.

 

J'ai en tête de réussir à automatiser le test de configuration Wildfly et l'appel au service d'envoi d'e-mails. Pour le moment je regarde du côté d'Apache James pour avoir un serveur de mail embarqué me permettant d'avoir des boîtes de réception factices.

 

Classé dans : software Mots clés : aucun

Cartouche de modification du code source

Rédigé par Pao Aucun commentaire

Ce n'est pas croyable. Vraiment.

Nous sommes en 2016, et je trouve encore des classes Java avec tout en haut des cartouches de modification :

/*
 * *********************************************
 * *        CARTOUCHE DES MODIFICATIONS        *
 * *********************************************
 *
 * - 20.01.2014 (user1) : JIRA-XXX
 * --> BLA BLA BLA
 *
 * - 08.08.2014 (user1) : JIRA-XXX
 * --> BLA BLA BLA
 *
 * - 11.12.2014 (user1) : JIRA-XXX
 * --> BLA BLA BLA
 *
 * - 12.11.2015 (user2) : JIRA-XXX
 * --> BLA BLA BLA
 */

 Sérieux, à quoi ça sert ?

C'est une pratique qui essaye de faire manuellement ce que tout gestionnaire de code source (SVN, Git) fait automatiquement et bien mieux. C'est de la maintenance artificielle d'un historique des modifications. Et je dis bien artificielle car quand je check l'historique des modifications SVN, il y en a plus que ça : classe créée en 2013 et 20 changements (ça va encore, ce n'est pas trop déconnant).

Alors soit la personne fait son job correctement et trace TOUTES les modifications, soit on est en 2016 et on utilise les outils qui le font très bien. Parce que mettre ce genre de choses c'est :

  1. Fastidieux (doublon avec le message du commit)
  2. Source d'erreur (est-on vraiment sûr que le commentaire reflète les changements ? Allez voir sur StackOveflow...)
  3. Incomplet (SVN et Git affichent bien plus d'information, comme les lignes modifiées par exemple !)
  4. Inutile (les outils le font pour nous)

Il est temps de se moderniser et d'utiliser l'outil de gestion du code source et le bug tracker.

Classé dans : software Mots clés : aucun

Ça marche sur mon poste

Rédigé par Pao Aucun commentaire

J'ai subi le "ça marche sur mon poste".

Après un refactoring de mon application, j'utilise maintenant les CDI Events :

    @Asynchronous
    public void updateFamille(@Observes UpdateFamilleEvent event) {
        if (event.isReferent()) { // Update only if the event concerns a referent
            List<Sejour> sejours = entityManager.createNamedQuery(Sejour.QUERY_SEJOURS_DE_LA_FAMILLE, Sejour.class)
                    .setParameter("familleId", event.getId())
                    .getResultList();
            sejours.forEach(s -> {
                s.setFamilleNom(event.getNom());
                s.setFamillePrenom(event.getPrenom());
            });
        }

    }

Tout content de la nouvelle implémentation, j'ai testé en local et tout fonctionnait à merveille.
Je déploie sur le serveur et... PAF ! Une erreur Weld (CDI RI) incompréhensible :

Caused by: org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type Sejour with qualifiers @Default
  at injection point [BackedAnnotatedParameter] Parameter 2 of [BackedAnnotatedMethod] private static fr.famivac.gestionnaire.sejours.control.SejourService.lambda$updateFamille$4(@Observes UpdateFamilleEvent, Sejour)

What ? Mais Sejour est une entité ! Et pourquoi il est fait référence de la lambda ? Et pourquoi ai-je besoin que le Sejour soit un bean CDI ?

En fait, la réponse se trouve être un bug Weld révélé suite au passage au JDK 8u60 et corrigé en version 2.2.16.Final.
Je suis donc allé vérifier mes versions en local et sur OpenShift :

  • Local : Java 1.8.0_77 / Wildfly 9.0.2.Final
  • OpenShift : Java 1.8.0_77 / Wildfly 9.0.1.Final

Pas de bol, Weld 2.2.16.Final n'est embarqué que dans Wildfly 9.0.2.

Ayant la flemme de créer un nouveau cartridge pour utiliser Wildfly 10, j'ai donc corrigé mon code pour que Weld soit content :

@Asynchronous
    public void updateFamille(@Observes UpdateFamilleEvent pEvent) {
        UpdateFamilleEvent event = pEvent; // FIX https://issues.jboss.org/browse/WELD-2019
        if (event.isReferent()) { // Update only if the event concerns a referent
            List<Sejour> sejours = entityManager.createNamedQuery(Sejour.QUERY_SEJOURS_DE_LA_FAMILLE, Sejour.class)
                    .setParameter("familleId", event.getId())
                    .getResultList();
            sejours.forEach(s -> {
                s.setFamilleNom(event.getNom());
                s.setFamillePrenom(event.getPrenom());
            });
        }

    }

Et au passage, j'ai modifié la version du Wildfly embedded des tests d'intégration Arquillian pour correspondre à la version sur OpenShift.

 

Moralité : Avoir la même configuration en développement et en production !

Classé dans : software Mots clés : aucun
Fil RSS des articles de cette catégorie