Grails Anti-Pattern: Everything is a Service
The context
Grails makes it very easy to put any logic of your application in a service. Just grails create-service
and you’re good to go. There’s a single instance by default, injectable anywhere. Powerful stuff and makes it easy to get up ‘n running very fast!
Creating a new application, following so-called “best practices” from blogs like these and the ‘idiomatic Grails-way’ described in the docs and in tutorials work in the beginning, but there’s always a tipping point — where the application has grown a reasonable size — where one should start following a different, maybe less-Grailsey, strategy.
So what can go wrong by creating services in your application?
In a previous anti-pattern post about dynamic finders I tried to explain what could happen from Day 1 of your project onwards.
A team really took this advice to heart and started centralising their Album queries in a AlbumService
, their Product queries in a ProductService
and so on.
Here’s what I saw happening.
Sprint 1: Life is beautiful
This team started out really sharp: they almost were implementing business-like logic in controllers, but could pull those into services just in time. The grails create-service
command would even immediately create an empty unit test — ready to implement.
The productivity was unparalleled. The team never had to manually create a class anymore with their IDEs and for the next sprints the team burned through the backlog like a hot knife through the butter.
Fast-forward 6 sprints.
Sprint 6
Looking at their code, it seems their services
folder consists of a dozens of classes:
grails-app/services/ └── example ├── AnotherProductService.groovy ├── ... ├── OrderService.groovy ├── OrderingService.groovy ├── ... ├── Product2Service.groovy ├── ProductAccountingService.groovy ├── ProductBuilderService.groovy ├── ProductCatalogService.groovy ├── ProductCreateService.groovy ├── ProductFinderService.groovy ├── ProductLineFileConverterDoodleService.groovy ├── ProductLineMakerService.groovy ├── ProductLineReaderService.groovy ├── ProductLineService.groovy ├── ProductLineTaglibHelperService.groovy ├── ProductLineUtilService.groovy ├── ProductManagementService.groovy ├── ProductManagerService.groovy ├── ProductMapperService.groovy ├── ProductOrderService.groovy ├── ProductReadService.groovy ├── ProductSaverService.groovy ├── ProductService.groovy ├── ProductTemplateOrderBuilderService.groovy ├── ProductUtilService.groovy ├── ProductWriterService.groovy ├── ProductsReadService.groovy ├── ProductsService.groovy └── ... 1 directory, 532 files
The pattern
This happened to me a gazillion times before. Me and the team value the simplicity and power of Grails. Hence, it’s pretty easy to start using the Grails commands to the fullest, such as all the create-*
commands:
grails> create- create-command create-controller create-domain-class create-functional-test create-integration-test create-interceptor create-scaffold-controller create-script create-service create-taglib create-unit-test
In many Grails projects, similar to the fictional one �� above, the create-service
command has been over-used, because it seems to be idiomatic way of creating “business logic in the service layer”.
Yes, this command does create a nice, empty unit test, and is automatically a handy Spring bean injectable in controllers, tag libraries and other Grails artefacts.
Yes, using a *Service
works well in blog posts, demo’s and tutorials.
However, it seems that we have forgotten basically everything is a “service” to someone else, but that we do not necessarily need to postfix (“Service”) every class as such.
Seems that people usually understand when something needs to be a controller (“let’s do create-controller
“) or a tag library (“let’s do create-taglib
“) and so forth, and for everything else: boom!, “let’s do create-service
“.
In any other, non-Grails project we’re used to calling a builder simply “PersonBuilder”, in Grails projects it’s suddenly “PersonBuilderService”. In any other project a factory is a “PersonFactory”, in a Grails project it’s a weird “PersonFactoryService”.
What if a “PersonReadService” is responsible for getting or finding persons? For years people having been using the Repository pattern for this and this can be reflected with a “Repository” postfix, e.g. “PersonRepository”.
Even in Grails a builder can be a Builder, a factory a Factory, a mapper a Mapper, a repository a Repository, a doodle a Doodle and whatever can end in Whatever — you can name every class the way you want.
What we can we do about it?
Stop calling everything a Service
First, next time you’re about to create a class following one of the Famous Design Patterns, such as Builder, Factory, Strategy, Template, Adapter, Decorator (see sourcemaking.com for a nice overview), or other “well-known” Java (EE) patterns, such as Producer or Mapper or something, ask yourself a question:
Can it be a regular class in src/main/groovy
?
Move and choose a better name
- Yes, then just create the class in
src/main/groovy
. Maybe choose a nice package, such asexample
. If you don’t want 532 classes in one package, you can always introduce sub-packages such asexample.accounting
. Give it a name which does not end in*Service
. Don’t forget to manually add an associated*Spec
insrc\test\groovy
.
Do you still want to have the benefit of Spring and Dependency Injection?
In other words, do you need an instance of your class to be able to be injected into any Grails classes, such as a controller, as you are used to with a service, like the ProductReadService
below?
// grails-app/controllers/example/HomepageController.groovy class HomepageController { ProductReadService productReadService def index() { ... } } // grails-app/services/example/ProductReadService.groovy class ProductReadService { SecurityService securityService Product findByName(String name) { assert securityService.isLoggedIn() Product.findByName(name) } }
The underlying container is created by the Spring Framework.
- There’s a great chapter in the docs about Grails and Spring. It’s this framework that will instantiate for example one
SecurityService
in the application, inject it in the “securityService” property when it creates one instance ofProductReadService
which it injects in theHomepageController
and so forth. - The
SecurityService
in the example — which might come from a Security plugin and the*Service
classes in your own application sources – they’re all automatically picked up and managed by the Spring container and injected in every other managed class that needs it. - It’s not so much the move of
grails-app/services/example
to thesrc/main/groovy/example
folder, but by renaming a class to something which doesn’t end in “Service” anymore, that’s when you lose the automatic management by Spring. This happens when we, as suggested, after the move, rename the classProductReadService
to aProductRepository
class.
Yes, it want them to be a Spring bean!
Declaring Spring beans the Grails way
Sure, we can do this ourselves. The Grails idomatic way is to specify beans in resources.groovy
.
// grails-app/conf/spring/resources.groovy import example.* beans = { productRepository(ProductRepository) { securityService = ref('securityService') } }
We’ve defined a a bean named “productRepository” of class ProductRepository
and we’ve indicated the SecurityService
needs to be injected.
This is how the original code has changed, but the behaviour has not: it’s now using ProductRepository
instead.
// grails-app/controllers/example/HomepageController.groovy class HomepageController { ProductRepository productRepository def index() { ... } } // src/main/groovy/example/ProductRepository.groovy class ProductRepository { SecurityService securityService Product findByName(String name) { assert securityService.isLoggedIn() Person.findByName(name) } }
This is not the only way to declare Spring beans.
Declaring Spring beans the Spring way
We declared Spring beans the Grails way, but we can also declare beans the Spring way.
Ok, there’s not just “a Spring way”, there are many ways, from the old XML declarations, classpath scanning to Java-style configuration.
Having (a subset of) your 532 classes in resources.groovy
might be considered not all that better than the XML configuration Spring used in the early days.
Even through the Beans DSL is a lot more powerful here than XML ever was (because: Groovy), we’re not transitioning our automatically picked up service beans to get manual labour back, in my opinion.
This is how it would look:
beans = { anotherProductRepository(AnotherProductRepository) { securityService = ref('securityService') orderingService = ref('orderingService') } productLineReader(ProductLineReader) productFinder(ProductFinder) { productRepository = ref('productRepository') productLineService = ref('productLineService') } productRepository(ProductRepository) { securityService = ref('securityService') productReader = ref('productReader') productWriter = ref('productWriter') } orderingService(OrderingService) { securityService = ref('securityService') productRepository = ref('productRepository') } ...
There are use cases where resources.groovy
is perfectly fine, but why not get rid of the boiler-plate and leverage the modern features of Spring at our disposal?
Try component scanning instead.
- Just once, set Spring’s
@ComponentScan
annotation ourApplication.groovy
class
// grails-app/init/example/Application.groovy package example import grails.boot.GrailsApp import grails.boot.config.GrailsAutoConfiguration import org.springframework.context.annotation.ComponentScan @ComponentScan class Application extends GrailsAutoConfiguration { static void main(String[] args) { GrailsApp.run(Application, args) } }
This makes Spring, at application startup, scan all components on the classpath under the package “example” and register them as Spring beans. Or specify @ComponentScan("example")
to be more explicit.
What are these “components” you say? All classes annotated with Spring’s stereotype annotation @Component
. Or @Service
or @Repository
which are just specializations.
- Annotate our classes to make them candidate for auto-detection.
import org.springframework.stereotype.Component @Component // or @Repository in this particular case class ProductRepository { SecurityService securityService Product findByName(String name) { .. } }
- At the moment, when we would restart our app, we’ll get at
NullPointerException
when we try to invoke anything onsecurityService
.Spring no longer recognizes it should do something with the property — it’s just a mere property now. To make theSecurityService
be injected by Spring we need to annotate the property with Spring’s@Autowired
, but that’s basically the same as the setter-injection we already had in the beginning. And@Autowired
is boiler-plate we don’t need.
While we’re at it, I recommend to use constructor-injection, which means we create (or let the IDE create) a constructor.
* We make the dependencies of ProductRepository
explicit.
* Spring will automatically “autowire” our constructor as long as we have exactly one, and inject all parameters of the constructor
import org.springframework.stereotype.Component @Component class ProductRepository { final SecurityService securityService ProductRepository(SecurityService securityService) { this.securityService = securityService }
This is it.
BTW having an explicit constructor with all the mandatory dependencies, is always a good practice — whether it’s a Spring bean or not.
- Finally, revert
resources.groovy
to its initial, empty state – we’re not using it anymore.
Naming is important
Now, if we would have done this to the original, 532 classes we might end up with a more enjoyable tree of files. E.g.
grails-app/services/ └── example ├── OrderService.groovy ├── ProductService.groovy └── SecurityService.groovy src/main/groovy/ └── example ├── order │ ├── OrderBuilder.groovy │ └── OrderRepository.groovy └── product ├── ProductBuilder.groovy ├── ProductFinder.groovy ├── ProductLineReader.groovy ├── ProductLineTaglibHelper.groovy ├── ProductMapper.groovy ├── ProductRepository.groovy ├── ProductUtils.groovy └── ProductWriter.groovy
Some actual *Service
classes cal still reside in grails-app/services
and the rest can become clearly named classes, neatly placed in src/main/groovy
, while you still enjoy the benefit of using them as Spring beans.
If you and the team early on in the process decide on proper naming conventions (packages, class prefixes and such), you don’t have to reorder everything like we did just now. Together with the team, create and name your classes in an organized place.
Reference: | Grails Anti-Pattern: Everything is a Service from our JCG partner Ted Vinke at the Ted Vinke’s Blog blog. |