SlideShare uma empresa Scribd logo
1 de 53
Baixar para ler offline
Grails: Patterns &
Practices
Paul Bowler
Senior Consultant, OpenCredo
Who are you?
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 ‘Maturity’ Levels
?
?
?
?
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.
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.”
Useful Commands
• grails create-app pomodoro
• grails create-domain-class <domain>
• grails generate-all <domain>
• grails generate-controller <domain> and
add ‘static scaffold = true’ to controller
Considerations
• Associations
• One-to-One
• One-to-Many
• Many-to-Many
• Constraints &Validation
• Time-Stamping?
• Default values (and field values inViews?)
You did create some
tests first, right?
Implementation
class Task {
Inventory inventory
String description
static belongsTo = [Inventory]
static constraints = {
description(nullable: false, blank: false)
}
}
class Inventory {
String name
static hasMany = [tasks: Task]
static constraints = {
name(nullable: false, blank: false, unique: true)
}
}
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()
! }
}
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?
Implementation (2)
class Task {
Inventory inventory
String description
static constraints = {
description(nullable: false, blank: false)
}
}
class Inventory {
String name
}
Side-effects?
• Different syntax for adding Tasks
• No cascading deletes
• Custom finder required to find all Tasks in
an Inventory
• Scaffolding breaks!
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.”
Considerations
• Does the ‘Today’ list share any common
attributes with the Inventory?
• How about a more intuitive URL scheme?
?
Level 1
?
?
?
Views
Level 1 -Views
Controller
Model
PageView PageViewPageView
Model Model
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
?
Level 2
?
?
Controllers
Views
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
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.”
Considerations
• Web Flow plugin?
• Command Objects?
• What changes need to be made to domain
classes?
Web Flow
class InventoryController {
…
def inventoryFlow = {
showInventory {
on("done").to "saveInventory"
on("continue").to "addTask"
}
…
addTask {
redirect(controller:"task", action:"create")
}
saveInventory()
}
}
<g:form action="inventory">
<g:submitButton name="continue" value="Add Another"></g:submitButton>
<g:submitButton name="done" value="I’m Done"></g:submitButton>
</g:form>
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.”
Considerations
• Can we do this without page refreshes?
• How can we test this?
• Domain changes?
Level 2 - Controllers
Controller
Domain
Controller Controller
Domain Domain Domain
Layout
Fragments Fragments
Layout
Fragments Fragments
Layout
Fragments Fragments
Level 2 ‘Smells’
• Large, complex Controllers
• Different scenarios driven by ‘If/Then’ logic
• Content negotiation increases complexity
further
• Many similar controller methods (not
DRY!)
• Poorly handled Transactions
?
Level 3 - Services
?
Services
Controllers
Views
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
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.”
Considerations
• Don’t clutter your Controllers!
• REST-ful URLs
• Content negotiation?
• Custom XML/JSON formats?
RESTful URL Mappings
static mappings = {
"/task/$id?"(resource:"task")
}
static mappings = {
"/task/$id"(controller:"task") {
action = [GET:"show", PUT:"update", DELETE:"delete", POST:"save"]
}
}
static mappings = {
"/task/$id"(controller:"task", parseRequest:true) {
action = [GET:"show", PUT:"update", DELETE:"delete", POST:"save"]
}
}
Content Negotiation
class InventoryController {
def inventory
def list = {
this.inventory = Inventory.list()
withFormat {
html inventoryList:inventory
json { render inventory as JSON }
xml { render inventory as XML }
}
}
}
Custom Formats?
def listAsXML = {
def inventory = Inventory.get(params.id)
def tasks = inventory.tasks
render(contentType:"text/xml") {
inventory(name:inventory.name) {
tasks {
for(t in tasks) {
task(title:t.title)
! }
}!
}
}
}
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.”
Level 3 - Services
Controller
Domain
Controller Controller
Domain Domain Domain
Services
Layout
Fragments Fragments
Layout
Fragments Fragments
Layout
Fragments Fragments
Level 3 ‘Smells’
• Large, complex Services
• Services acting as proxies for domain
behaviour
• ‘Cut-and-paste’ methods
?
Level 4 - Libraries
Libraries
Services
Controllers
Views
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
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.”
Level 4 - Libraries
Controller
Domain
Controller Controller
Domain Domain Domain
Services
Libraries Libraries
Layout
Fragments Fragments
Layout
Fragments Fragments
Layout
Fragments Fragments
Level 4 ‘Smells’
• Large, monolithic application
• Increased cognitive overhead
• New starters struggle
• Components ‘cut and pasted’ into similar
projects
Plugins
Level 5 - Plugins
Libraries
Services
Controllers
Views
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!
User Story 8
“As a pomodoro fan, I would like a simplified version of
my Inventory, so I can view it on my iPhone.”
Useful Commands
• grails create-plugin <plugin>
• grails package-plugin
• grails install-plugin /path/to/plugin/grails-
example-0.1.zip
Layouts and Fragments
<g:include action="show" id="1" />
<g:include action="show" id="${currentTask.id}" />
<g:include controller="task" />
<g:include controller="task" action="list" />
<g:include action="list" params="[sort:'title', order:'asc'] />
<html>
<head>
<title><g:layoutTitle default="An example decorator" /></title>
<g:layoutHead />
</head>
<body>
<div class="menu"><!--my common menu goes here--></menu>
<div class="body">
<g:layoutBody />
</div>
</div>
</body>
</html>
Layout Options
• In your views:
<meta name="layout" content="main"></meta>
• In your controller:
static layout = 'task'
static layout = 'custom/task'
• By Convention:
grails-app/views/layouts/task.gsp
grails-app/views/layouts/task/list.gsp
• Inline:
<g:applyLayout name="myLayout" template="taskTemplate" collection="${tasks}" />
<g:applyLayout name="myLayout" url="http://www.google.com" />
<g:applyLayout name="myLayout">The content to apply a layout to</g:applyLayout>
Level 5 - Plugins
Controller
Domain
Controller
Domain Domain
Plugins
Page
View
Page
View
Controller
Services
Libraries / Plugins
Domain Domain
Layout
Fragments Fragments
Layout
Fragments Fragments
Services
Libraries Libraries
Plugins
Libraries
Services
Controllers
The Full Picture
Views
Phew!
Well Done.

