3. Coding Dojo
• Agile!
• Teams of 2-4 people
• 1 sprint = 20 minutes
• Domain-Drive Design (I’m the Product Owner)
• Test-Driven Development (Maybe!)
• Yes, you can use the user guide and internet!
• User demo at the end of each sprint
• Discussion + Refactoring
• Prize for best app!
5. Domain-Driven Design
• “Domain-driven design (DDD) is an approach to developing
software for complex needs by deeply connecting the
implementation to an evolving model of the core business
concepts.”
• The premise of domain-driven design is the following:
• Placing the project's primary focus on the core domain and
domain logic
• Basing complex designs on a model
• Initiating a creative collaboration between technical and
domain experts to iteratively cut ever closer to the
conceptual heart of the problem.
6.
7. User Story 1
“As a pomodoro fan, I would like to be able to add
tasks to a uniquely named activity inventory, so that I
can see what work I need to complete over the next
few weeks.”
12. Domain Tests
class InventoryTests extends GrailsUnitTestCase {
void testConstraints() {
def existingInventory = new Inventory(name: "Paul’s Inventory")
mockForConstraintsTests(Inventory, [ existingInventory ])
! ! // Validation should fail if both properties are null.
! ! def inventory = new Inventory()
! ! assertFalse inventory.validate()
! ! assertEquals "nullable", inventory.errors["description"]
! ! // So let's demonstrate the unique constraint.
! ! inventory = new Inventory(name: "Paul’s Inventory")
! ! assertFalse inventory.validate()
! ! assertEquals "unique", inventory.errors["name"]
! ! // Validation should pass!
! ! inventory = new Inventory(name: "John’s Inventory")
! ! assertTrue inventory.validate()
! }
}
13. Gotcha!
• Potential performance issue with mapped
collections:
• Adding to the Set requires loading all
instances from the database to ensure
uniqueness
• Likewise for mapped List
• Works fine in development, but what if
you have 1,000,000+ rows?
14. Implementation (2)
class Task {
Inventory inventory
String description
static constraints = {
description(nullable: false, blank: false)
}
}
class Inventory {
String name
}
15. Side-effects?
• Different syntax for adding Tasks
• No cascading deletes
• Custom finder required to find all Tasks in
an Inventory
• Scaffolding breaks!
16. User Story 2
“As a pomodoro fan, I would like to be able move tasks
onto a ‘To Do Today’ sheet, so that I can see work to be
completed today and view my work history.”
17. Considerations
• Does the ‘Today’ list share any common
attributes with the Inventory?
• How about a more intuitive URL scheme?
20. Level 1 ‘Smells’
• Logic built into pages:
• Overuse of Request Parameters
• If-Then tags
• Inline groovy using ${...}
• Poor use of layouts
• Little use of tags
• Domain classes as simple ‘active records’
• Page-based information architecture
22. Level 1-2 Refactoring
• Move logic out of pages into controllers
• Reduce pages into fragments
• Use layouts to construct device or stakeholder-
centric views from pages and fragments
• Use available tag libraries
• Create your own tag libraries!
• Stylesheets rule - minimise markup
23. User Story 3
“As a pomodoro fan, I would like to have an optimised
workflow for US2, so that I can save time and reduce
input mistakes.”
24. Considerations
• Web Flow plugin?
• Command Objects?
• What changes need to be made to domain
classes?
26. User Story 4
“As a pomodoro fan, I would like to be able update the
number of iterations I’ve completed on each task in my
‘To Do Today’ list, so that I can keep track of my
progress and improve my future estimates.”
27. Considerations
• Can we do this without page refreshes?
• How can we test this?
• Domain changes?
31. Level 2-3 Refactoring
• Move domain transaction logic out of
controllers into services
• Controllers should be ‘glue’ that binds
business services to UI
• Service methods should reflect business
scenarios
• Make use of transactional capability of
services
32. User Story 5
“As a pomodoro partner, I would like a simple REST
API over your daily task view, so I can integrate your
data into my application.”
37. User Story 6
“As a pomodoro fan, I’d like to be able to add
unplanned and urgent tasks to the bottom of my daily
list, so that I can track and manage interruptions.”
41. Level 3-4 Refactoring
• Move common code out of services into
POGO’s (or POJO’s)
• Enrich our domain model to simplify services:
• Named Queries
• Derived Properties
• Criteria: Conjunctions, Disjunctions,
Projections, Restrictions
42. User Story 7
“As a pomodoro fan, I would like to be able to search
for tasks on my inventory through a simple interface, so
I can find and modify them easily.”
46. Level 4-5 Refactoring
• Componentise the application into plugins
• Construct applications by combining plugins
• Could your application itself be constructed
as a plugin for an organisation’s product
suite?
• Writing plugins that modify the Grails/Spring
context is beyond the scope of this
workshop!
47. User Story 8
“As a pomodoro fan, I would like a simplified version of
my Inventory, so I can view it on my iPhone.”