Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Aplicações web que permanecem: uma abordagem arquitetural Java que vai além do último framework JS da moda

Aplicações web que permanecem: uma abordagem arquitetural Java que vai além do último framework JS da moda

Incomodado com a velocidade das mudanças e obsolescência em frameworks JavaScript? E se você precisa construir uma aplicação corporativa que precisa durar mais que a vida curta destes frameworks? Nessa palestra vamos discutir uma abordagem arquitetural web com Java utilizada no desenvolvimento dos projetos Drools e jBPM da Red Hat. Entre os principais pontos explorados:

- Vantagens de uma arquitetura baseada em contratos e não baseada na arquitetura de um framework específico;
- A importância da construção de uma API poliglota;
- Como utilizar o modelo de programação Java EE no seu browser;
- A Importância de tipagem estática em grande bases de código;
- Vantagens de utilizar um framework de UX unificado em uma arquitetura corporativa.
Serão compartilhadas essas e outras técnicas, para manter uma aplicação web desenvolvida ao longo dos últimos sete anos, aplicando as tecnologias mais recentes do desenvolvimento web a uma base de código legada de mais de 1 milhão de linhas – de maneira sustentável, ágil e evolutiva.

B937ab5ebe4923869c0da0d3c1b58778?s=128

Eder Ignatowicz

April 24, 2017
Tweet

