Blog entries by Laura Médioni [3]
  • J'étais au raid agile #5 !

    2016/05/10 by Laura Médioni
    https://www.logilab.org/file/5920040/raw/gite.jpeg

    J'ai à mon tour eu l'opportunité de participer au raid agile #5 organisé par Pablo Pernot et Claude Aubry dans les Cévennes le mois dernier, et j'en suis revenue ravie. Ces quelques jours en immersion dans un cadre magnifique permettent de se déconnecter du quotidien pour se concentrer pleinement sur l'agilité, le tout dans une ambiance chaleureuse. La formation est dense, mais elle est orientée pratique, prévoit des pauses et fait la part belle aux échanges, conseils et retours d'expérience, ce qui fait qu'on ne voit pas le temps passer. J'y ai appris beaucoup de choses, principalement sur des outils de définition d'un produit que nous utilisons peu (pas assez ?) chez Logilab.

    J'ai donc apprécié tout particulièrement les ateliers sur la définition des parties prenantes, des personas (et dans la même idée, je vais me renseigner sur l'empathy mapping). J'ai également pu découvrir l'impact mapping, le petit plus étant de le précéder d'une étude d'impacts rétro-futuriste, qui permet d'identifier les vrais besoins : on se projette dans un futur où le produit connaît un succès total, en se mettant dans la peau de la ou des persona(s) principale(s). On se "souvient" des raisons (orientées comportement) qui font qu'on ne pourrait plus se passer du produit: les impacts.

    En mars 2015, Sylvain Thénault était revenu du raid agile avec ces réflexions. Un an après, je profite de l'occasion pour faire un point sur la façon dont nos pratiques ont évolué, et les choses sur lesquelles j'aimerais avancer suite à mon expérience du raid.

    En un an, nous avons progressé sur pas mal d'aspects à Toulouse :

    • Nous travaillons plus en équipe, chaque individu étant maintenant apte à intervenir sur davantage de projets différents. C'est extrêmement positif, puisque cela permet mieux de gérer la charge, surtout dans un contexte où nous sommes peu nombreux et intervenons sur beaucoup de projets petits à moyens, avec des dates butoir parfois serrées et des congés à gérer. Une montée en compétence a été réalisée au passage, et j'ai l'impression que globalement l'esprit d'équipe et la communication en ont été renforcés.
    • Après pas mal de réflexion et d'évolutions, notre "kanban" est maintenant un peu plus stable (il ressemble à un kanban mais n'en est pas vraiment un, car pas de limites ni de flux tiré). Nous utilisons les colonnes classiques "backlog", "ready", "doing", "review", et une ligne par projet en cours. Sur chaque post-it contenant une tâche, on ajoute une pastille de couleur représentant la personne en charge de sa réalisation. Un coup d’œil rapide permet donc de visualiser les projets sur lesquels il y a trop de travail en attente, en cours ou à intégrer, ainsi que les sous-charges ou surcharges des membres de l'équipe.
    • Toujours dans la catégorie du management visuel: nous avons maintenant un tableau d'obstacles, ainsi qu'un "tableau des contraintes" (mis à jour une fois par semaine) permettant de résumer par projet les risques, dates butoir, charge restante, absence de membres de l'équipe de développement, etc. Ce tableau facilite l'affectation des membres de l'équipe sur les différents projets et le respect des délais.
    • Nous avons effectué deux delegation board à un an d'intervalle. Cela nous a permis d'identifier des éléments clé dans notre travail au quotidien, de clarifier les rôles les concernant et de soulever des problèmes liés. On a pu noter des améliorations lors de la seconde session, par rapport à la première (principalement au niveau organisationnel).
    • Nous essayons de faire une rétrospective tous les mois. Celles que nous avons faites nous ont permis d'améliorer nos pratiques (nous avons notamment progressé sur nos réunions debout, et sur des notions de qualité via la rédaction commune d'un working agreement)

    En revanche, nous avons un nouveau fauteuil que personne n'utilise (peut-être ressemble-t-il trop à une chaise de bureau, me souffle-t-on dans l'oreillette) ! La question du rythme soutenable mentionnée par Sylvain ne semble pas être la préocupation principale, peut-être parce que malgré la charge fluctuante liée au contexte du travail dans une petite société de service, nous n'atteignons généralement pas un rythme insoutenable.

    Au cours de l'année à venir, je pense que nous pourrions travailler entre autres sur les points suivants :

    • Continuer à avancer sur le travail en équipe sur les projets, qui mérite d'être encore amélioré.
    • Travailler sur les rétrospectives : faire tourner le facilitateur, essayer de précéder la rétrospective d'un exercice d'"échauffement" pour se mettre dans le bain. Je suis revenue du raid avec de nouvelles idées de format, à tester !
    • Un atelier réalisé au cours du raid consistait à classer une grande quantité de pratiques agiles dans différentes catégories: en cours d'acquisition, acquis, non acquis, non souhaité. Réaliser cet exercice avec l'ensemble de l'équipe amènerait sûrement des discussions intéressantes. Cela permettrait en outre de partager une vision commune, et de repérer les points à améliorer en priorité dans nos pratiques.
    • Si l'occasion se présente, j'aimerais que nous essayions la cotation de l'extrême, découverte au cours du raid, efficace pour estimer grossièrement un gros backlog en peu de temps.
    • Utiliser dès que possible une partie des outils de définition de produit vus au cours du raid

  • Retour sur le hackaton Code_TYMPAN

    2015/10/14 by Laura Médioni
    https://www.logilab.org/file/2337488/raw/tympan-hackathon.png

    Logilab était présent au hackaton Code_TYMPAN des 5 et 6 octobre 2015, organisé par EDF dans les locaux d'af83 . L'objectif : réunir des développeurs et des experts en acoustique pour imaginer et maquetter de nouvelles fonctionnalités pour Code_TYMPAN.

    http://chercheurs.edf.com/fichiers/fckeditor/Commun/Innovation/logiciels/salome/Logo-Code_TYMPAN_2.jpg

    Cet évènement a été rendu possible par les travaux importants que nous avons conduit sur l'architecture de Code_TYMPAN au cours de ces deux dernières années. En effet, Code_TYMPAN dispose maintenant d'une interface utilisateur développée en Python, ce qui permet à quelqu'un ayant peu de connaissances en développement logiciel d'écrire des scripts de pilotage de simulations acoustiques, ou d'enrichir l'API... En peu de temps et tout en bénéficiant de l'écosystème Python qui facilite l'écriture de post-traitements (numpy, matplotlib, etc.).

    http://www.code-tympan.org/images/CodeIndustriel2.JPG

    Lundi matin, après un petit déjeuner permettant à la vingtaine de participants de faire connaissance, 3 groupes ont été formés autour d'un sujet général tel que "l'acoustique intérieure" ou "les sources acoustiques en mouvement". Le premier objectif de la matinée: brainstormer afin de choisir une ou deux fonctionnalités à prototyper ou implémenter au cours du hackaton.

    Un premier stand-up meeting en milieu de matinée a permis de faire le point sur les différentes idées, puis un cycle de développement/restitution a été conduit jusqu'au lendemain après-midi. Chaque restitution fournissait l'occasion d'échanger avec les membres des autres groupes, d'exposer des problèmes, de recueillir des solutions ou de nouvelles idées. Une restitution finale avec démonstrations a conclu la seconde journée.

    Dans le groupe où était présent Logilab, plusieurs idées ont été abordées:

    • Déplacer des sources au cours de la simulation acoustique, afin de pouvoir tracer l'évolution du bruit en fonction de la distance de la source au récepteur (exemple: cas du décollage d'un avion dans un aéroport). Pistes pour la suite: prendre en compte l'accélération et la décélération.
    • Disposer d'éléments de modélisation de formes plus complexes que de simple cubes, nécessaire pour une simulation au plus proche de la réalité urbaine, où les bâtiments ont souvent une forme irrégulière. Par exemple, ajouter des écrans à casquette (forme en T).
    • Rendre possible la création d'une directivité pour une source depuis l'API, afin de pouvoir modéliser des sources possédant des directivités différentes sur une même surface (exemple de la pale d'éolienne).

    Les autres groupes ont travaillé respectivement sur :

    • les calculs paramétriques et de sensibilité,
    • un démonstrateur d'acoustique intérieure basé sur des lancers de rayon et une modélisation acoustique simple codée directement en Python.
    http://www.code-tympan.org/images/CodeIndustriel.JPG

    Cet évènement a été positif à bien des égards. Outre le fait que c'était un moment très convivial, il a permis aux principaux développeurs de Code_TYMPAN (EDF et Logilab) d'échanger directement avec les utilisateurs et de recueillir leurs besoins. Ce hackaton nous a donné des pistes d'amélioration de l'API, et a mis en évidence la nécessité de renforcer l'aide à la mise en place de l'environnement sous Windows. Ce hackaton a été par ailleurs l'occasion de mettre en contact des gens de différents domaines d'activité qui ont un même type de besoin. Les différents participants ont ainsi pu avoir un aperçu des nombreuses applications possibles de Code_TYMPAN: bruit d'installations nucléaires, bruit intérieur, bruit éolien, bruit routier, bruit aéroportuaire, chantiers en milieu urbain, etc.

    Enfin, chaque participant est reparti avec Code_TYMPAN sur son poste, installé et fonctionnel, ainsi que l'environnement nécessaire à l'exécution de scripts Python. Il n'y a plus qu'à !


  • Ecriture de liaisons C++ pour Python

    2014/03/13 by Laura Médioni

    Dans le cadre des travaux d'interfaçage de l'application Code_TYMPAN avec du code Python, nous avons réalisé l'étude ci-dessous sur les différents moyens de générer des liaisons Python pour du code C++. Cette étude n'a pas vocation à être exhaustive et s'est concentrée sur les aspects qui nous intéressaient directement pour les travaux susmentionnés.

    Solutions existantes

    Une recherche des solutions existantes a été effectuée, qui a permis d'obtenir la liste suivante pour une écriture manuelle du code d'interfaçage :

    • Cython, un langage de programmation inspiré de Python, basé sur Pyrex
    • Boost.Python, une librairie C++ de la collection Boost permettant d'écrire des liaisons Python
    • PyBindGen, un outil implémenté en Python et permettant de décrire des liaisons C++ directement dans ce langage
    • Swig, un outil permettant de générer des liaisons C++ pour plusieurs langages de programmation
    • Shiboken, un générateur de code d'enrobage pour des bibliothèques C/C++ basé sur du CPython

    Des solutions existent pour automatiser cette écriture. Ce sont des outils qui se basent sur des compilateurs (gcc, clang) pour faire l'analyse grammaticale du code C++ et générer le code d'interfaçage correspondant. Par exemple :

    • XDress, qui permet de générer des fichiers Cython (.pyx, .pxd) à partir de gcc-xml ou de libclang
    • PyBindGen dispose de fonctionnalités permettant de générer des liaisons python à partir de gcc
    • Ce billet explique comment utiliser libclang pour parcourir l'AST d'un code C++ et générer des liaisons Boost.Python

    Aspects pris en compte

    Cet article est intéressant car il aborde de façon très complète les problématiques découlant de l'écriture de liaisons C++ pour des langages de haut niveau. Il a été écrit lors des travaux de développement de Shiboken.

    Dans notre cas, les critères pour le choix d'une solution finale portaient sur différents aspects :

    • Le coût de développement : prise en main de l'outil, quantité de code à écrire pour enrober une classe C++ donnée, coût de l'intégration dans le système de build, degré d'automatisation de la solution, lisibilité du code généré, etc.
    • La gestion de la mémoire : comptage de référence, gestion de la propriété des objets
    • La qualité et l'exhaustivité du support C++ : compatibilité STL, gestion des références et pointeurs, des templates, surcharges d'opérateurs, etc.
    • La pérennité de la solution : technologies mises en œuvre par l'outil, qualité de la documentation, support, taille et degré d'activité de la communauté de développeurs

    Solutions envisagées

    Swig n'a pas été retenu partant de l'a priori que c'était une solution plutôt lourde et davantage orientée C que C++, constat tiré lors de travaux réalisés par Logilab il y a quelques mois de cela. La solution Boost.Python n'a pas été explorée car notre souhait était de nous rapprocher davantage du Python que du C++. Shiboken semble prometteur, bien que peu documenté et mal référencé (les premières recherches tombent sur d'anciennes pages du projet, donnant l'impression que la dernière release date d'il y a plusieurs années, alors qu'en fait, non). Il a été écarté par manque de temps.

    PyBindGen et Cython ont fait l'objet de tests.

    La cible des tests a été l'interfaçage de smart pointers, puisque cela correspond à un de nos besoins sur le projet Code_TYMPAN.

    Les essais ont été réalisés sur des classes simplifiées:

    • MyElement, classe qui représente un élément à encapsuler dans un smart pointer et hérite de IRefCount qui implémente un comptage de référence
    • SmartPtr, classe smart pointer "maison" de l'application
    • Quelques fonctions de test manipulant des smart pointers SmartPtr

    Voici un extrait des en-têtes du code C++:

    #ifndef MY_ELEMENT_H
    #define MY_ELEMENT_H
    #include <iostream>
    using namespace std;
    #include "SmartPtr.h"
    
    class MyElement : public IRefCount
    {
        public:
            MyElement ();
            MyElement (string);
                string Name(){ return _name; }
                virtual ~MyElement ();
    
        protected:
            string _name;
    };
    typedef SmartPtr<MyElement> SPMyElement;
    #endif
    
    #ifndef SMART_PTR_H
    #define SMART_PTR_H
    template <class T> class SmartPtr
    {
        public:
            SmartPtr();
            SmartPtr(T*);
            const T* getRealPointer() const;
    
        protected:
            T* _pObj;
    }
    #endif
    
    SPMyElement BuildElement();
    void UseElement(SPMyElement elt);
    

    Cython

    Cet outil offre maintenant un bon support du C++ (globalement depuis la version 0.17). Son avantage est qu'il permet la manipulation d'objets à la fois C++ et Python dans des fichiers Cython.

    Utilisation
    • Écriture (facultative) d'un fichier .pxd qui contient une recopie des headers à enrober (avec un lien vers les fichiers): déclarations des types, classes, fonctions...
    • Écriture d'un fichier .pyx qui contient des appels de fonctions, constructions d'objets C ou python. Les fonctions et classes de ce module sont utilisables depuis un script Python
    • Compilation du code Cython décrivant les interfaçages C++, génération et compilation du code C++ correspondant et production d'une librairie Python.

    Cython offre un support pour les conteneurs de la STL, les templates, la surcharge de la plupart des opérateurs ("->" non supporté), le passage d'arguments par référence et par pointeur, etc.

    Actuellement en version 0.20.1, la dernière release date du 11 février 2014. Les outils Cython sont relativement bien documentés et sa communauté de développeurs est active.

    Exemple

    Voici le code d'interfaçage Cython correspondant à l'exemple exposé ci-dessus:

    setup.py:

    from distutils.core import setup
    from Cython.Build import cythonize
    
    setup(name='smartptr',
        ext_modules=cythonize('*.pyx',
            ),
    )
    

    smartptr.pxd:

    from libcpp.string cimport string
    
    cdef extern from "src/SmartPtr.h":
        cdef cppclass SmartPtr[T]:
            SmartPtr()
            SmartPtr(T *)
            T *getRealPointer() # Pas de surcharge de ->. L'accès à l'objet ne peut être qu'explicite
    
    cdef extern from "src/MyElement.h":
        cdef cppclass MyElement:
            MyElement()
            MyElement(string)
            string Name()
    
    cdef extern from "src/Test.h":
        SmartPtr[MyElement] BuildSPElement()
        void UseSPElement(SmartPtr[MyElement])
    

    smartptr.pyx:

    # distutils: language = c++
    # distutils: libraries = element
    
    cimport smartptr
    cimport cython
    
    cdef class PySPMyElement:
        cdef SmartPtr[MyElement] thisptr
    
        def __cinit__(self, name=""):
            """ PySPMyElement constructor """
            if name == "":
                self.thisptr = SmartPtr[MyElement](new MyElement())
            else:
                self.thisptr = SmartPtr[MyElement](new MyElement(name))
    
        def get_name(self):
            """ Returns the name of the element """
            return self.thisptr.getRealPointer().Name()
    
    @cython.locals(elt=PySPMyElement)
    def build_sp_elt():
        """ Calls the C++ API to build an element """
        elt = PySPMyElement.__new__(PySPMyElement)
        elt.thisptr = BuildSPElement()
        return elt
    
    @cython.locals(elt=PySPMyElement)
    def use_sp_elt(elt):
        """ Lends elt to the C++ API """
        UseSPElement(elt.thisptr)
    

    XDress

    XDress est un générateur automatique de code d'interfaçage C/C++ écrit en Python, basé sur Cython.

    Utilisation
    • On liste dans un fichier xdressrc.py les classes et fonctions à envelopper (il n'est pas nécessaire de mettre la signature, le nom suffit. On peut choisir d'envelopper seulement certaines classes d'un .h).
    • On exécute xdress qui génère les .pyx et .pxd correspondants

    XDress permet d'envelopper des conteneurs STL via son générateur stlwrap (les conteneurs à enrober doivent être listés dans le xdressrc.py). A titre d'exemple, les vecteurs sont convertis en numpy array du type contenu.

    Ce projet est récent et pas très documenté, mais il semble prometteur.

    PyBindGen

    Utilisation
    • Écriture d'un script Python qui décrit les classes/fonctions C++ à enrober en s'appuyant sur le module PyBindGen (1) → permet de générer un fichier .cpp
    • Compilation du code C++ généré, avec la librairie du programme à envelopper et génération d'une librairie Python.

    Ce processus peut être automatisé:

    • Écriture d'un script Python qui utilise les outils PyBindGen pour lister les modules (headers) à envelopper, les lire et lancer la génération automatique des liaisons c++

    ou:

    • Écriture d'un script Python qui utilise les outils PyBindGen pour lister les modules (headers) à envelopper et générer le script Python décrit en (1) (ce qui permettrait une étape intermédiaire pour personnaliser les liaisons)

    PyBindGen offre un support pour la STL, l'héritage (multiple), la gestion des exceptions C++ côté Python, la surcharge d'opérateurs, le comptage de référence, la gestion de la propriété des objets. Mais il supporte mal les templates.

    Actuellement en version 0.17, la dernière release date du 15 février 2014 (entre autres ajout de la compatibilité Python 3.3).

    Exemple

    PyBindGen, en l'état, n'offre pas la possibilité d'envelopper simplement des templates, ni des smart pointers "maison" par extension.

    Une classe de ce package permet d'envelopper des shared pointers de Boost (boost::shared_ptr). Il serait à priori possible de la modifier légèrement pour enrober les smart pointers de l'application Code_TYMPAN (non testé).

    Voici néanmoins à titre d'exemple le code permettant d'envelopper la classe MyElement et des fonctions manipulant non plus des smart pointers mais des 'MyElement *'

    Test.h :

    MyElement *BuildElement();
    void UseElement(MyElement *elt);
    

    smartptr.py :

    import pybindgen
    import sys
    from pybindgen import retval
    from pybindgen import param
    
    mod = pybindgen.Module('smartptr')
    
    # File includes
    mod.add_include('"src/MyElement.h"')
    mod.add_include('"src/Test.h"')
    
    # Class MyElement
    MyElement = mod.add_class('MyElement')
    MyElement.add_constructor([])
    MyElement.add_method('Name', retval('std::string'), [])
    
    
    # Test functions
    # transfer_ownership=False : here Python program keeps the ownership of the element it passes to the C++ API
    mod.add_function('UseElement', None, [param('MyElement *', 'elt', transfer_ownership=False)])
    # caller_owns_return=True : here Python program will be responsible for destructing the element returned by BuildElement
    mod.add_function('BuildElement', retval('MyElement *',  caller_owns_return=True), [])
    
    if __name__ == '__main__':
        mod.generate(sys.stdout)
    

    Boost.Python

    Les liaisons Python s'écrivent directement en C++.

    C'est un outil très fiable et pérenne, avec de par sa nature un très bon support C++ : gestion de la mémoire, templates, surcharges d'opérateurs, comptage de référence, smart pointers, héritage, etc.

    Inconvénient : la syntaxe (en mode templates C++) n'est pas très intuitive.

    Conclusion

    Les solutions Cython et PyBindGen ont été explorées autour de la problématique d'enrobage de smart pointers. Il en est ressorti que:

    • Il est possible d'enrober facilement des smart pointers Code_TYMPAN en Cython. L'approche qui a été choisie est de manipuler depuis Python les objets C++ directement au travers de smart pointers (les objets Python contenus dans le .pyx encapsulent des objets SmartPtr[T *], agissant donc comme des proxys vers les objets). De cette façon, l'utilisation depuis Python d'un objet C++ incrémente le compteur de référence côté C++ et cela garantit qu'on ne perdra pas la référence à un objet au cours de son utilisation côté Python. Un appel à getRealPointer() pour enrober des fonctions manipulant directement des T * sera toujours possible dans le code Cython au besoin.
    • PyBindGen présente l'intérêt d'offrir des moyens de gérer l'attribution de la propriété des éléments entre C++ et Python (transfer_ownership, caller_owns_return). Malheureusement, il n'offre pas la possibilité d'enrober des smart pointers sans modification de classes PyBindGen, ni d'envelopper des templates.

    Par ailleurs, après utilisation de PyBindGen, il nous a semblé que bien qu'il présente des idées intéressantes, sa documentation, ses tutoriels et son support sont trop succints. Le projet est développé par une seule personne et sa viabilité est difficile à déterminer. Cython en revanche offre un meilleur support et plus de fiabilité.

    Le choix final s'est donc porté sur Cython. Il a été motivé par un souci d'utiliser un outil fiable limitant les coûts de développement (élimination de PyBindGen), aussi proche de Python que possible (élimination de Boost.Python). Cet outil semble fournir un support C++ suffisant par rapport à nos besoins tels que perçus à ce stade du projet.

    De plus si on cherche un moyen de générer automatiquement les liaisons Python, XDress présente l'avantage de permettre l'utilisation de libclang comme alternative à gcc-xml (PyBindGen est basé sur gcc-xml uniquement). Une possibilité serait par ailleurs d'utiliser XDress pour générer uniquement le .pxd et d'écrire le .pyx manuellement.

    Une question qui n'a pas été abordée au cours de cette étude car elle ne correspondait pas à un besoin interne, mais qui est néanmoins intéressante est la suivante: est-il possible de dériver depuis Python des classes de base définies en C++ et enveloppées en Cython, et d'utiliser les objets résultants dans l'application C++ ?