50 оттенков play!

38
50 оттенков Play! Андрей Солнцев

Upload: andrei-solntsev

Post on 27-Jul-2015

431 views

Category:

Software


0 download

TRANSCRIPT

Page 1: 50 оттенков play!

50 оттенковPlay!

Андрей Солнцев

Page 2: 50 оттенков play!
Page 3: 50 оттенков play!

Play! framework 1

Лёгкость Ruby on Rails+

compile-safety Java

Page 4: 50 оттенков play!

Play! framework

- NO REDEPLOY

- Легковесный как RoR. Нет XML. Нет DAO.

- легко начать! классный туториал.

- простая структура проекта (по конвенции, нет пакетов)

- роутинг: * {controller}/{method}

Page 5: 50 оттенков play!

Масштабируемость

- Нет Java сессии

- Сессия в cookies (+кэш)

- Масштабируемость безгранична

Page 6: 50 оттенков play!

Всё что надо из коробки

- Configuration- JPA / Hibernate / DB transactions- H2 in-memory database- Шаблоны на Groovy- генерация PDF, Excel- Тесты

Page 7: 50 оттенков play!

Расширяемо

- плагины для всего-всего- модули (через Ivy)

Page 8: 50 оттенков play!

require: - play 1.3+ - play -> secure - play -> pdf 0.9 - play -> guice 1.3 - play -> excel 1.2.8 - play -> press 3.1 - play -> liquibase 3.4

dependencies.yml

Page 9: 50 оттенков play!

Play! framework 1

Спорные решения

Page 10: 50 оттенков play!

“потому что веб

по своей сути статический”

Методы контроллеров статические

- really?

- т.е. наследование

не нужно?

Page 11: 50 оттенков play!

Веб статический?

play.exceptions.UnexpectedException: Unexpected Errorat play.Classes.getAssignableClassesat play.Classloader.getAssignableClassesat play.utils.Java.invokeChildOrStatic(Java.java:199)at controllers.Secure$Security.invokeat controllers.Secure.logout

Page 12: 50 оттенков play!

play-secure

public static class Security extends Controller { static boolean authenticate(String username) { return true; }

static void onAuthenticated() {} static void onDisconnect() {} static void onDisconnected() {}

…}

- наследование не нужно, говоришь?

Page 13: 50 оттенков play!

Редирект через вызов методаpublic static class Payments extends Controller {

public static void submit(Payment payment) { payment.status = SUBMITTED; ... details(payment.id); }

public static void details(long paymentId) { render(payment); }}

WOW! Редирект!!!

Page 14: 50 оттенков play!

Редирект через вызов методаpublic static class Payments extends Controller {

public static void submit(Payment payment) { payment.status = SUBMITTED; payment.submittedBy = getUser(); details(payment.id); }

}

А здесь не редирект?

Page 15: 50 оттенков play!

Редирект через вызов методаpublic static class Payments extends Controller {

public static void submit(Payment payment) { payment.status = SUBMITTED; payment.submittedBy = getUser(); details(payment.id); }

public static void details(long paymentId) {...} static void getUser() {...}}

А здесь не редирект?А нет.

Page 16: 50 оттенков play!

МАГИЯ!

“код, который мы написали, и который бежит -несколько отличается”

- Редиректы- Автогенерация геттеров/сеттеров- JPA из коробки

Page 17: 50 оттенков play!

МАГИЯ!

- Магия - это плохо!- Ужасно плохо!!- Прям плохо!!!

- Медленно- Бажно- Возникает зависимость

Page 18: 50 оттенков play!

WTF1

Page 19: 50 оттенков play!

wtf BeanInfo?Oops: ClassNotFoundExceptionAn unexpected error occured caused by exception ClassNotFoundException: models.loans.LoanBeanInfo

play.exceptions.UnexpectedException: Unexpected Errorat play.classloading.ApplicationClasses.getAssignableClassesat play.classloading.ApplicationClassloader.getAssignableClassesat play.utils.Java.invokeChildOrStatic(Java.java:199)at controllers.Secure$Security.invoke(Secure.java:203)at controllers.Secure$Security.access$0(Secure.java:200)at controllers.Secure.logout(Secure.java:99)

- Чиво?

- У нас нет класса LoanBeanInfo...

Page 20: 50 оттенков play!

После 3 лет дебага...

