application architectures in grails

67

Click here to load reader

Upload: peter-ledbrook

Post on 10-May-2015

5.643 views

Category:

Technology


2 download

DESCRIPTION

Talk given at Spring One 2GX 2013. Tries to get Grails developers to start thinking about the structure of their applications.

TRANSCRIPT

Page 1: Application Architectures in Grails

Application architectures in GrailsPeter Ledbrook

e: [email protected]: @pledbrook

Wednesday, 11 September 13

Page 2: Application Architectures in Grails

Book Author

Wednesday, 11 September 13

We start with our domain classes using the usual hasMany, belongsTo etc.

Page 3: Application Architectures in Grails

Book AuthorDomain

Scaffolded BookController

Scaffolded AuthorController

Wednesday, 11 September 13

Create instant web UI with scaffolded controllersCan be retained for administrative UI if secured by Spring Security, Shiro, etc.

Page 4: Application Architectures in Grails

Book AuthorDomain

Scaffolded BookController

Scaffolded AuthorController

LibraryService

LibraryController Views

Wednesday, 11 September 13

Build out proper UI using controller actions and views, utilising business logic in the servicesControllers stick to HTTP management

Page 5: Application Architectures in Grails

Thank you

Wednesday, 11 September 13

Some time left for questions...

Page 6: Application Architectures in Grails

Only joking

Wednesday, 11 September 13

Page 7: Application Architectures in Grails

Is it always the best architecture?

Wednesday, 11 September 13

How many people are using it?

Page 8: Application Architectures in Grails

Book Author

Why do we start here?

Wednesday, 11 September 13

Page 9: Application Architectures in Grails

“The database is just a detail that you don’t need to figure out right away”

NO DB - May 2012Robert “Uncle Bob” Martin

Wednesday, 11 September 13

Page 10: Application Architectures in Grails

Domain-driven Design

Wednesday, 11 September 13

Not the same as domain classes firstModel your domain first without integration concernsIt’s in operation at all stages of development, not just up-frontReminded of a problem domain related to managing meetings and attendees - focused so hard on the DB tables that the program logic was a dog’s breakfast.

Page 11: Application Architectures in Grails

Think Physics

Friction

Gravity

Wednesday, 11 September 13

Page 12: Application Architectures in Grails

from Wikmedia CommonsWednesday, 11 September 13

We can use the model to calculate useful information, such as how long it takes for a ball to roll down a hillThe model only includes significant complexity - ignores the restFormula 1 makes use of CFD because they need it at the bleeding edge

Page 13: Application Architectures in Grails

Remember: you’re trying to solve a business problem

Wednesday, 11 September 13

You need to understand the problem domainThe model needs to reflect that understandingGradle is a great example of a rich, evolving, and useful domain model

Page 14: Application Architectures in Grails

The Life Preserver

Domain

RESTPersistenceMes

sagi

ng

EventsCourtesy of Simplicity Itself

Wednesday, 11 September 13

Note how persistence is treated as an integration pointOpens up novel approachesCould use mybatis + Flyway instead of GORM for example

Page 15: Application Architectures in Grails

An example - reporting

ReportController ReportService

Jasper

Wednesday, 11 September 13

High volume transactional web site, optimised for writeEverything was OK at this point

Page 16: Application Architectures in Grails

An example - reporting

ReportController ReportService

Jasper + HTML reports with paging

Breakage!

Wednesday, 11 September 13

The logic for building reports was complexWho is responsible for the paging? The HTML generation?Where is the state kept? The service? A domain class?

Page 17: Application Architectures in Grails

An example - reporting

PublisherReportHTTP

Request

SummaryTable 1Table 2...Table N

It’s a command object!

Wednesday, 11 September 13

Let’s try againThe logic for building the report and pagination is in the PublisherReport class

Page 18: Application Architectures in Grails

An example - reporting

class ReportController { def print(PublisherReport report) { JasperRenderer.render report }

def json(PublisherReport report) { render report as JSON }

...}