Transcript

  1. Aplicações web que permanecem: uma abordagem arquitetural Java que vai

    além do último framework JS da moda Eder Ignatowicz Sr. Software Engineer Red Hat
  2. None
  3. Qual arquitetura e frameworks para o backend?

  4. Java 9 modular, Reactive, Microservices, Vert.x Drools, Spring Boot, Zookeeper,

    Spark
  5. E o front-end?

  6. None
  7. None
  8. None
  9. None
  10. Desenvolvimento JavaScript é complexo

  11. Desenvolvimento JavaScript Web é complexo

  12. Desenvolvimento Web vai continuar sendo complexo

  13. None
  14. None
  15. None
  16. Qual stack web escolher?

  17. Qual a arquitetura mais viável para este problema?

  18. 5 pilares: Aplicação de Larga Escala Desenvolvedores full stack Integração

    com UX Life-Span de 5~10 anos Interoperabilidade
  19. 5 pilares: Aplicação de Larga Escala Desenvolvedores full stack Integração

    com UX Life-Span de 5~10 anos Interoperabilidade
  20. Aplicação de Larga Escala 1mi+ de linhas código web 5

    produtos ~150 sub-projetos ~30 devs 7+ anos de base de código
  21. Aplicação de Larga Escala Static Typing

  22. Aplicação de Larga Escala Refactoring

  23. None
  24. None
  25. Aplicação de Larga Escala Transpilers para JS

  26. None
  27. .java javac .class

  28. None
  29. None
  30. None
  31. GWT The Good Parts

  32. GWT GOOD PARTS Java to JavaScript

  33. GWT GOOD PARTS java.* emulation

  34. GWT GOOD PARTS DOM APis

  35. GWT GOOD PARTS Java 8 “client side"

  36. GWT GOOD PARTS Dev Tools

  37. None
  38. GWT GOOD PARTS JS Interop

  39. JS INTEROP - CONSUME Java @JsType(isNative = true) public abstract

    class JQuery { @JsMethod(namespace=GLOBAL) public native static JQuery $(String selector); public native JQuery css(String prop, String val); public native JQuery attr(String name, String val); } Java import static jquery.JQuery.$; // ... $("ul > li").css("color", "red").attr("data-level", "first");
  40. JS INTEROP - EXPOSE Java package foo; @JsType public class

    Dora { public boolean late = true; public Dora() {} public String auAu() { return "Hello QCon!";} } JavaScript var dora = new foo.Dora(); if (dora.late) { alert(dora.auAu()); }
  41. Aplicação de Larga Escala Refactoring

  42. 5 pilares: Aplicação de Larga Escala Desenvolvedores full stack Integração

    com UX Life-Span de 5~10 anos Interoperabilidade
  43. Devs Full Stack Desenvolvedores “end-to-end"

  44. Devs Full Stack Shared Codebase

  45. Devs Full Stack "Java EE” no browser

  46. None
  47. ERRAI CDI no Browser

  48. @Dependent public class ProjectsView { @Inject Document document; @Inject @DataField(

    "projects-view" ) Div view; @Inject @DataField( "new-project" ) Button newProject; @Inject @DataField( "projects-list" ) UnorderedList projectsList; @Inject Instance<ProjectItem> projects; CDI NO BROWSER
  49. if (!filter.doFilter(event)) { if (event.kind().equals(StandardWatchEventKind.ENTRY_ADD)) { resourceAddedEvent.fire(buildEvent(ResourceAddedEvent.class, event).getK2()); } …

    }
  50. public void onNewFile(@Observes ResourceAddedEvent event) { Window.alert( "ResourceAddedEvent:" + event.getPath().toURI()

    + " ['" + event.getMessage() + “‘]"); }
  51. None
  52. Server Browser Browser Browser Browser Long Polling Web Sockets SSE

    ERRAI BUS
  53. Devs Full Stack Shared Programming Model

  54. 5 pilares: Aplicação de Larga Escala Desenvolvedores full stack Integração

    com UX Life-Span de 5~10 anos Interoperabilidade
  55. <form action="orderResult.jsp" method="POST"> <h3>Pizza Types</h3> <div> <ul> <% for (

    Pizza pizza : pizzaTypes ) { %> <li> <input type="radio" name="pizzaTypeOptions" value="<%=pizza.getName()%>" checked /> <span class="pizzaType"><%=pizza.getName()%></span> <span class="pizzaPrice"><%=pizza.getPrice()%>$</span> </li> <% } %> </ul> </div> <h3>Size</h3> <ul> <li id="li_1"> <input id="pizza_size1" type="radio" name="pizzaSizeOptions" value="Small" checked/> <span class="pizzaSize">Small</span> <input id="pizza_size2" type="radio" name="pizzaSizeOptions" value="Medium"/> <span class="pizzaSize">Medium ( + 2$ )</span> <input id="pizza_size3" type="radio" name="pizzaSizeOptions" value="Large"/> <span class="pizzaSize">Large ( + 3$ )</span> </li> </ul> <h3>Extra Toppings</h3> <div class="section group"> <% for ( int j = 0; j < 3; j++ ) { %> <div class="col span_1_of_3"> <ul class="ul_2"> <% for ( int i = sliceSize * j; i < ( j + 1 ) * sliceSize; i++ ) { %> <li class="li_2"> <input type="checkbox" name="pizzaToppings" value="<%=pizzaToppings.get( i )%>"/> <%=pizzaToppings.get( i )%> </li> <% } if ( j == 0 && remainder > 0 ) { %> <li class="li_2"> <input type="checkbox" name="pizzaToppings" value="<%=pizzaToppings.get( pizzaToppings.size() - 2 )%>"/> <%=pizzaToppings.get( pizzaToppings.size() - 2 ) </li> <% } else if ( j == 1 && remainder > 1 ) { %> <li class="li_2"> <input type="checkbox" name="pizzaToppings" value="<%=pizzaToppings.get( pizzaToppings.size() - 1 )%>"/> <%=pizzaToppings.get( pizzaToppings.size() - 1 )%> </li> <% } %> </ul> </div> <% } %> </div> <h4>Each extra topping is 0.65$</h4> <input type="submit" value="Order"/> </form> ...
  56. <h1>{{title}}</h1> <h2>My favorite hero is: {{myHero}}</h2> <p>Heroes:</p> <ul> <li *ngFor="let

    hero of heroes"> {{ hero }} </li> </ul>
  57. <div> <ul class=“list-group" data-field="projects-list"> </ul> <button type="button" class="btn" data-field="new-project"> <i

    class="fa fa-plus"></i> New Project </button> </div>
  58. @Dependent @Templated public class ProjectsView { @Inject @DataField( "projects-view" )

    Div view; @Inject @DataField( "new-project" ) Button newProject; @Inject @DataField( "projects-list" ) UnorderedList projectsList; } ERRAI UI
  59. None
  60. <!-- Masthead --> <nav class="navbar navbar-default navbar-pf "> <div class="navbar-header

    "> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse-2"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a href="/" class="navbar-brand"> <img src="images/BPMSuite.svg" alt="JBoss BPM Suite" /> </a> </div> <div class="collapse navbar-collapse navbar-collapse-2"> <ul class="nav navbar-nav "><!-- navbar-iconic --> <li class="dropdown"> <a class="dropdown-toggle nav-item-iconic" id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> Home <span class="caret"></span> </a> <ul class="dropdown-menu" aria-labelledby="dropdownMenu2"> <li><a href="#">Design</a></li> <li><a href="#">Processes &amp; Tasks</a></li> <li><a href="#">Runtime</a></li> <li><a href="#">Settings</a></li> </ul> </li> </ul> <ul class="nav navbar-nav navbar-right"> <li class="dropdown"> <a class="dropdown-toggle nav-item-iconic" id="notifications" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> <span title="Notifications" class="fa pficon-warning-triangle-o"></span> Messages: 0 </a> <div class="dropdown-menu infotip bottom-right"> <div class="arrow"></div> <ul class="list-group"> <li class="list-group-item"> <span class="i pficon pficon-info"></span> Modified Datasources ExampleDS </li> <li class="list-group-item"> <span class="i pficon pficon-info"></span> Error: System Failure </li> </ul> <div class="footer"> <a>Clear Messages</a> </div> </div> </li> <li class="dropdown"> <a class="dropdown-toggle nav-item-iconic" id="dropdownMenu2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> <span title="Username" class="fa pficon-user"></span> Brian Johnson <span class="caret"></span> </a> <ul class="dropdown-menu" aria-labelledby="dropdownMenu2"> <li><a href="#">Preferences</a></li> <li><a href="#">Logout</a></li> </ul> </li> </ul> </div> </nav> <div class="container-fluid kie-blank-slate"> <!-- blank state content --> <div class="blank-slate-pf row"> <div class="col-xs-12 col-lg-9" style="text-align:right;"><a href=""><span class="fa fa-gear"></span> Settings</a></div> <h1 id="welcome"> <!--<div style="float:right;"><a href=""><span class="fa fa-gear"></span> Settings</a></div>--> Welcome to <b>BPM Suite</b> </h1> <p> Business Process Management (BPM) Suite offers a set of flexible, process management tools that support the way you need to work. Select a BPM tool below to get started. </p> <div class="blank-slate-pf-secondary-action">
  61. None
  62. Integração com UX Deixe o HTML/CSS em paz

  63. 5 pilares: Aplicação de Larga Escala Desenvolvedores full stack Integração

    com UX Life-Span de 5~10 anos Interoperabilidade
  64. None
  65. Arquitetura Hexagonal Architecture - Alistair Cockburn Onion Architecture - Jeffrey

    Palermo DCI - James Coplien e Trygve Reenskaug. BCE - Ivar Jacobson Clean Architecture - Robert C. Martin
  66. Princípios Independente de Frameworks Testável Independente de UI Independente de

    Database Independente de Agentes Externos
  67. None
  68. "Architecture is about intent. We have made it about frameworks

    and details” Robert C. Martin
  69. UBERFIRE VFS Use Cases VFS API Regular FS Clustering GIT

    FS
  70. None
  71. Qual framework Web escolher?

  72. Qual framework JS escolher?

  73. Escolha do framework JS Anos 1 2 3 4 5

    6 Primeiro Release Perigo 0
  74. What’s next for Angular 1.x? "In all honesty, no one

    really knows what will happen" https://toddmotto.com/future-of-angular-1-x
  75. 1 2 3 4 5 6 Anos Entrega Escolha do

    Framework JS Curva de Aprendizado Projeto Encerrado ou a nova versão não tem retrocompatibilidade Reescrita novo Framework JS Curva de Aprendizado Projeto Encerrado ou a nova versão não tem retrocompatibilidade Reescrita novo Framework JS Curva de Aprendizado
  76. "A good architecture allows volatile decisions to be easily changed”

    Robert C. Martin
  77. E se eu tratasse a volatilidade dos frameworks JS como

    fato?
  78. None
  79. None
  80. Modelo de Programação Componentes: - Screen - Editors - Perspectives

    - Popups
  81. Modelo de Programação LifeCycle: - OnStart - OnSave - IsDirty

    - OnClose - OnFocus - OnLostFocus - OnMayClose - OnReveal
  82. Perspective Editor Screen Screen

  83. Baseado em Contratos Screen -> Interface WorkbenchScreenActivity Editor -> Interface

    WorkbenchEditorActivity Perspective -> Interface PerspectiveActivity
  84. Perspectives Uberfire Lookup Perspective ERRAI CDI BEAN MANAGER Scan all

    Perspective Activity Implementations GWT Perspective Adapter OLD GWT WIDGET ERRAI UI Perspective Adapter Plain HTML Errai UI
  85. Código de 7 anos atrás com GWT “old school"

  86. Código da semana passada HTML 5 canvas

  87. Live-Span de 5~10 anos Trate a arquitetura Web com o

    mesmo respeito que você trata seu backend.
  88. 5 pilares: Aplicação de Larga Escala Desenvolvedores full stack Integração

    com UX Life-Span de 5~10 anos Interoperabilidade
  89. @WorkbenchPerspective(identifier = "HomePerspective", isDefault = true) @Templated public class HomePerspective

    implements IsElement { @Inject @DataField @WorkbenchPanel(parts = "MoodScreen?uber=fire&uber1=fire1") Div moodScreen; @Inject @DataField @WorkbenchPanel(parts = "HomeScreen?uber=fire") Div homeScreen; @Inject @DataField @WorkbenchPanel(parts = "AnotherScreen") Div anotherScreen; } @JsType public interface PerspectiveActivity{ PerspectiveDefinition getDefaultPerspectiveLayout(); @Override default String getName() { return getDefaultPerspectiveLayout().getName(); } boolean isDefault(); Menus getMenus(); ToolBar getToolBar(); }
  90. None
  91. function TodoCtrl($scope) { $scope.placeText = "MiscellaneousFeatures"; $scope.todos = [ {text:

    'learn angular', done: true}, {text: 'build an angular app', done: false} ]; $scope.addTodo = function () { $scope.todos.push({text: $scope.todoText, done: false}); $scope.todoText = ''; }; $scope.remaining = function () { var count = 0; angular.forEach($scope.todos, function (todo) { count += todo.done ? 0 : 1; }); return count; }; $scope.archive = function () { var oldTodos = $scope.todos; $scope.todos = []; angular.forEach(oldTodos, function (todo) { if (!todo.done) { $scope.todos.push(todo); } }); }; $scope["goto"] = function () { $goToPlace($scope.placeText); }; } <div class="container-fluid" ng-controller="TodoCtrl"> <div class="row"> <div class="col-md-12"> <p class="pull-right" style="margin-top: 10px;">{{remaining()}} of {{todos.length}} remaining [ <a href="" ng-click="archive()">archive</a> ] </p> <h4>Todos</h4> <ul class="list-group"> <li class="list-group-item" ng-repeat="todo in todos"> <span class="done-{{todo.done}}">{{todo.text}}</span> <input class="pull-right" type="checkbox" ng-model="todo.done"> </li> </ul> </div> </div> <div class="row"> <div class="col-md-6"> <form class="form-inline" ng-submit="goto()"> <div class="form-group"> <input type="text" ng-model="placeText" size="30" class="form-control" placeholder="place to go"> <input class="btn btn-primary" type="submit" value="GoTo"> </div> </form> </div> <div class="col-md-6"> <form class="form-inline pull-right" ng-submit="addTodo()"> <div class="form-group"> <input type="text" ng-model="todoText" size="30" class="form-control" placeholder="add new todo here"> <input class="btn btn-primary" type="submit" value="Add"> </div> </form> </div> </div> </div> $registerPlugin({ id: "my_angular_js", type: "angularjs", templateUrl: "angular.sample.html", title: function () { return "angular " + Math.floor(Math.random() * 10); }, on_close: function () { alert("this is a pure JS alert!"); } });
  92. Perspectives Uberfire Lookup Perspective ERRAI CDI BEAN MANAGER Scan all

    Perspective Activity Implementations GWT Perspective Adapter OLD GWT WIDGET ERRAI UI Perspective Adapter Plain HTML Errai UI Angular Perspective Adapter Angular native Perspective Any JS Perspective Adapter Any JS Framework
  93. Angular JS Screen

  94. Criação de Componentes em Runtime

  95. None
  96. None
  97. 5 pilares: Aplicação de Larga Escala Desenvolvedores full stack Integração

    com UX Life-Span de 5~10 anos Interoperabilidade
  98. Desenvolvimento Web é complexo

  99. Aplicações Web são parte da nossa arquitetura

  100. Princípios Independente de Frameworks Testável Independente de UI Independente de

    Database Independente de Agentes Externos
  101. Arquitetura de software é exercício de trade-offs

  102. 5 pilares: Aplicação de Larga Escala Desenvolvedores full stack Integração

    com UX Life-Span de 5~10 anos Interoperabilidade
  103. Eder Ignatowicz @ederign http://bit.ly/5-pilares-web