public class ApplicationClassloader extends ClassLoader {// ~~~~~~~~~~~~~~~~~~~~~~~public Class<?> loadApplicationClass(String name) { // name == 'LoanBeanInfo' ...

1: ApplicationClass appClass = Play.classes.getApplicationClass(name); // Эта сволочь добавляет в глобальный список: // Play.classes.put(name, new ApplicationClass(name, javaFile));

// ... здесь 45 строк кода (компиляция Loan.java) ...

if (!appClass.compile()) {2: Play.classes.classes.remove(name); return null; } return null;}

Page 21: 50 оттенков play!

WTF2

Page 22: 50 оттенков play!

Play.detectChanges()

public static synchronized void detectChanges() { try { pluginCollection.detectChange(); if (!Play.started) { throw new RuntimeException("Not started"); }

} catch (PlayException e) { throw e; } catch (Exception e) { // We have to do a clean refresh start(); }}

Page 23: 50 оттенков play!

Play.detectChanges()

public static synchronized void detectChanges() { try { pluginCollection.detectChange(); if (!Play.started) { throw new RuntimeException("Not started"); }

} catch (PlayException e) { throw e; } catch (Exception e) { // We have to do a clean refresh start(); }}

Получай StackOverflowException!

Page 24: 50 оттенков play!

WTF3

Page 25: 50 оттенков play!

play.Logger

try {...}catch (Exception e) { Logger.error("Failed to set global render args", e);}

- Ждёте stack trace?

- Ха-ха!

- Правильно так:

Logger.error(e, "Failed to set...");

Page 26: 50 оттенков play!

WTF4

Page 27: 50 оттенков play!

if (newDefinitions.size() > 0) { Cache.clear(); if (HotswapAgent.enabled) { try { HotswapAgent.reload(newDefinitions); } catch (Throwable e) { throw new RuntimeException("Need reload"); } } else { throw new RuntimeException("Need reload"); }}

RELOADING

Page 28: 50 оттенков play!

if (newDefinitions.size() > 0) { Cache.clear(); if (HotswapAgent.enabled) { try { HotswapAgent.reload(newDefinitions); } catch (Throwable e) { throw new RuntimeException("Need reload"); } } else { throw new RuntimeException("Need reload"); }}

RELOADING

● т.е. Play использует Hotswap.● Ничего больше. Только Hotswap. ● Который и так встроен в Java!

● Я чувствую себя обманутым...

Page 29: 50 оттенков play!

if (newDefinitions.size() > 0) { Cache.clear(); if (HotswapAgent.enabled) { try { HotswapAgent.reload(newDefinitions); } catch (Throwable e) { throw new RuntimeException("Need reload"); } } else { throw new RuntimeException("Need reload"); }}

RELOADING Всё, что загруженонепосильным трудом...

Page 30: 50 оттенков play!

Вредные советысоздателям фреймворков

от авторов Play!

Page 31: 50 оттенков play!

Глотайте ошибки

- Молча.- или запишите туда, где никто не найдёт

Page 32: 50 оттенков play!

Накажите юзераpublic static void init() {

URL log4jPath = getResource( "/log4j.xml");

if (log4jConf == null)

log4jConf = getResource( "/log4j.properties");

}

if (log4jConf == null) {

Properties shutUp = new Properties();

shutUp.setProperty("log4j.rootLogger", "OFF");

PropertyConfigurator.configure(shutUp);

}

}

Logger.java

Page 33: 50 оттенков play!

Пишите javadoc/**

* You know ...

*/

protected Class<?> loadClass(String name) {

/**

* You know ...

*/

public InputStream getResourceAsStream(String name) {

/**

* You know ...

*/

public URL getResource(String name) {

Page 34: 50 оттенков play!

Пишите комментарии

Page 35: 50 оттенков play!

Не унывайте!

try { … 40 строк кода ...}catch (Exception e) { // Well probably a compiled optimizer // (I hope so)}

Page 36: 50 оттенков play!

Спасибо Play!

- За революцию в Java web

- Это по-любому лучше любого

ъынтерпрайза

- Это open-source. Всё в наших руках.

Page 37: 50 оттенков play!

Play @ Codeborne

- Наш форк:

https://github.com/codeborne/play

(ветка 1.3.x-codeborne)

- Для тестов:

https://github.com/codeborne/play-tests

-

Page 38: 50 оттенков play!

Андрей Солнцев@asolntsev

ru.selenide.org

Бодрячком!