turducken - divide and conquer large gwt apps with multiple teams
DESCRIPTION
Complex GWT apps can involve multiple teams with different release cycles. Compile times can quickly become prohibitive when your codebase grows into millions of lines. “Turducken” is a technique to combine multiple GWT apps that can be built and released by separate teams while providing a seamless, snappy user experience.TRANSCRIPT
Turducken
Rob KeaneGoogle / Ad Exchange Front [email protected]
Divide and conquer large GWT apps with multiple teams
Complex GWT apps can involve multiple teams with different release cycles. Compile times can quickly become prohibitive when your codebase grows into millions of lines.
“Turducken” is a design pattern to combine multiple GWT apps that can be built and released by separate teams while providing a seamless, snappy user experience
Turducken
A note on the name...
Turkey + Duck + Chicken
For this...
...not this
Large projects
teams?release cycles?testers?frameworks?
Multiple...
Terminology
In the context of this talk...
Module == GWT Module with entry point
One last note...
This is a design pattern not a library
1. Bob’s Sticker Emporium2. Conquering Multiple Entry Points3. Other uses
Turducken
Bob’s GWT App
Bob has a sticker site
bobs-sticker-emporium.com
BOB’S STICKERSStickers
BUY! BUY! BUY!
Success!
Bob adds more options...
bobs-sticker-emporium.com
BOB’S STICKERSStickers
BUY! BUY! BUY!
Create your own!
Customize Customize Customize
Your Cart (2)
Sell a sticker!
Things are getting complex
➔ Still one giant GWT module
➔ Compilation takes several minutes
➔ A few megabytes of JS
➔ 5 teams!
➔ Continuous integration
➔ Release coordination
What should Bob do?
How do you split up a large GWT project?
One GWT module× One release
× One build
× Very large if code isn’t split properly
× Difficult to test
Many GWT modules× Full page reloads
× Code can’t be split between modules
One GWT module?
Many GWT modules?ಠ_ಠ
ಠ_ಠ
Ultimately multiple GWT modules
is the only real option
Multiple modules
Split into multiple GWT entry points
bobs-sticker-emporium.com
BOB’S STICKERSStickers
BUY! BUY! BUY!
Create your own!
Customize Customize Customize
Your Cart (2)
Sell a sticker!
Full page refresh between each module
Bob
half of aggregate user latency
Research showed that
was due to full page reloads
1. Bob’s Sticker Emporium2. Conquering Multiple Entry Points3. Other uses
Turducken
Tab A(GWT)
Tab B(GWT)
Tab C(GWT)
Container (GWT Module)
Inter-app Event Bus (JSNI)
Virtual historian
Virtual historian
Virtual historian
The container
➔ A GWT module (mostly)➔ The first thing to load on the page➔ Loads the other modules on demand➔ Communicates with modules through
inter-app event bus
Yes.This actually works
Loading all of the modules?
Bob’s container
bobs-sticker-emporium.com
BOB’S STICKERSStickers
BUY!
Create your own!
Your Cart (2)
Sell a sticker!
Load multiple GWT modules?
➔ When a module is loaded, a <script> tag is added to the <head>
➔ Everything lives in the same container
Memory usage
➔ Browsers are good at hiding elements➔ Memory only increases marginally when
loading new modules
// OldRootPanel.get().add(myRootWidget);
// NewContainerHelper.getModulePanel().add(myRootWidget);
<body> <div id=”modules”> <div id=”TAB_1_ROOT”>...</div> <div id=”TAB_2_ROOT” style=”display:none”>...</div> <div id=”TAB_3_ROOT” style=”display:none”>...</div> </div></body>
DOM Assumptions
CSS➔ Avoid @external as much as possible
➔ Avoid styling tags
... unless the style is truly global
➔ Should be in a “global” CSS file> global.css
a {
color: #999;
}
When Module “TAB_1” is loaded →
When Module “TAB_2” is loaded →
But I really want @external CSS...
/* no, no, no */@external .title;.title { color: pink; font-size: 72px;}
/* that’s better */@external .title;#TAB_1 .title { color: pink; font-size: 72px;}
CSS example
There’s just one tiny, little issue...
All problems in computer science can be solved by
another level of indirection
“
Butler Lampson
Tab A(GWT)
Tab B(GWT)
Tab C(GWT)
Container (GWT Module)
Inter-app Event Bus (JSNI)
Virtual historian
Virtual historian
Virtual historian
Virtual History Implementation
An history implementation that doesn’t alter the “real” URL but instead sends an event
Container History
Produces a “safe” URL that contains information about the module
For example:#MODULE_A/MyPlace
instead of#MyPlace
Tab A(GWT)
Tab B(GWT)
Tab C(GWT)
Container (GWT Module)
Inter-app Event Bus (JSNI)
Virtual historian
Virtual historian
Virtual historian
The event bus that broadcasts between modules needs to be JSNI since it must communicate between GWT modules
A simple publish/subscribe interface will do
Event bus implementation
Code example
// Container
InterAppEventBus.subscribe(“HISTORY_CHANGE”, updateUrlHandler);
// Virtual History in a submodule
InterAppEventBus.publish(“HISTORY_CHANGE”, “myNewUrl”);
Message trace for historyEvent bus
Change to virtual history
Module load event
Real URL is changed
Virtual Historian Container Browser
Summary of Turducken
➔ Separate your app into multiple entry points➔ A container module manages loading the
submodules➔ Carefully manage your CSS➔ The submodules talk to a virtual historian➔ A JavaScript/JSNI InterAppEventBus handles
events between modules and the container➔ Events are broadcast that the container handles
to alter the real URL
The future
➔ Shadow DOM eliminates a lot of the issues➔ Eliminate JSNI with GWT 3.0
But wait!
There’s more.
1. Bob’s Sticker Emporium2. Conquering Multiple Entry Points3. Other uses
Turducken
An inter-app event bus opens up some interesting doors
It’s all about the event bus
Inter-app communication
Load another module via an event
➔ Settings Module◆ Change settings from other modules◆ Global “Accept ToS” message
➔ Chat module
Example
➔ One team maintains “Chat” functionality➔ Another team maintains a “Profile” page➔ Launch a chat with a person from their
profile➔ Chat module doesn’t always need to be
loaded➔ Limited coupling between modules
Invisible Modules
There can be “background” modules that aren’t visible but handle events
➔ Monitoring session➔ Caching data for multiple modules
Non-GWT “modules”
➔ Follow the same CSS approach➔ Write an virtual history implementation➔ Add hashPrefix to $location in Angular
Where’s the code?
➔ A few small parts➔ A design pattern, not a library➔ Tends to be application specific
...but we are considering it
Complex GWT apps can involve multiple teams with different release cycles. Compile times can quickly become prohibitive when your codebase grows into millions of lines.
“Turducken” is a design pattern to combine multiple GWT apps that can be built and released by separate teams while providing a seamless, snappy user experience
Turducken
wow
wow
many modules
different releasessuch performance
no reloads
Questions?