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 6 months? What about maintaining your enterprise application for longer than the 2-year lifecycle of these frameworks? This talk can provide you with insightful answers, share challenges and the solutions through the 5 pillars of a successful Java Web application extracted directly from the development of jBPM and Drools web workbenches.
Come and join me for this talk. I'll share how we're able to keep a 7-year old Java application, that combines modern techniques with a legacy codebase of more than 1 million LOC, up-to-date with an agile, sustainable and evolutionary web approach. Some key points you'll learn are:
* The advantages of Contract Based Development instead of a Framework Centric Development;
* How static typing is a central point in a huge web application;
* How we use the same programming model (Java EE) on the backend and browser ;
* How a Java to JS APIs allow your application to evolve over time and support heterogeneous (polyglot) web frameworks;
* The importance of a clean and unified UI framework for your enterprise architecture and how to do it on Java;

B937ab5ebe4923869c0da0d3c1b58778?s=128

Eder Ignatowicz

July 11, 2017
Tweet

Transcript

  1. 5 pillars of a successful Java Web application Eder Ignatowicz

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

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

    Spark
  5. And on the front-end?

  6. None
  7. None
  8. None
  9. None
  10. Javascript Development is complex

  11. Web Javascript development is complex

  12. Web development will stay complex

  13. None
  14. None
  15. None
  16. None
  17. None
  18. Which web stack?

  19. Which web architecture is most doable for this problem?

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

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

    5~10 years life-span Interoperability
  22. Large Scale Application 1mi+ lines of web code 5 projects

    ~150 subprojects ~30 devs Code base of 7+ years
  23. Large Scale Application Static Typing

  24. Large Scale Application Refactoring

  25. None
  26. None
  27. Large Scale Application JS Transpilers

  28. None
  29. .java javac .class

  30. None
  31. None
  32. None
  33. None
  34. GWT <3

  35. GWT The Good Parts

  36. GWT GOOD PARTS Java to JavaScript

  37. GWT GOOD PARTS java.* emulation

  38. GWT GOOD PARTS DOM APIs

  39. GWT GOOD PARTS Java 8 “client side"

  40. Java 8 List<String> myList = Arrays.asList("Java7", “Java8", "Java6", "Kotlin"); myList

    .stream() .filter(s -> s.startsWith("J")) .map(String::toUpperCase) .sorted() .forEach(Console::log); Prints: JAVA6 JAVA7 JAVA8
  41. GWT GOOD PARTS Dev Tools

  42. None
  43. GWT GOOD PARTS JS Interop

  44. 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");
  45. 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()); }
  46. Large Scale Application Refactoring

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

    5~10 years life-span Interoperability
  48. Devs Full Stack “End-to-end” developers

  49. Devs Full Stack Shared Programming Model

  50. Devs Full Stack “Java EE” in browser

  51. None
  52. ERRAI CDI on Browser

  53. @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
  54. if (!filter.doFilter(event)) { if (event.kind().equals(StandardWatchEventKind.ENTRY_ADD)) { resourceAddedEvent.fire(buildEvent(ResourceAddedEvent.class, event).getK2()); } …

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

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

    ERRAI BUS
  58. Devs Full Stack Shared Programming Model

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

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

    hero of heroes"> {{ hero }} </li> </ul>
  62. <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>
  63. @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
  64. None
  65. <!-- 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">
  66. None
  67. UX Integration Leave the HTML/CSS in peace

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

    5~10 years life-span Interoperability
  69. None
  70. Architecture Hexagonal Architecture - Alistair Cockburn Onion Architecture - Jeffrey

    Palermo DCI - James Coplien e Trygve Reenskaug. BCE - Ivar Jacobson Clean Architecture - Robert C. Martin
  71. Principles Not coupled to Frameworks Testable Not coupled with UI

    technology Not coupled with Database Independent of another systems
  72. None
  73. "Architecture is about intent. We have made it about frameworks

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

    FS
  75. None
  76. Which web framework should I use?

  77. Which JS framework?

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

    First Release Danger 0
  79. 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
  80. 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
  81. "A good architecture allows volatile decisions to be easily changed”

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

    as a fact?
  83. None
  84. None
  85. Programming Model Components: - Screen - Editors - Perspectives -

    Popups
  86. Programming Model LifeCycle: - OnStart - OnSave - IsDirty -

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

  88. Contract Based Screen -> Interface WorkbenchScreenActivity Editor -> Interface WorkbenchEditorActivity

    Perspective -> Interface PerspectiveActivity
  89. Perspectives 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
  90. 7 years old code with “old school” GWT

  91. HTML 5 canvas fresh code

  92. 5~10 years life-span The Web architecture should be treated with

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

    5~10 years life-span Interoperability
  94. @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(); }
  95. None
  96. 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!"); } });
  97. Perspectives 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 Angular Perspective Adapter Angular native Perspective Any JS Perspective Adapter Any JS Framework
  98. Angular JS Screen

  99. Creating Components in Runtime

  100. None
  101. None
  102. 5 pillars: Large scale application Full stack Developers UX Integration

    5~10 years life-span Interoperability
  103. Web development is complex

  104. Web applications are important pieces of our architecture

  105. Principles Not coupled to Frameworks Testable Not coupled with UI

    technology Not coupled with Database Independent of another systems
  106. Software architecture is trade-offs exercise

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

    5~10 years life-span Interoperability
  108. Eder Ignatowicz @ederign http://bit.ly/5-pillars-web