Groovy

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 as example. If you don’t want 532 classes in one package, you can always introduce sub-packages such as example.accounting. Give it a name which does not end in *Service. Don’t forget to manually add an associated *Spec in src\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 of ProductReadService which it injects in the HomepageController 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 the src/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 class ProductReadService to a ProductRepository 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 our Application.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 on securityService.Spring no longer recognizes it should do something with the property — it’s just a mere property now. To make the SecurityService 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.

Ted Vinke

Ted is a Java software engineer with a passion for Web development and JVM languages and works for First8, a Java Web development company in the Netherlands.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button