Grails is designed to be an interactive agile based rapid development framework which advocates convention not configuration.
This article explained the usage and best practices around the Grails.
Always use domain-driven design: First create your basic domain model classes, and then use scaffolding to get them online. This will help you stay motivated and understand your domain better.
Use Test Driven Approach: Domain model test cases provide a great way of experimenting testing out your validations.
Validate: Use validators to keep your domain objects in order. Custom validators aren’t hard to implement, so don’t be afraid to roll your own if the situation demands. It’s better to encapsulate the validation logic in your domain class than to use dodgy controller hacks
Follow the Grails Convention
Follow Grails conventions: Grails is convention driven development which need to follow as per convention means Views should just be views. Controllers should just be controllers.
Service as Transactional: Keep the transactional part in service
Functional Logics: Functional logics will be implemented as part of Services and Model objects. This means pass the request to Controller and Controller in turn will invoke the service.
Grail is based on dependency injection on convention so we need focus on folder convention to put component on appropriate grails-app/folder and proper naming convention
Location Convention: Services go into the services folder. Controllers go into the controller’s folder.
Naming Convention: If you have a Xxx model object, and you need a controller and service for it, then your controller and service should be named XxxController and XxxService. Grail will auto wire based naming convention
Use pagination: Paginating large datasets creates a much better user experience and improves overall presentation performance.
Use custom tags: Develop reusable custom tag for your UI. It will improve overall development productivity and enhance maintenance.
Use Layout smarter. Handle basic flash message display in your layout rather than repeating it for each view.
Use convention-based layout: Favor convention-based layouts over explicit Meta tags. Often a specific layout for one particular action can make things much more maintainable than doing meta-magic branching. Take advantage of Meta tag styles when you need to style a subset of pages for a controller, but use convention layouts for the rest.
Externalize config file: Always include an externalized config file, so that any configuration that needs to be overridden on production can be done without even generating a new war file
Prefer dynamic scaffolding: Always prefer dynamic scaffolding over static scaffolding.
Use Datasorce config: Use DataSource.groovy property file to configure datasorce
Re-use custom validators: All custom validators place in a shared validator’s file, to support re-usability of these constraints amongst other domains.
Avoid logic in web layer: We should avoid putting lots of logic in the web layer to make a clear separation between presentation layer and business layer.
Use BuildConfig.groovy: To install any plugin in your application, declare it in BuildConfig.groovy rather than using the install-plugin command.
Keep simple view: Make view as simple as possible and use service layer for business logics
Re use template and custom taglib: Split out shared content into templates and g:render and build custom taglib for common UI elements
Use layouts: Use layout for consistent look across the UI.
DRY: Keep your views DRY ("Don't repeat yourself"). Split the repeated content into templates.
Keep Controller thin: Don’t perform business logic, web services, DB operation or transaction within controllers. Keep the controller as thin as possible. The purpose of a controller is to accept incoming request, invoke domain or a service for a result, give the result back to the requester.
Use command object: Take advantage of command objects for form submissions. Don’t just use them for validation—they can also be handy for encapsulating tricky business logic. Understand data binding. Data-binding options in Grails are plentiful and subtle.
Use the proper naming convention: Use the standard naming convention of “<DomainClass>Controller”.
Use flash scope. Flash scope is ideal for passing messages to the user (when a redirect is involved).
Use errors object: Make use of the errors object on your domain class to display validation messages. Take advantage of resource bundles to make error messages relevant to your application use cases.
Apply filters. Apply filters when you need to selectively fire backend logic based on URLs or controller-actions combos
A service is the right candidate for complex business logic or coarse grained code. If required, the service API can easily be exposed as a RESTful/SOAP web service.
Use for Transactional: Services are transactional by default, but can be made non-transactional if none of their methods update the persistence store.
Avoid code duplication - Common operations should be extracted and reuse across the application
Statelessness: Services should be stateless. Use domain object for state full operation.
Override setters and getters: Take advantage of the ability to override setters and getters to make properties easier to work with.
Decompose complex query: Assemble named queries by chaining to prepare complex query.
Restrict Specific logic to domain:Keep the logic specific to that object. More complex business logic that deals with groups of objects belongs in services
Use domain objects to model domain logic: Moving domain logic to Services is a hangover of inconvenient persistence layers
Don't mix with domain folder: Don’t mix any other common utility classes or value objects in the domain folder; rather they can go in src/groovy.
Use sensible constructors: Use sensible constructors for instantiating domain objects, to avoid any unwanted state and to construct only valid objects.
Simple taglib: Keep a tag simple and break a tag into reusable sub-tags if required.
Should contain logic: Taglib should contain more of logic than rendering
Use multiple custom taglib: Use multiple custom taglib for better organization.
Re-usable plugins: Construct re-usable functionality and logic parts of your application as independent re-usable Grails plugins which can be tested individually and will remove complexity from your main application(s).
Public plugin repository: re-usable plugin across the multiple applications could be published in the public plugin repository.
Use fixtures plugin : To bootstrap your data during development
Override plugin for small change: If you need to make a small change to the plugin you are using, then instead of making the plugin inline for this small change, you can override these files by following the same directory structure or package..
Use onChange: Use onChange, if your plugin adds dynamic methods or properties so that those methods and properties are retained after a reload.
Use local plugin repositories: Local plugin repositories serve several purposes such as sharing plugin across the applications
Modularize large or complex applications. Modularize large or complex applications using plugin to bring Separation of Concerns pattern.
Write functional tests for your plugins. For plugins to be reliable, you should write functional tests.
Test Driven Development Approach: Grails advocates TDD approach means test first so it make ensure that your functionality covered.
Test Often: Test often so you get quicker feedback when something breaks, which makes it easier to fix. This helps speed up the development cycle.
Use test coverage: Maintain test coverage and avoid gap in test coverage as much as possible
Favor units’ tests over integration tests: As well as being faster to run/debug they enforce loose coupling better. An exception is for service testing, where integration testing is generally more useful.
Use continuous integration (CI). Use a continuous integration (CI) to automate the build and deployment across various environments.
Use grails console to test: Use grails console to test, embed a Groovy console into your web UI - it's an invaluable tool to examine insides of a running application.
Use release plugin: Use the release plugin to deploy in-house plugins to your Maven repository.
Use continuous integration (CI). This is almost mandatory for any team bigger than one to catch those bugs that appear when changes from different people are merged together.
Automate the process: Write scripts to automate any repetitive task which reduce errors and improve overall productivity.
Familiar with resource plugin: Make yourself familiar with the resources plugin for handling of static resources