Mais conteúdo relacionado

Mais procurados

What is SharePoint Development??
What is SharePoint Development??What is SharePoint Development??
What is SharePoint Development??Mark Rackley
 
JavaFX Versus HTML5 - JavaOne 2014
JavaFX Versus HTML5 - JavaOne 2014JavaFX Versus HTML5 - JavaOne 2014
JavaFX Versus HTML5 - JavaOne 2014Ryan Cuprak
 
Moving to the Client - JavaFX and HTML5
Moving to the Client - JavaFX and HTML5Moving to the Client - JavaFX and HTML5
Moving to the Client - JavaFX and HTML5Stephen Chin
 
Java APIs- The missing manual (concurrency)
Java APIs- The missing manual (concurrency)Java APIs- The missing manual (concurrency)
Java APIs- The missing manual (concurrency)Hendrik Ebbers
 
Moving To The Client - JavaFX and HTML5
Moving To The Client - JavaFX and HTML5Moving To The Client - JavaFX and HTML5
Moving To The Client - JavaFX and HTML5Stephen Chin
 
Google App Engine Java, Groovy and Gaelyk
Google App Engine Java, Groovy and GaelykGoogle App Engine Java, Groovy and Gaelyk
Google App Engine Java, Groovy and GaelykGuillaume Laforge
 
Flash Platformアップデート
Flash PlatformアップデートFlash Platformアップデート
Flash PlatformアップデートMariko Nishimura
 
A new tool for measuring performance in Drupal 8 - DrupalCamp London
A new tool for measuring performance in Drupal 8 - DrupalCamp LondonA new tool for measuring performance in Drupal 8 - DrupalCamp London
A new tool for measuring performance in Drupal 8 - DrupalCamp LondonLuca Lusso
 
Alexander Zeng
Alexander ZengAlexander Zeng
Alexander ZengAlex Zeng
 
Top 8 benefits of react js
Top 8 benefits of react jsTop 8 benefits of react js
Top 8 benefits of react jsRani Sinha
 
Java WebStart Is Dead: What Should We Do Now?
Java WebStart Is Dead: What Should We Do Now?Java WebStart Is Dead: What Should We Do Now?
Java WebStart Is Dead: What Should We Do Now?Hendrik Ebbers
 
Moving to the Client - JavaFX and HTML5
Moving to the Client - JavaFX and HTML5Moving to the Client - JavaFX and HTML5
Moving to the Client - JavaFX and HTML5Stephen Chin
 
Scribe online 03 scribe online cdk and api overview
Scribe online 03   scribe online cdk and api overviewScribe online 03   scribe online cdk and api overview
Scribe online 03 scribe online cdk and api overviewScribe Software Corp.
 
