1
Göran Ehrsson
Technipelago AB
Cut your Grails App to Pieces
Build Feature Plugins
2
Technipelago AB
3
Custom Business Applications
Different industries
Common requirements
• Customers
• Communication (email)
• Documents
• Tasks
• …
4
The challenge
Customer want something simple but it should
rocket fuel their business process
Customer have looked at standard software but
found show stoppers or budget constraints
Developing from scratch each time would be too
expensive or feature limited
One app with VCS branches for each customer
would end up in maintenance hell
Copy code between projects is extremly bad
5
Say no to copy & paste!
⌘-C
⌘-V
⌘-C
⌘-V
6
Grails Plugins
Plugins extend the platform.

A plugin can:
extend the data model
add services
provide static resources
add command line scripts
…
The Grails platform provides

lots of extension points
7
Create a plugin
grails create-plugin myplugin
!
cd myplugin
grails run-app
A Grails plugin is a regular Grails project with
a plugin descriptor in the root of the project.
class MypluginGrailsPlugin {
def version = ”0.1”
}
8
Installing local plugins
grails maven-install
repositories {
…
mavenLocal()
}
!
plugins {
compile ”:myplugin:0.1”
}
theapp/grails-app/conf/BuildConfig.groovy
8
9
-SNAPSHOT versions
Prior to Grails 2.3 local plugins with -SNAPSHOT
versions was not supported due to ivy limitation
Workarounds:
Increment version number before each release
Delete ivy-cache efter each release
Use a remote repository manager (Artifactory)
Grails 2.3+ uses Aether as dependency resolver and
local -SNAPSHOT versions are supported
10
Publish plugins to your own
Repository Manager
You can use a remote repository manager, like
Archiva, Artifactory or Nexus. Host it yourself or
use an external pay-per-use cloud service.
grails.project.repos.mycompany.url =

"http://repo.mycompany.com/plugins-releases/"
grails.project.repos.mycompany.username = "admin"
grails.project.repos.mycompany.password = "password"
~/.grails/settings.groovy
grails publish-plugin --repository=mycompany
11
Configure

remote repositories
repositories {
…
mavenRepo ”http://repo.mycompany.com/plugins-snapshots/”
}
!
plugins {
compile ”:myplugin:1.0-SNAPSHOT”
}
theapp/grails-app/conf/BuildConfig.groovy
12
Inline plugins
grails.project.dependency.resolution = {
repositories {
…
}
plugins {
//compile ”:myplugin:0.1”
}
}
grails.plugin.location.myplugin = ”../../plugins/myplugin”
theapp/grails-app/conf/BuildConfig.groovy
Inline plugins lets you develop plugins as if the
code were part of the application. Auto-reloading
works so you immediately see changes.
13
Plugin Design
Separation of concern
Keep services and related UI
in separate plugins
Avoid intra-plugin
dependencies
Communicate with events
The application is the director
14
Separation of Concern
Each plugin should focus on one task or domain
A plugin should be tested isolated from others
Boundaries are strong and well defined
It forces the developer to stay inside the box
15
Keep services and UI in separate
plugins
Most of the logic are located in the service layer
You may want to have different user interface
plugins for different requirements
The same service plugin can be used in both the
web-front application and in back-office without
exposing admin UI to web-front
You can use the same service plugin in different
micro service style applications
16
Avoid intra-plugin dependencies
UI-plugins are allowed to talk directly to it’s
associated service plugin, but not the opposite
Place common features in one

or few common plugins.
Other plugins are allowed

to depend on common plugins
17
Communicate with events
Spring has built-in support for both synchronous
(default) and asynchronous events
Spring Integration includes advanced event support
Apache Camel supports Event Message pattern (EIP)
Grails platform-core plugin includes great event
handling
Synchronous, Asynchronous, Event Reply
The Grails events plugin is a evolution of platform-
core events
18
Application is the director
Individual plugins should not know about other
plugins
The Application route events from one plugin to
another
The Application can access all plugins if needed
The Application is the director that coordinate
events
19
Drawbacks
Debugging events can be hard
How to deal with exceptions
Not easy to follow code paths in IDE
20
DEMO
21
Real software…
22
Real Plugins - Demo Application
23
Real Plugins - Demo Application
24
GR8CRM
crm-contact & crm-contact-lite
crm-content & crm-content-ui
crm-task & crm-task-ui
crm-campaign & crm-campaign-ui
crm-product & crm-product-ui
crm-blog & crm-blog-ui
crm-ui-bootstrap
~40 plugins in total
25
Dynamic Associations
If a domain class in a feature plugin need to
associate with a domain instance in another
plugin, use ”dynamic associations”
”crmContact@42”
The framework will lookup the domain instance
when needed
Lookup Spring bean ”crmContact”
Call crmContact.get(42)
26
Summary
Focus on domain model (not persistent entities)
Decouple business logic from user interface
Publish events asynchronously

(synchronously if you must)
Let the application be just a container for plugins
Put customer unique code and message routing
rules in the application

(or in a separate plugin unique for each app)
27
References
http://gr8crm.github.io
https://github.com/goeh
https://github.com/technipelago
(all plugins open sourced under the Apache 2.0 License)
@goeh
goran@technipelago.se
http://www.technipelago.se
https://www.linkedin.com/in/gehrsson

