2014 iforum - grails in startup
TRANSCRIPT
Grails - как эффективно использовать Java в стартапе?
Богдан Данилюк
iForum | апрель 2014 | @bogdand
Кто я?
● C Grails начиная с 2008 года
● Преподаватель курса Groovy / Grails в проекте
GeekHub
● В TransferWise со стадии MVP
О проекте
TransferWise
TransferWise
Проблема
Потребности бизнеса разные на разных этапах
Этапы развития проекта
Proof of concept
Proof of concept
Этапы развития проекта
MVP
Этапы развития проекта
Эксперементирование и наращивание функциональности
Этапы развития проекта
От скорости к качеству
Этапы развития проекта
Отказоустойчивость и масштабируемость
Grails
Что такое Grails?Groovy / Java web framework который:
● Rapid● Dynamic● Robust
Быстрая разработка
C Grails вы получаете функционирующее web
приложение через 6 секунд :)
Grails
Структура папок
Grailsбыстрая разработка
Быстрая разработка
Groovy - динамический язык с опциональной типизацией
обратно совместимый с Java
Groovy
Обилие синтаксического сахараdef foo = nulldef bar = foo?.something?.myMethod()assert bar == null
assert 'a' == bar ?: 'a'
assert -1 == 3 <=> 4
assert 3 == [1, 2, 3].find {it > 2}
Groovypublic class User { private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; } public String greet(String guest) { return "Hello " + name + ", I am " + guest; }}User user = new User();user.setName("Vasya");
System.out.println(user.greet("Petya"));
Groovypublic class User { private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; } public String greet(String guest) { return "Hello " + name + ", I am " + guest; }}User user = new User();user.setName("Vasya");
System.out.println(user.greet("Petya"));
Точки с запятыми
Groovypublic class User { private String name
public String getName() { return name }
public void setName(String name) { this.name = name } public String greet(String guest) { return "Hello " + name + ", I am " + guest }}User user = new User()user.setName("Vasya")
System.out.println(user.greet("Petya"))
Groovypublic class User { private String name
public String getName() { return name }
public void setName(String name) { this.name = name } public String greet(String guest) { return "Hello " + name + ", I am " + guest }}User user = new User()user.setName("Vasya")
System.out.println(user.greet("Petya"))
Скобки
Groovypublic class User { private String name
public String getName() { return name }
public void setName(String name) { this.name = name } public String greet(String guest) { return "Hello " + name + ", I am " + guest }}User user = new User()user.setName "Vasya"
System.out.println user.greet("Petya")
Groovypublic class User { private String name
public String getName() { return name }
public void setName(String name) { this.name = name } public String greet(String guest) { return "Hello " + name + ", I am " + guest }}User user = new User()user.setName "Vasya"
System.out.println user.greet("Petya")
return
Groovypublic class User { private String name
public String getName() { name }
public void setName(String name) { this.name = name } public String greet(String guest) { "Hello " + name + ", I am " + guest }}User user = new User()user.setName "Vasya"
System.out.println user.greet("Petya")
Groovypublic class User { private String name
public String getName() { name }
public void setName(String name) { this.name = name } public String greet(String guest) { "Hello " + name + ", I am " + guest }}User user = new User()user.setName "Vasya"
System.out.println user.greet("Petya")
public
Groovy class User { private String name
String getName() { name }
void setName(String name) { this.name = name } String greet(String guest) { "Hello " + name + ", I am " + guest }}User user = new User()user.setName "Vasya"
System.out.println user.greet("Petya")
Groovy class User { private String name
String getName() { name }
void setName(String name) { this.name = name } String greet(String guest) { "Hello " + name + ", I am " + guest }}User user = new User()user.setName "Vasya"
System.out.println user.greet("Petya")
Опциональная типизация
Groovy class User { private String name
String getName() { name }
void setName(String name) { this.name = name } String greet(String guest) { "Hello " + name + ", I am " + guest }}def user = new User()user.setName "Vasya"
System.out.println user.greet("Petya")
Groovy class User { private String name
String getName() { name }
void setName(String name) { this.name = name } String greet(String guest) { "Hello " + name + ", I am " + guest }}def user = new User()user.setName "Vasya"
System.out.println user.greet("Petya")
println
Groovy class User { private String name
String getName() { name }
void setName(String name) { this.name = name } String greet(String guest) { "Hello " + name + ", I am " + guest }}def user = new User()user.setName "Vasya"
println user.greet("Petya")
Groovy class User { private String name
String getName() { name }
void setName(String name) { this.name = name } String greet(String guest) { "Hello " + name + ", I am " + guest }}def user = new User()user.setName "Vasya"
println user.greet("Petya")
поле класса
Groovy class User { String name
String greet(String guest) { "Hello " + name + ", I am " + guest }}def user = new User()user.setName "Vasya"
println user.greet("Petya")
Groovy class User { String name
String greet(String guest) { "Hello " + name + ", I am " + guest }}def user = new User()user.setName "Vasya"
println user.greet("Petya")
Использование сеттера
Groovy class User { String name
String greet(String guest) { "Hello " + name + ", I am " + guest }}def user = new User()user.name = "Vasya"
println user.greet("Petya")
Groovy class User { String name
String greet(String guest) { "Hello " + name + ", I am " + guest }}def user = new User()user.name = "Vasya"
println user.greet("Petya")
Именованные аргументы
Groovy class User { String name
String greet(String guest) { "Hello " + name + ", I am " + guest }}def user = new User(name: "Vasya")
println user.greet("Petya")
Groovy class User { String name
String greet(String guest) { "Hello " + name + ", I am " + guest }}def user = new User(name: "Vasya")
println user.greet("Petya")
GString
Groovy class User { String name
String greet(String guest) { "Hello ${name}, I am ${guest}" }}def user = new User(name: "Vasya")
println user.greet("Petya")
Groovy class User { String name
String greet(String guest) { "Hello ${name}, I am ${guest}" }}def user = new User(name: "Vasya")
println user.greet("Petya")
Уберем пробелы
Groovyclass User { String name
String greet(String guest) { "Hello ${name}, I am ${guest}" }}
def user = new User(name: "Vasya")println user.greet("Petya")
Groovypublic class User { private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; } public String greet(String guest) { return "Hello " + name + ", I am " + guest; }}User user = new User();user.setName("Vasya");
System.out.println(user.greet("Petya"));
Groovyclass User { String name
String greet(String guest) { "Hello ${name}, I am ${guest}" }}
def user = new User(name: "Vasya")println user.greet("Petya")
Groovy
Замыканияdef finder = {it > 2}assert 3 == [1, 2, 3].find(finder)
def dynamicFinder = {limit -> { var -> var > limit }}
assert 4 == [1, 2, 3, 4].find(dynamicFinder(3))
Groovy
Идеален для создания DSLhtml { head { title 'Simple document' } body(id: 'main') { h1 'Building HTML the Groovy Way' p { strong 'Some bold text' } a href: 'more.html', 'Read more...' }}
Groovy
Узнать больше о Groovy
http://www.infoq.com/presentations/groovy-2-1-2gx
Быстрая разработка
Принципы Grails● DRY● Convention over Configuration
Быстрая разработка
GORM
package org.example
class Book {
static constraints = { }}
Быстрая разработка
package org.example
class Book { String title
static constraints = { title blank: false }}
Быстрая разработка
Мощный скаффолдинг
package org.example
class BookController {
def index() { }}
Быстрая разработка
package org.example
class BookController { def scaffold = Book
def index() { }}
Быстрая разработка
Быстрая разработка
1к+ плагинов
Быстрая разработка
● GORM● Security● OpenId / Facebook / LinkedIn● Cache● CMS● Rich client
Плагины
Grailsкачественная разработка
Качественная разработка
Вектор архитектуры● Реализован набор паттернов● Явное разделение
обязанностей● Набор устоявшихся практик
Качественная разработка
Построен на плечах титанов
Качественная разработка
Тестирование в крови
Качественная разработка
Хорошо проработанное Unit тестирование
Качественная разработка
void testMockDomain() { def jdoe = new User(name:"John Doe", role:"user") def suziq = new User(name:"Suzi Q", role:"admin") def jsmith = new User(name:"Jane Smith", role:"user")
mockDomain(User, [jdoe, suziq, jsmith])
def list = User.findAllByRole("admin") assertEquals 1, list.size()}
Тестирование динамических методов домена
Качественная разработка
Spock
● BDD / Specifications● Data Driven Testing● Mock / Stub / Spy● Расширяемый
плагинами
Качественная разработка
Spock пример Data Driven Testingclass MathSpec extends Specification { def "maximum of two numbers"() { expect: Math.max(a, b) == c
where: a | b || c 1 | 3 || 3 7 | 4 || 4 0 | 0 || 0 }}
Качественная разработка
Инструменты мониторнига
● JavaMelody Grails Plugin● Health Control● Application Info plugin ● Perf4J Integration Plugin● NewRelic
Качественная разработка
Инструменты контроля качества
● CodeNarc● GMetrics● SONAR● Cobertura
Grailsмасштабируемость
Масштабируемость
Горизонтальное масштабирование
Масштабируемоcть
Admin web appGrails app
Android iOSWeb Frontend
AngularJS
Database
3rd party
ServicesGrails app
Consumer REST APIGrails app
Monitoring APIs
Куда мы идем
CDN
Масштабируемоcть
Вариаанты подключения плагинов
Из репозитория
// grails-app/conf/BuildConfig.groovy
plugins {
build ":tomcat:7.0.52.1"
}
Из локальной папки
// grails-app/conf/BuildConfig.groovy
grails.plugin.location.blog = "../blog"
В чем подвох?
● У мета фреймворка - мета баги● Лучше бы знать что внутри● Медленные интеграционные
тесты● Скорость старта
Недостатки
Спасибо за внимание!
Вопросы