Developing Mobile HTML5 Apps with Grails
Developing Mobile HTML5 Apps with GrailsDeveloping Mobile HTML5 Apps with Grails
Developing Mobile HTML5 Apps with GrailsGR8Conf
 
Big ideas in small packages - How microservices helped us to scale our vision
Big ideas in small packages  - How microservices helped us to scale our visionBig ideas in small packages  - How microservices helped us to scale our vision
Big ideas in small packages - How microservices helped us to scale our visionSebastian Schleicher
 
S60 3rd FP2 Widgets
S60 3rd FP2 WidgetsS60 3rd FP2 Widgets
S60 3rd FP2 Widgetsromek
 
Moving to the Client - JavaFX and HTML5
Moving to the Client - JavaFX and HTML5Moving to the Client - JavaFX and HTML5
Moving to the Client - JavaFX and HTML5Stephen Chin
 
Micronaut: Changing the Micro Future
Micronaut: Changing the Micro FutureMicronaut: Changing the Micro Future
Micronaut: Changing the Micro FutureZachary Klein
 

Mais procurados (20)

What is SharePoint Development??
What is SharePoint Development??What is SharePoint Development??
What is SharePoint Development??
 
JavaFX Versus HTML5 - JavaOne 2014
JavaFX Versus HTML5 - JavaOne 2014JavaFX Versus HTML5 - JavaOne 2014
JavaFX Versus HTML5 - JavaOne 2014
 
Moving to the Client - JavaFX and HTML5
Moving to the Client - JavaFX and HTML5Moving to the Client - JavaFX and HTML5
Moving to the Client - JavaFX and HTML5
 
Java APIs- The missing manual (concurrency)
Java APIs- The missing manual (concurrency)Java APIs- The missing manual (concurrency)
Java APIs- The missing manual (concurrency)
 
Moving To The Client - JavaFX and HTML5
Moving To The Client - JavaFX and HTML5Moving To The Client - JavaFX and HTML5
Moving To The Client - JavaFX and HTML5
 
Google App Engine Java, Groovy and Gaelyk
Google App Engine Java, Groovy and GaelykGoogle App Engine Java, Groovy and Gaelyk
Google App Engine Java, Groovy and Gaelyk
 
Flash Platformアップデート
Flash PlatformアップデートFlash Platformアップデート
Flash Platformアップデート
 
Java 11 OMG
Java 11 OMGJava 11 OMG
Java 11 OMG
 
Crx 2.2 Deep-Dive
Crx 2.2 Deep-DiveCrx 2.2 Deep-Dive
Crx 2.2 Deep-Dive
 
A new tool for measuring performance in Drupal 8 - DrupalCamp London
A new tool for measuring performance in Drupal 8 - DrupalCamp LondonA new tool for measuring performance in Drupal 8 - DrupalCamp London
A new tool for measuring performance in Drupal 8 - DrupalCamp London
 
Alexander Zeng
Alexander ZengAlexander Zeng
Alexander Zeng
 
Top 8 benefits of react js
Top 8 benefits of react jsTop 8 benefits of react js
Top 8 benefits of react js
 
Java WebStart Is Dead: What Should We Do Now?
Java WebStart Is Dead: What Should We Do Now?Java WebStart Is Dead: What Should We Do Now?
Java WebStart Is Dead: What Should We Do Now?
 
Moving to the Client - JavaFX and HTML5
Moving to the Client - JavaFX and HTML5Moving to the Client - JavaFX and HTML5
Moving to the Client - JavaFX and HTML5
 
Scribe online 03 scribe online cdk and api overview
Scribe online 03   scribe online cdk and api overviewScribe online 03   scribe online cdk and api overview
Scribe online 03 scribe online cdk and api overview
 
Developing Mobile HTML5 Apps with Grails
Developing Mobile HTML5 Apps with GrailsDeveloping Mobile HTML5 Apps with Grails
Developing Mobile HTML5 Apps with Grails
 
Big ideas in small packages - How microservices helped us to scale our vision
Big ideas in small packages  - How microservices helped us to scale our visionBig ideas in small packages  - How microservices helped us to scale our vision
Big ideas in small packages - How microservices helped us to scale our vision
 
S60 3rd FP2 Widgets
S60 3rd FP2 WidgetsS60 3rd FP2 Widgets
S60 3rd FP2 Widgets
 
