4. “[The web] is enabling us to rediscover what we've always
known about being human: we are connected creatures
in a connected world about which we care passionately.”
David Weinberger - “Small Pieces Loosely Joined” via Wikipedia: https://en.wikipedia.org/wiki/Small_Pieces_Loosely_Joined
6. PROJECT TATSU @ AUTOSCOUT24
- Breaking apart the monolith using Microservices
- Moving out of the datacenter and to the AWS cloud
- Focus on the JVM and Scala in favor of .NET/C#
- Run it all on Linux instead of Windows
https://github.com/AutoScout24/scout24-it-principles
7. “[...]composition is the placement or arrangement of [...]
elements or ingredients in a work of art, as distinct from
the subject of a work.”
Wikipedia: https://en.wikipedia.org/wiki/Composition_(visual_arts)
8. I can do stuff!
Me too!
I can do
two things
at once!
I wish I
could do
stuff!
I love
lamp!
Woo! I’m here!
I’m really
boring but
important
What am I
supposed
to do?
I can do
other stuff!
18. Pages
are publicly accessible
get called from the client
include fragments
could be cacheable
define contracts
are parts of a page
get called from nginx SSI
could include fragments
should be cacheable
adhere to contracts
Fragments
19. SSI Include
<html>
<head>
<title>AutoScout24</title>
<!-- Minified and combined css used by this page (not by the fragments) -->
<link rel="stylesheet" href="/assets/home/ebacb8194-main.min.css" />
</head>
<body>
<!--#include virtual="/headerservice/fragment/header_de_DE" -->
Lorem ipsum....
<!-- Minified and combined javascript used by this page -->
<script type="text/javascript" src="/assets/home/66ee72f9-main.min.js"></script>
</body>
</html>
20. SSI Include Resolved
20
<html>
<head>
<title>AutoScout24</title>
<!-- Minified and combined css used by this page (not by the fragments) -->
<link rel="stylesheet" href="/assets/home/ebacb8194-main.min.css" />
</head>
<body>
<head>
<!-- Minified and combined css used by this fragment -->
<link rel="stylesheet" href="/assets/headerservice/08ffaf28-main.min.css" />
</head>
<ul><li>Home</li><li>Search</li><li>Sell</li></ul>
<script type="text/javascript" src="/assets/headerservice/26ed612f-main.js"></script>
Lorem ipsum....
<!-- Minified and combined javascript used by this page -->
<script type="text/javascript" src="/assets/home/66ee72f9-main.min.js"></script>
</body>
</html>
21. ngx_pagespeed: combine heads
<html>
<head>
<title>AutoScout24</title>
<!-- Minified and combined css used by this page (not by the fragments) -->
<link rel="stylesheet" href="/assets/home/ebacb8194-main.min.css" />
<link rel="stylesheet" href="/assets/headerservice/08ffaf28-main.min.css" />
</head>
<body>
<ul><li>Home</li><li>Search</li><li>Sell</li></ul>
<script type="text/javascript" src="/assets/headerservice/26ed612f-main.js"></script>
Lorem ipsum....
<!-- Minified and combined javascript used by this page -->
<script type="text/javascript" src="/assets/home/66ee72f9-main.min.js"></script>
</body>
</html>
27. THANK YOU
For questions or suggestions:
Arif Wider - awider@thoughtworks.com
Moritz Heiber - mheiber@thoughtworks.com
Notas del editor
THIS IS FOR HAMBURG ONLY
THIS IS FOR HAMBURG ONLY
Besides being a developer at ThoughtWorks, Arif is a serious coffee geek
Between (and while) drinking coffee he thinks about Microservices, writes preferably Scala code, and likes the challenge of generating insights out of large amounts of data
- This is Moritz’ official business card .. he’s calling himself a DevOps Birth Assistant, the male version of a midwife
- That’s because he’s helping his customers deliver babies .. software babies, with all their quirks, differences, and joyful moments
- and he does all this using the methodologies behind DevOps
This is a quote from the book “Small pieces loosely joined - a unified theory of the web” by David Weinberger, I’ll give you a moment to read it
Essentially, it is describing us as human beings in an interconnected world, and there are very true parallels if you want to explain the concept behind UI composition, “Small pieces loosely joined” describes it pretty well
The book is about the Internet, and how we use it, how we interact with it and through it, and the Internet as such is a composition!
A couple of million servers, in a network, at worldwide scale, presenting content of an incredible large variety
It is highly composed, while still performing at absolutely acceptable rates, with individual companies and teams in charge of the responsible layers
But what’s happening if things aren’t so well connected, or worse, even centralized and monolithic?
We are able to present this today because one of our clients, AutoScout24, embarked on an ambitious mission almost 2 years ago
They are still on it, and with a lot of success!
They had the same problem as any larger organization: Large, monolithic applications, very hard to maintain, carrying a lot interest and business logic in one huge blob
Inflexible and resistant to change
Intersecting responsibilities across teams
Architecture is dictated by requirements in existence aeons ago
Delivering updates, bugfixes and new features is bound to a single, manual process
The advantages though: It’s a single point of entry for consumers! Browsers don’t need to do anything special in order to use it
For them the monolith is an easy, one-stop solution, because it carries all the logic and feeds it to browsers
But, AutoScout24 wanted change
They wanted to be able to release faster, with teams working autonomously, carrying responsibilities towards business goals and values
They chose to not only achieve these goals with a single set of changes, but four separate ones
They are breaking apart their monolithic .NET application, moving towards Microservices
They are abandoning their own two datacenters for the AWS cloud
They are switching away from .NET and C# towards the JVM and Scala in particular
And on top of it all they are going to run all of it on Linux
Additionally:
Continuous Delivery and DevOps
Innovation and development in autonomous teams
Reduce time to market of features and bugfixes
Attract talent
Read more about it in their extraordinary IT principles, published on GitHub
If you want to start your own transformation it’s an excellent document to start with
They also chose the pattern of UI composition for bundling their applications together
But what is that exactly?
This is the Wikipedia definition of “Composition”, as you might realize it’s the description for “visual composition”, but it’s very much applicable to compositions of any sort
It a way it’s like a symphony, an arrangements of many different strains of instruments in perfect harmony
How do we map this to our software composition example, though?
If you want to shift that picture towards Microservices you can see a very easy pattern emerge
At first you have a single Microservice, which can do stuff
And then maybe there comes another one, and either of them can do stuff, and maybe they can do even more stuff when combined
However, as you might have guessed, this space gets crowded pretty easily, especially when you have different business goals driving you forward
And it gets even more complicated once each of the components has to talk to one another, has dependencies and expectations etc.
In a sense it’s like an orchestra: They all know the end result they’re supposed to provide, the symphony
or in the case of Microservices, their business focus
Any individual member of the orchestra might be excellent at what they are doing, and they are probably are going to be able to play beautiful music without any further help by just listening to one another or reading from the same sheet of music
Like our Microservices could do
But this gets more and more complicated the more interests (i.e. instruments) and intersecting responsibilities (i.e. different melodies) you are accumulating; they need somebody who is able to put it all together, make sense of the chaos.
They need a conductor
THIS IS FOR HAMBURG ONLY
If you haven’t recognized him from the first slide, this is Thomas Hengelbrock, he’s the current principal conductor of the NDR Elbphilharmonie Orchestra in Hamburg
He is the single point within the orchestra that makes the symphony possible with a reasonable amount of coordination and understanding
He doesn’t do much physically (waving a baton erratically, essentially), but he has the bigger picture in his head and is keeping track of the pace
All the different parts of the orchestra are coming together, they are providing value (music), and the conductor just tells them if they’re on the right track or not
And that’s what we need for our Microservices as well! We need a conductor ..
> Arif
- Thank you, Moritz
- Now let’s move to the actual UI Composition solution that we built at AutoScout and which we called Jigsaw
- And of course, we called it Jigsaw because it helps us to cut the AutoScout page into smaller pieces which fit together perfectly
- At the same time, we do not want to compromise page performance by any means
- We know that especially on mobile devices the responsiveness of a page dramatically determines how much users enjoy using the page
- For measuring page performance, we rely mainly on Google’s PageSpeed Insights. Who knows what PageSpeed Insights is?
- Imagine this is the AutoScout homepage and it consists of several UI components such as
- Now with the interpretation of Microservices that we implemented at AutoScout, each service delivers its own UI component, e.g., purple home page, later composed to a single web page
- We often speak of vertical slices here, because there is no layered architecture anymore and each service can contain a backend, a UI, and everything in between
- This way, each team can change their backend and their UI independently → Great for team autonomy
- Now, to allow for real autonomy, services also need to deliver their own assets, such as stylesheets and JavaScript
- However, if you naively combine this into one single page, the page performance will be terrible because you have CSS and JS scattered all over the page and render blocking content at various places
- You can then, for instance, try to make each service deliver their assets separately in order to optimize the page structures
- For instance by grouping the CSS loading up here
- And in fact, that was an approach that went for first
- However, things get really messy now when caching comes into play
- because a piece of HTML and a corresponding piece of CSS could be invalidated at different times so that you get version mismatches when releasing updates to the page
… of course there are alternatives to this UI composition approach, and a popular one is API Gateway Pattern combined with a Unified UI frontend
- However, there are some drawbacks of applying this pattern from which, for us, the most severe is that independent feature releases are no longer possible (as long as they contain UI changes)
- Instead, in the worst case three teams are involved and need to be coordinated when changing a feature: the backend service team, the API gateway layer team, and the web app team
- One could say that the API Gateway pattern one goes only half way to split the monolith, namely only in the backend
- but because team autonomy is one of the main reasons we went for Microservices in the first place, this issue made the API Gateway pattern no option for us
Here’s a diagram of how Jigsaw, our UI composition conductor, works under the hood:
Initially, there is always an entity requesting some resources, for our purposes that’s a browser requesting the content of a website to display to its consumer/user. Let’s say for this request the user wants to see the homepage of AutoScout24
The request, after navigating through Amazon’s CloudFront (not pictured) will hit our composer, Jigsaw, specifically its proxy module. Nginx, internally, knows which services it should serve under a certain Slash URL. For our homepage, which is a special case since it doesn’t usually care any prefix, that is /home. The re-routing is done by CloudFront.
Nginx fires off a sub-request to the service registered within its proxy registry, in this case the application responsible for serving the homepage. The homepage app is returning a proper Index page, written in HTML, with a slight trick up its sleeve.
It also includes so called Server Side Includes, instructing nginx to do further round-trips to gather other resources the Index needs in order to serve the request it has gotten initially for its Index. Nginx contains a module which is capable of resolving these resources we call fragments from other services via its proxy module, the SSI module. In the diagram the Index needs a fragments for the header and the footer, since those aren’t specific to the homepage, but rather for the whole web presence.
There will be sub-sequent request to the service able to resolve the required fragments the other service formulated in its Index. In our case that’s the Contentservice, who’s able to resolve the HTML for the header fragment and the footer fragment
It send these HTML fragments back to the SSI module, which is then putting it back together, to represent the Index of the service that was serving the original request, our homepage service. The resulting HTML is then passed on to the truly magical component in all of this: The ngx_pagespeed module. It’s a third party module developed by Google, to apply web development best practices to HTML code on the fly. With it we are able to satisfy the second important requirement we initially formulated: To be as fast as possible. Google, in this case, is our reference.
Now, we couldn’t do all of this with every request, especially since about 95-99% of the content doesn’t really change all that frequently. That’s why both, the proxy module and the ngx_pagespeed module are able to cache content dynamically, based on URL keys, parameters, certain headers and content types. Javascript and CSS for example, is cached indefinitely, since all of it is strong cached, by the individual service but also by the ngx_pagespeed module. However, all the other cache handling is at the discretion of the individual services. If they want a certain part cached they will need to use the right Cache-Control headers. This enables all of them to use Jigsaw’s caching facilities autonomously, without any limitations or superimposed guidelines.
7. After ngx_pagespeed is done with its optimizations the results are served back to the browser, strong cached and optimized for the relevant browser at hand, without any specific optimizations having to be done by the individual services.
Both, SSI and ngx_pagespeed are solving two very specific problems, and by combining them both we are unleashing their true power, enabling our teams to work without boundaries.
> Arif
- So before showing an example how this actually looks in code
- I have to explain that we conceptually distinguish between what we call a page and what we call a fragment
- ...and does not know the original request
- ...and this team is responsible for the performance and the stability of the page
- So when this page includes fragments, this team has to define a contract with the providers of this fragment
- The fragment on the other hand needs to obey this contract and behave well
Now let's look at a simple example page
Page, therefore HTML tag+ head and body
styles already minified by service
SSI include syntax
SSI resolved = include replaced with fragment (by Nginx)
fragment has its own head, with its own minified styles in there
also its own script section at its bottom
very bad page speed as of now
now comes mod pagespeed
combine heads
combine css
combine js, defer its loading
> Moritz
Obviously, one of the challenges of coming up with this interconnected system, with distributed responsibilities was that the result, the product, still needed to provide the highest value to our customer, i.e. a page that worked
We enabled all of our teams to test their composed services with a Jigsaw instance broad to your very machine using Docker and interchangeable services
You can, if you want to, run a certain services somewhere else, in a separate environment, on your laptop, on your toaster (as long as it has web access), and emulate the Jigsaw behaviour through the right set of headers
A test would use your version of Service A, but the production versions of Services B, C, D, etc.
That way you have a high level of assurance when it comes to testing, and you’re more confident when composing your pages
This is so easy, you can hand this out to your product management team and they would be able to test new revisions of your software, through Docker deployments, or even separate feature toggles, without any impact on production systems!
All the facilities you usually have for testing a monolithic applications are still viable and very much possible
This way of composing web services provides a maximum amount of flexibility for otherwise highly dependent teams; none can work without the other, but they all can work together efficiently and effectively
Due to the nature of the dynamic pipeline and the caching mechanism page owners have full control over how fast their pages are served to their customers, none of it is actively impairing performance
All the best practices web developers usually have to dance around with we are entrusting to a source of truth (hint: Google) not only responsible for serving a large portion of the traffic websites receives these days, but also an entity who’s at the forefront of best practice web development. The phrase “if it works for Google it should work for us” is truly alive with this concept.
This is Jigsaw, our UI composition conductor.