Orchestrating micro-frontends

How can we orchestrate our micro-frontends architecture?

Following the previous posts on micro-frontends (1 and 2), it’s time to talk about how to orchestrate micro-frontends.

First of all and foremost, there are 2 schools of thoughts about how a micro-frontend should look like, as explained in the previous article where I was explained different implementations of micro-frontends, there are implementations where a micro-frontend correspond to an area of the user interface, others where the micro-frontend is a SPA or a single page.

When we consider the micro-frontends implementation based on different logical areas of the application (like a header, a footer, a payment form and so on) we would face different challenges like:
Which team would assemble the aggregated view?
How can we avoid external dependencies in every team?
Which team is accountable for an issue in the aggregated view?
How do we ensure that a specific area of the application is not tightly coupled with the parent container?
How can we be sure there aren’t conflicts between dependencies?
Are we assembling at runtime or compile time?
If we decide to create the page at runtime time, is our application servers layer scalable?
Is the content cachable and for how long?
How do we ensure the development flow is not impacted by distributed teams?

And many other questions (technical and organisational) that could make our life way more complicated than how it could be.
Interestingly enough, this approach didn’t provide the expected benefits for Spotify working at scale and they reverted back to a more “classic” architecture based on SPA.

For the benefits of this post, let’s define our micro-frontends as SPA or single pages with a generation made at compile time in order to avoid any possible surprise happening at the composition layer.

Anyway, there are some challenges to face also with this approach, probably the main one is understanding how we want to orchestrate our micro-frontends and it is the focus of this post.
The orchestrator layer could be either on the client-side, server-side or edge-side; the solution depends on how “smart” the orchestrator layer should look like for our applications.

Server-side or edge-side orchestrator

A server-side or edge-side orchestrator would mean that for any deep-link or organic traffic hitting our domain has to be analysed by an application server or an edge solution (lambda@edge for instance), in both cases we need to maintain a map of URLs that correspond to static HTML files (aka micro-frontends).
For instance, if a user logs out from our application we should probably unload the authenticated micro-frontend and load the sign in/sign up micro-frontend, therefore the application server or the code running on the edge should know which HTML file to serve for every URL or group of URLs in the case we are going to work with SPAs.
This technique could work without any problem considering we can change quickly the micro-frontends map directly on the server without any impact on the client-side, but presents some potential challenges, like finding the best way to share data across micro-frontends considering there are some limits of storage inside the browser and doing too many roundtrips to the servers is not ideal in particular for slow connections.
Another challenge would be finding a solution for initialising the application, considering with micro-frontends we split the monolith into multiple subdomains, are we going to initialise the application every time a new micro-frontend is loaded? Are we going to use Server Side Rendering storing the configuration inside the HTML? How do we communicate between micro-frontends? How do we scale our application servers when there is bursty traffic?
Those are some of the challenges for implementing a server-side or edge-side orchestrator.

Client-side orchestrator

Another possible approach could be to create a client-side orchestrator responsible for:

— initialise the application
— sharing the application’s configurations to all the micro-frontends
— load/unload a micro-frontend based on the user’s state
— routing between micro-frontends
— exposing an API for interacting between a micro-frontend and the client-side orchestrator

One of the PROs of this solution is that you have more control over the application initialisation.
If well designed, the client-side orchestrator doesn’t need to change too often, therefore, will be fairly stable.
It provides additional functionality that could be used by various micro-frontends but it’s not domain specific, it’s also a great solution when our aim is to abstract our micro-frontends from the platform they are running on (browser instead of mobile devices or smart TVs).
The main CON is the initial investment in identifying which feature should be handled by this orchestrator because the risk of a big ball of mud is behind the corner, a bug on this layer could blow up the entire application and the implementation of new features, if not well co-ordinated, could slow down other teams creating a cross-team dependency.

In DAZN we opted for a client-side orchestrator that we called bootstrap.

Bootstrap has all the responsibilities listed above plus an additional one related to our use case, in fact, bootstrap is abstracting the I/O APIs of the platform where the application is running on, in this way each micro-frontend is completed unaware in which platform is loaded.
With this technique, we can re-use a micro-frontend across multiple smart TVs, consoles or set-top boxes without the need to rewrite specific device’s implementations, unless the implementation has memory leaks or performance issues.
Bootstrap is served every time a user types our domain in the browser or opens the application on a smart TV, it’s always present and never unloaded for the entire duration of the user session.

DAZN loading flow 

Let’s try to expand further about the bootstrap in order to understand the main ideas behind it:

Initialise the application

Bootstrap should be responsible to set the application context, first of all understanding if the user is authenticated or not and based on the application initialisation we can load the correct micro-frontend.
Any other meaningful information your application needs for setting the context for the entire application should be managed at this stage.
It could be a static configuration (JSON) or dynamic one where an API needs to be consumed, either way, having an external configuration for our frontend allow us to change some behaviours of our system without the need of bootstrap releases.
For instance, a configuration could provide valuable information for the application lifecycle like features toggles, localised labels for the user interface and so on.

Micro-frontends routing