Moving to the Client - JavaFX and HTML5
Moving to the Client - JavaFX and HTML5Moving to the Client - JavaFX and HTML5
Moving to the Client - JavaFX and HTML5
 
Micronaut: Changing the Micro Future
Micronaut: Changing the Micro FutureMicronaut: Changing the Micro Future
Micronaut: Changing the Micro Future
 

Semelhante a Grails patterns and practices

5 Common Mistakes You are Making on your Website
 5 Common Mistakes You are Making on your Website 5 Common Mistakes You are Making on your Website
5 Common Mistakes You are Making on your WebsiteAcquia
 
SharePoint 2014: Where to save my data, for devs!
SharePoint 2014: Where to save my data, for devs!SharePoint 2014: Where to save my data, for devs!
SharePoint 2014: Where to save my data, for devs!Ben Steinhauser
 
Add-On Development: EE Expects that Every Developer will do his Duty
Add-On Development: EE Expects that Every Developer will do his DutyAdd-On Development: EE Expects that Every Developer will do his Duty
Add-On Development: EE Expects that Every Developer will do his Dutyreedmaniac
 
Add-On Development: EE Expects that Every Developer will do his Duty
Add-On Development: EE Expects that Every Developer will do his DutyAdd-On Development: EE Expects that Every Developer will do his Duty
Add-On Development: EE Expects that Every Developer will do his DutyLeslie Doherty
 
Nsc 2013 06-17 - random rants on 2013
Nsc 2013 06-17 - random rants on 2013Nsc 2013 06-17 - random rants on 2013
Nsc 2013 06-17 - random rants on 2013Mikael Svenson
 
Creating a Documentation Portal
Creating a Documentation PortalCreating a Documentation Portal
Creating a Documentation PortalSteve Anderson
 
Using BladeRunnerJS to Build Front-End Apps that Scale - Fluent 2014
Using BladeRunnerJS to Build Front-End Apps that Scale - Fluent 2014Using BladeRunnerJS to Build Front-End Apps that Scale - Fluent 2014
Using BladeRunnerJS to Build Front-End Apps that Scale - Fluent 2014Phil Leggetter
 
CUST-2 New Client Configuration & Extension Points in Share
CUST-2 New Client Configuration & Extension Points in ShareCUST-2 New Client Configuration & Extension Points in Share
CUST-2 New Client Configuration & Extension Points in ShareAlfresco Software
 
Masterin Large Scale Java Script Applications
Masterin Large Scale Java Script ApplicationsMasterin Large Scale Java Script Applications
Masterin Large Scale Java Script ApplicationsFabian Jakobs
 
CUST-1 Share Document Library Extension Points
CUST-1 Share Document Library Extension PointsCUST-1 Share Document Library Extension Points
CUST-1 Share Document Library Extension PointsAlfresco Software
 
Office 365 Saturday (Sydney) - SharePoint framework – build integrated user e...
Office 365 Saturday (Sydney) - SharePoint framework – build integrated user e...Office 365 Saturday (Sydney) - SharePoint framework – build integrated user e...
Office 365 Saturday (Sydney) - SharePoint framework – build integrated user e...Anupam Ranku
 
Advantages of Rails Framework
Advantages of Rails FrameworkAdvantages of Rails Framework
Advantages of Rails FrameworkSathish Mariappan
 
Git Going w/ Git
Git Going w/ GitGit Going w/ Git
Git Going w/ GitheyMP
 
Designing your API Server for mobile apps
Designing your API Server for mobile appsDesigning your API Server for mobile apps
Designing your API Server for mobile appsMugunth Kumar
 
How to Contribute to Apache Usergrid
How to Contribute to Apache UsergridHow to Contribute to Apache Usergrid
How to Contribute to Apache UsergridDavid M. Johnson
 

Semelhante a Grails patterns and practices (20)

5 Common Mistakes You are Making on your Website
 5 Common Mistakes You are Making on your Website 5 Common Mistakes You are Making on your Website
5 Common Mistakes You are Making on your Website
 
SharePoint 2014: Where to save my data, for devs!
SharePoint 2014: Where to save my data, for devs!SharePoint 2014: Where to save my data, for devs!
SharePoint 2014: Where to save my data, for devs!
 
Add-On Development: EE Expects that Every Developer will do his Duty
Add-On Development: EE Expects that Every Developer will do his DutyAdd-On Development: EE Expects that Every Developer will do his Duty
Add-On Development: EE Expects that Every Developer will do his Duty
 
