solid grails apps with verbose groovy
DESCRIPTION
Codemotion 2014 Video de la charla: https://www.youtube.com/watch?v=YwT1ccikv3s Tras 5 años programando con Grails, me he dado cuenta de que lo he estado haciendo mal. Por programar rápido y hacer un código minúsculo, he perdido muchas cosas por el camino que si tenía cuando programaba aplicaciones web con Java. Voy a contar mi experiencia personal de cómo he evolucionado mis desarrollos para que sean fáciles de mantener y de testear. Vuelven los POJOS y el código estático, pero solo para ayudar a poner un poco de oden. Aplicando al extremo la "S" de SOLID y aplicando patrones de diseño, hablaré de una manera (más) de diseñar aplicaciones web con Grails usando Commands, organizando el código de los controllers y clasificando los servicios y sus respuestas con pequeñas clases.TRANSCRIPT
MADRID · NOV 21-22 · 2014
Solid Grails Apps
with verbose Groovy
Alberto Vilches
Consultant at Virtual Software
@albertovilches
Greach Conference Organizer
http://greachconf.com
MADRID · NOV 21-22 · 2014
Disclaimer
1. I’m not a guru, I’m not trying to teach you
nothing.
2. This is not a talk about something specific,
this is my personal opinion, I can be
wrong.
3. It’s just my way to do the things…. Now.
Tomorrow I can change my mind, again.
MADRID · NOV 21-22 · 2014
About me
16 years developing, last 5
years with Groovy/Grails
Madrid GUG usual suspect
Greachconf organizer
2 kids, Maclover, gamer and skeptical
Now working at Virtual Software
MADRID · NOV 21-22 · 2014
About me
And my code sucks!… and probably yours too.
I can’t be the best
but I can be better than yesterday.
This is a talk about my problems, but I’ll show
you solutions.
MADRID · NOV 21-22 · 2014
IntroductionPART 0/3
MADRID · NOV 21-22 · 2014
I want to tell you something…
MADRID · NOV 21-22 · 2014
I want to tell you about…
The
Grails trap
MADRID · NOV 21-22 · 2014
A trap? Are you sure?
It’s not a trap for everybody
Some people are invulnerable
MADRID · NOV 21-22 · 2014
A trap? Are you sure?
It’s not a trap for everybody
Some people are invulnerable
It depends how much
you have suffered with
j2Ee
MADRID · NOV 21-22 · 2014
Please, kill me
I was lost
in the f*cking J2EE World
Three tiers application servers, EJB, RMI, CORBA, JMS, JDBC direct access,
really slooow source java code generation, JNDI, huge monolitic applications
full of jar, war and ear, fighting against DTOs, VO, Facade and Service
Locators, and of course XML, XML, XML, I told you about XML? Yes XML!
MADRID · NOV 21-22 · 2014
And then…
MADRID · NOV 21-22 · 2014
And then…
MADRID · NOV 21-22 · 2014
And then…
MADRID · NOV 21-22 · 2014
And then…
Groovy and Grails
The same shit but you ride them with a magic
flying unicorn with rocket launcher
0 boilerplate!
Working app from scratch in minutes!
MADRID · NOV 21-22 · 2014
Grails: the trap explained
Really new and young
Not much documentation
Not real complex examples (no petstore!)
MADRID · NOV 21-22 · 2014
Grails: the trap explained
“With great power comes great responsibility”Spiderman movie
“La potencia sin control no sirve de nada”Some old TV ad
“Ten cuidao no corras tanto que te vas a dar”My mother
MADRID · NOV 21-22 · 2014
Grails: the trap explained
Software architecture?
Design patterns?
MADRID · NOV 21-22 · 2014
Grails: the trap explained
Software architecture?
Design patterns?
WHO CARES! WE HAVE
ARTIFACTS(remember? no packages at begining!)
MADRID · NOV 21-22 · 2014
Grails: the trap explained
No boilerplate and CoC becomes the
NEW TRUTH
MADRID · NOV 21-22 · 2014
Grails: the trap explained
No boilerplate and CoC becomes the
NEW TRUTH
the world needs to know
it
MADRID · NOV 21-22 · 2014
“Look, my code is really cool!”
MADRID · NOV 21-22 · 2014
“Look, my code is really cool!”
MADRID · NOV 21-22 · 2014
“Look, my code is really cool!”
(In fact, it really really really sucks)
MADRID · NOV 21-22 · 2014
Grails: the trap explained
no architectural patterns needed, just artifacts
MADRID · NOV 21-22 · 2014
Grails: the trap explained
(no architectural patterns needed, just artifacts
+ really easy data access with gorm)
MADRID · NOV 21-22 · 2014
Grails: the trap explained
(no architectural patterns needed, just artifacts
+ really easy data access with gorm)
x (avoiding the “anemic domain model”
results in more business logic in controllers,
services and domain objects)
MADRID · NOV 21-22 · 2014
Grails: the trap explained
(no architectural patterns needed, just artifacts
+ really easy data access with gorm)
x (avoiding the “anemic domain model”
results in more business logic in controllers,
services and domain objects)
^ (Grails infrastructure everywhere)
MADRID · NOV 21-22 · 2014
Grails: the trap explained
(no architectural patterns needed, just artifacts
+ really easy data access with gorm)
x (avoiding the “anemic domain model”
results in more business logic in controllers,
services and domain objects)
^ (Grails infrastructure everywhere)
===================================
Shit, now i’m lost with grails
too
MADRID · NOV 21-22 · 2014
My new mess (Grails version)
MADRID · NOV 21-22 · 2014
My new mess (Grails version)
MADRID · NOV 21-22 · 2014
PART 1/3The theoric and long part,
with patterns and other stuff.
MADRID · NOV 21-22 · 2014
How I’m solving it
PROBLEM #1
No control about where the business logic lives
Grails hides Spring and Hibernate, offering to
you new infrastructure you spread in artifacts
MADRID · NOV 21-22 · 2014
How I’m solving it
PROBLEM #1
No control about where the business logic lives
Create a taxonomy and rules
Grails hides Spring and Hibernate, offering to
you new infrastructure you spread in artifacts
Isolate it
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
My house, my rules:
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
My house, my rules:
1) Only use services
2) Return rich responses (and use enums!)
3) Too much services? create your own
taxonomy
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
1) Only use services
2) Return rich responses (use enums!)
Controllers just call services methods.
To avoid logic in controllers, services have to
return rich object responses.
Controllers and views only have to check
responses status calling short methods with
meaningful names (clean code!).
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
The good parts:
You can add more info into response
classes without change all the app.
Easy to test and mocks.
Meaningful actions.
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
The good parts:
You can add more info into response
classes without change all the app.
Easy to test and mocks.
Meaningful actions.
The bad parts:
Verbose.
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
The good parts:
You can add more info into response
classes without change all the app.
Easy to test and mocks.
Meaningful actions.
The bad parts:
Verbose.
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
What about to put logic in domain classes?
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
What about to put logic in domain classes?
IT’S
A
TRAP!
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
What about to put logic in domain classes?
“Create methods
in your domain classes,
but delegate calls to
service methods.”
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
3) Too much services? create your own
taxonomy
My house, my rules:
“Repository” services
“External” services
“Business” services
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
“Repository” services
One responsability: access data
Gorm/HQL/JDBC, grailsApplication.config,
fileSystem
No transactional!
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
“Repository” services, the good parts:
Isolate Grails infrastructure.
Easy to refactor: better rename (only one
place to modify) or change data source.
Easy to mantain: only one place to look.
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
“Repository” services, the good parts:
Isolate Grails infrastructure.
Easy to refactor: better rename (only one
place to modify) or change data source.
Easy to mantain: only one place to look.
The bad parts:
Verbose, specially the wraping service of
grailsApplication.config
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
“Repository” services, the good parts:
Isolate Grails infrastructure.
Easy to refactor: better rename (only one
place to modify) or change data source.
Easy to mantain: only one place to look.
The bad parts:
Verbose, specially the wraping service of
grailsApplication.config
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
“External” services
One responsability
access to remote servers
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
“External” services
One responsability
access to remote servers
Web Services (rest/soap), apis, mail servers, …
FTP, SNMP, JMX, XMPP, …
Amazon S3, Facebook, Google, Twitter, …
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
“External” services, the good parts
Vertical design.
Each integration has one implementation.
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
“External” services, the good parts
Vertical design.
Each integration has one implementation.
The bad parts
Too simple: keep in mind some integrations
could need design patterns to avoid huge
service classes full of spaghetti code.
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
External services, good parts
Vertical design.
Each integration has one implementation.
The bad parts
Too simple: keep in mind some integrations
could need design patterns to avoid huge
service classes full of spaghetti code.
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
“Business” services
One responsability: your business logic
Can be transactional
Orchest all other services
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
“Business” services, the good parts
Isolate business logic without infrastructure.
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
“Business” services, the good parts
Isolate business logic without infrastructure.
The bad parts
Verbose: you always have to pass through
them.
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
“Business” services, the good parts
Isolate business logic without infrastructure.
The bad parts
Verbose: you always have to pass through
them.
Hey, you can break your own rules and call
directly to repositoy services.
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
“Business” services, the good parts
Isolate business logic without infrastructure.
The bad parts
Verbose: you always have to pass through
them.
Hey, you can break your own rules and call
directly to repositoy services.
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
My rules
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
My rules
Controllers call to business services only
Business services call to any kind of service
Repositories can call other repositories only
External services can’t call other services
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
Create a taxonomy with your own rules
MADRID · NOV 21-22 · 2014
#1 No control about where the
business logic lives
Create a taxonomy with your own rules
But ensure all the
team respect them
MADRID · NOV 21-22 · 2014
PART 2/3About the views.
Sweet and short!
MADRID · NOV 21-22 · 2014
How I’m solving it
PROBLEM #2:
Controllers have too much duplicated and
dynamic code with map arguments (buggy!)
MADRID · NOV 21-22 · 2014
How I’m solving it
PROBLEM #2:
Controllers have too much duplicated and
dynamic code with map arguments (buggy!)
Clean code: hide infrastructure in single
methods (or classes)
MADRID · NOV 21-22 · 2014
#2 Controllers have too much
duplicated and dynamic code
MADRID · NOV 21-22 · 2014
#2 Controllers have too much
duplicated and dynamic code
MADRID · NOV 21-22 · 2014
#2 Controllers have too much
duplicated and dynamic code
MADRID · NOV 21-22 · 2014
#2 Controllers have too much
duplicated and dynamic code
MADRID · NOV 21-22 · 2014
#2 Controllers have too much
duplicated and dynamic code
The good parts
Meaningful actions, easy reading, reusable
Easy to rename model values or view names
Better testingYou don’t have to assert model or view, just assert method calls
Static code, if you like
MADRID · NOV 21-22 · 2014
#2 Controllers have too much
duplicated and dynamic code
The good parts
Meaningful actions, easy reading, reusable
Easy to rename model values or view names
Better testingYou don’t have to assert model or view, just assert method calls
Static code, if you like
The bad parts
Less flexible than using dynamic methods.
MADRID · NOV 21-22 · 2014
PART 3/3Final part. A lot of
technical knowledge about data binding.
BONUS TRACK: 10 TRICKS!
MADRID · NOV 21-22 · 2014
PART 3/3Final part. A lot of
technical knowledge about data binding.
Shut up and keep your eyes open!
MADRID · NOV 21-22 · 2014
How I’m solving it
PROBLEM #3:
What about the input?
Divide input data in minimal commands
Use new Grails 2.3 binding events
And let me show you some tricks :-)
MADRID · NOV 21-22 · 2014
#3 How Commands works
A new command instance is created, then:
1 Data is bound from request (json/params),
before and after events are called.
2 Dependency Injection.
3 command.validate() is called.
Finally, your action is executed.
MADRID · NOV 21-22 · 2014
#3 How Commands works
ControllersApi.class
(org.codehaus.groovy.grails.plugins.web.api)
initializeCommandObject method.
DataBindingUtils.class
(org.codehaus.groovy.grails.web.binding)
ValidationSupport.class
(org.codehaus.groovy.grails.web.plugins.support)
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #0
Never ever use domain classes as
commands in your actions.
It’s a really bad practice, you are exposing your
datamodel to the world!
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #1
You musn’t validate commands in your
actions.
Grails did that for you already!
Maybe database access will be executed twice.
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #2
Yes, you can use more than one command
in your actions.
All of them will be bound using the same data
input.
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #3
Pay attention when using new data binding
annotations.
The annotations are bound to the command
class at compile time forever. And maybe you
want a different behavior.
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #3
Pay attention when using new data binding
annotations.
Are you sure to use that? What happens if you want to use the
command for importing data from a file using other format date?
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #4 The @BindUsing is tricky!
Use the same field name!
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #4 The @BindUsing is tricky
How it works? QUIZZ TIME!
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #4 The @BindUsing is tricky
email emailOther value bound
[email protected] empty ?
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #4 The @BindUsing is tricky
email emailOther value bound
[email protected] empty empty!
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #4 The @BindUsing is tricky
email emailOther value bound
[email protected] empty empty!
empty [email protected] ?
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #4 The @BindUsing is tricky
email emailOther value bound
[email protected] empty empty!
empty [email protected] empty too!
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #4 The @BindUsing is tricky
email emailOther value bound
[email protected] empty empty!
empty [email protected] empty too!
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #4 The @BindUsing is tricky
email emailOther value bound
[email protected] empty empty!
empty [email protected] empty too!
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #4 The @BindUsing is tricky
So, be careful…
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #5 Default value converters are tricky
Locale.default is used if no request bound to
current thread.
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #5 Default value converters are tricky
You have to create another implementation if
you want to use commands without request.
(i.e.: importing from file in a Quartz job)
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #6
Use the binding events
Especially, afterBinding event allows you to do
some ad-hoc binding and validations.
Best part: these events are executed before
validate.
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #7
Delegate binding events to the commands.
Instead to create a listener for every command,
create a generic listener and delegate the event
call to your command.
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #7
Delegate binding events to the commands.
It’s just an idea, you can do it better :-)
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #8
Don’t let Grails to load entities for you.
Only you can access to database in your
business logic, not Grails!
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #8
Don’t let Grails to load entities for you.
controller/action?productType.id=25
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #8
Don’t let Grails to load entities for you.
controller/action?productType.id=25
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #8
Don’t let Grails to load entities for you.
Doing that, you have to create a constraint validator to
ensure the ownership of the entity.
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #8
Don’t let Grails to load entities for you.
I don’t like because it needs up to 4 db selects to
get the info.
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #8
Don’t let Grails to load entities for you.
Alternative way to do it using afterBinding event. With
only 1 select against db!
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #9
You can bind whatever you want!
Just call to
DataBindingUtils.bindObjectToInstance()
It will call to all of your events too!
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #9
You can bind whatever you want!
All my commands inherits from this class (kind of…)
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #10 Use commands as input in your
services
Ensure they don’t
have errors!
MADRID · NOV 21-22 · 2014
THE END?You wanna more tricks?
2 MORE TRICKS!
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #11 Dependency injection starts
AFTER all the events (even the
beforeBinding)
So, if you need services or any other artifact
injected in your commands, just use:
Holders.applicationContext.autowireCapableBeanFactory.
autowireBeanProperties(command,
AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false)
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #12 Create your own annotations!
Just create a listener and read the command
annotation in the beforeBinding or afterBinding
event.
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #12 Create your own annotations!
Annotation example. It just take a Closure as
the only argument.
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #12 Create your own annotations!
How to read the annotation and call the
command from a binding listener:
MADRID · NOV 21-22 · 2014
#3 How Commands works
TRICK #12 Create your own annotations!
Using the annotation from a command. Real
example!
MADRID · NOV 21-22 · 2014
No more tricks, no more rules!
New Grails 2.3 Data Binding is very powerful!
Use at your own risk and read documentation!
Divide input data in minimal commands.
Combine with previous patterns.
Create your own rules and respect it.
MADRID · NOV 21-22 · 2014
Questions? Thank you!
@albertovilches
http://albertovilches.com
@greachconf
http://greachconf.com
10-11 April
2015