Grails... microservices...
you must be crazy man!
20 years Java
10+ years Spring
6+ years Groovy/Grails
PowerBuilder
C/C++
FORTRAN
1st career in aviation/aerospace
twitter: @jackfrosch linkedin: ../in/jackfrosch
email: jackfrosch@gmail.com grails.slack.com: @jackfrosch
{ "about-me" :
{ "experience" : [ "20 years Java",
"6+ years Groovy/Grails",
"PowerBuilder, C/C++, FORTRAN"
"Aviation/Aerospace before Software Development"],
"community" : [ "Gateway JUG founder and leader",
"Past DFW GGUG Co-leader",
"Always cookin' up something ..."],
"contacts" : [ {"twitter" : "@jackfrosch"},
{"linkedin" : "../in/jackfrosch"},
{"email" : "jackfrosch@gmail.com"},
{"grails.slack.com":"@jackfrosch"}]
}
}
Microservices are small, autonomous services that work together.
Sam Newman Building Microservices, O'Reilly Media
http://www.whattofix.com/images/ComplexERDExample.gif
Probably not small functional scope...
Everything should be made as simple as possible, but not simpler*
* though attributed to Einstein, this simple quote is actually from
Roger Sessions paraphrasing (and simplifying!) a statement by Albert Einstein
A system that is hard to understand is hard to change.
— Eric Evans, Domain-Driven Design
http://www.memes.com/meme/498049
http://bit.ly/thoughtworks-consumer-driven-contracts
http://famouswonders.com/wp-content/gallery/pyramids-of-egypt/pyramid-of-khafre.jpg
http://martinfowler.com/articles/microservices.html
http://www.openmakesoftware.com/images/ReleaseEngineer/CI-CD.png
https://media.licdn.com/mpr/mpr/p/8/005/083/1a8/257d716.jpg
http://kennysilva.net/wp-content/uploads/2010/12/orchestra-conductor.jpg
class Passenger {
String accountNo
String firstName
String lastName
Address billingAddress
Payment paymentPreference
List<Payment> paymentHistory
Phone home
Phone mobile
Phone work
BloodType bloodType
...
}
// For Trip Management
class Passenger {
String accountNo
String firstName
String lastName
Phone mobile
...
}
// For Billing
class Passenger {
String accountNo
String firstName
String lastName
Address billingAddress
List<Payment> paymentHistory
Phone home
Phone work
...
}
The evils of too much coupling between services are far worse than the problems caused by code duplication.
- Sam Newman, Building Microservices
"ELK Stack"
"They're inside the room!"
"Yikes!"
"Mmm, you look tasty."
Perimeter security reminds me of the movie, Aliens
Spring Boot & Spring Cloud to the rescue!
There are many metrics out of the box, but you can create your own.
http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html
http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html
http://bit.ly/vignette2_wikia_nocookie_net_ghostbusters
http://martinfowler.com/bliki/CircuitBreaker.html
http://martinfowler.com/bliki/images/microservicePrerequisites/sketch.png
Full stack != monolith
Web UI, SQL / NOSQL Database Support, Spring, Hibernate, Security, REST, Java, Groovy...
$grails create-app HelloWorld
grails> create-controller demo.Hello
package demo
class HelloController {
def index() {
render 'Hello SpringOne2GX 2015!'
}
}
Full stack CRUD apps are about as easy...
1. Create controller
2. Make it do something
3. See it to believe it!
package demo
class Person {
String firstName
String lastName
String email
String twitterHandle
static constraints = {
firstName blank:false, maxSize: 32
lastName blank: false, maxSize: 64
email blank: false, maxSize: 128, email:true
twitterHandle nullable:true, maxSize:64
}
}
grails> run-app
package demo
import grails.rest.RestfulController
class PersonController extends RestfulController<Person> {
static responseFormats =['json', 'xml']
PersonController() {
super(Person)
}
def findPersonsWithLastNameLike(String likeness) {
respond Person.findByLastNameLike("${likeness}%")
}
}
class UrlMappings {
static mappings = {
"/persons"(resources:'person')
"/persons/search/withLastNameLike/$likeness"(controller: 'person',
action: 'findPersonsWithLastNameLike')
}
}
$ curl -i -X GET http://localhost:8080/persons.xml
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Application-Context: application:development
Content-Type: text/xml;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 07 Sep 2015 21:26:16 GMT
<?xml version="1.0" encoding="UTF-8"?><list />
$
200 OK good ... XML weird, but you wanted weird
$ curl -i -X GET http://localhost:8080/persons
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Application-Context: application:development
Content-Type: text/xml;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 07 Sep 2015 21:26:16 GMT
[]
$
200 OK good ... JSON good.
package demo
import grails.rest.Resource
@Resource(uri='/persons', formats=['json', 'xml'])
class Person {
String firstName
String lastName
String email
String twitterHandle
static constraints = {
firstName blank:false, maxSize: 32
lastName blank: false, maxSize: 64
email blank: false, maxSize: 128, email:true
twitterHandle nullable:true, maxSize:64
}
}
$ curl -i -X GET --header "Accept:application/json" http://localhost:8080/persons
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Application-Context: application:development
Content-Type: text/xml;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 07 Sep 2015 21:26:16 GMT
[]
$
200 OK good ... JSON good.
$ curl -i -X GET http://localhost:8080/persons.json
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Application-Context: application:development
Content-Type: text/xml;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 07 Sep 2015 21:26:16 GMT
[]
$
200 OK good ... JSON good.
package demo
import grails.rest.Resource
@Resource(uri='/persons')
class Person {
String firstName
String lastName
String email
String twitterHandle
static constraints = {
firstName blank:false, maxSize: 32
lastName blank: false, maxSize: 64
email blank: false, maxSize: 128, email:true
twitterHandle nullable:true, maxSize:64
}
}
grails create-app RestfulCrud
$ curl -i -X GET http://localhost:8080/persons
[jfrosch@localhost demo]$ HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Application-Context: application:development
Content-Type: text/xml;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 07 Sep 2015 21:26:16 GMT
<?xml version="1.0" encoding="UTF-8"?><list />
$
Hmm... 200 OK good ... XML bad.
/catalog acts as the root of the uri
This is the default after error in recommendation engine
... After killing recommendation engine ...
You'd be crazy to adopt a microservice architecture using Grails...
unless your application needs to be ...
(even if your company isn't ready for the cloud yet)