Cut your Grails application to pieces - build feature plugins

  • 1.
    1 Göran Ehrsson Technipelago AB Cutyour Grails App to Pieces Build Feature Plugins
  • 2.
  • 3.
    3 Custom Business Applications Differentindustries Common requirements • Customers • Communication (email) • Documents • Tasks • …
  • 4.
    4 The challenge Customer wantsomething simple but it should rocket fuel their business process Customer have looked at standard software but found show stoppers or budget constraints Developing from scratch each time would be too expensive or feature limited One app with VCS branches for each customer would end up in maintenance hell Copy code between projects is extremly bad
  • 5.
    5 Say no tocopy & paste! ⌘-C ⌘-V ⌘-C ⌘-V
  • 6.
    6 Grails Plugins Plugins extendthe platform.
 A plugin can: extend the data model add services provide static resources add command line scripts … The Grails platform provides
 lots of extension points
  • 7.
    7 Create a plugin grailscreate-plugin myplugin ! cd myplugin grails run-app A Grails plugin is a regular Grails project with a plugin descriptor in the root of the project. class MypluginGrailsPlugin { def version = ”0.1” }
  • 8.
    8 Installing local plugins grailsmaven-install repositories { … mavenLocal() } ! plugins { compile ”:myplugin:0.1” } theapp/grails-app/conf/BuildConfig.groovy 8
  • 9.
    9 -SNAPSHOT versions Prior toGrails 2.3 local plugins with -SNAPSHOT versions was not supported due to ivy limitation Workarounds: Increment version number before each release Delete ivy-cache efter each release Use a remote repository manager (Artifactory) Grails 2.3+ uses Aether as dependency resolver and local -SNAPSHOT versions are supported
  • 10.
    10 Publish plugins toyour own Repository Manager You can use a remote repository manager, like Archiva, Artifactory or Nexus. Host it yourself or use an external pay-per-use cloud service. grails.project.repos.mycompany.url =
 "http://repo.mycompany.com/plugins-releases/" grails.project.repos.mycompany.username = "admin" grails.project.repos.mycompany.password = "password" ~/.grails/settings.groovy grails publish-plugin --repository=mycompany
  • 11.
    11 Configure
 remote repositories repositories { … mavenRepo”http://repo.mycompany.com/plugins-snapshots/” } ! plugins { compile ”:myplugin:1.0-SNAPSHOT” } theapp/grails-app/conf/BuildConfig.groovy
  • 12.
    12 Inline plugins grails.project.dependency.resolution ={ repositories { … } plugins { //compile ”:myplugin:0.1” } } grails.plugin.location.myplugin = ”../../plugins/myplugin” theapp/grails-app/conf/BuildConfig.groovy Inline plugins lets you develop plugins as if the code were part of the application. Auto-reloading works so you immediately see changes.
  • 13.
    13 Plugin Design Separation ofconcern Keep services and related UI in separate plugins Avoid intra-plugin dependencies Communicate with events The application is the director
  • 14.
    14 Separation of Concern Eachplugin should focus on one task or domain A plugin should be tested isolated from others Boundaries are strong and well defined It forces the developer to stay inside the box
  • 15.
    15 Keep services andUI in separate plugins Most of the logic are located in the service layer You may want to have different user interface plugins for different requirements The same service plugin can be used in both the web-front application and in back-office without exposing admin UI to web-front You can use the same service plugin in different micro service style applications
  • 16.
    16 Avoid intra-plugin dependencies UI-pluginsare allowed to talk directly to it’s associated service plugin, but not the opposite Place common features in one
 or few common plugins. Other plugins are allowed
 to depend on common plugins
  • 17.
    17 Communicate with events Springhas built-in support for both synchronous (default) and asynchronous events Spring Integration includes advanced event support Apache Camel supports Event Message pattern (EIP) Grails platform-core plugin includes great event handling Synchronous, Asynchronous, Event Reply The Grails events plugin is a evolution of platform- core events
  • 18.
    18 Application is thedirector Individual plugins should not know about other plugins The Application route events from one plugin to another The Application can access all plugins if needed The Application is the director that coordinate events
  • 19.
    19 Drawbacks Debugging events canbe hard How to deal with exceptions Not easy to follow code paths in IDE
  • 20.
  • 21.
  • 22.
    22 Real Plugins -Demo Application
  • 23.
    23 Real Plugins -Demo Application
  • 24.
    24 GR8CRM crm-contact & crm-contact-lite crm-content& crm-content-ui crm-task & crm-task-ui crm-campaign & crm-campaign-ui crm-product & crm-product-ui crm-blog & crm-blog-ui crm-ui-bootstrap ~40 plugins in total
  • 25.
    25 Dynamic Associations If adomain class in a feature plugin need to associate with a domain instance in another plugin, use ”dynamic associations” ”crmContact@42” The framework will lookup the domain instance when needed Lookup Spring bean ”crmContact” Call crmContact.get(42)
  • 26.
    26 Summary Focus on domainmodel (not persistent entities) Decouple business logic from user interface Publish events asynchronously
 (synchronously if you must) Let the application be just a container for plugins Put customer unique code and message routing rules in the application
 (or in a separate plugin unique for each app)
  • 27.
    27 References http://gr8crm.github.io https://github.com/goeh https://github.com/technipelago (all plugins opensourced under the Apache 2.0 License) @goeh [email protected] http://www.technipelago.se https://www.linkedin.com/in/gehrsson