presentation
presentationpresentation
presentation
 
presentation
presentationpresentation
presentation
 
Add-On Development: EE Expects that Every Developer will do his Duty
Add-On Development: EE Expects that Every Developer will do his DutyAdd-On Development: EE Expects that Every Developer will do his Duty
Add-On Development: EE Expects that Every Developer will do his Duty
 
JS Essence
JS EssenceJS Essence
JS Essence
 
Nsc 2013 06-17 - random rants on 2013
Nsc 2013 06-17 - random rants on 2013Nsc 2013 06-17 - random rants on 2013
Nsc 2013 06-17 - random rants on 2013
 
Creating a Documentation Portal
Creating a Documentation PortalCreating a Documentation Portal
Creating a Documentation Portal
 
Using BladeRunnerJS to Build Front-End Apps that Scale - Fluent 2014
Using BladeRunnerJS to Build Front-End Apps that Scale - Fluent 2014Using BladeRunnerJS to Build Front-End Apps that Scale - Fluent 2014
Using BladeRunnerJS to Build Front-End Apps that Scale - Fluent 2014
 
Where to save my data, for devs!
Where to save my data, for devs!Where to save my data, for devs!
Where to save my data, for devs!
 
CUST-2 New Client Configuration & Extension Points in Share
CUST-2 New Client Configuration & Extension Points in ShareCUST-2 New Client Configuration & Extension Points in Share
CUST-2 New Client Configuration & Extension Points in Share
 
Masterin Large Scale Java Script Applications
Masterin Large Scale Java Script ApplicationsMasterin Large Scale Java Script Applications
Masterin Large Scale Java Script Applications
 
CUST-1 Share Document Library Extension Points
CUST-1 Share Document Library Extension PointsCUST-1 Share Document Library Extension Points
CUST-1 Share Document Library Extension Points
 
Office 365 Saturday (Sydney) - SharePoint framework – build integrated user e...
Office 365 Saturday (Sydney) - SharePoint framework – build integrated user e...Office 365 Saturday (Sydney) - SharePoint framework – build integrated user e...
Office 365 Saturday (Sydney) - SharePoint framework – build integrated user e...
 
Advantages of Rails Framework
Advantages of Rails FrameworkAdvantages of Rails Framework
Advantages of Rails Framework
 
Git Going w/ Git
Git Going w/ GitGit Going w/ Git
Git Going w/ Git
 
Welcome to React.pptx
Welcome to React.pptxWelcome to React.pptx
Welcome to React.pptx
 
Designing your API Server for mobile apps
Designing your API Server for mobile appsDesigning your API Server for mobile apps
Designing your API Server for mobile apps
 
How to Contribute to Apache Usergrid
How to Contribute to Apache UsergridHow to Contribute to Apache Usergrid
How to Contribute to Apache Usergrid
 

Último

Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Victor Rentea
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontologyjohnbeverley2021
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Victor Rentea
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelMcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelDeepika Singh
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Orbitshub
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistandanishmna97
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfOrbitshub
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesrafiqahmad00786416
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...apidays
 
Introduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDMIntroduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDMKumar Satyam
 
JohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptxJohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptxJohnPollard37
 
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)Samir Dash
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxRustici Software
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxRemote DBA Services
 

Último (20)

Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Six Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal OntologySix Myths about Ontologies: The Basics of Formal Ontology
Six Myths about Ontologies: The Basics of Formal Ontology
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelMcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
Introduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDMIntroduction to use of FHIR Documents in ABDM
Introduction to use of FHIR Documents in ABDM
 
JohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptxJohnPollard-hybrid-app-RailsConf2024.pptx
JohnPollard-hybrid-app-RailsConf2024.pptx
 
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
AI+A11Y 11MAY2024 HYDERBAD GAAD 2024 - HelloA11Y (11 May 2024)
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 