Wednesday, 11 September 13

The controller is now very thinThe report can support parameters for sub-reports etc.The domain model is embodied in the command object

Page 19: Application Architectures in Grails

CQRS

Wednesday, 11 September 13

Page 20: Application Architectures in Grails

CQRS

ommandueryesponsibilityegregation

Wednesday, 11 September 13

The writes use a different model from the readsWill be coming back to this later

Page 21: Application Architectures in Grails

What is my domain?

Domain Model

HTTP Database

? ?

Wednesday, 11 September 13

Always ask yourself this question throughout life of projectAnd is it closer to the user’s perspective or the persistence model? Or neither?Former argues for a model based on command objects, the latter based on domain classes.

Page 22: Application Architectures in Grails

Post content

Wednesday, 11 September 13

The command model is very simple: author + post content + date

Page 23: Application Architectures in Grails

Wednesday, 11 September 13

Query model much more complexMultiple timelinesConversation threadsRetweets

Page 24: Application Architectures in Grails

Wednesday, 11 September 13

So working from your domain first is a good thingAnd remember that different contexts have potentially different views of the model, i.e. the user/client, persistence, other system componentsDDD doesn’t preclude the CRUD/service-based architectureSo what are the driving forces behind architecture beyond the model?

Page 25: Application Architectures in Grails

Rich clients

Wednesday, 11 September 13

We’re not talking Warren Buffet hereThings like GMail

Page 26: Application Architectures in Grails

Once upon a time...

Wednesday, 11 September 13

Page 27: Application Architectures in Grails

Flash

Wednesday, 11 September 13

Pretty (but often useless - or just pretty useless)

Page 28: Application Architectures in Grails

Java

Wednesday, 11 September 13

Remember applets?Liked the approach (particularly WebStart) but not often used. The browser was a delivery mechanism, not a platform

Page 29: Application Architectures in Grails

It’s all about the Javascript!

AngularJSKnockout.js

Backbone.js

Underscore.jsjQuery.js

Moustache

Wednesday, 11 September 13

The browser is now a platform for rich applicationsBut how do these impact the Grails app?The whole process of building a page on each request goes out the window

Page 30: Application Architectures in Grails

Google I/O 2012

Android activations to date

400 million

Apple WWDC 2012

iOS devices sold to date

365 million

Wednesday, 11 September 13

Let’s not forget Firefox OSLots of people potentially hitting a site at any one time!Typical Grails architecture may struggle to handle the load (OpenSessionInViewInterceptor, transactions, GSPs, thread-per-request)

Page 31: Application Architectures in Grails

An aside

If the whole Java client thing had worked out, would you use it for every web application you wrote?

Would you use it for Wikipedia?

Wednesday, 11 September 13

Before jumping onto the whole “single-page app” bandwagon, work out whether it’s appropriate for your app

Page 32: Application Architectures in Grails

Shared templates

HandlebarsViewResolver

or

<hbt:render template="..."/>

GSP

Wednesday, 11 September 13

Not much to talk about on client architecture, but template reuse is something to think aboutView resolver only makes sense if client-side templates are complete viewshbt is a fictitious tag namespace representing a plugin based on Handlebars for Java

Page 33: Application Architectures in Grails

AJAX + JSON endpoints

enabler for async

Wednesday, 11 September 13

Rich UIs don’t talk HTML - use JSON endpoints (aka “REST”)Asset delivery via Resources or asset-pipeline pluginsMore scope for asynchronicity, since no wait for full page updateGrails 2.3 introduces some nice features for REST

Page 34: Application Architectures in Grails

What’s the need for SiteMesh & GSP then?

Wednesday, 11 September 13

Difficult to impossible to remove these currentlyGrails 3 will finally extricate them, allowing you to remove them from your project

Page 35: Application Architectures in Grails

Aside 2

Don’t be afraid to use Ruby/Node.js tooling

