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

6c7fb4b051926511027cec4116cfe8cf?s=128

Jérémie Grodziski

June 25, 2013
Tweet

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
  2. Jérémie Grodziski Software Designer and Programmer @jgrodziski jeremie@grodziski.com blog.zenmodeler.com www.redsen.fr/blog

  3. Qu’est ce que la conception ?

  4. Concevoir (v.t.) : Action d’élaborer quelque chose dans son esprit,

    en arranger les divers éléments
  5. Conception (n.f.) : Résultat d’un travail de représentation d’une chose

    concrète ou abstraite
  6. Conception : Besoin => Solution

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

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

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

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

    de Implémentation sous forme de Quoi ? Comment ? Spécification Code Conception
  11. Besoins ≠ Fonctions

  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...
  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
  14. Besoin Solution = Système opérationnel Pourquoi ? Fonctions sous forme

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

    de Implémentation sous forme de Quoi ? Comment ? Spécification Code Conception
  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
  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.
  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
  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
  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.
  21. Comment spécifier cet usage ? Comment concevoir à partir de

    cet usage ?
  22. Une Histoire de Conception

  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.
  24. Comment décrire l’usage d’un système et son comportement ?

  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
  26. 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 €> 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
  27. Système dans un état donné 1

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

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

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

    observés Scénarios = Enchaînement d’actions
  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
  32. Given When Then

  33. Structure Scénario n : Etant donné <Etat connu> Quand je

    fais <Actions> Alors <retour et état attendus> Scénario de test n : Etant donné un <Etat connu> Quand je fais <Action> Alors je constate <Retour et état attendu> ... Quand je fais <Action> Alors je constate <Retour et état attendu> User Story En tant que <Role> Je veux faire <Actions> Afin d’obtenir <Valeur ajoutée métier>
  34. Quoi d’autre ?

  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 €
  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 €"
  37. Démo

  38. None
  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
  40. Feedback Loops Solution Usage

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

    les niveaux de détails
  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
  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<dk.tigerteam.mdsd.demo.model .internal.Booking> bookingCollection = new java.util.HashSet<dk.tigerteam.mdsd.demo.m odel.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
  44. Où en sommes nous ?

  45. Besoin Solution = Système opérationnel Pourquoi ? Fonctions sous forme

    de Implémentation sous forme de Quoi ? Comment ? Spécification Code Conception
  46. Sous le capot...

  47. Domain-Driven Design ?

  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é
  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
  50. Pourquoi le DDD ?

  51. Code as a Model

  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;                      }                  }                        }  
  53. Le code du domaine est indépendant des aspects technologiques (persistance,

    interface utilisateur, etc.)
  54. None
  55. None
  56. Objectif : Un maximum de « Feedback » et d’interactions

    avec le problème, au plus tôt
  57. Les scénarios exécutables sont un moyen pour interagir au plus

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

    tôt entre la spécification et le code
  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
  60. La spécification « exécutable » devient un outil de conception

  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
  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é
  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.
  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”
  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
  66. Questions ? In French or English...