Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Iqnite Geneva 2013 - Conception et Test avec DDD et BDD

Iqnite Geneva 2013 - Conception et Test avec DDD et BDD

Pourquoi et comment concevoir et tester avec les approches Domain-Driven Design (DDD) et Behavior-Driven Development (BDD) ?
La démo est accessible à http://www.grodziski.com/iqnite/demo.mp4

Jérémie Grodziski

June 25, 2013
Tweet

More Decks by Jérémie Grodziski

Other Decks in Programming

Transcript

  1. La conception et les tests sont les
    deux faces d’une même pièce
    Iqnite Genève
    Jérémie Grodziski
    25 juin 2013

    View Slide

  2. Jérémie Grodziski
    Software Designer and Programmer
    @jgrodziski
    [email protected]
    blog.zenmodeler.com
    www.redsen.fr/blog

    View Slide

  3. Qu’est ce que la conception ?

    View Slide

  4. Concevoir (v.t.)
    :
    Action d’élaborer quelque chose dans
    son esprit, en arranger les divers
    éléments

    View Slide

  5. Conception (n.f.)
    :
    Résultat d’un travail de représentation
    d’une chose concrète ou abstraite

    View Slide

  6. Conception :
    Besoin => Solution

    View Slide

  7. Besoin
    Solution = Système
    opérationnel
    Fonctions
    Implémentation

    View Slide

  8. Besoin
    Solution = Système
    opérationnel
    Fonctions
    Implémentation
    Conception

    View Slide

  9. Besoin
    Solution = Système
    opérationnel
    Fonctions
    sous forme de
    Implémentation
    sous forme de
    Spécification
    Code
    Conception

    View Slide

  10. Besoin
    Solution = Système
    opérationnel
    Pourquoi ?
    Fonctions
    sous forme de
    Implémentation
    sous forme de
    Quoi ?
    Comment ?
    Spécification
    Code
    Conception

    View Slide

  11. Besoins ≠ Fonctions

    View Slide

  12. Harry Hillaker,
    designer of F16
    fighter aircraft
    What we want is a
    new aircraft that
    reach speeds of
    Mach 2-2.5 Why is that
    important ?
    To be able to escape
    from combat ! I think a good
    maneuverability
    is a better
    response...

    View Slide

  13. Harry Hillaker,
    designer of F16
    fighter aircraft
    What we want is a
    new aircraft that
    reach speeds of
    Mach 2-2.5 Why is that
    important ?
    To be able to
    escape from
    combat ! I think a good
    maneuverability
    is a better
    solution...
    Résultat : beaucoup d’innovations et un succès commercial
    inégalé jusqu’à aujourd’hui !
    What ! Function
    Why ! Requirement

    View Slide

  14. Besoin
    Solution = Système
    opérationnel
    Pourquoi ?
    Fonctions
    sous forme de
    Implémentation
    sous forme de
    Quoi ?
    Comment ?
    Spécification
    Code
    Conception

    View Slide

  15. Besoin
    Solution = Système
    opérationnel
    Pourquoi ?
    Fonctions
    sous forme de
    Implémentation
    sous forme de
    Quoi ?
    Comment ?
    Spécification
    Code
    Conception

    View Slide

  16. Objectifs des spécifications
    Comprendre
    le métier
    Développer le
    logiciel avec le
    comportement
    attendu
    •  Besoin de
    précisions,
    d’exemples
    Définir le
    produit
    Valider le
    produit
    •  Besoin
    d’interactivité
    avec le logiciel
    pour obtenir un
    feedback
    Point de vue
    développeur
    Point de vue
    métier

    View Slide

  17. Une problématique ancienne...
    « The most deadly thing in software is the concept, [...],
    that you are going to specify what you are going to do,
    and then do it [...]. The projects that are called
    successful, have met their specifications. But those
    specifications were based upon the designers’
    ignorance before they started the job. »
    D.T. Ross in the proceedings of the NATO conference on Software
    Engineering, 1968
    « The hardest part of the software task is arriving
    at a complete and consistent specification, and
    Much of the essence of building a program is in
    fact the debugging of the specification »
    Fred Brooks in « The Mythical Man-Month » 1975.

    View Slide

  18. Problèmes « habituels » avec les
    spécifications
    Point de vue Développeur
    •  Manque de précisions
    •  Manque d’exemples
    •  Indique parfois la structure et
    l’algorithme du système et non
    uniquement le comportement
    Point de vue Métier
    •  Difficulté à passer du besoin
    métier au comportement du
    système (du quoi au comment ?)
    •  Difficile de prévoir l’ensemble
    des fonctionnalités au
    démarrage
    •  Difficulté à définir précisément le
    comportement sans interactions
    avec le système
    •  Difficile de « valider » des
    spécifications abstraites
    •  La validation et la spécification
    sont des activités dé-corrélées

    View Slide

  19. Autres problèmes habituels...
    De manière générale
    •  Les spécifications, les tests et la conception/réalisation sont
    souvent réalisés par des équipes différentes
    •  => coût d’apprentissage du domaine dupliqués
    •  Problèmes de conception sont remontés tardivement dans
    la chaine de réalisation
    •  => coût de corrections élevés
    •  Temps qui passe
    •  => divergence entre la spécification “papier” et le
    code

    View Slide

  20. As t’on conçu une bonne ou
    mauvaise solution ?
    Une solution n’est ni bonne ni
    mauvaise, une solution est
    adaptée à un usage ou pas.

    View Slide

  21. Comment spécifier cet usage ?
    Comment concevoir à partir de
    cet usage ?

    View Slide

  22. Une Histoire de Conception

    View Slide

  23. Exemple : Retrait d’argent à un
    distributeur automatique de billet
    Besoin
    Permettre au client de retirer de l’argent avec sa carte
    bancaire de manière autonome
    User Story « Retirer de l’argent »
    En tant que client porteur de carte bancaire
    Je veux retirer de l’argent à un distributeur
    Afin de pouvoir obtenir de l’argent liquide à toute heure
    Scénarios et Exemples Clés
    Retirer de l’argent – succès - cas courant
    Retirer de l’argent – échec - code incorrect
    Retirer de l’argent – échec - solde insuffisant
    etc.

    View Slide

  24. Comment décrire l’usage d’un
    système et son comportement ?

    View Slide

  25. Exemple
    Scénario de test nominal : retrait accepté
    Etant donné que mon compte a un solde de 200 €
    Quand je fais un retrait de 50 € avec demande de reçu
    Alors le distributeur me fournit des billets d’un montant de 50 €
    Alors mon compte a maintenant un solde de 150 €
    Alors je reçoit un reçu indiquant un montant de retrait de 50 €
    Cas d’utilisation : retrait au distributeur
    En tant que client
    Je veux faire des retraits avec une carte nominative
    Afin d’obtenir de l’argent liquide facilement à tout heure

    View Slide

  26. Exemple
    Scénario de test nominal : retrait accepté
    Etant donné que
    Quand je fais
    Alors < le distributeur me fournit des billets d’un montant de 50 €>
    Alors
    Alors
    Scénario de test : retrait trop important, solde insuffisant
    Etant donné que mon compte a un solde de 200 €
    Quand je fais un retrait de 300 €
    Alors le distributeur affiche un message « le retrait est refusé pour
    cause de solde insuffisant »
    Cas d’utilisation : retrait au distributeur
    En tant que client
    Je veux faire des retraits avec une carte nominative
    Afin d’obtenir de l’argent liquide facilement à tout heure

    View Slide

  27. Système dans un
    état donné
    1

    View Slide

  28. Système dans un
    état donné
    1
    2 Actions

    View Slide

  29. Système dans un
    état donné
    1
    2 Actions
    3 Résultats observés

    View Slide

  30. Système dans un
    état donné
    1
    2 Actions
    3 Résultats observés
    Scénarios = Enchaînement d’actions

    View Slide

  31. « Soit un contexte… »
    Dans quel état se trouve le système ?
    1
    « Quand je fais l’action… »
    Quelles actions sont effectuées par l’utilisateur ? Quelles
    données sont entrées par l’utilisateur ?
    2
    « Alors j’observe … »
    qu’observe l’utilisateur en retour de ses actions ?
    3

    View Slide

  32. Given When Then

    View Slide

  33. Structure
    Scénario n :
    Etant donné
    Quand je fais
    Alors
    Scénario de test n :
    Etant donné un
    Quand je fais
    Alors je constate
    ...
    Quand je fais
    Alors je constate
    User Story
    En tant que
    Je veux faire
    Afin d’obtenir

    View Slide

  34. Quoi d’autre ?

    View Slide

  35. Scénario de test nominal : retrait accepté
    Etant donné que le porteur possède la carte 1234
    4567 8901 2345 avec un solde de 1000 €
    Quand le porteur effectue un retrait de 200 EUR au
    DAB de Paris_Pelletier
    Alors il obtient 200 € en espèces
    Alors le DAB émet le ticket récapitulatif
    Alors le solde du compte est de 800 €

    View Slide

  36. Scénario de test nominal : retrait accepté!
    Etant donné que le porteur possède la carte
    1234 4567 8901 2345 avec un solde de 1000 €"
    Quand le porteur effectue un retrait de 200 EUR
    au DAB de Paris_Pelletier"
    Alors il obtient 200 € en espèces"
    Alors le DAB émet le ticket récapitulatif"
    Alors le solde du compte est de 800 €"

    View Slide

  37. Démo

    View Slide

  38. View Slide

  39. Pourquoi tester ?
    « The act of writing a unit test is
    more an act of design than of
    verification. It is also more an act
    of documentation than of
    verification. The act of writing a
    unit test closes a remarkable
    number of feedback loops, the
    least of which is the one pertaining
    to verification of function »
    Robert « Bob »
    Martin

    View Slide

  40. Feedback Loops
    Solution
    Usage

    View Slide

  41. Conception =
    Toutes les décisions prises
    concernant le produit...à
    tous les niveaux de détails

    View Slide

  42. Tout le monde fait de la
    conception
    de l’analyste métier au
    développeur en passant par
    l’architecte
    ...mais à des niveaux de détails
    différents

    View Slide

  43. Les niveaux d’abstraction dans la vrai vie
    Préférez vous utiliser ceci
    ou cela ?
    package
    dk.tigerteam.mdsd.demo.model.internal;
    @javax.persistence.Entity
    @javax.persistence.Table(name =
    "Customer")
    public class Customer extends
    dk.tigerteam.mdsd.demo.model.AbstractEntit
    y {
    private static final long serialVersionUID
    = 2098912667L;
    @javax.persistence.Basic
    @javax.persistence.Column(name = "name",
    nullable = false) private String name;
    @javax.persistence.OneToOne(cascade = {
    javax.persistence.CascadeType.MERGE,
    javax.persistence.CascadeType.PERSIST,
    javax.persistence.CascadeType.REFRESH}
    , fetch =
    javax.persistence.FetchType.LAZY)
    @javax.persistence.JoinColumn(name =
    "addressId")
    @org.hibernate.validator.NotNull
    private
    dk.tigerteam.mdsd.demo.model.internal.Addr
    ess address;
    @javax.persistence.OneToMany(cascade = {
    javax.persistence.CascadeType.MERGE,
    javax.persistence.CascadeType.PERSIST,
    javax.persistence.CascadeType.REFRESH}
    @javax.persistence.Basic
    @javax.persistence.Column(name =
    "comment", nullable = false) private
    String comment;
    @javax.persistence.Basic
    @javax.persistence.Temporal(javax.persiste
    nce.TemporalType.TIMESTAMP)
    @javax.persistence.Column(name = "time",
    nullable = false)
    private java.util.Date time;
    @javax.persistence.Basic
    @javax.persistence.Column(name =
    "timeslot", nullable = false) private int
    timeslot;
    @javax.persistence.ManyToOne(cascade = {
    javax.persistence.CascadeType.MERGE,
    javax.persistence.CascadeType.PERSIST,
    javax.persistence.CascadeType.REFRESH}
    , fetch =
    javax.persistence.FetchType.LAZY)
    @javax.persistence.JoinColumn(nullable =
    false, name = "customerId") private
    dk.tigerteam.mdsd.demo.model.internal.Cust
    omer customer;
    public String getComment() {
    return comment;
    public void setComment(String parameter) {
    } this.comment = parameter; public
    java.util.Date getTime() {
    package
    dk.tigerteam.mdsd.demo.model.internal;
    @javax.persistence.Entity
    @javax.persistence.Table(name = "Address")
    public class Address extends
    dk.tigerteam.mdsd.demo.model.AbstractEntit
    y { private static final long
    serialVersionUID = 1697028161L;
    @javax.persistence.Basic
    @javax.persistence.Column(name = "street",
    nullable = false) private String street;
    @javax.persistence.Basic
    @javax.persistence.Column(name =
    "zipCode", nullable = false) private
    String zipCode; @javax.persistence.Basic
    @javax.persistence.Column(name = "city",
    nullable = false) private String city;
    public String getStreet() { return
    street; }
    public void setStreet(String parameter)
    { this.street = parameter; } public String
    getZipCode() { return zipCode; public void
    setZipCode(String parameter)
    { this.zipCode = parameter; } public
    String getCity() { return city; } public
    void setCity(String parameter) { this.city
    = parameter; } public
    dk.tigerteam.mdsd.demo.model.internal.Addr
    ess withStreet( String street)
    { setStreet(street); return
    (dk.tigerteam.mdsd.demo.model.internal.Add
    ress) this; public
    dk.tigerteam.mdsd.demo.model.internal.Addr
    ess withZipCode( String zipCode)
    { setZipCode(zipCode); return
    (dk.tigerteam.mdsd.demo.model.internal.Add
    ress) this; public
    dk.tigerteam.mdsd.demo.model.internal.Addr
    ess withCity(String city) { setCity(city);
    return
    (dk.tigerteam.mdsd.demo.model.internal.Add
    ress) this; } public
    dk.tigerteam.foundation.bean.mdsd.runtime.
    RuntimeMetaClazz getMetaType() { return
    metaType; }
    }
    , targetEntity =
    dk.tigerteam.mdsd.demo.model.internal.Book
    ing.class, mappedBy = "customer", fetch =
    javax.persistence.FetchType.LAZY)
    private
    java.util.Set.internal.Booking> bookingCollection = new
    java.util.HashSetodel.internal.Booking>();
    public String getName() { } return name;
    public void setName(String parameter) {
    this.name = parameter; }
    public
    dk.tigerteam.mdsd.demo.model.internal.Addr
    ess getAddress() { if (address instanceof
    org.hibernate.proxy.HibernateProxy) {
    return time;
    public void setTime(java.util.Date
    parameter) {
    this.time = parameter
    43

    View Slide

  44. Où en sommes nous ?

    View Slide

  45. Besoin
    Solution = Système
    opérationnel
    Pourquoi ?
    Fonctions
    sous forme de
    Implémentation
    sous forme de
    Quoi ?
    Comment ?
    Spécification
    Code
    Conception

    View Slide

  46. Sous le capot...

    View Slide

  47. Domain-Driven Design ?

    View Slide

  48. Pourquoi le Domain Driven Design ?
    L’objectif du Domain Driven Design (DDD) est de
    créer de meilleurs logiciels plus facilement en se
    concentrant sur le domaine métier plutôt que
    la technologie
    Le cœur du logiciel est sa capacité à traiter des
    problèmes liés au domaine
    Lorsque le domaine est complexe cela devient difficile,
    le DDD propose des solutions pour gérer cette
    complexité

    View Slide

  49. Que propose le DDD ?
    Une approche
    –  La conception est dirigée par des modèles situés
    dans des contextes particuliers
    –  Le langage utilisé pour communiquer entre la
    technique et le métier doit être le même : ubiquitous
    language
    Des blocs de construction (building blocks)
    Des principes de conception :
    –  Pour la souplesse : Supple design
    –  Pour gérer l’effort et les priorités : Strategic design

    View Slide

  50. Pourquoi le DDD ?

    View Slide

  51. Code as a Model

    View Slide

  52. Modèle graphique ou textuel ?
    Application  Library  {  
           basePackage  =  org.library  
       
           Module  movie  {  
           
                   Service  LibraryService  {  
                       findLibraryByName  delegates  to  LibraryRepository.findLibraryByName;  
                       saveLibrary  delegates  to  LibraryRepository.save;  
                       findMovieByName  delegates  to  MovieRepository.findByName;  
                   }  
           
                   Entity  Library  {  
                       String  name  key  
                       reference  Set<@Movie>  movies  
                         
                       Repository  LibraryRepository  {  
                           save;  
                           @Library  findLibraryByName(String  name)    
                               throws  LibraryNotFoundException;  
                           protected  findByCriteria;  
                       }  
                   }  
                     
                   Entity  Movie  {  
                       String  title  not  changeable  
                       String  urlIMDB  key    
                       Integer  playLength  
             
                       Repository  MovieRepository  {  
                           List<@Movie>  findByName(Long  libraryId,  String  name)    
                               delegates  to  FindMovieByNameAccess;  
                       }  
                   }                
           }  

    View Slide

  53. Le code du domaine est
    indépendant des aspects
    technologiques
    (persistance, interface utilisateur, etc.)

    View Slide

  54. View Slide

  55. View Slide

  56. Objectif :
    Un maximum de « Feedback » et
    d’interactions avec le problème,
    au plus tôt

    View Slide

  57. Les scénarios exécutables sont un
    moyen pour interagir au plus tôt
    entre le besoin et la solution

    View Slide

  58. Les scénarios exécutables sont un
    moyen pour interagir au plus tôt
    entre la spécification et le code

    View Slide

  59. L’interaction entre les scénarios et le
    code permettent de manipuler le
    domaine au plus tôt et de
    « découvrir » et valider toutes les
    décisions de conception au plus tôt

    View Slide

  60. La spécification « exécutable »
    devient un outil de conception

    View Slide

  61. Liens entre BDD / DDD et Agilité
    Des scénarios exécutables permettent de
    valider et de
    construire le logiciel dans des
    itérations courtes, de manière incrémentale
    avec feedback immédiat

    View Slide

  62. Liens entre BDD / DDD et Agilité
    Des scénarios exécutables permettent de
    valider et de
    construire le logiciel dans des
    itérations courtes, de manière incrémentale
    avec feedback immédiat
    BDD
    DDD
    Agilité

    View Slide

  63. Bénéfices de l’interaction BDD / DDD
    Connaissance fine du domaine au plus tôt
    Décisions de conception prises au plus tôt
    « Spécifications » toujours en phase avec le
    code
    Meilleure qualité de l’application
    t0
    t1
    t2
    t3

    Connaissance
    du domaine

    Tradi.
    Spec. Exec.

    View Slide

  64. A emporter
    Exprimer le comportement attendu du système
    –  Avec des scénarios d’exemples :
    •  Given / When / Then
    –  “Behavior-Driven Development”
    Conception : se concentrer sur le domaine
    –  Collaboration avec l’expert du domaine
    –  Interagir entre le modèle et la spec au plus tôt grâce
    à “Code as a Model”
    –  Dirigée par un modèle
    –  Validée par des scénarios
    –  “Domain-Driven Design”

    View Slide

  65. Pour aller plus loin
    Domain-Driven Design. Tackling
    complexity in the Hearth of Software.
    Eric Evans
    Specification by Example. How
    successful teams deliver the
    right software
    Gojko Adzic

    View Slide

  66. Questions ?
    In French or English...

    View Slide