Grunt

Bower

Yeoman

Compass/SASS

Wednesday, 11 September 13

If you go for a heavy Javascript UI, consider Ruby/Node.js toolingGenerally richer than Java-based tooling

Page 36: Application Architectures in Grails

Async

for scalability

Wednesday, 11 September 13

To solve the problem of dealing with large number of concurrent requestsWithout adding lots more servers

Page 37: Application Architectures in Grails

Grails Promise API

import static grails.async.Promises.*

class ReportController { def print(PublisherReport report) { task { // Expensive report creation here } } ...}

Wednesday, 11 September 13

We can now return Promise instances from actionsThe expensive task no longer blocks the request thread, but...

Page 38: Application Architectures in Grails

Controller

Request Thread Pool

Worker Thread Pool

HTTP Request

OffloadTask

Return thread

Wednesday, 11 September 13

The request threads are now free, but burden is on worker thread poolIf all worker tasks are synchronous, have we gained scalability?In cases where just a few URLs are blocking for long(ish) periods of time, yes (kind of)But otherwise, now bottleneck is on worker thread pool

Page 39: Application Architectures in Grails

Make efficient use of server resources

Wednesday, 11 September 13

Async all the way through - Grails Promises, GPars, messagingRemember that some things are inherently synchronous (think Fibonacci)

Page 40: Application Architectures in Grails

Grails app

ReportController

TagService PostService

Remote access

Wednesday, 11 September 13

NetFlix style model: coarse-grained, self-contained services/apps accessed from other appsUsually via REST

Page 41: Application Architectures in Grails

Async controllersimport static grails.async.Promises.*

class ReportController { def tagService def postService

def home() { tasks tags: tagService.tagsWithCount() trends: tagService.trendingTags() timeline: postService.timeline( params.userId) } ...}

Wednesday, 11 September 13

tagService and postService are both asyncThe model values are evaluated in parallelThis is a PromiseMap - view rendered only when all map values evaluated

Page 42: Application Architectures in Grails

Async controllersimport static grails.async.Promises.*

class TagService { def remoteTagService

def tagsWithCount() { task { remoteTagService.tagsWithCount() } } ...}

Wednesday, 11 September 13

You can also use @DelegateAsync to create async version of synchronous serviceCurrently not Grails’ sweet spot due to the solution’s lightweight nature......perhaps makes sense with Grails 3?

Page 43: Application Architectures in Grails

Rich domain model + Promises API/GPars?

Wednesday, 11 September 13

Fully async backendA good domain model makes it easy to identify parallelisable workNo simple solutions though! Concurrency is still a tricky problem.

Page 44: Application Architectures in Grails

GPars supports

• Dataflow

• Communicating Sequential Processes (CSP)

• Actor model

Wednesday, 11 September 13

Page 45: Application Architectures in Grails

Messaging

Wednesday, 11 September 13

A common solution to concurrency and scale

Page 46: Application Architectures in Grails

MyObject TheirObjectcall

Wednesday, 11 September 13

Page 47: Application Architectures in Grails

MyObject TheirObject

Router

Router

message

response response

message

Headers

Body

Wednesday, 11 September 13

Decoupling via messagesEncourages separation of concerns & responsibilities

Page 48: Application Architectures in Grails

MyObject OtherObject

Router

Router

messagemessage

responseresponse

Cloud

Wednesday, 11 September 13

Easy to change and move objectsScales well (think Actor model of concurrency)

Page 49: Application Architectures in Grails

Internal External

JMS

RabbitMQ

Events

Spring Integration

Apache Camel

Wednesday, 11 September 13

Internal and external can be integratedEvents is a special case of messaging (which I look at next)

Page 50: Application Architectures in Grails

Spring IntegrationMyController

MyService

message

DB Persister

SplitterJMS Twitter

A channel (pipe)

Message endpoint

Wednesday, 11 September 13

Based on Enterprise Integration Patterns (filters & pipes)Many options for routing and transforming messagesLogging adapters and wire tapping for debug

Page 51: Application Architectures in Grails

Spring Integration Groovy DSL

def builder = new IntegrationBuilder()

def ic = builder.doWithSpringIntegration { messageFlow("flow") { filter { it == "World" } transform(inputChannel: "transformerChannel") { "Hello " + it } handle { println "**** $it ****" } }}

ic.send "flow.inputChannel", "World"ic.send "transformerChannel", "Earth"

Wednesday, 11 September 13

Page 52: Application Architectures in Grails

Debugging

Code comprehension

Performance (kind of)

Wednesday, 11 September 13

Page 53: Application Architectures in Grails

Events

Wednesday, 11 September 13

Special case of messaging

Page 54: Application Architectures in Grails

Event bus - ApplicationContext

ApplicationContext

PluginService

publish

PluginUpdateService YourListener

GORM

Wednesday, 11 September 13

Page 55: Application Architectures in Grails

Event bus - ApplicationContextclass PluginService { def publish(PluginDetails info) { ... publishEvent(new PluginUpdateEvent(...)) }}

class PluginUpdateService implements ApplicationListener<PluginUpdateEvent> {

def onApplicationEvent(PluginUpdateEvent e) { ... }}

Wednesday, 11 September 13

with spring-events plugin

Page 56: Application Architectures in Grails

Immutable “mesages”

@groovy.transform.Immutableclass PluginUpdateEvent { String name String version String group ...}

Wednesday, 11 September 13

Event listeners on separate threads (from thread pool)

Page 57: Application Architectures in Grails

Event bus - (grails-)events

Event bus (Reactor)

PluginService

publish

PluginUpdateService YourListener

Wednesday, 11 September 13

Page 58: Application Architectures in Grails

Event bus - (grails-)events

Event bus (Reactor)

Browser

RabbitMQ (pending)

events-push plugin

Wednesday, 11 September 13

Page 59: Application Architectures in Grails

Event bus - (grails-)eventsclass PluginService { def publish(PluginDetails info) { ... event "pluginUpdate", info }}

class PluginUpdateService { @Selector def pluginUpdate(PluginDetails info) { ... }}

Wednesday, 11 September 13

with spring-events plugin

Page 60: Application Architectures in Grails

AppEvents.groovy

includes = ["push"]

doWithReactor = { reactor("grailsReactor") { ext "browser", ["pluginUpdate"] }}

Wednesday, 11 September 13

In grails-app/confCan control which events are propagated to the browserThe “push” include sets up a

Page 61: Application Architectures in Grails

Include grailsEvents.js

window.grailsEvents = new grails.Events(baseUrl)

grailsEvents.on("pluginUpdate", function(data) { // do something});

Wednesday, 11 September 13

Page 62: Application Architectures in Grails

A CQRS architecture

Updates

Views

Concurrency via event bus

Store changes

Separate data stores for queries

Wednesday, 11 September 13

Why? Updates and querying often have different data requirements.For example, Lanyrd use Redis structured data supportAll read databases can be rebuilt from master events DBCQRS designed for scale

Page 63: Application Architectures in Grails

Plugin ArchitecturesApp

Feature plugin 1

Feature plugin 2

Feature plugin 3

Events/SI/Message broker

Wednesday, 11 September 13

So why use messages to interact between the plugins?

Page 64: Application Architectures in Grails

Plugin ArchitecturesApp

Feature plugin 1

Feature plugin 2

Feature plugin 3

Events/SI/Message broker

App 2

Wednesday, 11 September 13

Easy to separate out into apps deployed independently

Page 65: Application Architectures in Grails

Ultimately, think about what you need...

Wednesday, 11 September 13

Page 66: Application Architectures in Grails

...don’t just go the “standard” route

automatically

Wednesday, 11 September 13

Page 67: Application Architectures in Grails

Thank you

Wednesday, 11 September 13