Monday, April 27, 2015

How to (finally) start doing DDD by using BDD

How to (finally) start doing DDD by using BDD



Slides from talk presented during 4 Developers Conference in Warsaw.

Techniques used in Domain-Driven Design enable advanced modelling of applications but also require you to analyse problems in a specific way. So how in cooperation with Domain Experts and using existing resources can we make most of it? Are there any tools in PHP world that can help us achieving this goal? In this talk you'll be introduced to “Modelling by Example” - a new approach to Behaviour-Driven Development - and shown how to effectively use it to model applications. We will make use of well known tools like Gherkin and Behat, which by design drive the project communication, but what if they can do more? It turns out if we look at these tools from a different perspective they also enable modelling of the problem like we do in DDD. We will analyse this approach on examples to give you a starting point for your own projects!
Published in: EngineeringSoftware


 Transcript

  • 1. Howto(finally)startdoing DDDbyusingBDD
  • 2. KacperGunia@cakper So!ware Engineer @SensioLabsUK / @Inviqa PHPers Silesia @PHPersPL
  • 3. WhatisBDD?
  • 4. Bug-driven Development;)
  • 5. Behaviour-driven development is about implementing an application by describing its behaviour from the perspective of its stakeholders. -- Dan North
  • 6. BDD is about establishing a shared understanding of “done” working from the outside in until you get there -- Dan North
  • 7. BDDshowsyouwhattodonext akaTechnicalDiscipline
  • 8. HowdoweBDD?
  • 9. Feature: Traveler searches for cheap itineraries In order to save money while travelling As a world traveler I want to search for the cheapest itinerary
  • 10. Productownerwritesscenario anddeveloperautomatesit
  • 11. Developerwritesscenario andthenautomatesit
  • 12. No!
  • 13. BDDisaboutcommunication! flickr.com/photos/dvids/5638829762
  • 14. Scenario: Successfully find cheapest direct flight Given the flight from "WAW" to "LHR" priced $30 was scheduled And the flight from "WAW" to "LHR" priced $50 was scheduled When I open the "/search" page And I fill "WAW" in the "Departure airport" field And I fill "LHR" in the "Destination airport" field And I click "Search" Then I should be redirected to "/results" page And I should see $30 in the "#cheapest-flight-price" block
  • 15. Scenario: Successfully find cheapest direct flight Given the flight from "WAW" to "LHR" priced $30 was scheduled And the flight from "WAW" to "LHR" priced $50 was scheduled When I open the "/search" page And I fill "WAW" in the "Departure airport" field And I fill "LHR" in the "Destination airport" field And I click "Search" Then I should be redirected to "/results" page And I should see $30 in the "#cheapest-flight-price" block
  • 16. Translation
  • 17. Canwedobetter?
  • 18. MissionaccomplishedBoys Wecangohomenow! flickr.com/photos/dvids/5638829762
  • 19. Translationagain
  • 20. Howtofixthat?
  • 21. DDD
  • 22. WhatisDDDabout?
  • 23. It’s about focusing on the domain and letting it affect the so"ware very much -- Jimmy Nilsson
  • 24. ButWHYdoweneedit?
  • 25. Everybodyknowsthejargon intheirOWNFIELD
  • 26. It'saboutcommon understanding
  • 27. Ubiquitouslanguage
  • 28. Concrete examples are rooted in the problem domain -- Matt Wynne
  • 29. DomainModel
  • 30. A domain model (...) is not just the knowledge in a domain expert’s head; it is a rigorously organized and selective abstraction of that knowledge -- Eric Evans
  • 31. Modeldocuments theknowledge
  • 32. Pushing for ubiquitous language hard enough makes your examples a domain model -- Konstantin Kudryashov
  • 33. Scenario: Successfully find cheapest direct flight Given the flight from "WAW" to "LHR" priced $30 was scheduled And the flight from "WAW" to "LHR" priced $50 was scheduled When I open the "/search" page And I fill "WAW" in the "Departure airport" field And I fill "LHR" in the "Destination airport" field And I click "Search" Then I should be redirected to "/results" page And I should see $30 in the "#cheapest-flight-price" block
  • 34. Scenario: Successfully find cheapest direct itinerary Given the search for the itinerary schedule And the itinerary from "WAW" to "LHR" priced $30 was planned in the schedule And the itinerary from "WAW" to "LHR" priced $50 was planned in the schedule When I search for cheapest itinerary from "WAW" to "LHR" Then the cheapest itinerary should cost $30
  • 35. Modellingbyexample
  • 36. Phase1
  • 37. Scenario: Successfully find cheapest direct itinerary Given the search for the itinerary schedule And the itinerary from "WAW" to "LHR" priced $30 was planned in the schedule And the itinerary from "WAW" to "LHR" priced $50 was planned in the schedule When I search for cheapest itinerary from "WAW" to "LHR" Then the cheapest itinerary should cost $30
  • 38. Given the search for the itinerary schedule /** * @Given /^the search for the itinerary schedule$/ */ public function theSearchForTheItinerarySchedule() { $this->itinerarySchedule = new ItinerarySchedule(); $this->search = new Search($this->itinerarySchedule); }
  • 39. Designemerges
  • 40. And the itinerary from "WAW" to "LHR" priced $30 was planned in the schedule /** * @Given the itinerary from :fromAirport to :toAirport * priced $:price was planned in the schedule */ public function theItineraryFromToPricedWasPlannedInTheSchedule( $fromAirport, $toAirport, $price ) { $itinerary = new Itinerary( Airport::code($fromAirport), Airport::code($toAirport), Money::usd($price) ); $this->itinerarySchedule->plan($itinerary); }
  • 41. When I search for cheapest itinerary from "WAW" to "LHR" /** * @When I search for cheapest itinerary from :fromAirport to :toAirport */ public function iSearchForCheapestItineraryFromTo($fromAirport, $toAirport) { $this->cheapestItinerary = $this->search->forCheapest( Airport::code($fromAirport), Airport::code($toAirport) ); }
  • 42. Then the cheapest itinerary should cost $30 /** * @Then the cheapest itinerary should cost $:price */ public function theCheapestItineraryShouldCost($price) { expect($this->cheapestItinerary->cost())->toBeLike(Money::usd($price)); }
  • 43. Phase2
  • 44. @ui Scenario: Successfully find cheapest direct itinerary Given the search for the itinerary schedule And the itinerary from "WAW" to "LHR" priced $30 was planned in the schedule And the itinerary from "WAW" to "LHR" priced $50 was planned in the schedule When I search for cheapest itinerary from "WAW" to "LHR" Then the cheapest itinerary should cost $30
  • 45. Given the search for the itinerary schedule /** * @Given the search for the itinerary schedule */ public function theSearchForTheItinerarySchedule() { $this->visit("/search"); }
  • 46. And the itinerary from "WAW" to "LHR" priced $30 was planned in the schedule /** * @Given the itinerary from :fromAirport to :toAirport * priced $:price was planned in the schedule */ public function theItineraryFromToPricedWasPlannedInTheSchedule( $fromAirport, $toAirport, $price ) { $itinerary = new Itinerary( Airport::code($fromAirport), Airport::code($toAirport), Money::usd($price) ); $this->get("itinerary_schedule")->plan($itinerary); }
  • 47. When I search for cheapest itinerary from "WAW" to "LHR" /** * @When I search for cheapest itinerary from :fromAirport to :toAirport */ public function iSearchForCheapestItineraryFromTo($fromAirport, $toAirport) { $this->fillIn("#from-airport", $fromAirport); $this->fillIn("#to-airport", $toAirport); $this->clickButton("Search"); }
  • 48. Then the cheapest itinerary should cost $30 /** * @Then the cheapest itinerary should cost $:price */ public function theCheapestItineraryShouldCost($price) { $cheapestItinerary = $this->find("#cheapest-itinerary"); expect($cheapestItinerary)->toContainText(sprintf("From $%s", $price)); }
  • 49. # behat.yml default: suites: domain: contexts: [ SearchContext ] ui: contexts: [ WebSearchContext ] filters: { tags: '@ui' }
  • 50. ModellingbyExample Inthree(easy)steps
  • 51. · Have the conversation · Model your objects · Go again through UI*
  • 52. *But
  • 53. You(really)don't havetoautomate everything!
  • 54. Butthereisa problem
  • 55. Weignoredthedepth ofthedomain
  • 56. Onpurpose
  • 57. Youcan'tmodelthe wholesystemusing onefeature
  • 58. Repeattheprocess andmodelthe planner
  • 59. Whatifmodelhasdifferentrequirements inthiscontext?
  • 60. BoundedContext
  • 61. Languageislimited
  • 62. Search Itinerary != Planner Itinerary != Booking Itinerary
  • 63. Donotbuildfragilemonoliths!
  • 64. Buildapplicationswith Boundedcontextinmind
  • 65. ---Wrapup---
  • 66. Havethe conversation
  • 67. Donotseparatethe conceptsfromthe implementation
  • 68. Youcannotbuild conceptualmodels withoutconsidering implementationissues
  • 69. Pushfor Ubiquitouslanguage
  • 70. UseBehattodriveyourModel NotonlytheUI
  • 71. "BDDisabout conversationsyouhaveto producesoftware"
  • 72. "DDDisabouthowyou exploredomainmodels andhowyouarticulatethis"
  • 73. Thanks! @cakper