Grails patterns and practices

  • 1. Grails: Patterns & Practices Paul Bowler Senior Consultant, OpenCredo
  • 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.”
  • 8. Useful Commands • grails create-app pomodoro • grails create-domain-class <domain> • grails generate-all <domain> • grails generate-controller <domain> and add ‘static scaffold = true’ to controller
  • 9. Considerations • Associations • One-to-One • One-to-Many • Many-to-Many • Constraints &Validation • Time-Stamping? • Default values (and field values inViews?)
  • 10. You did create some tests first, right?
  • 11. Implementation class Task { Inventory inventory String description static belongsTo = [Inventory] static constraints = { description(nullable: false, blank: false) } } class Inventory { String name static hasMany = [tasks: Task] static constraints = { name(nullable: false, blank: false, unique: true) } }
  • 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?
  • 19. Level 1 -Views Controller Model PageView PageViewPageView Model Model
  • 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?
  • 25. Web Flow class InventoryController { … def inventoryFlow = { showInventory { on("done").to "saveInventory" on("continue").to "addTask" } … addTask { redirect(controller:"task", action:"create") } saveInventory() } } <g:form action="inventory"> <g:submitButton name="continue" value="Add Another"></g:submitButton> <g:submitButton name="done" value="I’m Done"></g:submitButton> </g:form>
  • 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?
  • 28. Level 2 - Controllers Controller Domain Controller Controller Domain Domain Domain Layout Fragments Fragments Layout Fragments Fragments Layout Fragments Fragments
  • 29. Level 2 ‘Smells’ • Large, complex Controllers • Different scenarios driven by ‘If/Then’ logic • Content negotiation increases complexity further • Many similar controller methods (not DRY!) • Poorly handled Transactions
  • 30. ? Level 3 - Services ? Services Controllers Views
  • 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.”
  • 33. Considerations • Don’t clutter your Controllers! • REST-ful URLs • Content negotiation? • Custom XML/JSON formats?
  • 34. RESTful URL Mappings static mappings = { "/task/$id?"(resource:"task") } static mappings = { "/task/$id"(controller:"task") { action = [GET:"show", PUT:"update", DELETE:"delete", POST:"save"] } } static mappings = { "/task/$id"(controller:"task", parseRequest:true) { action = [GET:"show", PUT:"update", DELETE:"delete", POST:"save"] } }
  • 35. Content Negotiation class InventoryController { def inventory def list = { this.inventory = Inventory.list() withFormat { html inventoryList:inventory json { render inventory as JSON } xml { render inventory as XML } } } }
  • 36. Custom Formats? def listAsXML = { def inventory = Inventory.get(params.id) def tasks = inventory.tasks render(contentType:"text/xml") { inventory(name:inventory.name) { tasks { for(t in tasks) { task(title:t.title) ! } }! } } }
  • 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.”
  • 38. Level 3 - Services Controller Domain Controller Controller Domain Domain Domain Services Layout Fragments Fragments Layout Fragments Fragments Layout Fragments Fragments
  • 39. Level 3 ‘Smells’ • Large, complex Services • Services acting as proxies for domain behaviour • ‘Cut-and-paste’ methods
  • 40. ? Level 4 - Libraries Libraries Services Controllers Views
  • 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.”
  • 43. Level 4 - Libraries Controller Domain Controller Controller Domain Domain Domain Services Libraries Libraries Layout Fragments Fragments Layout Fragments Fragments Layout Fragments Fragments
  • 44. Level 4 ‘Smells’ • Large, monolithic application • Increased cognitive overhead • New starters struggle • Components ‘cut and pasted’ into similar projects
  • 45. Plugins Level 5 - Plugins Libraries Services Controllers Views
  • 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.”
  • 48. Useful Commands • grails create-plugin <plugin> • grails package-plugin • grails install-plugin /path/to/plugin/grails- example-0.1.zip
  • 49. Layouts and Fragments <g:include action="show" id="1" /> <g:include action="show" id="${currentTask.id}" /> <g:include controller="task" /> <g:include controller="task" action="list" /> <g:include action="list" params="[sort:'title', order:'asc'] /> <html> <head> <title><g:layoutTitle default="An example decorator" /></title> <g:layoutHead /> </head> <body> <div class="menu"><!--my common menu goes here--></menu> <div class="body"> <g:layoutBody /> </div> </div> </body> </html>
  • 50. Layout Options • In your views: <meta name="layout" content="main"></meta> • In your controller: static layout = 'task' static layout = 'custom/task' • By Convention: grails-app/views/layouts/task.gsp grails-app/views/layouts/task/list.gsp • Inline: <g:applyLayout name="myLayout" template="taskTemplate" collection="${tasks}" /> <g:applyLayout name="myLayout" url="http://www.google.com" /> <g:applyLayout name="myLayout">The content to apply a layout to</g:applyLayout>
  • 51. Level 5 - Plugins Controller Domain Controller Domain Domain Plugins Page View Page View Controller Services Libraries / Plugins Domain Domain Layout Fragments Fragments Layout Fragments Fragments Services Libraries Libraries