5 Pillars of a Successful Java Web Application

5 Pillars of a Successful Java Web Application

Swamped by new JavaScript frameworks that are born every six months? What about maintaining your enterprise application for longer than the two-year lifecycle of these frameworks? This session can provide you with insightful answers. It shares challenges and solutions through the five pillars of a successful Java web application, extracted directly from the development of jBPM and Drools web workbenches. The speaker how his team is able to keep a seven-year-old Java application that combines modern techniques with a legacy codebase of more than one million lines of code up to date with an agile, sustainable, and evolutionary web approach.

B937ab5ebe4923869c0da0d3c1b58778?s=128

Eder Ignatowicz

October 01, 2017
Tweet

Transcript

  1. 5 Pillars of a Successful Java Web Application Eder Ignatowicz

    Sr. Software Engineer @ Red Hat Alex Porcelli Principal Software Engineer @ Red Hat
  2. None
  3. Which backend architecture?

  4. And what about front-end?

  5. None
  6. Javascript Development is complex

  7. Web Javascript development is complex

  8. Web development will stay complex

  9. None
  10. None
  11. None
  12. Which web stack?

  13. Which web architecture best fits for this problem?

  14. 5 pillars: Large scale application Full stack Developers UX Integration

    5~10 years Life-Span Interoperability
  15. s 5 pillars: Large scale application Full stack Developers UX

    Integration 5~10 years Life-Span Interoperability
  16. 1mi+ lines of web code 5 projects ~150 subprojects ~30

    devs Code base of 7+ years Large Scale Application
  17. Static Typing Large Scale Application

  18. Refactoring Large Scale Application

  19. Large Scale Application

  20. JavaScript Transpilers Large Scale Application

  21. Large Scale Application

  22. .java javac .class Large Scale Application

  23. None
  24. None
  25. None
  26. None
  27. The Good Parts

  28. GWT • Good Parts Java to JavaScript

  29. GWT • Good Parts java.* emulation

  30. GWT • Good Parts JS Interop

  31. 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");
  32. 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()); }
  33. Refactoring Large Scale Application

  34. 5 pillars: Large scale application Full stack Developers UX Integration

    5~10 years Life-Span Interoperability
  35. Shared Programming Model Devs Full Stack

  36. “Java EE” in browser Devs Full Stack

  37. CDI-Lite Devs Full Stack

  38. Devs Full Stack

  39. CDI @ Browser ERRAI

  40. CDI no Browser @ApplicationScoped 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;
  41. CDI no Browser if (!filter.doFilter(event)) { ... if (event.kind().equals(StandardWatchEventKind.ENTRY_ADD)) {

    resourceAddedEvent.fire(buildEvent(ResourceAddedEvent.class, event).getK2()); } ... }
  42. CDI no Browser public void onNewFile(@Observes ResourceAddedEvent event) { Window.alert("ResourceAddedEvent:"

    + event.getPath().toURI() + " ['" + event.getMessage() + "']"); }
  43. CDI no Browser

  44. ERRAI BUS Server Browser Browser Browser Browser Long Polling Web

    Sockets SSE
  45. Shared Programming Model Devs Full Stack

  46. 5 pillars: Large scale application Full stack Developers UX Integration

    5~10 years Life-Span Interoperability
  47. <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> <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>
  48. <h1>{{title}}</h1> <h2>My favorite hero is: {{myHero}}</h2> <p>Heroes:</p> <ul> <li *ngFor="let

    hero of heroes"> {{ hero }} </li> </ul>
  49. <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>
  50. ERRAI UI @Dependent @Templated public class ProjectsView { @Inject @DataField(

    "projects-view" ) Div view; @Inject @DataField( "new-project" ) Button newProject; @Inject @DataField( "projects-list" ) UnorderedList projectsList; }
  51. None
  52. <!-- 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"> ...
  53. None
  54. Leave the HTML/CSS in peace UX Integration

  55. 5 pillars: Large scale application Full stack Developers UX Integration

    5~10 years Life-Span Interoperability
  56. None
  57. Hexagonal Architecture - Alistair Cockburn Onion Architecture - Jeffrey Palermo

    DCI - James Coplien e Trygve Reenskaug. BCE - Ivar Jacobson Clean Architecture - Robert C. Martin Architecture
  58. Decoupled from Frameworks Testable Decoupled from UI Decoupled from Database

    Independent of external systems Principles
  59. None
  60. “Architecture is about intent. We have made it about frameworks

    and details” Robert C. Martin
  61. APPFORMER VFS Use Cases VFS API Regular FS Clustering GIT

    FS
  62. None
  63. Which web framework should I use?

  64. Which JS framework?

  65. JS framework choice Years 1 2 3 4 5 6

    First Release Danger 0
  66. https://toddmotto.com/future-of-angular-1-x What’s next for Angular 1.x? “In all honesty, no

    one really knows what will happen”
  67. 1 2 3 4 5 6 Years Deliver JS Framework

    Choice Learning Curve Project Canceled or new version is incompatible Rewrite on the new JS framework Learning Curve Project Canceled or new version is incompatible Rewrite on the new JS framework Learning Curve
  68. “A good architecture allows volatile decisions to be easily changed”

    Robert C. Martin
  69. What if I dealt with the volatility of JS frameworks

    as a fact?
  70. None
  71. None
  72. Component Model: • Screen • Editors • Perspectives • Popups

    Programming Model
  73. LifeCycle: • OnStart • OnSave • IsDirty • OnClose Programming

    Model ...
  74. Screen Screen Editor Perspective

  75. Programming Model Screen Editor Perspective → Interface WorkbenchScreenActivity → Interface

    WorkbenchEditorActivity → Interface PerspectiveActivity
  76. Perspectives Lookup AppFormer 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
  77. 7+ years old code with “old school” GWT

  78. HTML 5 canvas fresh code

  79. 5~10 years Life-Span The Web architecture should be treated with

    the same respect as you treat your backend.
  80. 5 pillars: Large scale application Full stack Developers UX Integration

    5~10 years Life-Span Interoperability
  81. @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(); }
  82. None
  83. 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!"); } });
  84. Perspectives 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 AppFormer Lookup Perspective ERRAI CDI BEAN MANAGER Scan all Perspective Activity Implementations
  85. Angular JS Screen

  86. 5 pillars: Large scale application Full stack Developers UX Integration

    5~10 years Life-Span Interoperability
  87. Web development is complex

  88. Web applications are important pieces of our architecture

  89. Decoupled from Frameworks Testable Decoupled from UI Decoupled from Database

    Independent of external systems Principles
  90. Software architecture is trade-offs exercise

  91. 5 pillars: Large scale application Full stack Developers UX Integration

    5~10 years life-span Interoperability
  92. Thank you. Eder Ignatowicz Sr. Software Engineer @ Red Hat

    Alex Porcelli Principal Software Engineer @ Red Hat
  93. None