Bootstrap is definitely responsible for routing between micro-frontends, in our implementation, we have 2 routing spread between bootstrap and every micro-frontend.
Bootstrap doesn’t have the entire URLs map of our applications, instead, it loads in memory a map of which micro-frontend should be loaded based on the user status and the URL requested via user’s interactions or deep link.
Those two dimensions allow us to load the correct micro-frontend and leave to the micro-frontend code handling the URLs to manage inside different views that compose it.
A rule of thumb here is to assign a specific second level path for a micro-frontend so it would be easier to address the scope of a micro-frontend, for instance, the authentication micro-frontend should be loaded when the user types mydomain.com/account/*, instead, the micro-frontend for the help pages should be loaded when the user clicks on a link like mydomain.com/support/* and so on.
Inside every single micro-frontend, we can then decide to have additional paths like mydomain.com/support/help-page-A or mydomain.com/support/help-page-B, in this way the domain knowledge would be retained inside the micro-frontend without spreading it across multiple parts of the application.

The main takeaway here is that we have two types of routing in a micro-frontend application with a client-side orchestrator, a global one at bootstrap level and a local one inside the micro-frontend.

Micro-frontends lifecycle

As we mentioned before, each micro-frontends should be loaded via the boostrap, but how?
Single-spa, for instance, uses a javascript file as an entry point for mounting a new micro-frontend.
In DAZN, we took a different approach because using just a javascript file for loading a micro-fronted would have precluded the possibility to use server-side rendering at compile time that was an interesting option for us to provide faster feedback to our user meanwhile they were transitioning from a micro-frontend to another one.

Micro-frontend anatomy: HTML, JavaScript and CSS files

Considering an HTML file is basically an XML file with a specific schema, bootstrap can load and parse the file appending inside itself all the relevant nodes for loading a micro-frontend using DOMParser, a standard interface for parsing XML or HTML strings.
Anything inside the body or head tags could be appended inside bootstrap’s DOM tree.
Potentially, we can also decide to define specific attributes for all the tags we need to append in order to have a quick way of selecting them.
Anyway, the overall idea is parsing an HTML file and appending inside bootstrap what is needed for loading the micro-frontend, therefore any external dependency (like a JavaScript or CSS file) present in the micro-frontend HTML file will be appended and therefore loaded by the browser.

A huge benefit of this neat approach is that it’s not opinionated, anyone can start working on a new micro-frontend without learning the way we decided to deal with micro-frontends because at the end, as long the micro-frontend output results in the Frontend holy trinity: an HTML, a JavaScript and a CSS files.

I captured a video throttling the connection in order to show how the bootstrap appends the DOM elements inside itself, as you will see there are 4 phases:
— identifying the micro-frontend to load,
— load the HTML of the micro-frontend,
— parse it,
—append the relevant tags for displaying the micro-frontend in the page.
It’s a very simple but effective mechanism!

An additional feature added to each micro-frontend is the possibility to perform some actions after and before are mounted or unmounted, in this way the micro-frontend can do any logic for cleaning up any object appended to the window object or any other logic to run in one of the 4 lifecycle’s methods mentioned before.
Bootstrap is responsible to trigger the micro-frontend lifecycle methods and clean the memory before loading the next micro-frontend, this action ensures no conflicts are happening in different or the same versions of a library used by different micro-frontends.

Bootstrap memory and dependencies management

It’s time to deep dive into the micro-frontends memory management, considering bootstrap is loading one micro-frontend per time, as explained in the previous post, and each micro-frontend is not sharing any library or dependency with another micro-frontend, we could end up in a situation where a micro-frontend is loading React v.15 and the next one React v.16.
At the same time, we want to have the freedom to pick any technology and library version inside every micro-frontend because the development team that retain the business and technical knowledge should make the best implementation choice available instead of having constant trade-offs across the entire application as usually happens when we work with a Single Page Application.

At this stage, I believe is very easy to guess the challenge we are facing because any library or framework used by a micro-frontend will append objects on the global window one and in Javascript we cannot directly control the garbage collector but we can facilitate the disposal of an element removing all the references and instances of a given object.

For achieving this goal, an additional bootstrap responsibility is keeping track of any object that is appended to the window object by any micro-frontend and cleaning the window object after unloading the micro-frontend but before a new one is loaded (the joy of metaprogramming in JavaScript 🎉).
Bootstrap takes a snapshot of all the keys appended to the window object and removes them before loading a new micro-frontend, in this way we keep track of what should be removed without duplicating any objects in memory and with a simple iteration of this array we delete any objects used by the unloaded micro-frontends inside the window object.

APIs layer for communicating between bootstrap and a micro-frontend

The last bit worth mentioning is the APIs layer exposed by the bootstrap via the window object.
If you asked yourself how we share data and communicate between micro-frontends, bootstrap is the answer!

Remember that our implementation is based on the assumption we always load one micro-frontend per time and we slice a micro-frontend based on a subdomain of our application, you will soon realise that the data shared across micro-frontends are not happening too often if you work well in the initial session where you define all your subdomains.
Sharing data between micro-frontends is pretty easy, bootstrap shares some APIs for storing and retrieving information accessible by any micro-frontends, it’s up to you deciding which storage is more convenient for your implementation and what kind of limits you wanna add to the objects to store locally.
Considering the bootstrap is a tiny layer written in vanilla JavaScript in between a platform and a micro-frontends and it’s initialising the application, we need also to expose an API layer for abstracting the I/O layer for storing or retrieving information from and to a micro-frontend.
Working with multiple devices require to have different APIs for storing and retrieving files because web storage APIs are not always consistent across all those platforms.
Another important part to highlight is the configuration retrieved from a static JSON file or an API that usually is shared with all the micro-frontends to understand the context where they are running (for instance sharing particular configuration based on the country or languages).

The most important thing when we design the APIs exposed by the bootstrap is trying to be forward-thinking because the bootstrap should be a layer that doesn’t change at every release otherwise you could break some contracts with micro-frontends and coupling the micro-frontends to bootstrap functionalities could jeopardise all the great work done splitting up your business domain in multiple subdomains.

Summary

During this post, we have explored the possibilities for orchestrating micro-frontends, we deep dive into the client-side orchestrator that in DAZN is called bootstrap, in particular, we have seen the benefits and the challenges of this approach and how we have managed to solve them.
In particular, we saw the bootstrap has 3 main responsibilities:

— routing between micro-frontends (load, unload and lifecycle methods)
— initialise the application
— exposing an APIs layer for micro-frontends communication and web storage

One of the questions I received very often after sharing those posts is if and when the bootstrap will be open-sourced, the answer is that we are thinking about that but we cannot commit to a timeline at the moment (that’s also the reason why I didn’t share code in this post, sorry again 🙏).

I really hope you are getting a clearer idea of how to structure your next micro-frontends project if not feel free to reach out, so I can have food for thoughts for the next post! ✌️

Advertisements

Micro-frontends, the future of Frontend architectures

Micro-frontends architecture

In the past 30 months, I had the opportunity to work on one of the most challenging architectures I’ve ever designed in my career.
The main requirements were based on the speed of delivery, scalability and code quality.
Frontend applications are becoming more challenging daily and achieving those requirements in a company with a massive growth like DAZN was far to be an easy task.

The first step for me was identifying how to achieve those requirements in a meaningful manner, therefore, I started thinking how I can reach those goals in an ideal world and then work retrospectively through the constraints we had inside our company.

The speed of delivery could have been achieved parallelising tasks in multiple teams the real challenge although is having teams independent enough to not be stopped by external dependencies in particular when the teams are distributed and not co-located.

Scalability on the Frontend ecosystem is not only represented by technical challenges but mainly by autonomous teams, too often I experienced the frustration of frontend developers from external dependencies and because they have to maintain and improve a codebase started for one purpose and evolved in a monster becoming unmanageable after some months or a few years of work, ideally we should be able to scale our teams organically and adapting them to the business needs without too much friction, more than being trapped inside codebases that do not really follow the “business rhythm”.

Code Quality is a non-functional requirement that is always aimed by any team and company out there but often, despite the goodwill of each team members, due to pressure from the business, we had to make some hard decisions cutting some corners so the tech debt increases and, without being addressed properly, having a knock-out effect on the entire organization and the teams morale.

On top of those key goals, a personal one I thought was key for the project I was about to redesign was innovation, in the JavaScript community there are plenty of talented teams and individuals that are contributing to open source projects with great libraries, frameworks but more in general solutions, that could make our life easier or even accelerate the time to market of specific feature, ignoring this fantastic ecosystem would have been a technical suicide considering I was working on an architecture for the future that should have remained in the company for the foreseeable future.

For achieving all of these goals I had to think outside the box, leveraging the past experiences and the learnings from successes as well as failures happened in my career.
It’s then that I thought about micro-frontends, following the microservices principles, I was able to extract a manifesto based on what I need to achieve:

DAZN micro-frontends manifesto

Usually, when we design new architecture we need to bear in mind that architecture and technical decisions are not affecting merely the code and our technical teams but also the entire organization we work for, therefore is essential understanding the impact of those choices across our company.

If you wanna learn more, I summarise this incredible journey in this talk with my colleague Max Gallo during the last edition of Frontend Developer Love Conference, the feedback at the conference was really positive, but I decided to use this platform for understanding what other people think and create a genuine discussion around a topic that is going to change the future of our Frontend applications: micro-frontends.

Enjoy the talk and feel free to comment or ask any questions, I’d really like to gather the experience and common questions/doubts of the community around micro-frontends doing my best to answer them all.

Last but not least, if you wanna learn more on micro-frontends I warmly recommend joining me the 26th April in the 3 hours online workshop organised in collaboration with O’Reilly Media

Geo-routing, A/B testing and dynamic configuration with Lambda@Edge — part 1

Working at the edge is one of the fantastic opportunities offered by Amazon and AWS Lambda is the key component for enhancing our infrastructure on the edge.
More recently many other vendors started to offer similar services like Cloudflare with edge workers for instance, in general many CDNs providers are looking to add a similar service like the AWS one.

Lambda@Edge introduction

Lambda@Edge provides you the possibility to extend the behaviours of a request or response directly on the edge.
This paradigm, in conjunction with the serverless one, can provide a great flexibility in structuring our applications and it can prevent that too many requests hit our application servers executing operations directly on the edge like headers manipulation, access control, redirection rules, images manipulation and so on.
In order to work with Lambda@Edge in AWS we just need to setup a Cloudfront distribution in front of our infrastructure, the Cloudfront distribution will allow us to setup our logic on the edge because we are able to intercept the 4 states of a request and interact with them.
In fact Lambda@Edge can be triggered at:

· viewer request: in this case the lambda is triggered when Cloudfront receives a request from a client
· origin request: the lambda is triggered before Cloudfront forwards the request to origin
· origin response: this state happens after origin replies to a request and Cloudfront receives it
· viewer response: the last state is triggered when Cloudfront forwards the response to the client.

Cloudfront is a global CDN therefore Lambda@Edge is triggered on any edge available across the world.
This means that independently from the region we set our data centre, we can manipulate or serve responses on the edge before they even arrive to our application servers.

I spent some time working on a spike for handling 2 specific features, geo-routing and a/b testing, in the mix I tried also to dynamically retrieve configurations parameters for the Lambda in order to avoid code deployment for every change I needed to do.
I’ll share the results of my spike between 2 posts, this one talks about the initial thoughts, goals and results achieved with Lambda@Edge, the second one will be more technical and I’ll explain how I configure Cloudfront, the Lambda code and setup and the overall setup for interacting with other AWS services on the edge.

Spike goals

Before we start I think is valuable understanding what I wanted to achieve with this spike, the goals are:

1. geo-routing a request to a specific static file stored in S3 bucket based on user country
2. A/B testing different applications serving always maintaining a sticky session per browser so a user always interacts with the same version
3. The previous 2 goals shouldn’t significantly impact the response time, Lambda@Edge has to be executed redirecting the user to the correct static file in 50ms or so
4. “bonus goal” is the possibility to dynamically apply different configurations without redeploying the Lambda code and without impacting too much the response time

Lambda@Edge configuration and limits

All that glitters ain’t gold! Lamba@Edge has several limitations that we need to be aware of before taking it in considerations.
In order to achieve the geo-routing we need to receive from Cloudfront the country viewer header, that will be used to determine where the request is coming from.
This header is received right after Cloudfront forwards the request to origin, we won’t receive at the viewer request state, therefore our Lambda has to be triggered as origin request.
Bear in mind that Cloudfront removes all the headers if not whitelisted for increasing the response cachability, so when we configure our distribution we need to whitelist some specific headers or all of them, depends from our needs.

Lambda@Edge is a particular kind of Lambda with different limitations than the one we are used to work inside an AWS data centre.
First of all the Lambda@Edge has to be created in North Virginia only, we can associate only a numeric released with Cloudfront and not the $latestversion.
When we debug our Lambda@Edge we need to remember that all the logs in Cloudwatch won’t be available in North Virginia only but in the nearest data centre from where the Lambda was executed, for instance I’m based in London therefore during the spike, all the logs on Cloudwatch were available in the London AWS data centre only.
Finally we have also some soft limits to take in consideration like max memory associated to our Lambda@Edge, concurrent executions and so on, you can find them in the image below:

An important thing to remember is how to debug our Lambda@Edge, luckily AWS thought pretty well about this point and they provide a way to simulate an origin request customising the parameters to send it directly from the Lambda console:

Geo-routing

The Geo-routing feature was really easy to achieve considering that Cloudfront provides everything we need out-of-the-box.
After whitelisting the cloudfront-viewer-country header we can receive in our Lambda@Edge the country from where the request was coming from and we can apply the behaviour we need for that specific country.

After configuring Cloudfront distribution properly we can think about describing our behaviour in the Lambda@Edge, in this case I used Node.js for defining the logic:

These are the headers we are going to receive from Cloudfront:

As we can see the implementation is really easy despite the APIs that could have been designed in a more “friendly” way, but I appreciate they are very extensible and flexible allowing the introduction of new features and maintaining retro-compatibility.

A/B testing

For A/B testing the best way to achieve that on the edge is using cookies after select the static file to serve, also in this case we need to configure properly the Cloudfront distribution for forwarding the cookies to the Lambda@Edge:

In this spike for a specific country I was able to redirect a certain percentage of users to a static file and all the others to another one.
This mechanism becomes very handy when we want to test new versions of our web applications, so we can do a canary release and see how the new version behaves compare to the previous one.
Combining A/B testing functionality with the geo-routing feature we can deploy a new artifact in a specific country with a small percentage of users redirected to it, leaving the majority of our users consuming the previous version.
Considering we are using cookies, bear in mind that all the latest version of the browsers allow to store a cookie before doing a redirection but if you are targeting older browsers like IE 10 or similar it’s better to give it a try.
The same concern is valid if you have in your logic multiple redirections in place.

Dynamic Configuration

The bonus feature for the spike was retrieving a configuration for the URLs and the percentage of users we need to redirect on a region basis.
In this case I tried a couple of solutions, the first one with DynamoDB and the second with an S3 bucket where I stored a JSON file.
First of all I need to admit I was surprised that I was able to access a Dynamo table from the edge considering Dynamo is not global like S3 or Cloudfront, so I decided to give it a go.
I structured my table with an ID for each single information I wanted to make dynamic (the URL of an experiment, the percentage of users to redirect to a static file or the other one…) and then I tried 2 approaches, one using scanmethod and the other using get method.
Using scan was slightly slower than using get method but in any case I was over 50ms for Lambda execution therefore DynamoDB wasn’t a viable option for this use case.

I then tried a simple JSON file stored in a S3 bucket, in this case I was able to quickly configure my Lambda retrieving all the parameters I needed for changing URLs or percentage of users redirected to a specific experiment without redeploy the Lambda code.

This could look a small win but you will understand soon that for deploying a new version of a Lambda@Edge we need around 15 minutes before it’s fully propagated across the world.
Retrieving the parameters from an external file allowed to change the key part of the script in a matter of seconds, just the time to make the change in the JSON file and upload on S3.

Considering the operations we usually handle on the edge are very delicates for our infrastructure, having a mechanism to quickly change the behaviour of our logic is fundamental in particular if you are running a B2C service like in my case.

Performances

I didn’t mention in the post any metric because I wanted to gather them in a paragraph for easily compare them, so I created this table related to the executed time in each test I did for achieving the full functionality.
In the table you will see 4 scenarios:
. without any external configuration
. retrieving a JSON file from a S3 bucket
. using DynamoDB with the get method
. using DynamoDB with the scan method

I’d like to add a bit of more context just to make sure you understand how these metrics were retrieved.
DynamoDB was created in North Virginia and the Lambda was running from Europe, I didn’t try yet working with Global Tables but that will be part of a new spike I need to do in the next month, Global Tables could effectively change the execution time of the Lambda but we’ll see.
The execution time for each lambda was gathered from Cloudwatch running each scenario at least 10 times and providing the average you can see in the table.

I leave to you the considerations on the different methods used during the spike.

Useful resources

Following I gathered some useful resources for starting your journey… on the edge

Lambda@Edge limits
Lambda@Edge restrictions
Lambda@Edge pricing
Cloudfront and Lambda@Edge
Routing at the edge tutorial

Wrap up

As we have seen in this post, Lambda@Edge can become very handy for many situations, in particular for alleviating the load of our application servers.
The spike described above is just one of the many possibilities that Lambda provides on the edge, searching on the web you can find interesting tutorials like image manipulations or JWT validation on the edge, this could be just the beginning of a new way to structure our applications providing better performances and easy configurations for our web applications or APIs.
If you are wondering what would be the cost of using Lambda at the edge I leave you with this cost scenario available on the AWS website:

In the next post I’ll present how I set up Cloudfront, S3 and the Lambda code for achieving the goals of my spike, keep an eye on my social accounts 😉

Running Webpack on AWS Lambda

AWS Lambda, but more importantly the serverless ecosystem, is changing the way we can create and think our softwares on the cloud.
With serverless we can really focus on coding our service more than worrying about the infrastructure. Serverless is not useful in any occasion but there is a wide range of situation where using it becomes handy and very powerful.

For instance, let’s think for a moment our automation build pipeline: what would you say if I can tell you that you won’t need to tight them with a specific tool like Jenkins or Bamboo but you should use Jenkins or similar as luncher running multiple Lambda functions, in parallel or in sequence, levering the power of the cloud?

I can give you a concrete example, yesterday night I was doing a spike in order to generate a Javascript bundle on the cloud with Webpack.
Therefore I invested some time creating an AWS Lambda that executes Webpack for bundling a simple example that contains lodash and some ES6 code like this one:

import _ from ‘lodash’;
function component () {
       var element = document.createElement(‘div’);
       element.innerHTML = _.join([‘Hello’,’webpack’], ‘ ‘);
       return element;
}
document.body.appendChild(component());

This is an example that you can find in the webpack official website, I used that just for the sake of the demo.
What we want to do now is the possibility to bundle this ES6 code and its library to a unique Javascript file that could be used inside our hypothetic application or website, mimicking what a step of a build pipeline would do.
Obviously you could run any other executables inside AWS Lambda, I choose Webpack because was the one used in my working place.

AWS Lambda at the rescue

If you create an automation pipeline on the cloud and maybe you don’t have many devops in your team or company, you should spend some time learning AWS Lambda, it could help out in these kind of activities.

What is AWS Lambda? Long story short: it’s a stateless docker container that is maintained by AWS where you can focus on writing the business logic of your activity more than thinking on the infrastructure.
Too good for being true? Yeah, you are right, Lambda has some limitations:

Information retrieved from Amazon documentation in March 2017
Information retrieved from Amazon documentation in March 2017
Information retrieved from Amazon documentation in March 2017

More information regarding the limits are available in the Lambda documentation website

But still the amount of things you can do with it is pretty impressive!

So, going back to our main goal, we want to bundle our Javascript project with Webpack inside Lambda, how can we achieve that?

First thing first, I created a git repository where you can find a Javascript project to simply use inside a AWS Lambda function. In this way you won’t need to create a custom project and you can focus more on the AWS side.
There are few points that I’d like to highlight in this simple project because usually are the ones that you can waste your time:

  1. Lambda functions can save temporary files inside the /tmp/ folder (bear in mind that you are running your code inside a docker container!).
    If you try to save somewhere else you will receive an error trying executing it.
  2. With Lambda you can run executables or node CLI tools like NPM or Webpack just uploading them inside your Lambda environment and referring to them with relative path.
  3. AWS Lambda runs for not more than 300 seconds therefore if you have a complex operation you could split it up in different chained Lambda functions that are triggered in sequence.
    This should help you in debugging your operations too.

In the project I set up the webpack config file in this way:

var path = require('path');
module.exports = {
   entry: './app/index.js',
   output: {
      filename: 'bundle.js',
      path: path.resolve('/tmp/')
   }
};

As you can see I’m saving my bundle in the tmp folder because is the only one with write permissions (remember the capacity limit of 512MB for that folder).

Then I created an index.js file where I describe my Lambda function:

var spawn = require('child_process').spawn;
var fs = require('fs');


exports.handler = (event, context, callback) => {
   var wp = spawn('./node_modules/.bin/webpack', ['--config', 'webpack.config.js']);

   wp.stdout.on('data', function(data){
     console.log('stdout: ' + data);
   });

   wp.stderr.on('data', function(err){
     context.fail("writeFile failed: " + err);
   });


   wp.on('close', (code) => {
     fs.readFile('/tmp/bundle.js', 'utf8', function (err, data) {
         if (err) context.fail("read file failed: " + err);
         context.succeed(data);
     });
   });
};

Very simple code here, I’m using Node, as you can see, but potentially you could use Python or Java (these 3 languages are supported by AWS Lambda at the moment), up to you peeking your favourite.
I import the spawn method in order to run webpack and once it has finished I read the content inside the Javascript bundle file created by Webpack in the tmp folder and I return it via context.succeed method.
Context is an object, always available inside a Lambda function, that will allow you to interact with Lambda for retrieving some useful information or, like in this case, to define when the function succeed or failed.

Now we are ready to upload the application in an AWS Lambda function.
In order to do that you will need to zip your project files (not the parent folder but just the files) and upload then in AWS.
If you didn’t install the project dependencies after cloning the repository, you should do it before uploading it to AWS.

Select and compress only the files inside your project not the parent folder 

Inside your AWS console, after selecting Lambda service, you should be able to create a new function (as far as I know not all the regions are supporting AWS Lambda).
Choose your favorite language, in my case Node 4.3, and define the basic information like “function name”, “description” and so on.
Then instead of writing the Lambda function code inside the editor provided by AWS, open the dropdown and select Upload a ZIP file

Select upload a ZIP file

Then setup the handler, role and advanced settings in this way

it’s important set at least 30 seconds as Timeout period

The important part will be setting up the docker container where the Lambda is going to be executed with enough memory size and with a decent timeout because we are running an executable therefore we don’t want to block the execution due to a Lambda timeout.
If for any reason, you need to increase the 300 seconds soft limit set by default, you will need to contact Amazon and ask to increase it.
Another important information to remember is when the Lambda is not active for a certain amount of time (it’s estimated to 5 mins), the container used by your code will be re-used for other Lambda functions.
Therefore when you will trigger your function again it will be recreated (cold Lambda), instead if the Lambda function runs several times in few mins (warm Lambda) we will have better performances because the container will be already available and live to execute a new activity again.

Now if you want to test your Lambda function, you will need to click the button test and you should have an output similar to this one:

you can see easily the output produced by this Lambda function that is the content inside the Javascript bundle created by Webpack

If you want to test live the Lambda I created you can trigger it from this link

Where to go from here

Obviously the example described is very basic and it works mainly with the project I created, but it is useful to know also how you could expand this example:

  1. AWS Lambda functions accept arguments passed when we trigger them, therefore potentially you could upload your project files in S3 and trigger the Lambda function directly after the upload.
    In fact Lambda can be triggered by several cloud software in AWS like DynamoDB, SNS and so on; S3 is present in the list.
  2. In order to expose the Lambda externally you will need to connect it via API Gateway, another tool provided by AWS.
    In the example I shared above I configured API Gateway to trigger my Lambda function when someone is calling a specific URL.
  3. The fastest way, and my personal recommendation, to work with AWS Lambda is via a CLI tool like Serverless Framework, you won’t need to configure manually API Gateway and your Lambda environment because Serverless Framework will provide a boilerplate to work with.
    On top of that it will allow you to test your Lambda functions locally without uploading them every time on AWS.
    There are many other CLI tools available but at the moment Serverless is the most complete and documented with a large community behind it.
  4. Recently Amazon added the possibility to set environment variables for Lambda functions, therefore if your project requires them you will have the possibility to configure easily via AWS console or inside Serverless framework configuration file.
  5. If you don’t want to upload a CLI tool with the node_modules folder, you can create an executable with all static dependencies and upload just that file inside the ZIP file.
    For Node I found a tool that works pretty well with Webpack and NPM called EncloseJS.
  6. Remember to not abuse the power of the serverless ecosystem but understand the pros and the cons before starting using it because in some cases it’s definitely not the right choice
  7. An important consideration of the combination API Gateway + Lambda is that could work with HTTP2 protocol out of the box and you can use Cloudfront to cache your responses (also if they are dynamic) with just few configurations to set in the API Gateway console.
  8. With Lambda you pay just what you use, therefore if you use it for cron services, automation pipelines, triggering databse backup operations or similar, you could end up savings quite few dollars compare to an EC2 instance.

Visual Studio Code extensions demystified

When I tried for the first time Visual Studio Code on my Mac I remained quite impressed about its performances.
The investment Microsoft did during the last few years on this editor is really remarkable, considering also that it’s an open source software and not a commercial one.
As you know with Visual Studio Code you can create your own extensions and then share with the community inside the marketplace.
This for me was just an interesting and quick pet project before going back the my reactive studies, but it is worth to share it

I created a simple extensions for retrieving all the annotations in my Javascript projects grouping per categories inside the output panel or in a markdown file.

vscode-annotations-panel

You can download the extension called vscode-annotations directly from the marketplace or inside the extensions panel in Visual Studio Code editor.
If you want instead take a look to the source, feel free to clone the project from Github.

 

extensionpanel

First steps

If you wanna quickly start working on an extension, there is a Yeoman generator provided by the Visual Studio Code team that will create the folder structure and the necessary files for publishing your extension later on.
In order to use it just run these commands in your terminal window:

npm install -g yo generator-code
yo code

During the generation, the interactive generator will ask if you prefer working with Typescript or pure Javascript, in my case I picked the latter one.
After that you will have your project ready and you can start to have fun with Visual Studio Code!
if you prefer start with the classic Hello World project feel free to check Microsoft tutorial.

In my annotations extension what I’ve done is just providing 3 commands available in the command palette (CMD+SHIFT+P or View > Command Palette) :

. output all the annotations in the file opened inside the editor
. output all the annotations in a specific project
. export all the annotations in a specific project to a Markdown file

The first two will create an output panel inside the editor showing the annotations present inside a specific file or an entire workspace, the third one will create a markdown file with all the annotations for a specific project.

When you want to create a command inside the command palette, you need to set it up in few files, the first one is the package.json:

"activationEvents": [
     "onCommand:extension.getAnnotations",
     "onCommand:extension.getAllAnnotations",
     "onCommand:extension.createAnnotationsOutput"
 ]

and then in the commands array:

"contributes": {
    "commands": [
    {
        "command": "extension.getAnnotations",
        "title": "ANNOTATIONS: check current file"
    },
    {
        "command": "extension.createAnnotationsOutput",
        "title": "ANNOTATIONS: export markdown file"
    },
    {
        "command": "extension.getAllAnnotations",
        "title": "ANNOTATIONS: check current project"
    }]
 }

so in the commands array we are just defining the label that will be inside the command palette and the action that should be triggered when the user selects a specific command.
Then we will need to add each of them in the extension.js file (created by the scaffolder) inside the activate method that will be triggered once the editor will have loaded your extension:

vscode.commands.registerCommand('extension.getAnnotations', function () {
    // extension code here
 });

Just with these few lines of code you can see the expected results of having your commands present in the palette

vscode-annotations-palette

Microsoft is providing a well documented APIs for interacting with the editor, obviously, because it’s based on Electron bear in mind that you can also use Node.js APIs for extending the functionalities of your extension, for instance to create a file or interacting with the operating system.

Working with the workspace

When you want to interact with the editor manipulating files or printing inside the embedded console you need to deal with the workspace APIs.
In order to do that you need to become confident with a couple of objects of the vscode library:

  • window
  • workspace

With window and workspace you can handle end to end the editor UI and the project selected.
Window object is mainly use to understand what’s happening inside a file meanwhile an user is editing it.
You can also use the window object for showing notification or error messages or change the status bar

With the workspace object instead, you will be able to manage all the interactions that are happening inside the menu or editor interface.
Workspace object is useful when you want to iterate trough the project files or if you need to understand which files are currently open in the editor and when they will be closed for instance.

In my extension I used these 2 objects for showing a notification to the user:

vscode.window.showErrorMessage('There aren\'t javascript files in the open project!');

for interacting with the output panel:

vscode.window.createOutputChannel(outputWin_NAME);

[....]

outputWin.appendLine(`FILE -> file://${doc.fileName}`);
outputWin.appendLine("-----------------------------------------");
outputWin.appendLine(getBody(data, OUTPUT_PANEL_CONFIG))
outputWin.appendLine(OUTPUT_PANEL_CONFIG.newline);

outputWin.show(true);

and for iterating and opening a javascript file present inside a proejct:

vscode.workspace.openTextDocument(file.path)

[...]

vscode.workspace.findFiles('**/*.js', '**/node_modules/**', 1000).then(onFilesRetrieved)

Debugging an extension

Considering you are developing an extension for an editor you can easily debug what you are doing simply running the extension debug mode (F5 or fn+F5 from your macbook).

screen-shot-2017-01-31-at-04-06-39

Few suggestions regarding the debug mode:

  • console.dir doesn’t work, console.log will substitute what console.dir does if you are inspecting an object but not an array!
  • when an error occurs it’s not very self-explained (kudos to Facebook for the react native errors handling, best implementation ever!) so you will need to follow the stack trace as usual

Publishing an extension

Last part of this brief post will be related to the submission of your extension to the Visual Studio Code marketplace.
Also in this case Microsoft did a good job creating an extensive guide on how to do that, few suggestions also in this case:

  • in order to submit an extension in the marketplace you will need to create a Microsoft and a Visual Studio Team Service accounts
  • when you create the Personal Access Token for publishing your extension, bear in mind to set access to all accounts and all scope otherwise you could end up with a 401 or 404 error when you try to publish the extension
    screen-shot-2017-01-31-at-04-26-47
  • vsce command line tool is pretty good in order to create a publisher identity and super fast to publish an application on the marketplace.
    Considering that is a CLI tool you can also automate few part of the publishing process (increasing release number for instance) adding a scripts in your package.json
  • to make your extension more accessible in the marketplace, remember to add the keywords array inside the package.json with meaningful words and the appropriate category, at the moment there are the following categories available:
    Debuggers
    Extension Packs
    Formatters
    Keymaps
    Languages
    Linters
    Snippets
    Themes
    Other

    screen-shot-2017-01-31-at-22-14-31

Wrap up

There could be tons of other things to do and to discover for developing a Visual Studio Code extension but I think that could be a good recap of the lessons learnt for creating one that you could use along with the Microsoft guide.

HTTP2: the good, the bad and the ugly

I spent last few weeks investigating on HTTP2, the successor of HTTP1.1 and I’d like to share my findings and thoughts in this post.

Let’s start saying that if the question you have in mind at this point is: “Can I really use it today, not only for experiments but also in production?”
My answer would be: “YES, you can!”

First of all, I’d like to share with you the browsers implementation status for this protocol

screen-shot-2016-09-06-at-23-00-23

As you can see from the screenshot taken from caniuse.com it’s definitely well supported on the latest version of the major browsers with some caveats obviously.

If you are not convinced yet, please check this website with one of the browsers that currently supports HTTP2 and look how fast to load is!
I’d suggest to install the HTTP2 indicator Chrome extension to discover how many web apps or online services are using this protocol:

screen-shot-2016-09-07-at-21-41-09

Not yet convince?! OK let’s move to a deeper analysis then!

HTTP2 is a binary protocol with a multiplexing requests method implemented, that means all the browser requests will be handled asynchronously.

This massive change will increase drastically the performance of your application.
Considering at the moment a browser can download simultaneously a maximum of 5 resources per domain (let’s avoid talking about “resource sharding” for now), with HTTP2 we will be able to request all the resources and render them when the browser will accomplish their download, check this demo made with Go Lang for a proper comparison between the 2 protocols and check also the Network panel in the Chrome Dev Tools or Firefox dev tools in order to understand how the 2 protocols differ.

The Good

HTTP2 has really few rules in order to be implemented:

  • it works ONLY with https protocol (therefore you need a valid SSL certificate)
  • it’s backward compatible, so if a browser or a device where your application is running, don’t support HTTP2 it will fall back to HTTP1.1
  • it comes with great performance improvements out-of-the-box
  • it doesn’t require to do anything on the client side but on the server side for a basic implementation
  • few new interesting features will allow to speed up the load of your web project in a way that is not even imaginable with HTTP1.1 implementation

Despite the short list, HTTP2 is bringing a substantial change to the internet ecosystem.
One of my favourite feature is the server PUSH where a server can pass a link header specifying what the browser should download in advance before starting to parse entirely the HTML document.
In this case, we can educate the browser to download several resources like images, css or even javascript files before the engine recognise them inside the DOM, providing a better user experience to our web apps and/or games.

The Bad

There is still plenty of works to do in order to have a great penetration of this protocol, few specs are still on going (read the next paragraph: the ugly) and probably it will take quite few months before we will see a lot of services moving to this new protocol.

A part from the high level overview of the downsides, let’s look what will change on the technical side.

Considering that HTTP2 is not restrict on the amount of requests a browser is doing in order to download resources few techniques for optimising our websites will need to be reviewed or even removed from our pipeline.
Delivering all the application inside a unique javascript file won’t have any benefit with HTTP2, so we need to move our logic downloading only what we need when we need it.
Knowing that downloading large files won’t be a problem we could use sprites instead of several small images to handle the icons of our website.
Probably the different tools like Grunt, Gulp or Webpack will need to review their strategies or update their plugin in order to provide real value to this new project pipeline.

The Ugly

Google Chrome protocol implementation!
Chrome is my favorite browser and I use it extensively, in particular, when I need to debug a specific script or I need to gather metrics from a specific behavior of a web app.
At the moment it’s the only browser that requires HTTP2 server negotiation via ALPN (Application-Layer Protocol Negotiation) that basically is an extension allowing the application layer to negotiate which protocol will be used within the TLS connection.

Considering that OpenSSL integrates ALPN only from version 1.0.2, we won’t be able to enable HTTP2 protocol support for Chrome (from build 51 and above) if we don’t configure our server correctly.
For instance, on Linux OS, only Ubuntu from version 16.04 has that OpenSSL version installed by default, for all the other major Linux version you will either install the newer version manually or you’ll need to wait for the next major OS release.

I’d suggest reading carefully the article that describes this “issue” on ngnix blog before you start to configure your server for Chrome.

Wrap up

HTTP2 is not perfect and probably is not supported as it should be but, definitely, could improve (drastically in certain cases) your web project performance.
A lot of “big players” are already using HTTP2 protocols in production (Instagram, Twitter or Facebook for instance) and the results are remarkable.

Why not starting catching up with the future today?

Hot and Cold observables

One important thing to understand when you are working with Reactive Programming is the difference between hot and cold observables.
Let’s start with the definition of both types:

Cold Observables

Cold observables start running upon subscription: the observable sequence only starts pushing values to the observers when subscribe is called.

Values are also not shared among subscribers.

Hot Observables

When an observer subscribes to a hot observable sequence, it will get all values in the stream that are emitted after it subscribes.

The hot observable sequence is shared among all subscribers, and each subscriber is pushed the next value in the sequence.

Let’s see now how these 2 different observables are used across a sample application.

Using the same application I started to describe in my previous blog post, we can spot in the main class some code that is commented.
The first part represent how a cold observable works, so if you try to have the following code inside App.js you can immediately understand what’s going on when an observer subscribes to a cold observable:

let engine = new BallsCallSystem(); 
let t1 = new Ticket("t1", engine.ballStream); 

setTimeout(()=>{
    let t2 = new Ticket("t2", engine.ballStream);
}, 5000);

engine.startGame();

Our game engine instead has the following code in order to share the balls called across the tickets:

let stream = Rx.Observable
    .interval(INTERVAL)
    .map((value) => {return numbersToCall[value]})
    .take(TOTAL_CALLS);
 
this.published = stream.publish();

As you can see when we start the game there is only 1 ticket bought by the user, then after 5 seconds the user bought a new ticket and in theory we should check if in that ticket all the numbers previously called are present or not.

coldObservables
But with cold observables when an observer subscribe, it won’t be able to receive the previous data but just the data since when it subscribed, completely broken the main purpose of our bingo game… we definitely need something different in order to work with it, potentially something that won’t completely change our game logic but that could be useful to fix the issue…

That’s where the hot observables come in!
The cool part of hot observables is that you can define how much data you want to buffer inside the memory, sometimes you need to store all of them (like in the bingo game) sometimes you need only the last 4-5 occurrences, but as you will see changing from a cold to an hot observables it’s a matter of 1 line of code!

Inside the same git repo, you can find a class called BallsCallSystemReplay, this class implement an hot observable, let’s see how much the code changed inside our game engine:

this.stream = Rx.Observable
   .interval(INTERVAL)
   .map((value) => {return numbersToCall[value]})
   .take(TOTAL_CALLS)
   .shareReplay();

Basically we removed the publish method after creating the stream (that was useful if you want to control when the observable starts to stream data) and we added shareReplay that is a method that transform a cold observable to an hot one sharing all the data pass trough the stream every time a new observer subscribe to it.

So now if we change the code in App.js in this way:

let engine = new BallsCallSystemReplay();
let t1 = new Ticket("t1", engine.ballStream);
 
setTimeout(function() {
    let t2 = new Ticket("t2", engine.ballStream);
}, 5000);

Now you can see that when the second ticket is bought after the game started, we’re going anyway to check all the values called by the engine without doing a massive refactor of our game logic! Below you can see when the second ticket subscribe to the hot observable, the first thing is going to receive are all the previous values called by the engine and then is receiving the data with a certain interval following the logic of the game.

hotObservables