SlideShare a Scribd company logo
at

Composable and streamable Play apps
About me

Part of the Service Infrastructure team, which is bringing
the Play Framework to LinkedIn engineers.
At LinkedIn, we’ve been running Play apps
in production for over a year
More than 60 apps on Play now, including:

Recommended for you

Spring Security
Spring SecuritySpring Security
Spring Security

This session will explain 'Spring Security', a powerful and highly customizable authentication and access-control framework.

springspring securityjava
What is tackled in the Java EE Security API (Java EE 8)
What is tackled in the Java EE Security API (Java EE 8)What is tackled in the Java EE Security API (Java EE 8)
What is tackled in the Java EE Security API (Java EE 8)

The Java EE Security API (JSR-375) wants to simplify the implementation of security-related features in your Java EE application. Application server specific configuration changes will be no longer needed and things will be much more app developer friendly. Aligning security with the ease of development we saw in the recent version of Java EE. We will show you the basic goals and concepts behind Java EE Security API. And of course, demos with the current version of the RI, named Soteria, how you can do Authentication and Authorization.

javaee jsr375 security soteria
From a monolith to microservices + REST: The evolution of LinkedIn's architec...
From a monolith to microservices + REST: The evolution of LinkedIn's architec...From a monolith to microservices + REST: The evolution of LinkedIn's architec...
From a monolith to microservices + REST: The evolution of LinkedIn's architec...

This is the story of LinkedIn's journey from a monolithic web application to a microservice based architecture, some of the challenges they faced along the way, and the tools they built to make this transition possible, including the Rest.li and Deco frameworks.

microservicesarchitecturerestli
Channels
Recruiter Mobile
Jobs
Polls in Groups

Recommended for you

GraphQL
GraphQLGraphQL
GraphQL

This presentation explores the concepts around facebook query language for information retrieval & transformation.

graphqlfacebookquery language
Service workers
Service workersService workers
Service workers

Service Workers is coming. Bring your own magic with the first programmable cache in your script, and more! Presented at the GDG Korea DevFest 2014 on the 31st of May 2014: https://sites.google.com/site/gdgdevfestkorea2014/

gdg devfestservice worker
Spring Security 5
Spring Security 5Spring Security 5
Spring Security 5

This document provides an overview of Spring Security including: I. It distinguishes Spring Framework, Spring Boot, and Spring Security and their relationships. II. It defines Spring Security as a framework focusing on authentication and authorization for Java applications. III. It outlines some of the core concepts in Spring Security such as Principal, Authentication, Authorization, GrantedAuthority etc. The document serves as an introduction to Spring Security fundamentals and architecture.

spring securityspring security 5
Play Labs (e.g. InDemand)
Many internal tools (e.g. REST search)
Plus many backends services that don’t
have sexy screenshots
We love Play… but we’ve had a
couple tiny problems:

Recommended for you

REST vs GraphQL
REST vs GraphQLREST vs GraphQL
REST vs GraphQL

This presentation takes you through the basics of GraphQL and the differences between the approaches of building an API in REST and GraphQL.

graphqlapirest api
OAuth2 and Spring Security
OAuth2 and Spring SecurityOAuth2 and Spring Security
OAuth2 and Spring Security

The document discusses OAuth2 and Spring Security. It provides an overview of OAuth2 concepts including the four main roles (resource owner, resource server, client, and authorization server), four common grant types (authorization code, implicit, resource owner password credentials, and client credentials), and how to implement OAuth2 flows in Spring Security. Sample OAuth2 applications using Spring Security are also mentioned.

oauthsecurityjava
Lets make a better react form
Lets make a better react formLets make a better react form
Lets make a better react form

Use Higher oder components to separate complicated validation logics from the UI components and make them to be more pure, simpler and easier to test.

reactreact.jsredux
We love Play… but we’ve had a
couple tiny problems:
1. Unmanageable complexity
We love Play… but we’ve had a
couple tiny problems:
1. Unmanageable complexity
2. Terrible performance
It’s probably not what you think.
This talk is about a couple techniques to
deal with complexity and performance
problems.

Recommended for you

Express JS
Express JSExpress JS
Express JS

Express is a web framework for Node.js that allows routing, middleware, templating and more. It is inspired by Sinatra and uses Connect as its middleware framework. Key features include routing, middleware support, template rendering with engines like Jade, and session handling with storage options. Errors can be handled via the app.error() method. Express provides a full-featured and easy to use web development framework for Node.js.

nodejsweb design and development
Spring Boot
Spring BootSpring Boot
Spring Boot

Spring Boot is a framework for creating stand-alone, production-grade Spring based applications that can be "just run". It takes an opinionated view of the Spring platform and third-party libraries so that new and existing Spring developers can quickly get started with minimal configuration. Spring Boot aims to get developers up and running as quickly as possible with features like embedded HTTP servers, automatic configuration, and opinions on structure and dependencies.

spring frameworkjavaspring boot
Event-driven microservices
Event-driven microservicesEvent-driven microservices
Event-driven microservices

1) Event-driven microservices involve microservices communicating primarily through events published to an event backbone. This loosely couples microservices and allows for eventual data consistency. 2) Apache Kafka is an open-source streaming platform that can be used to build an event backbone, allowing microservices to reliably publish and subscribe to events. It supports streaming, storage, and processing of event data. 3) Common patterns for event-driven microservices include database per service for independent data ownership, sagas for coordinated multi-step processes, event sourcing to capture all state changes, and CQRS to separate reads from writes.

apache kafkamicroservicesevent-driven
These techniques are experimental.
But fun.
Enjoy!
You can find the code from this presentation at:
https://github.com/brikis98/ping-play

Recommended for you

NestJS
NestJSNestJS
NestJS

NestJS (https://nestjs.com/) is a Node.js framework for building server-side applications. This slide give you a brief introduction of Nest, and shows the examples like Service, Middleware, and Pipe, etc.

javascriptjsnodejs
Building secure applications with keycloak
Building secure applications with keycloak Building secure applications with keycloak
Building secure applications with keycloak

Building an enterprise level single sign-on application with the help of keycloak (Open Source Identity and Access Management). And understanding the way to secure your application; frontend & backend API’s. Managing user federation with minimum configuration.

jsfoojsfoopunekeycloak
REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with Spring

This talk introduces Spring's REST stack - Spring MVC, Spring HATEOAS, Spring Data REST, Spring Security OAuth and Spring Social - while refining an API to move higher up the Richardson maturity model

datarepositoryrest
Outline
1. Complexity
2. Composition
3. HTTP
4. Performance
5. Enumerators
6. Streaming
Outline
1. Complexity
2. Composition
3. HTTP
4. Performance
5. Enumerators
6. Streaming
Web pages can get complex
For example, consider the LinkedIn home page

Recommended for you

Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...
Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...
Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...

This document outlines an AngularJS certification training agenda that covers directives. It defines directives as classes that extend HTML and transform the DOM. There are three types of directives: components, structural directives, and attribute directives. Built-in directives like NgFor and NgIf are covered, which add and remove elements. The document demonstrates how to create a custom attribute directive by using the @Directive decorator and accessing native DOM elements.

edurekaangular directives advanceangularjs custom directives
Graphql
GraphqlGraphql
Graphql

This document provides an introduction and overview of GraphQL, including: - A brief history of GraphQL and how it was created by Facebook and adopted by other companies. - How GraphQL provides a more efficient alternative to REST APIs by allowing clients to specify exactly the data they need in a request. - Some key benefits of GraphQL like its type system, declarative data fetching, schema stitching, introspection, and versioning capabilities. - Some disadvantages like potential complexity in queries and challenges with rate limiting.

Play Framework: async I/O with Java and Scala
Play Framework: async I/O with Java and ScalaPlay Framework: async I/O with Java and Scala
Play Framework: async I/O with Java and Scala

This document discusses asynchronous I/O in Java and Scala using the Play Framework. It describes how LinkedIn uses a service-oriented architecture with hundreds of services making requests to each other. It then covers how Play supports non-blocking I/O using asynchronous code, promises, and futures to allow parallel requests without blocking threads. Key points covered include using map and flatMap to transform promises and futures, handling errors and timeouts, and the benefits of non-blocking I/O for scalability.

play frameworkjavalinkedin
Almost every part of the page is dynamic, highly
customized for the user, and interactive.
Trying to cram this all into one controller and
one template is completely unmaintainable
“Managing complexity is the most important
technical topic in software development.”
Steve McConnell, Code Complete
Abstraction and Composition

Recommended for you

LinkedIn - A highly scalable Architecture on Java!
LinkedIn - A highly scalable Architecture on Java!LinkedIn - A highly scalable Architecture on Java!
LinkedIn - A highly scalable Architecture on Java!

The document summarizes the evolution of LinkedIn's communication platform and network updates system from handling 0 to 23 million members. It describes how the initial communication platform was built on Java and used technologies like Tomcat, ActiveMQ, and Spring. It then discusses how the network updates system transitioned from a pull-based to push-based architecture to more efficiently distribute updates across the growing user base. Key challenges addressed in scaling the systems included partitioning data and services, optimizing database usage, and building for asynchronous flows and failure handling.

The Play Framework at LinkedIn
The Play Framework at LinkedInThe Play Framework at LinkedIn
The Play Framework at LinkedIn

Video of the presentation: http://www.youtube.com/watch?v=8z3h4Uv9YbE At LinkedIn, we have started to use the Play Framework to build front-end and back-end services at massive scale. Play does things a little differently: it's a Java and Scala web framework, but it doesn't follow the servlet spec; it's fairly new, but it runs on top of robust technologies like Akka and Netty; it uses a thread pool, but it's built for non-blocking I/O and reactive programming; most importantly, it's high performance, but also high productivity. We've found that the Play Framework is one of the few frameworks that is able to maintain the delicate balance of performance, reliability, and developer productivity. In the Java and Scala world, nothing even comes close. In this talk, I'll share what we've learned so far, including details of rapid iteration with Java and Scala, the story behind async I/O on the JVM, support for real time web apps (comet, WebSockets), and integrating Play into a large existing codebase.

play frameworkweb developmentjava
An intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECSAn intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECS

This talk is a very quick intro to Docker, Terraform, and Amazon's EC2 Container Service (ECS). In just 15 minutes, you'll see how to take two apps (a Rails frontend and a Sinatra backend), package them as Docker containers, run them using Amazon ECS, and to define all of the infrastructure-as-code using Terraform.

dockerdevopssoftware
“Abstraction is the ability to engage with a
concept while safely ignoring some of its details.”
Steve McConnell, Code Complete
Abstraction allows you to take a simpler view of a
complex concept
Composition: assemble complex behavior by
combining simpler behavior
Composable and streamable Play apps

Recommended for you

Introduction to Iteratees (Scala)
Introduction to Iteratees (Scala)Introduction to Iteratees (Scala)
Introduction to Iteratees (Scala)

Slides originating from a talk I gave at ScalaMUC on 2013-12-17. The corresponding code can be found at https://github.com/afwlehmann/iteratee-tutorial .

playiterateescala
Node.js vs Play Framework (with Japanese subtitles)
Node.js vs Play Framework (with Japanese subtitles)Node.js vs Play Framework (with Japanese subtitles)
Node.js vs Play Framework (with Japanese subtitles)

Video: http://www.nicovideo.jp/watch/1410857293 Here's the showdown you've been waiting for: Node.js vs Play Framework. Both are popular open source web frameworks that are built for developer productivity, asynchronous I/O, and the real time web. But which one is easier to learn, test, deploy, debug, and scale? Should you pick Javascript or Scala? The Google v8 engine or the JVM? NPM or Ivy? Grunt or SBT? Two frameworks enter, one framework leaves. This version of the presentation has Japanese subtitles. For the English only version, see http://www.slideshare.net/brikis98/nodejs-vs-play-framework

javaweb developmentjavascript
Infrastructure as code: running microservices on AWS using Docker, Terraform,...
Infrastructure as code: running microservices on AWS using Docker, Terraform,...Infrastructure as code: running microservices on AWS using Docker, Terraform,...
Infrastructure as code: running microservices on AWS using Docker, Terraform,...

This is a talk about managing your software and infrastructure-as-code that walks through a real-world example of deploying microservices on AWS using Docker, Terraform, and ECS.

devopssoftwareaws
Abstraction: structure your app so you
can focus on one part while safely
ignoring the rest
Abstraction: structure your app so you
can focus on one part while safely
ignoring the rest

Composition: structure your app so
you can easily combine the simpler
parts into more complicated parts
Outline
1. Complexity
2. Composition
3. HTTP
4. Performance
5. Enumerators
6. Streaming
We’ll start by building a completely standalone “Who’s
Viewed Your Profile” (WVYP) module

Recommended for you

Iteratee and stream with Play2 scala
Iteratee and stream with Play2 scalaIteratee and stream with Play2 scala
Iteratee and stream with Play2 scala

This document discusses managing streams with Iteratee and Play framework. It provides an example of using Iteratee to handle an HTTP request body stream by consuming it chunk by chunk to calculate a hash, without loading the entire body into memory. Iteratee allows streaming data to be processed in a modular way without blocking threads. The document encourages using the coupon code "tokyoscala" for free hosting on Clever Cloud.

streamscala
Data Workflows for Machine Learning - SF Bay Area ML
Data Workflows for Machine Learning - SF Bay Area MLData Workflows for Machine Learning - SF Bay Area ML
Data Workflows for Machine Learning - SF Bay Area ML

Presented at SF Bay Area ML meetup (2014-04-09) http://www.meetup.com/SF-Bayarea-Machine-Learning/events/173759442/

machine learningbig dataenterprise data workflows
From Data to Decisions Makers: A Behind the Scenes Look at Building The Most ...
From Data to Decisions Makers: A Behind the Scenes Look at Building The Most ...From Data to Decisions Makers: A Behind the Scenes Look at Building The Most ...
From Data to Decisions Makers: A Behind the Scenes Look at Building The Most ...

The document discusses building the Verizon Data Breach Investigations Report (DBIR), the most respected report in cybersecurity. It involves analyzing over 200 million records of security incidents and data breaches from over 20,000 organizations. Researchers use R and R Markdown to analyze the data, create visualizations, and document their findings. Lessons learned include using version control, packages over loose scripts, and ensuring analyses can be reproduced with the same data and code.

data visualizationcybersecurityr
We need:
1. Data: WVYP count, search count
2. Template: to render the HTML
3. Controller: to tie it all together
Backend
Server
Frontend
Server
Internet

Load
Balancer

Backend
Server

Frontend
Server

Data
Store

Backend
Server

Frontend
Server

Backend
Server
Backend
Server

Data
Store

Data
Store

Data
Store

For data, LinkedIn uses a Service Oriented Architecture
For this talk, we’re going to simulate service
calls by calling a mock endpoint
object Mock extends Controller {
def mock(serviceName: String) = Action.async {
serviceName match {
case "wvyp" => respond(data = "56", delay = 10)
case "search" => respond(data = "10", delay = 5)
case "likes" => respond(data = "150", delay = 40)
case "comments" => respond(data = "14", delay = 20)
}
}

private def respond(data: String, delay: Long) = Promise.timeout(Ok(data), delay)
}

app/mock/Mock.scala

For each “service”, this endpoint returns mock data after a
fixed delay. In the real world, the data might be JSON.

Recommended for you

Chicago Hadoop Users Group: Enterprise Data Workflows
Chicago Hadoop Users Group: Enterprise Data WorkflowsChicago Hadoop Users Group: Enterprise Data Workflows
Chicago Hadoop Users Group: Enterprise Data Workflows

Cascading is an open source framework for building enterprise data workflows. It provides a simple API and domain-specific languages to build robust applications that can operate at scale. Cascading uses a pattern language to ensure best practices and uses taps to integrate different data sources. It supports various topologies including Hadoop, local mode, and in-memory grids.

hadoopdata sciencecascading
Spring 3.1 and MVC Testing Support - 4Developers
Spring 3.1 and MVC Testing Support - 4DevelopersSpring 3.1 and MVC Testing Support - 4Developers
Spring 3.1 and MVC Testing Support - 4Developers

Please note that this presentation is an abridged version of the one given by Rossen Stoyanchev and me at SpringOne 2GX 2012. This session will give attendees an overview of the new testing features in Spring 3.1 as well the new Spring MVC test support. Sam Brannen will demonstrate how to use the Spring TestContext Framework to write integration tests for Java-based Spring configuration using @Configuration classes. He'll then compare and contrast this approach with XML-based configuration and follow up with a discussion of the new testing support for bean definition profiles. Next, attendees will see how testing server-side code with annotated controllers and client-side code with the RestTemplate just got a whole lot easier with the new Spring MVC test support. Come to this session to see these new Spring testing features in action.

springjavamvc
Reactive Programming With Akka - Lessons Learned
Reactive Programming With Akka - Lessons LearnedReactive Programming With Akka - Lessons Learned
Reactive Programming With Akka - Lessons Learned

This presentation was given by Daniel Deogun and Daniel Sawano at the 33rd Degree Conference, Krakow, 2014. When mentioning Akka, most of us think of a framework allowing one to design high performant, scalable, and fault tolerant systems. But the question is, how can one utilize the power of reactive programming when surrounded by legacy? In this talk, we will share our insights and experiences from developing high performance systems with Akka. Despite that Akka APIs are more favorable in Scala, we have chosen and successfully used Akka’s Java APIs. A strategy that may have significant impact on the business and the success of a project. In addition, we will present how domain specific requirements influences your design options, the traps we have walked into, and how everyone may benefit from Akka regardless of green or brown field development.

33rd degree conferencereactiveakka
GET

/mock/:serviceName

controllers.Mock.mock(serviceName: String)

conf/routes

The routes entry for the mock endpoint
object ServiceClient {
def makeServiceCall(serviceName: String): Future[String] = {
WS.url(s"http://localhost:9000/mock/$serviceName").get().map(_.body)
}
}

app/data/ServiceClient.scala

A simple client to make a remote call to the mock endpoint
and return a Future with the body of the HTTP response
@(wvypCount: Int, searchCount: Int)
<html>
<head>
<link rel="stylesheet" href="/assets/stylesheets/wvyp.css"/>
</head>
<body>
<div class="wvyp">
<h2>Who's Viewed Your Profile</h2>
@views.html.wvyp.wvypCount(wvypCount)
@views.html.wvyp.searchCount(searchCount)
</div>
</body>
</html>

app/views/wvyp/wvyp.scala.html

For the template, we use Play’s Scala templates (.scala.
html). This template uses two partials for the body.
@(wvypCount: Int)

<p class="wvyp-count">
<span class="large-number">@wvypCount</span>
<span>Your profile has been viewed by <b>@wvypCount</b> people in the past 3 days</span>
</p>

app/views/wvyp/wvypCount.scala.html
@(searchCount: Int)

<p class="search-count">
<span class="large-number">@searchCount</span>
<span>Your have shown up in search results <b>@searchCount</b> times in the past 3 days</span>
</p>

app/views/wvyp/searchCount.scala.html

The markup for the two partials that show the counts

Recommended for you

The no-framework Scala Dependency Injection Framework
The no-framework Scala Dependency Injection FrameworkThe no-framework Scala Dependency Injection Framework
The no-framework Scala Dependency Injection Framework

Using a DI framework/container may seem obvious. But when was the last time you considered *why* do you really need one? After all, "dependency injection" is just a fancy name for passing arguments to a constructor. In the talk we'll walk through some of the features of DI containers and see if we can replace them with pure Scala code. We'll start with "manual" DI, followed with using MacWire to generate the wiring code for us. Then we'll proceed to a no-framework scopes implementation (e. g. request or session), which are very useful in web applications. We will also discuss possibilities of adding interceptors using macros. And finally, we'll see how to use traits to create and compose modules (similar to the module concept known from Guice), which can be viewed as a simplified cake pattern. As MacWire heavily uses macros, as a bonus, I'll explain how Scala Macros work and when they can be useful.

macwireframeworksdependency injection
A Sceptical Guide to Functional Programming
A Sceptical Guide to Functional ProgrammingA Sceptical Guide to Functional Programming
A Sceptical Guide to Functional Programming

This document provides a skeptical guide to functional programming through a series of slides presented at a BASH event. It begins by acknowledging that the presenter likes FP but is skeptical of FP programmers. It then discusses some functional programming languages like Lisp, Haskell, and Scala. It explores the differences between pure and hybrid languages. Several slides provide examples of code in languages like Clojure and Scala to demonstrate functional concepts. The presentation questions whether the language itself matters and argues the audience may already be using FP techniques without realizing it.

c#javaclojure
Actor Based Asyncronous IO in Akka
Actor Based Asyncronous IO in AkkaActor Based Asyncronous IO in Akka
Actor Based Asyncronous IO in Akka

Asynchronous IO is one of the most important building blocks when designing high-performance systems. Over the years various patterns emerged on top of the selector based services provided by the operating system. In this talk I will give a quick overview of the most important asynchronous IO patterns from callbacks to iteratees. Finally I will show how these approaches map to the actor world, introducing the new IO model designed by the Akka and Spray team available in Akka 2.2.

akkaioasynchronous
object WVYP extends Controller {
def index = Action.async {
val wvypCountFuture = ServiceClient.makeServiceCall("wvyp")
val searchCountFuture = ServiceClient.makeServiceCall("search")

}
}

app/controllers/WVYP.scala

Next, the WVYP controller. First, we make two service calls in
parallel to fetch the WVYP count and search count.
object WVYP extends Controller {
def index = Action.async {
val wvypCountFuture = ServiceClient.makeServiceCall("wvyp")
val searchCountFuture = ServiceClient.makeServiceCall("search")

for {
wvypCount <- wvypCountFuture
searchCount <- searchCountFuture
} yield {
Ok(views.html.wvyp.wvyp(wvypCount.toInt, searchCount.toInt))
}
}
}

app/controllers/WVYP.scala

Next, we compose the two Futures into a single Future and
render the WVYP template.
GET

/mock/:serviceName

controllers.Mock.mock(serviceName: String)

GET

/wvyp

controllers.WVYP.index

conf/routes

Add a routes entry for the WVYP controller
The result

Recommended for you

Effective akka scalaio
Effective akka scalaioEffective akka scalaio
Effective akka scalaio

This document contains slides from a presentation on effective actor patterns in Akka. It discusses patterns like using extra actors to handle individual messages without blocking the original actor. It also covers request aggregation, where an actor delegates work to multiple services concurrently. The document emphasizes testing actors and provides an example test for an actor that retrieves account balances from multiple services.

DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...
DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...
DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...

Выступление на DUMP-2015.

конференцияdump-2015
Playing with Scala
Playing with ScalaPlaying with Scala
Playing with Scala

A fast intro to Scala and Play, to prepare the audience for a live demo of a Play Application using Futures to get weather data from Yahoo in a non blocking way, then display to the user the results. The code is available here https://github.com/tabdulradi/weather

play frameworkfuturesscala
We now have one small module
Now, imagine we also have another standalone module
called “Who’s Viewed Your Updates” (WVYU)
GET

/mock/:serviceName

controllers.Mock.mock(serviceName: String)

GET

/wvyp

controllers.WVYP.index

GET

/wvyu

controllers.WVYU.index

conf/routes

It has a controller, template, and routes entry just like WVYP
How can we combine the two modules?

Recommended for you

[Start] Playing
[Start] Playing[Start] Playing
[Start] Playing

「PlayFramework関西ビギナーズ in OsakanSpace 第1回」 http://atnd.org/events/33666 Play frameworkの概要と今後についてゆるく説明して、 Playとそのコミュニティを雰囲気を知っていただこうという趣旨で発表しました。 参加された方の半数がPHPユーザだったので、冒頭でPHPユーザの方向けの説明を特別に入れたりして工夫しています。

play frameworkplay framework 2.0play framework 2.1
Server side rendering with React and Symfony
Server side rendering with React and SymfonyServer side rendering with React and Symfony
Server side rendering with React and Symfony

This document discusses server-side rendering (SSR) of React components with Symfony. It begins with an overview of the problems SSR addresses like slow page loads. It then covers key React concepts like components, state, and rendering. Finally, it discusses integrating React and Symfony through tools like React on Rails, React Router for routing, and extracting meta tags from components. It also briefly mentions using an external JavaScript server to render components on the server-side.

reactreactjsphp
Angular resolver tutorial
Angular resolver tutorialAngular resolver tutorial
Angular resolver tutorial

This document discusses Angular resolvers, which are used to pre-fetch data before navigating to a component. Angular resolvers implement the Resolve interface to return data via Observable or Promise before the route is activated. An example is provided demonstrating how to create a resolver service to fetch product data from an API, configure routes to use the resolver, and access the resolved data in a component. A loading spinner is also added to improve the user experience while data is loading.

angularangular resolverangular application
trait Action[A] extends EssentialAction {
def apply(request: Request[A]): Future[SimpleResult]
}

play/api/mvc/Action.scala

In Play, an Action is a function
Request[A] => Future[SimpleResult]

The actions in each standalone module are just functions
from Request to Result. Functions can be composed!
@(wvypCount: Int, searchCount: Int)

<html>
<head>
<link rel="stylesheet" href="/assets/stylesheets/wvyp.css"/>
</head>
<body>
@views.html.wvyp.wvypBody(wvypCount, searchCount)
</body>
</html>

app/views/wvyp/wvyp.scala.html

We need one change to each module: move the body into a
partial. Scala templates are functions, so they also compose!
def index(embed: Boolean) = Action.async {
val wvypCountFuture = ServiceClient.makeServiceCall("wvyp")
val searchCountFuture = ServiceClient.makeServiceCall("search")

for {
wvypCount <- wvypCountFuture
searchCount <- searchCountFuture
} yield {
if (embed) Ok(views.html.wvyp.wvypBody(wvypCount.toInt, searchCount.toInt))
else Ok(views.html.wvyp.wvyp(wvypCount.toInt, searchCount.toInt))
}
}

app/controllers/WVYP.scala

Update each module’s controller to accept an “embed”
parameter: if it’s set to true, render only the body partial.

Recommended for you

Itb 2021 - Bulding Quick APIs by Gavin Pickin
Itb 2021 - Bulding Quick APIs by Gavin PickinItb 2021 - Bulding Quick APIs by Gavin Pickin
Itb 2021 - Bulding Quick APIs by Gavin Pickin

In this session we will use ColdBox’s built in REST BaseHandler, and with CBSecurity and Quick ORM we will setup a secure API using fluent query language - and you’ll see how Quick Quick development can be!

quickapicoldbox
MongoDB World 2018: Ch-Ch-Ch-Ch-Changes: Taking Your Stitch Application to th...
MongoDB World 2018: Ch-Ch-Ch-Ch-Changes: Taking Your Stitch Application to th...MongoDB World 2018: Ch-Ch-Ch-Ch-Changes: Taking Your Stitch Application to th...
MongoDB World 2018: Ch-Ch-Ch-Ch-Changes: Taking Your Stitch Application to th...

The document discusses the evolution of MongoDB and the introduction of MongoDB Stitch and Triggers. Key points include: 1) MongoDB Stitch allows developers to build event-driven functions that execute in response to events like database changes or third party webhooks. 2) Stitch Triggers coordinate change streams from MongoDB to pass change events to an event coordinator, which ensures functions execute correctly. 3) An example application called the MongoDB Swagstore is presented to demonstrate how Stitch Triggers could be used to update inventory, send shipping notifications, and more in response to database changes.

mongodbmongodb world
Sherlock Homepage - A detective story about running large web services - NDC ...
Sherlock Homepage - A detective story about running large web services - NDC ...Sherlock Homepage - A detective story about running large web services - NDC ...
Sherlock Homepage - A detective story about running large web services - NDC ...

The site was slow. CPU and memory usage everywhere! Some dead objects in the corner. Something terrible must have happened! We have some IIS logs. Some traces from a witness. But not enough to find out what was wrong. In this session, we’ll see how effective telemetry, a profiler or two as well as a refresher of how IIS runs our ASP.NET web applications can help solve this server murder mystery.

nugetcloudasp.net mvc
GET

/mock/:serviceName

controllers.Mock.mock(serviceName: String)

GET

/wvyp

controllers.WVYP.index(embed: Boolean ?= false)

GET

/wvyu

controllers.WVYU.index(embed: Boolean ?= false)

conf/routes

Update the routes file too
object Pagelet {

def readBody(result: SimpleResult)(implicit codec: Codec): Future[Html] = {
result.body.run(Iteratee.consume()).map(bytes => Html(new String(bytes, codec.charset)))
}
}

app/ui/Pagelet.scala

Add a helper that can take a SimpleResult and return its body
as Future[Html]. We’ll talk more about Iteratees later.
object Aggregator extends Controller {
def index = Action.async { request =>
val wvypFuture = Wvyp.index(embed = true)(request)
val wvyuFuture = Wvyu.index(embed = true)(request)

}
}

app/controllers/Aggregator.scala

Now for the aggregator controller. First, we call the two
submodules. Each returns a Future[SimpleResult].
object Aggregator extends Controller {
def index = Action.async { request =>
val wvypFuture = Wvyp.index(embed = true)(request)
val wvyuFuture = Wvyu.index(embed = true)(request)
for {
wvyp <- wvypFuture
wvyu <- wvyuFuture
wvypBody <- Pagelet.readBody(wvyp)
wvyuBody <- Pagelet.readBody(wvyu)
} yield {

}
}
}

app/controllers/Aggregator.scala

Read the body of each Future[SimpleResult] as Html using
the Pagelet helper we just added

Recommended for you

Behind the scenes of Scaleway Functions : when Kubernetes meets our products
Behind the scenes of Scaleway Functions : when Kubernetes meets our productsBehind the scenes of Scaleway Functions : when Kubernetes meets our products
Behind the scenes of Scaleway Functions : when Kubernetes meets our products

This document provides an overview of Scaleway Functions, a serverless computing platform that allows users to run code without provisioning or managing servers. It discusses key concepts like functions, runtimes, and autoscaling. The platform is built on open source technologies like Kubernetes, Knative, and Istio and leverages Scaleway's container registry, object storage, and Kubernetes services to provide an serverless environment.

scalewayserverless2019
"Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native ""Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native "

Service workers allow web applications to work offline by intercepting network requests, caching responses, and serving cached resources when there is no network connection. They also handle background synchronization and push notifications. Key capabilities include making apps available offline, controlling the cache and network requests, and subscribing to push notifications. Service workers operate separately from the main thread of the page, intercepting and modifying fetch events to return cached responses when available.

javascriptservice workerfrontend
Java servlet life cycle - methods ppt
Java servlet life cycle - methods pptJava servlet life cycle - methods ppt
Java servlet life cycle - methods ppt

This document provides an overview of web application development and servlet technology. It discusses the history and evolution of web pages to dynamic web applications. It then defines web applications and the request-response model. Common Gateway Interface (CGI) is introduced as the first technique for dynamic content, along with its limitations which led to the creation of servlets. Key servlet concepts like the servlet interface, generic servlet, HTTP servlet, and servlet lifecycle methods are covered. The document also examines the HttpServletRequest and HttpServletResponse interfaces and their various methods. Finally, it discusses session tracking approaches including cookies and the session API.

servlet methodsservlet life cyclejava servlet
object Aggregator extends Controller {
def index = Action.async { request =>
val wvypFuture = Wvyp.index(embed = true)(request)
val wvyuFuture = Wvyu.index(embed = true)(request)
for {
wvyp <- wvypFuture
wvyu <- wvyuFuture
wvypBody <- Pagelet.readBody(wvyp)
wvyuBody <- Pagelet.readBody(wvyu)
} yield {
Ok(views.html.aggregator.aggregator(wvypBody, wvyuBody))
}
}
}

app/controllers/Aggregator.scala

Pass the Html to the aggregator template
GET
@(wvypBody:/mock/:serviceName controllers.Mock.mock(serviceName: String)
Html, wvyuBody: Html)
GET

/wvyp

controllers.WVYP.index(embed: Boolean ?= false)

GET
<html>

/wvyu

controllers.WVYU.index(embed: Boolean ?= false)

GET
<head>

/aggregate

controllers.Aggregator.index

<link rel="stylesheet" href="/assets/stylesheets/wvyp.css"/>
<link rel="stylesheet" href="/assets/stylesheets/wvyu.css"/>
</head>
<body>
@wvypBody
@wvyuBody
</body>
</html>

app/views/aggregator/aggregator.scala

Add the aggregator to the routes file
The result. We’ve composed two Play modules!
Wins
1.

Abstraction: we can focus on just one small part of the page while safely
ignoring all the rest.

2.

Composition: we can build complicated pages by putting together simpler
parts. We can get lots of reuse from common pieces.

3.

Testing and iterating on a small, standalone unit is much easier and faster.

Recommended for you

using Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'susing Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API's

Slides from my talk on #ruby-mg meeting. Intro about how we in catars.me are using postgREST to create fast and simple API that can be represented with various mithril.js components.

postgrestapipostgresql
Sherlock Homepage (Maarten Balliauw)
Sherlock Homepage (Maarten Balliauw)Sherlock Homepage (Maarten Balliauw)
Sherlock Homepage (Maarten Balliauw)

The site was slow. CPU and memory usage everywhere! Some dead objects in the corner. Something terrible must have happened! We have some IIS logs. Some traces from a witness. But not enough to find out what was wrong. In this session, we’ll see how effective telemetry, a profiler or two as well as a refresher of how IIS runs our ASP.NET web applications can help solve this server murder mystery.

Sherlock Homepage - A detective story about running large web services (VISUG...
Sherlock Homepage - A detective story about running large web services (VISUG...Sherlock Homepage - A detective story about running large web services (VISUG...
Sherlock Homepage - A detective story about running large web services (VISUG...

The site was slow. CPU and memory usage everywhere! Some dead objects in the corner. Something terrible must have happened! We have some IIS logs. Some traces from a witness. But not enough to find out what was wrong. In this session, we’ll see how effective telemetry, a profiler or two as well as a refresher of how IIS runs our ASP.NET web applications can help solve this server murder mystery.

asp.net mvccsharpcloud
Caveats
1.

Standalone modules may be inefficient in terms of duplicated service calls.
However, de-duping is straightforward.

2.

Have to merge and dedupe static content.
Outline
1. Complexity
2. Composition
3. HTTP
4. Performance
5. Enumerators
6. Streaming
The composition code glosses over a few details
Some questions:
1. How do we set cookies?
2. How do we handle errors?
3. How do we aggregate static content?

Recommended for you

Rethinking Syncing at AltConf 2019
Rethinking Syncing at AltConf 2019Rethinking Syncing at AltConf 2019
Rethinking Syncing at AltConf 2019

Presented this talk at AltConf 2019. Covers typical REST API approach to syncing data between servers and mobile apps; then discusses how new eventually consistent databases with syncing technology built in can be used to make syncing simpler and easier to work with.

iosdevelopmentcouchbase
Into The Box | Alexa and ColdBox Api's
Into The Box | Alexa and ColdBox Api'sInto The Box | Alexa and ColdBox Api's
Into The Box | Alexa and ColdBox Api's

This document provides information on building skills for Alexa using APIs and ColdBox frameworks. It discusses setting up Amazon developer accounts and AWS services accounts. It also covers creating Lambda functions in Node.js to call APIs from Alexa skills and building ColdBox REST APIs to interface with Alexa skills. The document includes code snippets for sample Lambda functions and ColdBox handlers to integrate with Alexa skills.

ortus solutionscfmlcoldfusion
What's new in Rails 5 - API Mode & Action Cable overview
What's new in Rails 5 - API Mode & Action Cable overviewWhat's new in Rails 5 - API Mode & Action Cable overview
What's new in Rails 5 - API Mode & Action Cable overview

Rails 5 introduces several new features including API mode for backend-only applications, improvements to Active Support like ArrayInquirer and pluck, and Action Cable for building real-time features with WebSockets. Action Cable provides a WebSocket backend integrated with Rails that allows broadcasting messages to clients, and a JavaScript library for building the frontend. Before WebSocket, developers used techniques like HTTP polling, long polling, and server-sent events to enable real-time functionality in browsers.

railsrails5websocket
It turns out HTTP is an elegant way to answer
these questions.
object WVYP extends Controller {
def index(embed: Boolean) = Action {
// [snip]
Ok(views.html.wvyp.wvyp(wvypCount.toInt, searchCount.toInt)).withCookies(Cookie(“foo”, “bar”))
}
}

app/controllers/WVYP.scala

For example, imagine a standalone module sets a Cookie
object Aggregator extends Controller {
def index = Action.async { request =>
val wvypFuture = Wvyp.index(embed = true)(request)

for {
wvyp <- wvypFuture
wvypBody <- Pagelet.readBody(wvyp)
wvypHeaders = wvyp.header.headers // The Cookie header here will contain the “foo” cookie!
} yield {
Ok(views.html.aggregator.aggregator(wvypBody))
}
}
}

app/controllers/Aggregator.scala

The aggregator will see that as a Cookie header!
object Pagelet {

def mergeCookies(results: SimpleResult*): Seq[Cookie] = {
results.flatMap { result =>
result.header.headers.get(HeaderNames.SET_COOKIE).map(Cookies.decode).getOrElse(Seq.empty)
}
}
}

app/ui/Pagelet.scala

We can add a helper to merge the cookies from multiple
SimpleResult objects

Recommended for you

Battle of React State Managers in frontend applications
Battle of React State Managers in frontend applicationsBattle of React State Managers in frontend applications
Battle of React State Managers in frontend applications

The complexity of frontend applications over the years led to the creation of more robust solutions, where data logic won’t be messed up at scale. A shift took place from the traditional services approach, in which data is tightly coupled to the Views of their Components, towards more composable and shareable solutions. Each of these solutions is what we call a "state-manager". Goal of this presentation is the comparative analysis between different react frontend state managers such as Redux, MobX, Recoil and React-Query. State Machines will also be presented, showing a completely different perception of how state can be orchestrated. Different mental models of the aforementioned state managers along with their different technical implementations will be presented to the audience. Ultimately, the audience can use this presentation for future reference on faster deciding which state-manager fits their own projects. Before delving into the comparison there will be a description of the main data flow in the browser. Concepts like reactivity, immutability, predictability, concurrency and performance will be detected on the main flow and will act as our comparison metrics among the state-managers.

reduxrecoilmobx
Functional UIs with Java 8 and Vaadin JavaOne2014
Functional UIs with Java 8 and Vaadin JavaOne2014Functional UIs with Java 8 and Vaadin JavaOne2014
Functional UIs with Java 8 and Vaadin JavaOne2014

Slides for the JavaOne 2014 talk about how the functional features of Java 8 and Vaadin empower you to write clearer UI code.

functional programmingvaadinfunctional reactive programming
Elefrant [ng-Poznan]
Elefrant [ng-Poznan]Elefrant [ng-Poznan]
Elefrant [ng-Poznan]

This document introduces Elefrant, an open source Node.js framework for building scalable APIs. It provides modularity, customizability, authentication, documentation, and other features out of the box. The creator developed it to meet his needs for building real-time, multidevice apps. The framework is currently in version 0.1 but future versions will offer more extensibility through custom components.

ngpoznanservernodejs
def index = Action.async { request =>
val wvypFuture = Wvyp.index(embed = true)(request)
val wvyuFuture = Wvyu.index(embed = true)(request)
for {
wvyp <- wvypFuture
wvyu <- wvyuFuture
wvypBody <- Pagelet.readBody(wvyp)
wvyuBody <- Pagelet.readBody(wvyu)
} yield {
Ok(views.html.aggregator.aggregator(wvypBody, wvyuBody))
.withCookies(Pagelet.mergeCookies(wvyp, wvyu):_*)
}
}

app/controllers/Aggregator.scala

Update the aggregator to write out the merged cookies
We can see the aggregate endpoint is now setting cookies
HTTP headers are a good way to handle error
cases too.
A quick review of HTTP status codes

Recommended for you

Active object of Symbian in the lights of client server architecture
Active object of Symbian in the lights of client server architectureActive object of Symbian in the lights of client server architecture
Active object of Symbian in the lights of client server architecture

This document discusses the client-server architecture in Symbian and how it relates to asynchronous functions and the active object framework. It provides an example of using an asynchronous function in a server to read data from a communication port, while allowing the client UI to remain responsive. Code examples are given of a client-server application with an asynchronous function in the server that is called from the client UI using the active object framework. This allows the server function to run asynchronously without blocking the client.

symbianactive objects
Http programming in play
Http programming in playHttp programming in play
Http programming in play

Actions, Controllers and Results HTTP routing Manipulating results Session and Flash scopes Body parsers Actions composition Content negotiation

play frameworkscala
Mvc interview questions – deep dive jinal desai
Mvc interview questions – deep dive   jinal desaiMvc interview questions – deep dive   jinal desai
Mvc interview questions – deep dive jinal desai

Can you describe ASP.NET MVC Request Life Cycle? 1. Receive request, look up Route object in RouteTable collection and create RouteData object. 2. Create RequestContext instance. 3. Create MvcHandler and pass RequestContext to handler. 4. Identify IControllerFactory from RequestContext. 5. Create instance of class that implements ControllerBase. 6. Call MyController.Execute method. 7. The ControllerActionInvoker determines which action to invoke on the controller and executes the action on the controller, which results in calling the model and returning a view.

asp.net mvc interview questionsasp.net mvc 3 interview questionsmvc
For example, if a module has no content, return a 204
Invalid module request? Return 404.
Plus other important status codes
Composable and streamable Play apps

Recommended for you

Cloud adoption fails - 5 ways deployments go wrong and 5 solutions
Cloud adoption fails - 5 ways deployments go wrong and 5 solutionsCloud adoption fails - 5 ways deployments go wrong and 5 solutions
Cloud adoption fails - 5 ways deployments go wrong and 5 solutions

"All happy cloud deployments are alike; each unhappy cloud deployment is unhappy in its own way." — Leo Tolstoy, Site Reliability Engineer At Gruntwork, I've had the chance to see the cloud adoption journeys of hundreds of companies, from tiny startups to Fortune 50 giants. I've seen those journeys go well. I've seen those journeys go poorly. In this talk, I discuss a few of the ways cloud adoption can go horribly wrong (massive cost overruns, endless death marches, security disasters), and more importantly, how you can get it right. To help you get it right, we looked at the cloud journeys that were successful and extracted from them the patterns they had in common. We distilled all this experience down into something called the Gruntwork Production Framework, which defines five concrete steps you can follow to adopt the cloud at your own company—and hopefully, to end up with your very own happy cloud deployment.

clouddevopsaws
How to test infrastructure code: automated testing for Terraform, Kubernetes,...
How to test infrastructure code: automated testing for Terraform, Kubernetes,...How to test infrastructure code: automated testing for Terraform, Kubernetes,...
How to test infrastructure code: automated testing for Terraform, Kubernetes,...

This talk is a step-by-step, live-coding class on how to write automated tests for infrastructure code, including the code you write for use with tools such as Terraform, Kubernetes, Docker, and Packer. Topics covered include unit tests, integration tests, end-to-end tests, test parallelism, retries, error handling, static analysis, and more.

awsterraformkubernetes
Lessons learned from writing over 300,000 lines of infrastructure code
Lessons learned from writing over 300,000 lines of infrastructure codeLessons learned from writing over 300,000 lines of infrastructure code
Lessons learned from writing over 300,000 lines of infrastructure code

This talk is a concise masterclass on how to write infrastructure code. I share key lessons from the “Infrastructure Cookbook” we developed at Gruntwork while creating and maintaining a library of over 300,000 lines of infrastructure code that’s used in production by hundreds of companies. Come and hear our war stories, laugh about all the mistakes we’ve made along the way, and learn what Terraform, Packer, Docker, and Go look like in the wild.

devopsdockerinfrastructure as code
def index = Action.async { request =>
val wvypFuture = Wvyp.index(embed = true)(request)
for {
wvyp <- wvypFuture
wvypBody <- Pagelet.readBody(wvyp)
} yield {
if (wvyp.status == 200) {
Ok(views.html.aggregator.aggregator(wvypBody))
} else {
// Handle errors
}
}
}

app/controllers/Aggregator.scala

The aggregator can read the status codes and react
accordingly
CSS and JS dependencies can be set as a
header and aggregated too.
object StaticContent {
val cssHeaderName = "X-CSS"
val jsHeaderName = "X-JS"

def asHeaders(css: Seq[String], js: Seq[String]): Seq[(String, String)] = {
Seq(cssHeaderName -> css.mkString(","), jsHeaderName -> js.mkString(","))
}
}

app/ui/StaticContent.scala

Add a helper to create the headers
def index(embed: Boolean) = Action {
// [...] all other code is the same as before [...]

val css = Vector("/assets/stylesheets/wvyp.css")
val js = Vector.empty[String]

if (embed) {
Ok(views.html.wvyp.wvypBody(wvypCount.toInt, searchCount.toInt))
.withHeaders(StaticContent.asHeaders(css, js):_*)
} else {
Ok(views.html.wvyp.wvyp(wvypCount.toInt, searchCount.toInt, css, js))
}
}

app/controllers/WVYP.scala

In embed mode, return CSS/JS dependencies as headers. In
standalone mode, render them in the template.

Recommended for you

Gruntwork Executive Summary
Gruntwork Executive SummaryGruntwork Executive Summary
Gruntwork Executive Summary

A brief overview of what we do at Gruntwork. Learn what we mean by "DevOps as a Service" and how you can get your entire infrastructure, defined as code, in about a day. https://www.gruntwork.io/

devopsdevops as a serviceinfrastructure as code
Reusable, composable, battle-tested Terraform modules
Reusable, composable, battle-tested Terraform modulesReusable, composable, battle-tested Terraform modules
Reusable, composable, battle-tested Terraform modules

Listen up, developers. You are not special. Your infrastructure is not a beautiful and unique snowflake. You have the same tech debt as everyone else. This is a talk about a better way to build and manage infrastructure: Terraform Modules. It goes over how to build infrastructure as code, package that code into reusable modules, design clean and flexible APIs for those modules, write automated tests for the modules, and combine multiple modules into an end-to-end techs tack in minutes. You can find the video here: https://www.youtube.com/watch?v=LVgP63BkhKQ

terraforminfrastructureaws
The Truth About Startups: What I wish someone had told me about entrepreneurs...
The Truth About Startups: What I wish someone had told me about entrepreneurs...The Truth About Startups: What I wish someone had told me about entrepreneurs...
The Truth About Startups: What I wish someone had told me about entrepreneurs...

This is the talk I gave at MIT's Martin Center for Entrepreneurship. It's a talk I wish someone gave me when I was in college to help me think about the role of entrepreneurship and startups in my career. You can find the video of the talk here: https://www.youtube.com/watch?v=Rus32iR_Ag0

silicon valleyentrepreneurshipcareer
object StaticContent {
def mergeCssHeaders(results: SimpleResult*): Seq[String] = mergeHeaderValues(cssHeaderName, results:
_*)

def mergeJsHeaders(results: SimpleResult*): Seq[String] = mergeHeaderValues(jsHeaderName, results:_*)

private def mergeHeaderValues(headerName: String, results: SimpleResult*): Seq[String] = {
results.flatMap { result =>
result.header.headers.get(headerName).map(_.split(",").toSeq).getOrElse(Seq.empty)
}.distinct
}
}

app/ui/StaticContent.scala

Helpers to merge CSS and JS headers from multiple
SimpleResult objects
def index = Action.async { request =>
val wvypFuture = Wvyp.index(embed = true)(request)
val wvyuFuture = Wvyu.index(embed = true)(request)
for {
wvyp <- wvypFuture
wvyu <- wvyuFuture
wvypBody <- Pagelet.readBody(wvyp)
wvyuBody <- Pagelet.readBody(wvyu)
} yield {
val css = StaticContent.mergeCssHeaders(wvyp, wvyu)
val js = StaticContent.mergeCssHeaders(wvyp, wvyu)
Ok(views.html.aggregator.aggregator(wvypBody, wvyuBody, css, js))
}
}

app/controllers/Aggregator.scala

The aggregator can merge and de-dupe the static content
and pass it to its template for rendering
Wins
1.

Modules are truly standalone

2.

Can dynamically compose modules using Play’s router

3.

Can compose modules from remote endpoints

4.

Can reuse endpoints from the browser via AJAX

5.

Static content dependencies explicitly defined
Caveats
1.

Managing static content in a controller, instead of a view, feels clunky.

Recommended for you

Comprehensive Terraform Training
Comprehensive Terraform TrainingComprehensive Terraform Training
Comprehensive Terraform Training

A comprehensive walkthrough of how to manage infrastructure-as-code using Terraform. This presentation includes an introduction to Terraform, a discussion of how to manage Terraform state, how to use Terraform modules, an overview of best practices (e.g. isolation, versioning, loops, if-statements), and a list of gotchas to look out for. For a written and more in-depth version of this presentation, check out the "Comprehensive Guide to Terraform" blog post series: https://blog.gruntwork.io/a-comprehensive-guide-to-terraform-b3d32832baca

programmingterraformsoftware
Agility Requires Safety
Agility Requires SafetyAgility Requires Safety
Agility Requires Safety

To go faster in a car, you need not only a powerful engine, but also safety mechanisms like brakes, air bags, and seat belts. This is a talk about the safety mechanisms that allow you to build software faster. It's based on the book "Hello, Startup" (http://www.hello-startup.net/). You can find the video of the talk here: https://www.youtube.com/watch?v=4fKm6ImKml8

programmingdevopstesting
Startup Ideas and Validation
Startup Ideas and ValidationStartup Ideas and Validation
Startup Ideas and Validation

Every startup begins with an idea. This is a talk on how to come up with startup ideas and how to use validation to pick the ones worth working on. It's based on the book "Hello, Startup" (http://www.hello-startup.net/). You can find the video of the talk here: https://www.youtube.com/watch?v=GkmiE8d_5Pw

creativitystartupsideas
Outline
1. Complexity
2. Composition
3. HTTP
4. Performance
5. Enumerators
6. Streaming
So far, we’ve been using a mock endpoint to
simulate remote service calls
What happens if one of the remote calls is slow?
object Mock extends Controller {
def mock(serviceName: String) = Action.async {
serviceName match {
case "wvyp" => respond(data = "56", delay = 10)
case "search" => respond(data = "10", delay = 2000) // SLOW!
case "likes" => respond(data = "150", delay = 40)
case "comments" => respond(data = "14", delay = 20)
}
}

private def respond(data: String, delay: Long) = Promise.timeout(Ok(data), delay)
}

app/mock/Mock.scala

As an extreme example, let’s make the search service take
two seconds to respond

Recommended for you

A Guide to Hiring for your Startup
A Guide to Hiring for your StartupA Guide to Hiring for your Startup
A Guide to Hiring for your Startup

A guide to hiring based on my book, "Hello, Startup". Learn who to hire, where to find them, how to interview them, and how to make an offer they can't refuse. Recording: https://www.youtube.com/watch?v=jaSmYLymc0U Book: http://www.hello-startup.net

hiringstart upentrepreneur
Startup DNA: Speed Wins
Startup DNA: Speed WinsStartup DNA: Speed Wins
Startup DNA: Speed Wins

This is an excerpt from my talk "Startup DNA" (http://www.slideshare.net/brikis98/startup-dna) that just focuses on the "Speed Wins" concept. For more info, check out my book "Hello, Startup: A Programmer's Guide to Building Products, Technologies, and Teams" at http://www.hello-startup.net.

leanstart upproducts
Node.js vs Play Framework
Node.js vs Play FrameworkNode.js vs Play Framework
Node.js vs Play Framework

Video: https://www.youtube.com/watch?v=b6yLwvNSDck Here's the showdown you've been waiting for: Node.js vs Play Framework. Both are popular open source web frameworks that are built for developer productivity, asynchronous I/O, and the real time web. But which one is easier to learn, test, deploy, debug, and scale? Should you pick Javascript or Scala? The Google v8 engine or the JVM? NPM or Ivy? Grunt or SBT? Two frameworks enter, one framework leaves. This is the English version of the presentation. For the version with Japanese subtitles, see http://www.slideshare.net/brikis98/nodejs-vs-play-framework-with-japanese-subtitles

javascriptnode.jsplay framework
Time to first byte is 2 seconds! Everything has to wait for
the one slow service, including static content.
Is there a way to start sending the response
before all the data is available?
Facebook solves this problem with BigPipe
https://www.facebook.com/note.php?note_id=389414033919
Can we build BigPipe with Play?

Recommended for you

Rapid prototyping
Rapid prototypingRapid prototyping
Rapid prototyping

This document discusses rapid prototyping techniques for quickly building products from ideas. Rapid prototyping allows developers to build products faster through instant feedback on code changes and leveraging existing open source libraries. It is suggested that dynamic languages, interactive development environments, and pushing code to the browser can provide very fast feedback. While prototypes may be thrown away, the rapid trial and error process of prototyping can lead to higher quality products and better engineers through continuously improving ideas.

software engineeringlinkedinrapid prototyping
Kings of Code Hack Battle
Kings of Code Hack BattleKings of Code Hack Battle
Kings of Code Hack Battle

LinkedIn is sponsoring the Kings of Code Hack Battle at the 2013 Next Web Conference. What will you do for the "business hack" challenge?

hackdayapislinkedin
Hackdays and [in]cubator
Hackdays and [in]cubatorHackdays and [in]cubator
Hackdays and [in]cubator

This is the story of the Hackday and[in]cubator programs at LinkedIn; this is the story of scalable, best-of-breed methods for driving innovation; this is the story of transformation: of your career, company, and the world. Video of the live presentation: http://tcbaltics.com/video/jim-brikman

(Well, yea, or I wouldn’t have made this talk)
We can use Enumerators!
Outline
1. Complexity
2. Composition
3. HTTP
4. Performance
5. Enumerators
6. Streaming
Enumerators are part of the Play Iteratees library.

Recommended for you

Startup DNA: the formula behind successful startups in Silicon Valley (update...
Startup DNA: the formula behind successful startups in Silicon Valley (update...Startup DNA: the formula behind successful startups in Silicon Valley (update...
Startup DNA: the formula behind successful startups in Silicon Valley (update...

[Updated May 5, 2017] "Successful startups are all alike; every unsuccessful startup is unsuccessful in its own way." These are my personal observations on a few traits that make startups successful. You can find a video of the talk at https://www.youtube.com/watch?v=z_D9oXCK2lM and the book at http://www.hello-startup.net/.

start upsilicon valleylinkedin
Dust.js
Dust.jsDust.js
Dust.js

The document discusses LinkedIn's adoption of the Dust templating language in 2011. Some key points: - LinkedIn needed a unified view layer as different teams were using different templating technologies like JSP, GSP, ERB. - They evaluated 26 templating options and selected Dust as it best met their criteria like performance, i18n support, and being logic-less. - Dust templates are compiled to JavaScript for client-side rendering and to Java for server-side rendering (SSR) through Google's V8 engine, allowing templates to work on both client and server. - SSR addresses challenges like SEO, supporting clients without JavaScript, and i18n by rendering

web developmenttemplatesjavascript
LinkedIn Overview
LinkedIn OverviewLinkedIn Overview
LinkedIn Overview

A look at the company behind the world's largest professional network. Learn about our products, technologies and culture.

technologyproductslinkedin
Quick Review
1.

An Enumerator is a Producer. It pumps out chunks of data.

2.

An Iteratee is a Consumer. It reactively consumes chunks of data.

3.

An Enumeratee is an Adapter. You can attach them in front of Iteratees
and Enumerators to filter the chunks of data.
Producer, consumer, and adapter
These are all composable abstractions for
working with streams of data
Let’s look at some examples

Recommended for you

Details of description part II: Describing images in practice - Tech Forum 2024
Details of description part II: Describing images in practice - Tech Forum 2024Details of description part II: Describing images in practice - Tech Forum 2024
Details of description part II: Describing images in practice - Tech Forum 2024

This presentation explores the practical application of image description techniques. Familiar guidelines will be demonstrated in practice, and descriptions will be developed “live”! If you have learned a lot about the theory of image description techniques but want to feel more confident putting them into practice, this is the presentation for you. There will be useful, actionable information for everyone, whether you are working with authors, colleagues, alone, or leveraging AI as a collaborator. Link to presentation recording and transcript: https://bnctechforum.ca/sessions/details-of-description-part-ii-describing-images-in-practice/ Presented by BookNet Canada on June 25, 2024, with support from the Department of Canadian Heritage.

a11yaccessibilityalt text
Pigging Solutions Sustainability brochure.pdf
Pigging Solutions Sustainability brochure.pdfPigging Solutions Sustainability brochure.pdf
Pigging Solutions Sustainability brochure.pdf

Sustainability requires ingenuity and stewardship. Did you know Pigging Solutions pigging systems help you achieve your sustainable manufacturing goals AND provide rapid return on investment. How? Our systems recover over 99% of product in transfer piping. Recovering trapped product from transfer lines that would otherwise become flush-waste, means you can increase batch yields and eliminate flush waste. From raw materials to finished product, if you can pump it, we can pig it.

pigging solutionsprocess piggingproduct transfers
Cookies program to display the information though cookie creation
Cookies program to display the information though cookie creationCookies program to display the information though cookie creation
Cookies program to display the information though cookie creation

Java Servlet programs

object EnumeratorExample extends Controller {

def index = Action {
Ok.chunked(/* We need an Enumerator here */)
}
}

app/controllers/EnumeratorExamples.scala

Play has an Ok.chunked method which can stream out the
contents of an Enumerator
object EnumeratorExample extends Controller {

def index = Action {
Ok.chunked(Enumerator("Created", " using", " Enumerator", ".apply()nn"))
}
}

app/controllers/EnumeratorExamples.scala

The Enumerator object has several factory methods. For
example, Enumerator.apply creates one from a fixed list.
Basic “Hello World” example using Enumerator.apply.
object EnumeratorExample extends Controller {

def index = Action {
Ok.chunked(Enumerator.repeatM(Promise.timeout("Hellon", 500)))
}
}

app/controllers/EnumeratorExamples.scala

You can also create an Enumerator that repeats a value
generated from a Future

Recommended for you

INDIAN AIR FORCE FIGHTER PLANES LIST.pdf
INDIAN AIR FORCE FIGHTER PLANES LIST.pdfINDIAN AIR FORCE FIGHTER PLANES LIST.pdf
INDIAN AIR FORCE FIGHTER PLANES LIST.pdf

These fighter aircraft have uses outside of traditional combat situations. They are essential in defending India's territorial integrity, averting dangers, and delivering aid to those in need during natural calamities. Additionally, the IAF improves its interoperability and fortifies international military alliances by working together and conducting joint exercises with other air forces.

air force fighter planebiggest submarinezambia port
Best Practices for Effectively Running dbt in Airflow.pdf
Best Practices for Effectively Running dbt in Airflow.pdfBest Practices for Effectively Running dbt in Airflow.pdf
Best Practices for Effectively Running dbt in Airflow.pdf

As a popular open-source library for analytics engineering, dbt is often used in combination with Airflow. Orchestrating and executing dbt models as DAGs ensures an additional layer of control over tasks, observability, and provides a reliable, scalable environment to run dbt models. This webinar will cover a step-by-step guide to Cosmos, an open source package from Astronomer that helps you easily run your dbt Core projects as Airflow DAGs and Task Groups, all with just a few lines of code. We’ll walk through: - Standard ways of running dbt (and when to utilize other methods) - How Cosmos can be used to run and visualize your dbt projects in Airflow - Common challenges and how to address them, including performance, dependency conflicts, and more - How running dbt projects in Airflow helps with cost optimization Webinar given on 9 July 2024

apache airflowdbtdbt-core
Coordinate Systems in FME 101 - Webinar Slides
Coordinate Systems in FME 101 - Webinar SlidesCoordinate Systems in FME 101 - Webinar Slides
Coordinate Systems in FME 101 - Webinar Slides

If you’ve ever had to analyze a map or GPS data, chances are you’ve encountered and even worked with coordinate systems. As historical data continually updates through GPS, understanding coordinate systems is increasingly crucial. However, not everyone knows why they exist or how to effectively use them for data-driven insights. During this webinar, you’ll learn exactly what coordinate systems are and how you can use FME to maintain and transform your data’s coordinate systems in an easy-to-digest way, accurately representing the geographical space that it exists within. During this webinar, you will have the chance to: - Enhance Your Understanding: Gain a clear overview of what coordinate systems are and their value - Learn Practical Applications: Why we need datams and projections, plus units between coordinate systems - Maximize with FME: Understand how FME handles coordinate systems, including a brief summary of the 3 main reprojectors - Custom Coordinate Systems: Learn how to work with FME and coordinate systems beyond what is natively supported - Look Ahead: Gain insights into where FME is headed with coordinate systems in the future Don’t miss the opportunity to improve the value you receive from your coordinate system data, ultimately allowing you to streamline your data analysis and maximize your time. See you there!

The word “Hello” is pumped out every 500ms. Note: when
testing streaming, use “curl -N” so curl doesn’t buffer.
def index = Action {
val helloEnumerator = Enumerator("hello ")
val goodbyeEnumerator = Enumerator("goodbyenn")

val helloGoodbyeEnumerator = helloEnumerator.andThen(goodbyeEnumerator)

Ok.chunked(helloGoodbyeEnumerator)
}

app/controllers/EnumeratorExamples.scala

Most importantly, you can combine Enumerators. Here is an
example using the andThen method.
With andThen, we see all the data from the first enumerator
and then all the data from the second one
def index = Action {
val helloEnumerator = Enumerator.repeatM(Promise.timeout("Hellon", 500))
val goodbyeEnumerator = Enumerator.repeatM(Promise.timeout("Goodbyen", 1000))

val helloGoodbyeEnumerator = Enumerator.interleave(helloEnumerator, goodbyeEnumerator)

Ok.chunked(helloGoodbyeEnumerator)
}

app/controllers/EnumeratorExamples.scala

We can also combine Enumerators using Enumerator.
interleave

Recommended for you

Mitigating the Impact of State Management in Cloud Stream Processing Systems
Mitigating the Impact of State Management in Cloud Stream Processing SystemsMitigating the Impact of State Management in Cloud Stream Processing Systems
Mitigating the Impact of State Management in Cloud Stream Processing Systems

Stream processing is a crucial component of modern data infrastructure, but constructing an efficient and scalable stream processing system can be challenging. Decoupling compute and storage architecture has emerged as an effective solution to these challenges, but it can introduce high latency issues, especially when dealing with complex continuous queries that necessitate managing extra-large internal states. In this talk, we focus on addressing the high latency issues associated with S3 storage in stream processing systems that employ a decoupled compute and storage architecture. We delve into the root causes of latency in this context and explore various techniques to minimize the impact of S3 latency on stream processing performance. Our proposed approach is to implement a tiered storage mechanism that leverages a blend of high-performance and low-cost storage tiers to reduce data movement between the compute and storage layers while maintaining efficient processing. Throughout the talk, we will present experimental results that demonstrate the effectiveness of our approach in mitigating the impact of S3 latency on stream processing. By the end of the talk, attendees will have gained insights into how to optimize their stream processing systems for reduced latency and improved cost-efficiency.

How RPA Help in the Transportation and Logistics Industry.pptx
How RPA Help in the Transportation and Logistics Industry.pptxHow RPA Help in the Transportation and Logistics Industry.pptx
How RPA Help in the Transportation and Logistics Industry.pptx

Revolutionize your transportation processes with our cutting-edge RPA software. Automate repetitive tasks, reduce costs, and enhance efficiency in the logistics sector with our advanced solutions.

rpa in transportationrpa in transportation industryrpa in transportation sector
20240702 QFM021 Machine Intelligence Reading List June 2024
20240702 QFM021 Machine Intelligence Reading List June 202420240702 QFM021 Machine Intelligence Reading List June 2024
20240702 QFM021 Machine Intelligence Reading List June 2024

Everything that I found interesting about machines behaving intelligently during June 2024

quantumfaxmachine
With interleave, data can come in any order. Above, we see
“Hello” every 500ms and “Goodbye” every 1000ms.
Let’s use Enumerators to stream the results
of our remote service calls
object WVYPEnumerator extends Controller {
def index = Action {
val wvypCountFuture = ServiceClient.makeServiceCall("wvyp")
val searchCountFuture = ServiceClient.makeServiceCall("search")

}
}

app/controllers/WVYPEnumerator.scala

Create the new WVYP controller. Again, we start with two
service calls.
object WVYPEnumerator extends Controller {
def index = Action {
val wvypCountFuture = ServiceClient.makeServiceCall("wvyp")
val searchCountFuture = ServiceClient.makeServiceCall("search")

val wvypCountEnum = Enumerator.flatten(wvypCountFuture.map(str => Enumerator(str + "n")))
val searchCountEnum = Enumerator.flatten(searchCountFuture.map(str => Enumerator(str + "n")))

}
}

app/controllers/WVYPEnumerator.scala

Next, convert each Future[String] into an Enumerator[String]

Recommended for you

7 Most Powerful Solar Storms in the History of Earth.pdf
7 Most Powerful Solar Storms in the History of Earth.pdf7 Most Powerful Solar Storms in the History of Earth.pdf
7 Most Powerful Solar Storms in the History of Earth.pdf

Solar Storms (Geo Magnetic Storms) are the motion of accelerated charged particles in the solar environment with high velocities due to the coronal mass ejection (CME).

solar storms
[Talk] Moving Beyond Spaghetti Infrastructure [AOTB] 2024-07-04.pdf
[Talk] Moving Beyond Spaghetti Infrastructure [AOTB] 2024-07-04.pdf[Talk] Moving Beyond Spaghetti Infrastructure [AOTB] 2024-07-04.pdf
[Talk] Moving Beyond Spaghetti Infrastructure [AOTB] 2024-07-04.pdf

Kief Morris rethinks the infrastructure code delivery lifecycle, advocating for a shift towards composable infrastructure systems. We should shift to designing around deployable components rather than code modules, use more useful levels of abstraction, and drive design and deployment from applications rather than bottom-up, monolithic architecture and delivery.

infrastructure as codeclouddevops
WhatsApp Image 2024-03-27 at 08.19.52_bfd93109.pdf
WhatsApp Image 2024-03-27 at 08.19.52_bfd93109.pdfWhatsApp Image 2024-03-27 at 08.19.52_bfd93109.pdf
WhatsApp Image 2024-03-27 at 08.19.52_bfd93109.pdf

Profile portofolio

object WVYPEnumerator extends Controller {
def index = Action {
val wvypCountFuture = ServiceClient.makeServiceCall("wvyp")
val searchCountFuture = ServiceClient.makeServiceCall("search")

val wvypCountEnum = Enumerator.flatten(wvypCountFuture.map(str => Enumerator(str + "n")))
val searchCountEnum = Enumerator.flatten(searchCountFuture.map(str => Enumerator(str + "n")))

val body = wvypCountEnum.andThen(searchCountEnum)

Ok.chunked(body)
}
}

app/controllers/WVYPEnumerator.scala

Finally, compose the two Enumerators and use Ok.chunked
to stream them out
GET
@(wvypBody:/mock/:serviceName controllers.Mock.mock(serviceName: String)
Html, wvyuBody: Html)
GET

/wvyp

controllers.WVYP.index(embed: Boolean ?= false)

GET
<html>

/wvyu

controllers.WVYU.index(embed: Boolean ?= false)

GET
<head>

/aggregate

controllers.Aggregator.index

GET <link rel="stylesheet" href="/assets/stylesheets/wvyp.css"/>
/wvyp/enumerator
controllers.WVYPEnumerator.index
<link rel="stylesheet" href="/assets/stylesheets/wvyu.css"/>
</head>
<body>
@wvypBody
@wvyuBody
</body>
</html>

app/views/aggregator/aggregator.scala

Add a routes entry for the enumerator-based WVYP controller
Almost immediately, we see “56”, from the wvyp service.
2 seconds later, we see “10”, from the search service.

Recommended for you

BT & Neo4j: Knowledge Graphs for Critical Enterprise Systems.pptx.pdf
BT & Neo4j: Knowledge Graphs for Critical Enterprise Systems.pptx.pdfBT & Neo4j: Knowledge Graphs for Critical Enterprise Systems.pptx.pdf
BT & Neo4j: Knowledge Graphs for Critical Enterprise Systems.pptx.pdf

Presented at Gartner Data & Analytics, London Maty 2024. BT Group has used the Neo4j Graph Database to enable impressive digital transformation programs over the last 6 years. By re-imagining their operational support systems to adopt self-serve and data lead principles they have substantially reduced the number of applications and complexity of their operations. The result has been a substantial reduction in risk and costs while improving time to value, innovation, and process automation. Join this session to hear their story, the lessons they learned along the way and how their future innovation plans include the exploration of uses of EKG + Generative AI.

neo4jneo4j webinarsgraph database
How Social Media Hackers Help You to See Your Wife's Message.pdf
How Social Media Hackers Help You to See Your Wife's Message.pdfHow Social Media Hackers Help You to See Your Wife's Message.pdf
How Social Media Hackers Help You to See Your Wife's Message.pdf

In the modern digital era, social media platforms have become integral to our daily lives. These platforms, including Facebook, Instagram, WhatsApp, and Snapchat, offer countless ways to connect, share, and communicate.

social media hackerfacebook hackerhire a instagram hacker
Paradigm Shifts in User Modeling: A Journey from Historical Foundations to Em...
Paradigm Shifts in User Modeling: A Journey from Historical Foundations to Em...Paradigm Shifts in User Modeling: A Journey from Historical Foundations to Em...
Paradigm Shifts in User Modeling: A Journey from Historical Foundations to Em...

Slide of the tutorial entitled "Paradigm Shifts in User Modeling: A Journey from Historical Foundations to Emerging Trends" held at UMAP'24: 32nd ACM Conference on User Modeling, Adaptation and Personalization (July 1, 2024 | Cagliari, Italy)

user modelinguser profilinguser model
We’re streaming!
However, we’re only streaming plain text.
How do we stream a template?
Outline
1. Complexity
2. Composition
3. HTTP
4. Performance
5. Enumerators
6. Streaming
play.Keys.templatesTypes ++= Map("stream" -> "ui.HtmlStreamFormat")
play.Keys.templatesImport ++= Vector("ui.HtmlStream", "ui.HtmlStream._", "ui.StaticContent")

build.sbt

Play allows you to define a new template type. This will allow
us to create .scala.stream files instead of .scala.html.

Recommended for you

Comparison Table of DiskWarrior Alternatives.pdf
Comparison Table of DiskWarrior Alternatives.pdfComparison Table of DiskWarrior Alternatives.pdf
Comparison Table of DiskWarrior Alternatives.pdf

To help you choose the best DiskWarrior alternative, we've compiled a comparison table summarizing the features, pros, cons, and pricing of six alternatives.

data recoverydatadiskwarrior
Transcript: Details of description part II: Describing images in practice - T...
Transcript: Details of description part II: Describing images in practice - T...Transcript: Details of description part II: Describing images in practice - T...
Transcript: Details of description part II: Describing images in practice - T...

This presentation explores the practical application of image description techniques. Familiar guidelines will be demonstrated in practice, and descriptions will be developed “live”! If you have learned a lot about the theory of image description techniques but want to feel more confident putting them into practice, this is the presentation for you. There will be useful, actionable information for everyone, whether you are working with authors, colleagues, alone, or leveraging AI as a collaborator. Link to presentation recording and slides: https://bnctechforum.ca/sessions/details-of-description-part-ii-describing-images-in-practice/ Presented by BookNet Canada on June 25, 2024, with support from the Department of Canadian Heritage.

a11yaccessibilityalt text
20240705 QFM024 Irresponsible AI Reading List June 2024
20240705 QFM024 Irresponsible AI Reading List June 202420240705 QFM024 Irresponsible AI Reading List June 2024
20240705 QFM024 Irresponsible AI Reading List June 2024

Everything that I found interesting last month about the irresponsible use of machine intelligence

quantumfaxmachine
The new template type must define an
“Appendable” and a “Format” for it
trait Appendable[T] {
def +=(other: T): T
}

play/api/templates/Templates.scala

The Appendable trait is simple: it’s anything with an append
(+=) operator.
class Html(buffer: StringBuilder) extends Appendable[Html](buffer) {
def +=(other: Html) = {
buffer.append(other.buffer)
this
}
}

play/api/templates/Templates.scala

The default Appendable built into Play is Html, which just
wraps a StringBuilder.
case class HtmlStream(enumerator: Enumerator[Html]) extends Appendable[HtmlStream] {
def +=(other: HtmlStream): HtmlStream = andThen(other)

def andThen(other: HtmlStream): HtmlStream = HtmlStream(enumerator.andThen(other.enumerator))
}

app/ui/HtmlStream.scala

For streaming templates, we create an HtmlStream
Appendable that wraps an Enumerator[Html].

Recommended for you

Manual | Product | Research Presentation
Manual | Product | Research PresentationManual | Product | Research Presentation
Manual | Product | Research Presentation

Manual Method of Product Research | Helium10 | MBS RETRIEVER

product researchhelium10 | mbs retriever
TrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-In
TrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-InTrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-In
TrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-In

Six months into 2024, and it is clear the privacy ecosystem takes no days off!! Regulators continue to implement and enforce new regulations, businesses strive to meet requirements, and technology advances like AI have privacy professionals scratching their heads about managing risk. What can we learn about the first six months of data privacy trends and events in 2024? How should this inform your privacy program management for the rest of the year? Join TrustArc, Goodwin, and Snyk privacy experts as they discuss the changes we’ve seen in the first half of 2024 and gain insight into the concrete, actionable steps you can take to up-level your privacy program in the second half of the year. This webinar will review: - Key changes to privacy regulations in 2024 - Key themes in privacy and data governance in 2024 - How to maximize your privacy program in the second half of 2024

data privacyprivacy complianceai
object HtmlStream {

def interleave(streams: HtmlStream*): HtmlStream = {
HtmlStream(Enumerator.interleave(streams.map(_.enumerator)))
}

def flatten(eventuallyStream: Future[HtmlStream]): HtmlStream = {
HtmlStream(Enumerator.flatten(eventuallyStream.map(_.enumerator)))
}
}

app/ui/HtmlStream.scala

We add an HtmlStream companion object with helper
methods to combine HtmlStreams just like Enumerators
object HtmlStream {

def apply(text: String): HtmlStream = {
apply(Html(text))
}

def apply(html: Html): HtmlStream = {
HtmlStream(Enumerator(html))
}

def apply(eventuallyHtml: Future[Html]): HtmlStream = {
flatten(eventuallyHtml.map(apply))
}
}

app/ui/HtmlStream.scala

Also, we add several methods to the HtmlStream companion
object to help create HtmlStream instances.
trait Format[T <: Appendable[T]] {
type Appendable = T

def raw(text: String): T

def escape(text: String): T
}

play/api/templates/Templates.scala

The Format trait is what Play will use to create your
Appendable from a String
object HtmlStreamFormat extends Format[HtmlStream] {

def raw(text: String): HtmlStream = {
HtmlStream(text)
}

def escape(text: String): HtmlStream = {
raw(HtmlFormat.escape(text).body)
}
}

app/ui/HtmlStream.scala

Here’s the HtmlStreamFormat implementation

Recommended for you

object HtmlStreamImplicits {

// Implicit conversion so HtmlStream can be passed directly to Ok.feed and Ok.chunked
implicit def toEnumerator(stream: HtmlStream): Enumerator[Html] = {
// Skip empty chunks, as these mean EOF in chunked encoding
stream.enumerator.through(Enumeratee.filter(!_.body.isEmpty))
}
}

app/ui/HtmlStream.scala

We also include an implicit conversion so HtmlStream can be
passed directly to Ok.chunked
@(body:ui.HtmlStream)
<html>
<head>
<link rel="stylesheet" href="/assets/stylesheets/wvyp.css"/>
</head>
<body>
<div class="wvyp">
<h2>Who's Viewed Your Profile</h2>
@body
</div>
</body>
</html>

app/views/wvyp/wvyp.scala.stream

We can now create a .scala.stream template that has markup
mixed with HtmlStream elements.
object WVYPStream extends Controller {
def index = Action {
val wvypCountFuture = ServiceClient.makeServiceCall("wvyp")
val searchCountFuture = ServiceClient.makeServiceCall("search")

}
}

app/controllers/WVYPStream.scala

Now for the streaming controller. As usual, start with the
service calls.
object WVYPStream extends Controller {
def index = Action {
val wvypCountFuture = ServiceClient.makeServiceCall("wvyp")
val searchCountFuture = ServiceClient.makeServiceCall("search")

val wvypCountHtmlFuture = wvypCountFuture.map(str => views.html.wvyp.wvypCount(str.toInt))
val searchCountHtmlFuture = searchCountFuture.map(str => views.html.wvyp.searchCount(str.toInt))

}
}

app/controllers/WVYPStream.scala

Next, render the data in each Future as Html

Recommended for you

object WVYPStream extends Controller {
def index = Action {
val wvypCountFuture = ServiceClient.makeServiceCall("wvyp")
val searchCountFuture = ServiceClient.makeServiceCall("search")

val wvypCountHtmlFuture = wvypCountFuture.map(str => views.html.wvyp.wvypCount(str.toInt))
val searchCountHtmlFuture = searchCountFuture.map(str => views.html.wvyp.searchCount(str.toInt))

val wvypCountStream = HtmlStream(wvypCountHtmlFuture)
val searchCountStream = HtmlStream(searchCountHtmlFuture)

}
}

app/controllers/WVYPStream.scala

Convert each Future[Html] to an HtmlStream using the factory
methods we created earlier
object WVYPStream extends Controller {
def index = Action {
val wvypCountFuture = ServiceClient.makeServiceCall("wvyp")
val searchCountFuture = ServiceClient.makeServiceCall("search")

val wvypCountHtmlFuture = wvypCountFuture.map(str => views.html.wvyp.wvypCount(str.toInt))
val searchCountHtmlFuture = searchCountFuture.map(str => views.html.wvyp.searchCount(str.toInt))

val wvypCountStream = HtmlStream(wvypCountHtmlFuture)
val searchCountStream = HtmlStream(searchCountHtmlFuture)

val body = wvypCountStream.andThen(searchCountStream)
Ok.chunked(views.stream.wvypStreaming(body))
}
}

app/controllers/WVYPStream.scala

Finally, combine the streams using andThen and render the
streaming template
GET
@(wvypBody:/mock/:serviceName controllers.Mock.mock(serviceName: String)
Html, wvyuBody: Html)
GET

/wvyp

controllers.WVYP.index(embed: Boolean ?= false)

GET
<html>

/wvyu

controllers.WVYU.index(embed: Boolean ?= false)

GET
<head>

/aggregate

controllers.Aggregator.index

GET <link rel="stylesheet" href="/assets/stylesheets/wvyp.css"/>
/wvyp/enumerator
controllers.WVYPEnumerator.index
GET <link rel="stylesheet" href="/assets/stylesheets/wvyu.css"/>
/wvyp/stream
controllers.WVYPStream.index
</head>
<body>
@wvypBody
@wvyuBody
</body>
</html>

app/views/aggregator/aggregator.scala

Add a routes entry for the stream-based WVYP controller
The page loads almost immediately and we see the WVYP
count right away.

Recommended for you

2 seconds later, the search count appears.
Also, the CSS starts downloading immediately!
This is a huge win if the stuff at the top of the
page loads quickly. But what if it’s slow?
object Mock extends Controller {
def mock(serviceName: String) = Action.async {
serviceName match {
case "wvyp" => respond(data = "56", delay = 2000) // SLOW!
case "search" => respond(data = "10", delay = 20)
case "likes" => respond(data = "150", delay = 40)
case "comments" => respond(data = "14", delay = 20)
}
}

private def respond(data: String, delay: Long) = Promise.timeout(Ok(data), delay)
}

app/mock/Mock.scala

Modify the mock endpoint so wvyp is slow and search is fast

Recommended for you

Again, the page loads almost immediately, but this time,
neither count is visible.
2 seconds later, both counts appear.
Fortunately, the CSS still loads right at the beginning.
So it’s still a big win, even if the top of the
page is slow, but not by as much.

Recommended for you

Is there a way to stream the data out of
order but still render it in order?
JavaScript!
@(contents: Html, id: String)

<script type="text/html-stream" id="@id-contents">
@contents
</script>

<script type="text/javascript">
document.getElementById("@id").innerHTML = document.getElementById("@id-contents").innerHTML;
</script>

app/views/ui/pagelet.scala.html

Create a “pagelet” template that will take a snippet of HTML
and use JS to inject it into the proper spot on the page.
object Pagelet {
def render(html: Html, id: String): Html = {
views.html.ui.pagelet(html, id)
}

def renderStream(html: Html, id: String): HtmlStream = {
HtmlStream(render(html, id))
}

def renderStream(htmlFuture: Future[Html], id: String): HtmlStream = {
HtmlStream.flatten(htmlFuture.map(html => renderStream(html, id)))
}
}

app/ui/Pagelet.scala

Add a Pagelet class with helper methods to wrap Html and
Future[Html] in the pagelet template.

Recommended for you

@(body: ui.HtmlStream)
<html>
<head>
<link rel="stylesheet" href="/assets/stylesheets/wvyp.css"/>
</head>
<body>
<div class="wvyp">
<h2>Who's Viewed Your Profile</h2>
<div id="wvypCount"></div>
<div id="searchCount"></div>
</div>
@body
</body>
</html>

app/views/wvyp/wvyp.scala.stream

Update the WVYP streaming template to include placholder
divs for the WVYP and search counts
def index = Action {
val wvypCountFuture = ServiceClient.makeServiceCall("wvyp")
val searchCountFuture = ServiceClient.makeServiceCall("search")

val wvypCountHtmlFuture = wvypCountFuture.map(str => views.html.wvyp.wvypCount(str.toInt))
val searchCountHtmlFuture = searchCountFuture.map(str => views.html.wvyp.searchCount(str.toInt))

}

app/controllers/WVYPStream.scala

Finally, update the WVYPStream controller. We still make two
service calls and render each as HTML.
def index = Action {
val wvypCountFuture = ServiceClient.makeServiceCall("wvyp")
val searchCountFuture = ServiceClient.makeServiceCall("search")

val wvypCountHtmlFuture = wvypCountFuture.map(str => views.html.wvyp.wvypCount(str.toInt))
val searchCountHtmlFuture = searchCountFuture.map(str => views.html.wvyp.searchCount(str.toInt))

val wvypCountStream = Pagelet.renderStream(wvypCountHtmlFuture, "wvypCount")
val searchCountStream = Pagelet.renderStream(searchCountHtmlFuture, "searchCount")

}

app/controllers/WVYPStream.scala

This time, we convert the Future[Html] into an HtmlStream
using the Pagelet.renderStream helper method.
def index = Action {
val wvypCountFuture = ServiceClient.makeServiceCall("wvyp")
val searchCountFuture = ServiceClient.makeServiceCall("search")

val wvypCountHtmlFuture = wvypCountFuture.map(str => views.html.wvyp.wvypCount(str.toInt))
val searchCountHtmlFuture = searchCountFuture.map(str => views.html.wvyp.searchCount(str.toInt))

val wvypCountStream = Pagelet.renderStream(wvypCountHtmlFuture, "wvypCount")
val searchCountStream = Pagelet.renderStream(searchCountHtmlFuture, "searchCount")

val body = HtmlStream.interleave(wvypCountStream, searchCountStream)

Ok.chunked(views.stream.wvypStreaming(body))
}

app/controllers/WVYPStream.scala

Instead of using andThen, we compose the streams using
interleave. This way, the Html will stream as soon as it’s ready.

Recommended for you

The page loads almost immediately, but now we see the
search count first
2 second later, the WVYP count appears.
We now have the basics for out-of-order,
BigPipe style rendering!
Wins
1.

Much faster time to first byte

2.

Static content can start loading much earlier

3.

User can see and start interacting with the page almost immediately

4.

Out of order rendering with JavaScript allows even deeper optimizations

Recommended for you

Caveats
1.

Once you’ve streamed out the HTTP headers, you can’t change them. This
means cookies and error handling may have to be done client-side.

2.

Have to be careful with “pop in” and redraws. Client side code should
intelligently choose when to insert items into the DOM.

3.

Need to handle CSS and JS dependencies differently

4.

Testing is harder

5.

May need to disable JavaScript rendering for SEO
You can find the code from this presentation at:
https://github.com/brikis98/ping-play
Thank you!

More Related Content

What's hot

Spring boot introduction
Spring boot introductionSpring boot introduction
Spring boot introduction
Rasheed Waraich
 
Spring Boot
Spring BootSpring Boot
Spring Boot
Jiayun Zhou
 
Introduction to GraphQL
Introduction to GraphQLIntroduction to GraphQL
Introduction to GraphQL
Amazon Web Services
 
Spring Security
Spring SecuritySpring Security
Spring Security
Knoldus Inc.
 
What is tackled in the Java EE Security API (Java EE 8)
What is tackled in the Java EE Security API (Java EE 8)What is tackled in the Java EE Security API (Java EE 8)
What is tackled in the Java EE Security API (Java EE 8)
Rudy De Busscher
 
From a monolith to microservices + REST: The evolution of LinkedIn's architec...
From a monolith to microservices + REST: The evolution of LinkedIn's architec...From a monolith to microservices + REST: The evolution of LinkedIn's architec...
From a monolith to microservices + REST: The evolution of LinkedIn's architec...
Karan Parikh
 
GraphQL
GraphQLGraphQL
GraphQL
Joel Corrêa
 
Service workers
Service workersService workers
Service workers
jungkees
 
Spring Security 5
Spring Security 5Spring Security 5
Spring Security 5
Jesus Perez Franco
 
REST vs GraphQL
REST vs GraphQLREST vs GraphQL
REST vs GraphQL
Squareboat
 
OAuth2 and Spring Security
OAuth2 and Spring SecurityOAuth2 and Spring Security
OAuth2 and Spring Security
Orest Ivasiv
 
Lets make a better react form
Lets make a better react formLets make a better react form
Lets make a better react form
Yao Nien Chung
 
Express JS
Express JSExpress JS
Express JS
Alok Guha
 
Spring Boot
Spring BootSpring Boot
Spring Boot
Pei-Tang Huang
 
Event-driven microservices
Event-driven microservicesEvent-driven microservices
Event-driven microservices
Andrew Schofield
 
NestJS
NestJSNestJS
NestJS
Wilson Su
 
Building secure applications with keycloak
Building secure applications with keycloak Building secure applications with keycloak
Building secure applications with keycloak
Abhishek Koserwal
 
REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with Spring
Joshua Long
 
Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...
Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...
Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...
Edureka!
 
Graphql
GraphqlGraphql
Graphql
Niv Ben David
 

What's hot (20)

Spring boot introduction
Spring boot introductionSpring boot introduction
Spring boot introduction
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 
Introduction to GraphQL
Introduction to GraphQLIntroduction to GraphQL
Introduction to GraphQL
 
Spring Security
Spring SecuritySpring Security
Spring Security
 
What is tackled in the Java EE Security API (Java EE 8)
What is tackled in the Java EE Security API (Java EE 8)What is tackled in the Java EE Security API (Java EE 8)
What is tackled in the Java EE Security API (Java EE 8)
 
From a monolith to microservices + REST: The evolution of LinkedIn's architec...
From a monolith to microservices + REST: The evolution of LinkedIn's architec...From a monolith to microservices + REST: The evolution of LinkedIn's architec...
From a monolith to microservices + REST: The evolution of LinkedIn's architec...
 
GraphQL
GraphQLGraphQL
GraphQL
 
Service workers
Service workersService workers
Service workers
 
Spring Security 5
Spring Security 5Spring Security 5
Spring Security 5
 
REST vs GraphQL
REST vs GraphQLREST vs GraphQL
REST vs GraphQL
 
OAuth2 and Spring Security
OAuth2 and Spring SecurityOAuth2 and Spring Security
OAuth2 and Spring Security
 
Lets make a better react form
Lets make a better react formLets make a better react form
Lets make a better react form
 
Express JS
Express JSExpress JS
Express JS
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 
Event-driven microservices
Event-driven microservicesEvent-driven microservices
Event-driven microservices
 
NestJS
NestJSNestJS
NestJS
 
Building secure applications with keycloak
Building secure applications with keycloak Building secure applications with keycloak
Building secure applications with keycloak
 
REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with Spring
 
Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...
Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...
Angular Directives | Angular 2 Custom Directives | Angular Tutorial | Angular...
 
Graphql
GraphqlGraphql
Graphql
 

Viewers also liked

Play Framework: async I/O with Java and Scala
Play Framework: async I/O with Java and ScalaPlay Framework: async I/O with Java and Scala
Play Framework: async I/O with Java and Scala
Yevgeniy Brikman
 
LinkedIn - A highly scalable Architecture on Java!
LinkedIn - A highly scalable Architecture on Java!LinkedIn - A highly scalable Architecture on Java!
LinkedIn - A highly scalable Architecture on Java!
manivannan57
 
The Play Framework at LinkedIn
The Play Framework at LinkedInThe Play Framework at LinkedIn
The Play Framework at LinkedIn
Yevgeniy Brikman
 
An intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECSAn intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECS
Yevgeniy Brikman
 
Introduction to Iteratees (Scala)
Introduction to Iteratees (Scala)Introduction to Iteratees (Scala)
Introduction to Iteratees (Scala)
Alexander Lehmann
 
Node.js vs Play Framework (with Japanese subtitles)
Node.js vs Play Framework (with Japanese subtitles)Node.js vs Play Framework (with Japanese subtitles)
Node.js vs Play Framework (with Japanese subtitles)
Yevgeniy Brikman
 
Infrastructure as code: running microservices on AWS using Docker, Terraform,...
Infrastructure as code: running microservices on AWS using Docker, Terraform,...Infrastructure as code: running microservices on AWS using Docker, Terraform,...
Infrastructure as code: running microservices on AWS using Docker, Terraform,...
Yevgeniy Brikman
 
Iteratee and stream with Play2 scala
Iteratee and stream with Play2 scalaIteratee and stream with Play2 scala
Iteratee and stream with Play2 scala
Quentin Adam
 
Data Workflows for Machine Learning - SF Bay Area ML
Data Workflows for Machine Learning - SF Bay Area MLData Workflows for Machine Learning - SF Bay Area ML
Data Workflows for Machine Learning - SF Bay Area ML
Paco Nathan
 
From Data to Decisions Makers: A Behind the Scenes Look at Building The Most ...
From Data to Decisions Makers: A Behind the Scenes Look at Building The Most ...From Data to Decisions Makers: A Behind the Scenes Look at Building The Most ...
From Data to Decisions Makers: A Behind the Scenes Look at Building The Most ...
Bob Rudis
 
Chicago Hadoop Users Group: Enterprise Data Workflows
Chicago Hadoop Users Group: Enterprise Data WorkflowsChicago Hadoop Users Group: Enterprise Data Workflows
Chicago Hadoop Users Group: Enterprise Data Workflows
Paco Nathan
 
Spring 3.1 and MVC Testing Support - 4Developers
Spring 3.1 and MVC Testing Support - 4DevelopersSpring 3.1 and MVC Testing Support - 4Developers
Spring 3.1 and MVC Testing Support - 4Developers
Sam Brannen
 
Reactive Programming With Akka - Lessons Learned
Reactive Programming With Akka - Lessons LearnedReactive Programming With Akka - Lessons Learned
Reactive Programming With Akka - Lessons Learned
Daniel Sawano
 
The no-framework Scala Dependency Injection Framework
The no-framework Scala Dependency Injection FrameworkThe no-framework Scala Dependency Injection Framework
The no-framework Scala Dependency Injection Framework
Adam Warski
 
A Sceptical Guide to Functional Programming
A Sceptical Guide to Functional ProgrammingA Sceptical Guide to Functional Programming
A Sceptical Guide to Functional Programming
Garth Gilmour
 
Actor Based Asyncronous IO in Akka
Actor Based Asyncronous IO in AkkaActor Based Asyncronous IO in Akka
Actor Based Asyncronous IO in Akka
drewhk
 
Effective akka scalaio
Effective akka scalaioEffective akka scalaio
Effective akka scalaio
shinolajla
 
DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...
DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...
DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...
it-people
 
Playing with Scala
Playing with ScalaPlaying with Scala
Playing with Scala
Tamer Abdul-Radi
 
[Start] Playing
[Start] Playing[Start] Playing
[Start] Playing
佑介 九岡
 

Viewers also liked (20)

Play Framework: async I/O with Java and Scala
Play Framework: async I/O with Java and ScalaPlay Framework: async I/O with Java and Scala
Play Framework: async I/O with Java and Scala
 
LinkedIn - A highly scalable Architecture on Java!
LinkedIn - A highly scalable Architecture on Java!LinkedIn - A highly scalable Architecture on Java!
LinkedIn - A highly scalable Architecture on Java!
 
The Play Framework at LinkedIn
The Play Framework at LinkedInThe Play Framework at LinkedIn
The Play Framework at LinkedIn
 
An intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECSAn intro to Docker, Terraform, and Amazon ECS
An intro to Docker, Terraform, and Amazon ECS
 
Introduction to Iteratees (Scala)
Introduction to Iteratees (Scala)Introduction to Iteratees (Scala)
Introduction to Iteratees (Scala)
 
Node.js vs Play Framework (with Japanese subtitles)
Node.js vs Play Framework (with Japanese subtitles)Node.js vs Play Framework (with Japanese subtitles)
Node.js vs Play Framework (with Japanese subtitles)
 
Infrastructure as code: running microservices on AWS using Docker, Terraform,...
Infrastructure as code: running microservices on AWS using Docker, Terraform,...Infrastructure as code: running microservices on AWS using Docker, Terraform,...
Infrastructure as code: running microservices on AWS using Docker, Terraform,...
 
Iteratee and stream with Play2 scala
Iteratee and stream with Play2 scalaIteratee and stream with Play2 scala
Iteratee and stream with Play2 scala
 
Data Workflows for Machine Learning - SF Bay Area ML
Data Workflows for Machine Learning - SF Bay Area MLData Workflows for Machine Learning - SF Bay Area ML
Data Workflows for Machine Learning - SF Bay Area ML
 
From Data to Decisions Makers: A Behind the Scenes Look at Building The Most ...
From Data to Decisions Makers: A Behind the Scenes Look at Building The Most ...From Data to Decisions Makers: A Behind the Scenes Look at Building The Most ...
From Data to Decisions Makers: A Behind the Scenes Look at Building The Most ...
 
Chicago Hadoop Users Group: Enterprise Data Workflows
Chicago Hadoop Users Group: Enterprise Data WorkflowsChicago Hadoop Users Group: Enterprise Data Workflows
Chicago Hadoop Users Group: Enterprise Data Workflows
 
Spring 3.1 and MVC Testing Support - 4Developers
Spring 3.1 and MVC Testing Support - 4DevelopersSpring 3.1 and MVC Testing Support - 4Developers
Spring 3.1 and MVC Testing Support - 4Developers
 
Reactive Programming With Akka - Lessons Learned
Reactive Programming With Akka - Lessons LearnedReactive Programming With Akka - Lessons Learned
Reactive Programming With Akka - Lessons Learned
 
The no-framework Scala Dependency Injection Framework
The no-framework Scala Dependency Injection FrameworkThe no-framework Scala Dependency Injection Framework
The no-framework Scala Dependency Injection Framework
 
A Sceptical Guide to Functional Programming
A Sceptical Guide to Functional ProgrammingA Sceptical Guide to Functional Programming
A Sceptical Guide to Functional Programming
 
Actor Based Asyncronous IO in Akka
Actor Based Asyncronous IO in AkkaActor Based Asyncronous IO in Akka
Actor Based Asyncronous IO in Akka
 
Effective akka scalaio
Effective akka scalaioEffective akka scalaio
Effective akka scalaio
 
DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...
DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...
DUMP-2015: «Распределенная обработка миллионов документов на Scala и Akka» Ст...
 
Playing with Scala
Playing with ScalaPlaying with Scala
Playing with Scala
 
[Start] Playing
[Start] Playing[Start] Playing
[Start] Playing
 

Similar to Composable and streamable Play apps

Server side rendering with React and Symfony
Server side rendering with React and SymfonyServer side rendering with React and Symfony
Server side rendering with React and Symfony
Ignacio Martín
 
Angular resolver tutorial
Angular resolver tutorialAngular resolver tutorial
Angular resolver tutorial
Katy Slemon
 
Itb 2021 - Bulding Quick APIs by Gavin Pickin
Itb 2021 - Bulding Quick APIs by Gavin PickinItb 2021 - Bulding Quick APIs by Gavin Pickin
Itb 2021 - Bulding Quick APIs by Gavin Pickin
Gavin Pickin
 
MongoDB World 2018: Ch-Ch-Ch-Ch-Changes: Taking Your Stitch Application to th...
MongoDB World 2018: Ch-Ch-Ch-Ch-Changes: Taking Your Stitch Application to th...MongoDB World 2018: Ch-Ch-Ch-Ch-Changes: Taking Your Stitch Application to th...
MongoDB World 2018: Ch-Ch-Ch-Ch-Changes: Taking Your Stitch Application to th...
MongoDB
 
Sherlock Homepage - A detective story about running large web services - NDC ...
Sherlock Homepage - A detective story about running large web services - NDC ...Sherlock Homepage - A detective story about running large web services - NDC ...
Sherlock Homepage - A detective story about running large web services - NDC ...
Maarten Balliauw
 
Behind the scenes of Scaleway Functions : when Kubernetes meets our products
Behind the scenes of Scaleway Functions : when Kubernetes meets our productsBehind the scenes of Scaleway Functions : when Kubernetes meets our products
Behind the scenes of Scaleway Functions : when Kubernetes meets our products
Scaleway
 
"Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native ""Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native "
FDConf
 
Java servlet life cycle - methods ppt
Java servlet life cycle - methods pptJava servlet life cycle - methods ppt
Java servlet life cycle - methods ppt
kamal kotecha
 
using Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'susing Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API's
Antônio Roberto Silva
 
Sherlock Homepage (Maarten Balliauw)
Sherlock Homepage (Maarten Balliauw)Sherlock Homepage (Maarten Balliauw)
Sherlock Homepage (Maarten Balliauw)
Visug
 
Sherlock Homepage - A detective story about running large web services (VISUG...
Sherlock Homepage - A detective story about running large web services (VISUG...Sherlock Homepage - A detective story about running large web services (VISUG...
Sherlock Homepage - A detective story about running large web services (VISUG...
Maarten Balliauw
 
Rethinking Syncing at AltConf 2019
Rethinking Syncing at AltConf 2019Rethinking Syncing at AltConf 2019
Rethinking Syncing at AltConf 2019
Joe Keeley
 
Into The Box | Alexa and ColdBox Api's
Into The Box | Alexa and ColdBox Api'sInto The Box | Alexa and ColdBox Api's
Into The Box | Alexa and ColdBox Api's
Ortus Solutions, Corp
 
What's new in Rails 5 - API Mode & Action Cable overview
What's new in Rails 5 - API Mode & Action Cable overviewWhat's new in Rails 5 - API Mode & Action Cable overview
What's new in Rails 5 - API Mode & Action Cable overview
Maxim Veksler
 
Battle of React State Managers in frontend applications
Battle of React State Managers in frontend applicationsBattle of React State Managers in frontend applications
Battle of React State Managers in frontend applications
Evangelia Mitsopoulou
 
Functional UIs with Java 8 and Vaadin JavaOne2014
Functional UIs with Java 8 and Vaadin JavaOne2014Functional UIs with Java 8 and Vaadin JavaOne2014
Functional UIs with Java 8 and Vaadin JavaOne2014
hezamu
 
Elefrant [ng-Poznan]
Elefrant [ng-Poznan]Elefrant [ng-Poznan]
Elefrant [ng-Poznan]
Marcos Latorre
 
Active object of Symbian in the lights of client server architecture
Active object of Symbian in the lights of client server architectureActive object of Symbian in the lights of client server architecture
Active object of Symbian in the lights of client server architecture
Somenath Mukhopadhyay
 
Http programming in play
Http programming in playHttp programming in play
Http programming in play
Knoldus Inc.
 
Mvc interview questions – deep dive jinal desai
Mvc interview questions – deep dive   jinal desaiMvc interview questions – deep dive   jinal desai
Mvc interview questions – deep dive jinal desai
jinaldesailive
 

Similar to Composable and streamable Play apps (20)

Server side rendering with React and Symfony
Server side rendering with React and SymfonyServer side rendering with React and Symfony
Server side rendering with React and Symfony
 
Angular resolver tutorial
Angular resolver tutorialAngular resolver tutorial
Angular resolver tutorial
 
Itb 2021 - Bulding Quick APIs by Gavin Pickin
Itb 2021 - Bulding Quick APIs by Gavin PickinItb 2021 - Bulding Quick APIs by Gavin Pickin
Itb 2021 - Bulding Quick APIs by Gavin Pickin
 
MongoDB World 2018: Ch-Ch-Ch-Ch-Changes: Taking Your Stitch Application to th...
MongoDB World 2018: Ch-Ch-Ch-Ch-Changes: Taking Your Stitch Application to th...MongoDB World 2018: Ch-Ch-Ch-Ch-Changes: Taking Your Stitch Application to th...
MongoDB World 2018: Ch-Ch-Ch-Ch-Changes: Taking Your Stitch Application to th...
 
Sherlock Homepage - A detective story about running large web services - NDC ...
Sherlock Homepage - A detective story about running large web services - NDC ...Sherlock Homepage - A detective story about running large web services - NDC ...
Sherlock Homepage - A detective story about running large web services - NDC ...
 
Behind the scenes of Scaleway Functions : when Kubernetes meets our products
Behind the scenes of Scaleway Functions : when Kubernetes meets our productsBehind the scenes of Scaleway Functions : when Kubernetes meets our products
Behind the scenes of Scaleway Functions : when Kubernetes meets our products
 
"Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native ""Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native "
 
Java servlet life cycle - methods ppt
Java servlet life cycle - methods pptJava servlet life cycle - methods ppt
Java servlet life cycle - methods ppt
 
using Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'susing Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API's
 
Sherlock Homepage (Maarten Balliauw)
Sherlock Homepage (Maarten Balliauw)Sherlock Homepage (Maarten Balliauw)
Sherlock Homepage (Maarten Balliauw)
 
Sherlock Homepage - A detective story about running large web services (VISUG...
Sherlock Homepage - A detective story about running large web services (VISUG...Sherlock Homepage - A detective story about running large web services (VISUG...
Sherlock Homepage - A detective story about running large web services (VISUG...
 
Rethinking Syncing at AltConf 2019
Rethinking Syncing at AltConf 2019Rethinking Syncing at AltConf 2019
Rethinking Syncing at AltConf 2019
 
Into The Box | Alexa and ColdBox Api's
Into The Box | Alexa and ColdBox Api'sInto The Box | Alexa and ColdBox Api's
Into The Box | Alexa and ColdBox Api's
 
What's new in Rails 5 - API Mode & Action Cable overview
What's new in Rails 5 - API Mode & Action Cable overviewWhat's new in Rails 5 - API Mode & Action Cable overview
What's new in Rails 5 - API Mode & Action Cable overview
 
Battle of React State Managers in frontend applications
Battle of React State Managers in frontend applicationsBattle of React State Managers in frontend applications
Battle of React State Managers in frontend applications
 
Functional UIs with Java 8 and Vaadin JavaOne2014
Functional UIs with Java 8 and Vaadin JavaOne2014Functional UIs with Java 8 and Vaadin JavaOne2014
Functional UIs with Java 8 and Vaadin JavaOne2014
 
Elefrant [ng-Poznan]
Elefrant [ng-Poznan]Elefrant [ng-Poznan]
Elefrant [ng-Poznan]
 
Active object of Symbian in the lights of client server architecture
Active object of Symbian in the lights of client server architectureActive object of Symbian in the lights of client server architecture
Active object of Symbian in the lights of client server architecture
 
Http programming in play
Http programming in playHttp programming in play
Http programming in play
 
Mvc interview questions – deep dive jinal desai
Mvc interview questions – deep dive   jinal desaiMvc interview questions – deep dive   jinal desai
Mvc interview questions – deep dive jinal desai
 

More from Yevgeniy Brikman

Cloud adoption fails - 5 ways deployments go wrong and 5 solutions
Cloud adoption fails - 5 ways deployments go wrong and 5 solutionsCloud adoption fails - 5 ways deployments go wrong and 5 solutions
Cloud adoption fails - 5 ways deployments go wrong and 5 solutions
Yevgeniy Brikman
 
How to test infrastructure code: automated testing for Terraform, Kubernetes,...
How to test infrastructure code: automated testing for Terraform, Kubernetes,...How to test infrastructure code: automated testing for Terraform, Kubernetes,...
How to test infrastructure code: automated testing for Terraform, Kubernetes,...
Yevgeniy Brikman
 
Lessons learned from writing over 300,000 lines of infrastructure code
Lessons learned from writing over 300,000 lines of infrastructure codeLessons learned from writing over 300,000 lines of infrastructure code
Lessons learned from writing over 300,000 lines of infrastructure code
Yevgeniy Brikman
 
Gruntwork Executive Summary
Gruntwork Executive SummaryGruntwork Executive Summary
Gruntwork Executive Summary
Yevgeniy Brikman
 
Reusable, composable, battle-tested Terraform modules
Reusable, composable, battle-tested Terraform modulesReusable, composable, battle-tested Terraform modules
Reusable, composable, battle-tested Terraform modules
Yevgeniy Brikman
 
The Truth About Startups: What I wish someone had told me about entrepreneurs...
The Truth About Startups: What I wish someone had told me about entrepreneurs...The Truth About Startups: What I wish someone had told me about entrepreneurs...
The Truth About Startups: What I wish someone had told me about entrepreneurs...
Yevgeniy Brikman
 
Comprehensive Terraform Training
Comprehensive Terraform TrainingComprehensive Terraform Training
Comprehensive Terraform Training
Yevgeniy Brikman
 
Agility Requires Safety
Agility Requires SafetyAgility Requires Safety
Agility Requires Safety
Yevgeniy Brikman
 
Startup Ideas and Validation
Startup Ideas and ValidationStartup Ideas and Validation
Startup Ideas and Validation
Yevgeniy Brikman
 
A Guide to Hiring for your Startup
A Guide to Hiring for your StartupA Guide to Hiring for your Startup
A Guide to Hiring for your Startup
Yevgeniy Brikman
 
Startup DNA: Speed Wins
Startup DNA: Speed WinsStartup DNA: Speed Wins
Startup DNA: Speed Wins
Yevgeniy Brikman
 
Node.js vs Play Framework
Node.js vs Play FrameworkNode.js vs Play Framework
Node.js vs Play Framework
Yevgeniy Brikman
 
Rapid prototyping
Rapid prototypingRapid prototyping
Rapid prototyping
Yevgeniy Brikman
 
Kings of Code Hack Battle
Kings of Code Hack BattleKings of Code Hack Battle
Kings of Code Hack Battle
Yevgeniy Brikman
 
Hackdays and [in]cubator
Hackdays and [in]cubatorHackdays and [in]cubator
Hackdays and [in]cubator
Yevgeniy Brikman
 
Startup DNA: the formula behind successful startups in Silicon Valley (update...
Startup DNA: the formula behind successful startups in Silicon Valley (update...Startup DNA: the formula behind successful startups in Silicon Valley (update...
Startup DNA: the formula behind successful startups in Silicon Valley (update...
Yevgeniy Brikman
 
Dust.js
Dust.jsDust.js
LinkedIn Overview
LinkedIn OverviewLinkedIn Overview
LinkedIn Overview
Yevgeniy Brikman
 

More from Yevgeniy Brikman (18)

Cloud adoption fails - 5 ways deployments go wrong and 5 solutions
Cloud adoption fails - 5 ways deployments go wrong and 5 solutionsCloud adoption fails - 5 ways deployments go wrong and 5 solutions
Cloud adoption fails - 5 ways deployments go wrong and 5 solutions
 
How to test infrastructure code: automated testing for Terraform, Kubernetes,...
How to test infrastructure code: automated testing for Terraform, Kubernetes,...How to test infrastructure code: automated testing for Terraform, Kubernetes,...
How to test infrastructure code: automated testing for Terraform, Kubernetes,...
 
Lessons learned from writing over 300,000 lines of infrastructure code
Lessons learned from writing over 300,000 lines of infrastructure codeLessons learned from writing over 300,000 lines of infrastructure code
Lessons learned from writing over 300,000 lines of infrastructure code
 
Gruntwork Executive Summary
Gruntwork Executive SummaryGruntwork Executive Summary
Gruntwork Executive Summary
 
Reusable, composable, battle-tested Terraform modules
Reusable, composable, battle-tested Terraform modulesReusable, composable, battle-tested Terraform modules
Reusable, composable, battle-tested Terraform modules
 
The Truth About Startups: What I wish someone had told me about entrepreneurs...
The Truth About Startups: What I wish someone had told me about entrepreneurs...The Truth About Startups: What I wish someone had told me about entrepreneurs...
The Truth About Startups: What I wish someone had told me about entrepreneurs...
 
Comprehensive Terraform Training
Comprehensive Terraform TrainingComprehensive Terraform Training
Comprehensive Terraform Training
 
Agility Requires Safety
Agility Requires SafetyAgility Requires Safety
Agility Requires Safety
 
Startup Ideas and Validation
Startup Ideas and ValidationStartup Ideas and Validation
Startup Ideas and Validation
 
A Guide to Hiring for your Startup
A Guide to Hiring for your StartupA Guide to Hiring for your Startup
A Guide to Hiring for your Startup
 
Startup DNA: Speed Wins
Startup DNA: Speed WinsStartup DNA: Speed Wins
Startup DNA: Speed Wins
 
Node.js vs Play Framework
Node.js vs Play FrameworkNode.js vs Play Framework
Node.js vs Play Framework
 
Rapid prototyping
Rapid prototypingRapid prototyping
Rapid prototyping
 
Kings of Code Hack Battle
Kings of Code Hack BattleKings of Code Hack Battle
Kings of Code Hack Battle
 
Hackdays and [in]cubator
Hackdays and [in]cubatorHackdays and [in]cubator
Hackdays and [in]cubator
 
Startup DNA: the formula behind successful startups in Silicon Valley (update...
Startup DNA: the formula behind successful startups in Silicon Valley (update...Startup DNA: the formula behind successful startups in Silicon Valley (update...
Startup DNA: the formula behind successful startups in Silicon Valley (update...
 
Dust.js
Dust.jsDust.js
Dust.js
 
LinkedIn Overview
LinkedIn OverviewLinkedIn Overview
LinkedIn Overview
 

Recently uploaded

Details of description part II: Describing images in practice - Tech Forum 2024
Details of description part II: Describing images in practice - Tech Forum 2024Details of description part II: Describing images in practice - Tech Forum 2024
Details of description part II: Describing images in practice - Tech Forum 2024
BookNet Canada
 
Pigging Solutions Sustainability brochure.pdf
Pigging Solutions Sustainability brochure.pdfPigging Solutions Sustainability brochure.pdf
Pigging Solutions Sustainability brochure.pdf
Pigging Solutions
 
Cookies program to display the information though cookie creation
Cookies program to display the information though cookie creationCookies program to display the information though cookie creation
Cookies program to display the information though cookie creation
shanthidl1
 
INDIAN AIR FORCE FIGHTER PLANES LIST.pdf
INDIAN AIR FORCE FIGHTER PLANES LIST.pdfINDIAN AIR FORCE FIGHTER PLANES LIST.pdf
INDIAN AIR FORCE FIGHTER PLANES LIST.pdf
jackson110191
 
Best Practices for Effectively Running dbt in Airflow.pdf
Best Practices for Effectively Running dbt in Airflow.pdfBest Practices for Effectively Running dbt in Airflow.pdf
Best Practices for Effectively Running dbt in Airflow.pdf
Tatiana Al-Chueyr
 
Coordinate Systems in FME 101 - Webinar Slides
Coordinate Systems in FME 101 - Webinar SlidesCoordinate Systems in FME 101 - Webinar Slides
Coordinate Systems in FME 101 - Webinar Slides
Safe Software
 
Mitigating the Impact of State Management in Cloud Stream Processing Systems
Mitigating the Impact of State Management in Cloud Stream Processing SystemsMitigating the Impact of State Management in Cloud Stream Processing Systems
Mitigating the Impact of State Management in Cloud Stream Processing Systems
ScyllaDB
 
How RPA Help in the Transportation and Logistics Industry.pptx
How RPA Help in the Transportation and Logistics Industry.pptxHow RPA Help in the Transportation and Logistics Industry.pptx
How RPA Help in the Transportation and Logistics Industry.pptx
SynapseIndia
 
20240702 QFM021 Machine Intelligence Reading List June 2024
20240702 QFM021 Machine Intelligence Reading List June 202420240702 QFM021 Machine Intelligence Reading List June 2024
20240702 QFM021 Machine Intelligence Reading List June 2024
Matthew Sinclair
 
7 Most Powerful Solar Storms in the History of Earth.pdf
7 Most Powerful Solar Storms in the History of Earth.pdf7 Most Powerful Solar Storms in the History of Earth.pdf
7 Most Powerful Solar Storms in the History of Earth.pdf
Enterprise Wired
 
[Talk] Moving Beyond Spaghetti Infrastructure [AOTB] 2024-07-04.pdf
[Talk] Moving Beyond Spaghetti Infrastructure [AOTB] 2024-07-04.pdf[Talk] Moving Beyond Spaghetti Infrastructure [AOTB] 2024-07-04.pdf
[Talk] Moving Beyond Spaghetti Infrastructure [AOTB] 2024-07-04.pdf
Kief Morris
 
WhatsApp Image 2024-03-27 at 08.19.52_bfd93109.pdf
WhatsApp Image 2024-03-27 at 08.19.52_bfd93109.pdfWhatsApp Image 2024-03-27 at 08.19.52_bfd93109.pdf
WhatsApp Image 2024-03-27 at 08.19.52_bfd93109.pdf
ArgaBisma
 
BT & Neo4j: Knowledge Graphs for Critical Enterprise Systems.pptx.pdf
BT & Neo4j: Knowledge Graphs for Critical Enterprise Systems.pptx.pdfBT & Neo4j: Knowledge Graphs for Critical Enterprise Systems.pptx.pdf
BT & Neo4j: Knowledge Graphs for Critical Enterprise Systems.pptx.pdf
Neo4j
 
How Social Media Hackers Help You to See Your Wife's Message.pdf
How Social Media Hackers Help You to See Your Wife's Message.pdfHow Social Media Hackers Help You to See Your Wife's Message.pdf
How Social Media Hackers Help You to See Your Wife's Message.pdf
HackersList
 
Paradigm Shifts in User Modeling: A Journey from Historical Foundations to Em...
Paradigm Shifts in User Modeling: A Journey from Historical Foundations to Em...Paradigm Shifts in User Modeling: A Journey from Historical Foundations to Em...
Paradigm Shifts in User Modeling: A Journey from Historical Foundations to Em...
Erasmo Purificato
 
Comparison Table of DiskWarrior Alternatives.pdf
Comparison Table of DiskWarrior Alternatives.pdfComparison Table of DiskWarrior Alternatives.pdf
Comparison Table of DiskWarrior Alternatives.pdf
Andrey Yasko
 
Transcript: Details of description part II: Describing images in practice - T...
Transcript: Details of description part II: Describing images in practice - T...Transcript: Details of description part II: Describing images in practice - T...
Transcript: Details of description part II: Describing images in practice - T...
BookNet Canada
 
20240705 QFM024 Irresponsible AI Reading List June 2024
20240705 QFM024 Irresponsible AI Reading List June 202420240705 QFM024 Irresponsible AI Reading List June 2024
20240705 QFM024 Irresponsible AI Reading List June 2024
Matthew Sinclair
 
Manual | Product | Research Presentation
Manual | Product | Research PresentationManual | Product | Research Presentation
Manual | Product | Research Presentation
welrejdoall
 
TrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-In
TrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-InTrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-In
TrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-In
TrustArc
 

Recently uploaded (20)

Details of description part II: Describing images in practice - Tech Forum 2024
Details of description part II: Describing images in practice - Tech Forum 2024Details of description part II: Describing images in practice - Tech Forum 2024
Details of description part II: Describing images in practice - Tech Forum 2024
 
Pigging Solutions Sustainability brochure.pdf
Pigging Solutions Sustainability brochure.pdfPigging Solutions Sustainability brochure.pdf
Pigging Solutions Sustainability brochure.pdf
 
Cookies program to display the information though cookie creation
Cookies program to display the information though cookie creationCookies program to display the information though cookie creation
Cookies program to display the information though cookie creation
 
INDIAN AIR FORCE FIGHTER PLANES LIST.pdf
INDIAN AIR FORCE FIGHTER PLANES LIST.pdfINDIAN AIR FORCE FIGHTER PLANES LIST.pdf
INDIAN AIR FORCE FIGHTER PLANES LIST.pdf
 
Best Practices for Effectively Running dbt in Airflow.pdf
Best Practices for Effectively Running dbt in Airflow.pdfBest Practices for Effectively Running dbt in Airflow.pdf
Best Practices for Effectively Running dbt in Airflow.pdf
 
Coordinate Systems in FME 101 - Webinar Slides
Coordinate Systems in FME 101 - Webinar SlidesCoordinate Systems in FME 101 - Webinar Slides
Coordinate Systems in FME 101 - Webinar Slides
 
Mitigating the Impact of State Management in Cloud Stream Processing Systems
Mitigating the Impact of State Management in Cloud Stream Processing SystemsMitigating the Impact of State Management in Cloud Stream Processing Systems
Mitigating the Impact of State Management in Cloud Stream Processing Systems
 
How RPA Help in the Transportation and Logistics Industry.pptx
How RPA Help in the Transportation and Logistics Industry.pptxHow RPA Help in the Transportation and Logistics Industry.pptx
How RPA Help in the Transportation and Logistics Industry.pptx
 
20240702 QFM021 Machine Intelligence Reading List June 2024
20240702 QFM021 Machine Intelligence Reading List June 202420240702 QFM021 Machine Intelligence Reading List June 2024
20240702 QFM021 Machine Intelligence Reading List June 2024
 
7 Most Powerful Solar Storms in the History of Earth.pdf
7 Most Powerful Solar Storms in the History of Earth.pdf7 Most Powerful Solar Storms in the History of Earth.pdf
7 Most Powerful Solar Storms in the History of Earth.pdf
 
[Talk] Moving Beyond Spaghetti Infrastructure [AOTB] 2024-07-04.pdf
[Talk] Moving Beyond Spaghetti Infrastructure [AOTB] 2024-07-04.pdf[Talk] Moving Beyond Spaghetti Infrastructure [AOTB] 2024-07-04.pdf
[Talk] Moving Beyond Spaghetti Infrastructure [AOTB] 2024-07-04.pdf
 
WhatsApp Image 2024-03-27 at 08.19.52_bfd93109.pdf
WhatsApp Image 2024-03-27 at 08.19.52_bfd93109.pdfWhatsApp Image 2024-03-27 at 08.19.52_bfd93109.pdf
WhatsApp Image 2024-03-27 at 08.19.52_bfd93109.pdf
 
BT & Neo4j: Knowledge Graphs for Critical Enterprise Systems.pptx.pdf
BT & Neo4j: Knowledge Graphs for Critical Enterprise Systems.pptx.pdfBT & Neo4j: Knowledge Graphs for Critical Enterprise Systems.pptx.pdf
BT & Neo4j: Knowledge Graphs for Critical Enterprise Systems.pptx.pdf
 
How Social Media Hackers Help You to See Your Wife's Message.pdf
How Social Media Hackers Help You to See Your Wife's Message.pdfHow Social Media Hackers Help You to See Your Wife's Message.pdf
How Social Media Hackers Help You to See Your Wife's Message.pdf
 
Paradigm Shifts in User Modeling: A Journey from Historical Foundations to Em...
Paradigm Shifts in User Modeling: A Journey from Historical Foundations to Em...Paradigm Shifts in User Modeling: A Journey from Historical Foundations to Em...
Paradigm Shifts in User Modeling: A Journey from Historical Foundations to Em...
 
Comparison Table of DiskWarrior Alternatives.pdf
Comparison Table of DiskWarrior Alternatives.pdfComparison Table of DiskWarrior Alternatives.pdf
Comparison Table of DiskWarrior Alternatives.pdf
 
Transcript: Details of description part II: Describing images in practice - T...
Transcript: Details of description part II: Describing images in practice - T...Transcript: Details of description part II: Describing images in practice - T...
Transcript: Details of description part II: Describing images in practice - T...
 
20240705 QFM024 Irresponsible AI Reading List June 2024
20240705 QFM024 Irresponsible AI Reading List June 202420240705 QFM024 Irresponsible AI Reading List June 2024
20240705 QFM024 Irresponsible AI Reading List June 2024
 
Manual | Product | Research Presentation
Manual | Product | Research PresentationManual | Product | Research Presentation
Manual | Product | Research Presentation
 
TrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-In
TrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-InTrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-In
TrustArc Webinar - 2024 Data Privacy Trends: A Mid-Year Check-In
 

Composable and streamable Play apps

  • 2. About me Part of the Service Infrastructure team, which is bringing the Play Framework to LinkedIn engineers.
  • 3. At LinkedIn, we’ve been running Play apps in production for over a year
  • 4. More than 60 apps on Play now, including:
  • 9. Play Labs (e.g. InDemand)
  • 10. Many internal tools (e.g. REST search)
  • 11. Plus many backends services that don’t have sexy screenshots
  • 12. We love Play… but we’ve had a couple tiny problems:
  • 13. We love Play… but we’ve had a couple tiny problems: 1. Unmanageable complexity
  • 14. We love Play… but we’ve had a couple tiny problems: 1. Unmanageable complexity 2. Terrible performance
  • 15. It’s probably not what you think.
  • 16. This talk is about a couple techniques to deal with complexity and performance problems.
  • 17. These techniques are experimental.
  • 20. You can find the code from this presentation at: https://github.com/brikis98/ping-play
  • 21. Outline 1. Complexity 2. Composition 3. HTTP 4. Performance 5. Enumerators 6. Streaming
  • 22. Outline 1. Complexity 2. Composition 3. HTTP 4. Performance 5. Enumerators 6. Streaming
  • 23. Web pages can get complex
  • 24. For example, consider the LinkedIn home page
  • 25. Almost every part of the page is dynamic, highly customized for the user, and interactive.
  • 26. Trying to cram this all into one controller and one template is completely unmaintainable
  • 27. “Managing complexity is the most important technical topic in software development.” Steve McConnell, Code Complete
  • 29. “Abstraction is the ability to engage with a concept while safely ignoring some of its details.” Steve McConnell, Code Complete
  • 30. Abstraction allows you to take a simpler view of a complex concept
  • 31. Composition: assemble complex behavior by combining simpler behavior
  • 33. Abstraction: structure your app so you can focus on one part while safely ignoring the rest
  • 34. Abstraction: structure your app so you can focus on one part while safely ignoring the rest Composition: structure your app so you can easily combine the simpler parts into more complicated parts
  • 35. Outline 1. Complexity 2. Composition 3. HTTP 4. Performance 5. Enumerators 6. Streaming
  • 36. We’ll start by building a completely standalone “Who’s Viewed Your Profile” (WVYP) module
  • 37. We need: 1. Data: WVYP count, search count 2. Template: to render the HTML 3. Controller: to tie it all together
  • 39. For this talk, we’re going to simulate service calls by calling a mock endpoint
  • 40. object Mock extends Controller { def mock(serviceName: String) = Action.async { serviceName match { case "wvyp" => respond(data = "56", delay = 10) case "search" => respond(data = "10", delay = 5) case "likes" => respond(data = "150", delay = 40) case "comments" => respond(data = "14", delay = 20) } } private def respond(data: String, delay: Long) = Promise.timeout(Ok(data), delay) } app/mock/Mock.scala For each “service”, this endpoint returns mock data after a fixed delay. In the real world, the data might be JSON.
  • 42. object ServiceClient { def makeServiceCall(serviceName: String): Future[String] = { WS.url(s"http://localhost:9000/mock/$serviceName").get().map(_.body) } } app/data/ServiceClient.scala A simple client to make a remote call to the mock endpoint and return a Future with the body of the HTTP response
  • 43. @(wvypCount: Int, searchCount: Int) <html> <head> <link rel="stylesheet" href="/assets/stylesheets/wvyp.css"/> </head> <body> <div class="wvyp"> <h2>Who's Viewed Your Profile</h2> @views.html.wvyp.wvypCount(wvypCount) @views.html.wvyp.searchCount(searchCount) </div> </body> </html> app/views/wvyp/wvyp.scala.html For the template, we use Play’s Scala templates (.scala. html). This template uses two partials for the body.
  • 44. @(wvypCount: Int) <p class="wvyp-count"> <span class="large-number">@wvypCount</span> <span>Your profile has been viewed by <b>@wvypCount</b> people in the past 3 days</span> </p> app/views/wvyp/wvypCount.scala.html @(searchCount: Int) <p class="search-count"> <span class="large-number">@searchCount</span> <span>Your have shown up in search results <b>@searchCount</b> times in the past 3 days</span> </p> app/views/wvyp/searchCount.scala.html The markup for the two partials that show the counts
  • 45. object WVYP extends Controller { def index = Action.async { val wvypCountFuture = ServiceClient.makeServiceCall("wvyp") val searchCountFuture = ServiceClient.makeServiceCall("search") } } app/controllers/WVYP.scala Next, the WVYP controller. First, we make two service calls in parallel to fetch the WVYP count and search count.
  • 46. object WVYP extends Controller { def index = Action.async { val wvypCountFuture = ServiceClient.makeServiceCall("wvyp") val searchCountFuture = ServiceClient.makeServiceCall("search") for { wvypCount <- wvypCountFuture searchCount <- searchCountFuture } yield { Ok(views.html.wvyp.wvyp(wvypCount.toInt, searchCount.toInt)) } } } app/controllers/WVYP.scala Next, we compose the two Futures into a single Future and render the WVYP template.
  • 49. We now have one small module
  • 50. Now, imagine we also have another standalone module called “Who’s Viewed Your Updates” (WVYU)
  • 52. How can we combine the two modules?
  • 53. trait Action[A] extends EssentialAction { def apply(request: Request[A]): Future[SimpleResult] } play/api/mvc/Action.scala In Play, an Action is a function
  • 54. Request[A] => Future[SimpleResult] The actions in each standalone module are just functions from Request to Result. Functions can be composed!
  • 55. @(wvypCount: Int, searchCount: Int) <html> <head> <link rel="stylesheet" href="/assets/stylesheets/wvyp.css"/> </head> <body> @views.html.wvyp.wvypBody(wvypCount, searchCount) </body> </html> app/views/wvyp/wvyp.scala.html We need one change to each module: move the body into a partial. Scala templates are functions, so they also compose!
  • 56. def index(embed: Boolean) = Action.async { val wvypCountFuture = ServiceClient.makeServiceCall("wvyp") val searchCountFuture = ServiceClient.makeServiceCall("search") for { wvypCount <- wvypCountFuture searchCount <- searchCountFuture } yield { if (embed) Ok(views.html.wvyp.wvypBody(wvypCount.toInt, searchCount.toInt)) else Ok(views.html.wvyp.wvyp(wvypCount.toInt, searchCount.toInt)) } } app/controllers/WVYP.scala Update each module’s controller to accept an “embed” parameter: if it’s set to true, render only the body partial.
  • 57. GET /mock/:serviceName controllers.Mock.mock(serviceName: String) GET /wvyp controllers.WVYP.index(embed: Boolean ?= false) GET /wvyu controllers.WVYU.index(embed: Boolean ?= false) conf/routes Update the routes file too
  • 58. object Pagelet { def readBody(result: SimpleResult)(implicit codec: Codec): Future[Html] = { result.body.run(Iteratee.consume()).map(bytes => Html(new String(bytes, codec.charset))) } } app/ui/Pagelet.scala Add a helper that can take a SimpleResult and return its body as Future[Html]. We’ll talk more about Iteratees later.
  • 59. object Aggregator extends Controller { def index = Action.async { request => val wvypFuture = Wvyp.index(embed = true)(request) val wvyuFuture = Wvyu.index(embed = true)(request) } } app/controllers/Aggregator.scala Now for the aggregator controller. First, we call the two submodules. Each returns a Future[SimpleResult].
  • 60. object Aggregator extends Controller { def index = Action.async { request => val wvypFuture = Wvyp.index(embed = true)(request) val wvyuFuture = Wvyu.index(embed = true)(request) for { wvyp <- wvypFuture wvyu <- wvyuFuture wvypBody <- Pagelet.readBody(wvyp) wvyuBody <- Pagelet.readBody(wvyu) } yield { } } } app/controllers/Aggregator.scala Read the body of each Future[SimpleResult] as Html using the Pagelet helper we just added
  • 61. object Aggregator extends Controller { def index = Action.async { request => val wvypFuture = Wvyp.index(embed = true)(request) val wvyuFuture = Wvyu.index(embed = true)(request) for { wvyp <- wvypFuture wvyu <- wvyuFuture wvypBody <- Pagelet.readBody(wvyp) wvyuBody <- Pagelet.readBody(wvyu) } yield { Ok(views.html.aggregator.aggregator(wvypBody, wvyuBody)) } } } app/controllers/Aggregator.scala Pass the Html to the aggregator template
  • 62. GET @(wvypBody:/mock/:serviceName controllers.Mock.mock(serviceName: String) Html, wvyuBody: Html) GET /wvyp controllers.WVYP.index(embed: Boolean ?= false) GET <html> /wvyu controllers.WVYU.index(embed: Boolean ?= false) GET <head> /aggregate controllers.Aggregator.index <link rel="stylesheet" href="/assets/stylesheets/wvyp.css"/> <link rel="stylesheet" href="/assets/stylesheets/wvyu.css"/> </head> <body> @wvypBody @wvyuBody </body> </html> app/views/aggregator/aggregator.scala Add the aggregator to the routes file
  • 63. The result. We’ve composed two Play modules!
  • 64. Wins 1. Abstraction: we can focus on just one small part of the page while safely ignoring all the rest. 2. Composition: we can build complicated pages by putting together simpler parts. We can get lots of reuse from common pieces. 3. Testing and iterating on a small, standalone unit is much easier and faster.
  • 65. Caveats 1. Standalone modules may be inefficient in terms of duplicated service calls. However, de-duping is straightforward. 2. Have to merge and dedupe static content.
  • 66. Outline 1. Complexity 2. Composition 3. HTTP 4. Performance 5. Enumerators 6. Streaming
  • 67. The composition code glosses over a few details
  • 68. Some questions: 1. How do we set cookies? 2. How do we handle errors? 3. How do we aggregate static content?
  • 69. It turns out HTTP is an elegant way to answer these questions.
  • 70. object WVYP extends Controller { def index(embed: Boolean) = Action { // [snip] Ok(views.html.wvyp.wvyp(wvypCount.toInt, searchCount.toInt)).withCookies(Cookie(“foo”, “bar”)) } } app/controllers/WVYP.scala For example, imagine a standalone module sets a Cookie
  • 71. object Aggregator extends Controller { def index = Action.async { request => val wvypFuture = Wvyp.index(embed = true)(request) for { wvyp <- wvypFuture wvypBody <- Pagelet.readBody(wvyp) wvypHeaders = wvyp.header.headers // The Cookie header here will contain the “foo” cookie! } yield { Ok(views.html.aggregator.aggregator(wvypBody)) } } } app/controllers/Aggregator.scala The aggregator will see that as a Cookie header!
  • 72. object Pagelet { def mergeCookies(results: SimpleResult*): Seq[Cookie] = { results.flatMap { result => result.header.headers.get(HeaderNames.SET_COOKIE).map(Cookies.decode).getOrElse(Seq.empty) } } } app/ui/Pagelet.scala We can add a helper to merge the cookies from multiple SimpleResult objects
  • 73. def index = Action.async { request => val wvypFuture = Wvyp.index(embed = true)(request) val wvyuFuture = Wvyu.index(embed = true)(request) for { wvyp <- wvypFuture wvyu <- wvyuFuture wvypBody <- Pagelet.readBody(wvyp) wvyuBody <- Pagelet.readBody(wvyu) } yield { Ok(views.html.aggregator.aggregator(wvypBody, wvyuBody)) .withCookies(Pagelet.mergeCookies(wvyp, wvyu):_*) } } app/controllers/Aggregator.scala Update the aggregator to write out the merged cookies
  • 74. We can see the aggregate endpoint is now setting cookies
  • 75. HTTP headers are a good way to handle error cases too.
  • 76. A quick review of HTTP status codes
  • 77. For example, if a module has no content, return a 204
  • 78. Invalid module request? Return 404.
  • 79. Plus other important status codes
  • 81. def index = Action.async { request => val wvypFuture = Wvyp.index(embed = true)(request) for { wvyp <- wvypFuture wvypBody <- Pagelet.readBody(wvyp) } yield { if (wvyp.status == 200) { Ok(views.html.aggregator.aggregator(wvypBody)) } else { // Handle errors } } } app/controllers/Aggregator.scala The aggregator can read the status codes and react accordingly
  • 82. CSS and JS dependencies can be set as a header and aggregated too.
  • 83. object StaticContent { val cssHeaderName = "X-CSS" val jsHeaderName = "X-JS" def asHeaders(css: Seq[String], js: Seq[String]): Seq[(String, String)] = { Seq(cssHeaderName -> css.mkString(","), jsHeaderName -> js.mkString(",")) } } app/ui/StaticContent.scala Add a helper to create the headers
  • 84. def index(embed: Boolean) = Action { // [...] all other code is the same as before [...] val css = Vector("/assets/stylesheets/wvyp.css") val js = Vector.empty[String] if (embed) { Ok(views.html.wvyp.wvypBody(wvypCount.toInt, searchCount.toInt)) .withHeaders(StaticContent.asHeaders(css, js):_*) } else { Ok(views.html.wvyp.wvyp(wvypCount.toInt, searchCount.toInt, css, js)) } } app/controllers/WVYP.scala In embed mode, return CSS/JS dependencies as headers. In standalone mode, render them in the template.
  • 85. object StaticContent { def mergeCssHeaders(results: SimpleResult*): Seq[String] = mergeHeaderValues(cssHeaderName, results: _*) def mergeJsHeaders(results: SimpleResult*): Seq[String] = mergeHeaderValues(jsHeaderName, results:_*) private def mergeHeaderValues(headerName: String, results: SimpleResult*): Seq[String] = { results.flatMap { result => result.header.headers.get(headerName).map(_.split(",").toSeq).getOrElse(Seq.empty) }.distinct } } app/ui/StaticContent.scala Helpers to merge CSS and JS headers from multiple SimpleResult objects
  • 86. def index = Action.async { request => val wvypFuture = Wvyp.index(embed = true)(request) val wvyuFuture = Wvyu.index(embed = true)(request) for { wvyp <- wvypFuture wvyu <- wvyuFuture wvypBody <- Pagelet.readBody(wvyp) wvyuBody <- Pagelet.readBody(wvyu) } yield { val css = StaticContent.mergeCssHeaders(wvyp, wvyu) val js = StaticContent.mergeCssHeaders(wvyp, wvyu) Ok(views.html.aggregator.aggregator(wvypBody, wvyuBody, css, js)) } } app/controllers/Aggregator.scala The aggregator can merge and de-dupe the static content and pass it to its template for rendering
  • 87. Wins 1. Modules are truly standalone 2. Can dynamically compose modules using Play’s router 3. Can compose modules from remote endpoints 4. Can reuse endpoints from the browser via AJAX 5. Static content dependencies explicitly defined
  • 88. Caveats 1. Managing static content in a controller, instead of a view, feels clunky.
  • 89. Outline 1. Complexity 2. Composition 3. HTTP 4. Performance 5. Enumerators 6. Streaming
  • 90. So far, we’ve been using a mock endpoint to simulate remote service calls
  • 91. What happens if one of the remote calls is slow?
  • 92. object Mock extends Controller { def mock(serviceName: String) = Action.async { serviceName match { case "wvyp" => respond(data = "56", delay = 10) case "search" => respond(data = "10", delay = 2000) // SLOW! case "likes" => respond(data = "150", delay = 40) case "comments" => respond(data = "14", delay = 20) } } private def respond(data: String, delay: Long) = Promise.timeout(Ok(data), delay) } app/mock/Mock.scala As an extreme example, let’s make the search service take two seconds to respond
  • 93. Time to first byte is 2 seconds! Everything has to wait for the one slow service, including static content.
  • 94. Is there a way to start sending the response before all the data is available?
  • 95. Facebook solves this problem with BigPipe https://www.facebook.com/note.php?note_id=389414033919
  • 96. Can we build BigPipe with Play?
  • 97. (Well, yea, or I wouldn’t have made this talk)
  • 98. We can use Enumerators!
  • 99. Outline 1. Complexity 2. Composition 3. HTTP 4. Performance 5. Enumerators 6. Streaming
  • 100. Enumerators are part of the Play Iteratees library.
  • 101. Quick Review 1. An Enumerator is a Producer. It pumps out chunks of data. 2. An Iteratee is a Consumer. It reactively consumes chunks of data. 3. An Enumeratee is an Adapter. You can attach them in front of Iteratees and Enumerators to filter the chunks of data.
  • 103. These are all composable abstractions for working with streams of data
  • 104. Let’s look at some examples
  • 105. object EnumeratorExample extends Controller { def index = Action { Ok.chunked(/* We need an Enumerator here */) } } app/controllers/EnumeratorExamples.scala Play has an Ok.chunked method which can stream out the contents of an Enumerator
  • 106. object EnumeratorExample extends Controller { def index = Action { Ok.chunked(Enumerator("Created", " using", " Enumerator", ".apply()nn")) } } app/controllers/EnumeratorExamples.scala The Enumerator object has several factory methods. For example, Enumerator.apply creates one from a fixed list.
  • 107. Basic “Hello World” example using Enumerator.apply.
  • 108. object EnumeratorExample extends Controller { def index = Action { Ok.chunked(Enumerator.repeatM(Promise.timeout("Hellon", 500))) } } app/controllers/EnumeratorExamples.scala You can also create an Enumerator that repeats a value generated from a Future
  • 109. The word “Hello” is pumped out every 500ms. Note: when testing streaming, use “curl -N” so curl doesn’t buffer.
  • 110. def index = Action { val helloEnumerator = Enumerator("hello ") val goodbyeEnumerator = Enumerator("goodbyenn") val helloGoodbyeEnumerator = helloEnumerator.andThen(goodbyeEnumerator) Ok.chunked(helloGoodbyeEnumerator) } app/controllers/EnumeratorExamples.scala Most importantly, you can combine Enumerators. Here is an example using the andThen method.
  • 111. With andThen, we see all the data from the first enumerator and then all the data from the second one
  • 112. def index = Action { val helloEnumerator = Enumerator.repeatM(Promise.timeout("Hellon", 500)) val goodbyeEnumerator = Enumerator.repeatM(Promise.timeout("Goodbyen", 1000)) val helloGoodbyeEnumerator = Enumerator.interleave(helloEnumerator, goodbyeEnumerator) Ok.chunked(helloGoodbyeEnumerator) } app/controllers/EnumeratorExamples.scala We can also combine Enumerators using Enumerator. interleave
  • 113. With interleave, data can come in any order. Above, we see “Hello” every 500ms and “Goodbye” every 1000ms.
  • 114. Let’s use Enumerators to stream the results of our remote service calls
  • 115. object WVYPEnumerator extends Controller { def index = Action { val wvypCountFuture = ServiceClient.makeServiceCall("wvyp") val searchCountFuture = ServiceClient.makeServiceCall("search") } } app/controllers/WVYPEnumerator.scala Create the new WVYP controller. Again, we start with two service calls.
  • 116. object WVYPEnumerator extends Controller { def index = Action { val wvypCountFuture = ServiceClient.makeServiceCall("wvyp") val searchCountFuture = ServiceClient.makeServiceCall("search") val wvypCountEnum = Enumerator.flatten(wvypCountFuture.map(str => Enumerator(str + "n"))) val searchCountEnum = Enumerator.flatten(searchCountFuture.map(str => Enumerator(str + "n"))) } } app/controllers/WVYPEnumerator.scala Next, convert each Future[String] into an Enumerator[String]
  • 117. object WVYPEnumerator extends Controller { def index = Action { val wvypCountFuture = ServiceClient.makeServiceCall("wvyp") val searchCountFuture = ServiceClient.makeServiceCall("search") val wvypCountEnum = Enumerator.flatten(wvypCountFuture.map(str => Enumerator(str + "n"))) val searchCountEnum = Enumerator.flatten(searchCountFuture.map(str => Enumerator(str + "n"))) val body = wvypCountEnum.andThen(searchCountEnum) Ok.chunked(body) } } app/controllers/WVYPEnumerator.scala Finally, compose the two Enumerators and use Ok.chunked to stream them out
  • 118. GET @(wvypBody:/mock/:serviceName controllers.Mock.mock(serviceName: String) Html, wvyuBody: Html) GET /wvyp controllers.WVYP.index(embed: Boolean ?= false) GET <html> /wvyu controllers.WVYU.index(embed: Boolean ?= false) GET <head> /aggregate controllers.Aggregator.index GET <link rel="stylesheet" href="/assets/stylesheets/wvyp.css"/> /wvyp/enumerator controllers.WVYPEnumerator.index <link rel="stylesheet" href="/assets/stylesheets/wvyu.css"/> </head> <body> @wvypBody @wvyuBody </body> </html> app/views/aggregator/aggregator.scala Add a routes entry for the enumerator-based WVYP controller
  • 119. Almost immediately, we see “56”, from the wvyp service.
  • 120. 2 seconds later, we see “10”, from the search service.
  • 122. However, we’re only streaming plain text. How do we stream a template?
  • 123. Outline 1. Complexity 2. Composition 3. HTTP 4. Performance 5. Enumerators 6. Streaming
  • 124. play.Keys.templatesTypes ++= Map("stream" -> "ui.HtmlStreamFormat") play.Keys.templatesImport ++= Vector("ui.HtmlStream", "ui.HtmlStream._", "ui.StaticContent") build.sbt Play allows you to define a new template type. This will allow us to create .scala.stream files instead of .scala.html.
  • 125. The new template type must define an “Appendable” and a “Format” for it
  • 126. trait Appendable[T] { def +=(other: T): T } play/api/templates/Templates.scala The Appendable trait is simple: it’s anything with an append (+=) operator.
  • 127. class Html(buffer: StringBuilder) extends Appendable[Html](buffer) { def +=(other: Html) = { buffer.append(other.buffer) this } } play/api/templates/Templates.scala The default Appendable built into Play is Html, which just wraps a StringBuilder.
  • 128. case class HtmlStream(enumerator: Enumerator[Html]) extends Appendable[HtmlStream] { def +=(other: HtmlStream): HtmlStream = andThen(other) def andThen(other: HtmlStream): HtmlStream = HtmlStream(enumerator.andThen(other.enumerator)) } app/ui/HtmlStream.scala For streaming templates, we create an HtmlStream Appendable that wraps an Enumerator[Html].
  • 129. object HtmlStream { def interleave(streams: HtmlStream*): HtmlStream = { HtmlStream(Enumerator.interleave(streams.map(_.enumerator))) } def flatten(eventuallyStream: Future[HtmlStream]): HtmlStream = { HtmlStream(Enumerator.flatten(eventuallyStream.map(_.enumerator))) } } app/ui/HtmlStream.scala We add an HtmlStream companion object with helper methods to combine HtmlStreams just like Enumerators
  • 130. object HtmlStream { def apply(text: String): HtmlStream = { apply(Html(text)) } def apply(html: Html): HtmlStream = { HtmlStream(Enumerator(html)) } def apply(eventuallyHtml: Future[Html]): HtmlStream = { flatten(eventuallyHtml.map(apply)) } } app/ui/HtmlStream.scala Also, we add several methods to the HtmlStream companion object to help create HtmlStream instances.
  • 131. trait Format[T <: Appendable[T]] { type Appendable = T def raw(text: String): T def escape(text: String): T } play/api/templates/Templates.scala The Format trait is what Play will use to create your Appendable from a String
  • 132. object HtmlStreamFormat extends Format[HtmlStream] { def raw(text: String): HtmlStream = { HtmlStream(text) } def escape(text: String): HtmlStream = { raw(HtmlFormat.escape(text).body) } } app/ui/HtmlStream.scala Here’s the HtmlStreamFormat implementation
  • 133. object HtmlStreamImplicits { // Implicit conversion so HtmlStream can be passed directly to Ok.feed and Ok.chunked implicit def toEnumerator(stream: HtmlStream): Enumerator[Html] = { // Skip empty chunks, as these mean EOF in chunked encoding stream.enumerator.through(Enumeratee.filter(!_.body.isEmpty)) } } app/ui/HtmlStream.scala We also include an implicit conversion so HtmlStream can be passed directly to Ok.chunked
  • 134. @(body:ui.HtmlStream) <html> <head> <link rel="stylesheet" href="/assets/stylesheets/wvyp.css"/> </head> <body> <div class="wvyp"> <h2>Who's Viewed Your Profile</h2> @body </div> </body> </html> app/views/wvyp/wvyp.scala.stream We can now create a .scala.stream template that has markup mixed with HtmlStream elements.
  • 135. object WVYPStream extends Controller { def index = Action { val wvypCountFuture = ServiceClient.makeServiceCall("wvyp") val searchCountFuture = ServiceClient.makeServiceCall("search") } } app/controllers/WVYPStream.scala Now for the streaming controller. As usual, start with the service calls.
  • 136. object WVYPStream extends Controller { def index = Action { val wvypCountFuture = ServiceClient.makeServiceCall("wvyp") val searchCountFuture = ServiceClient.makeServiceCall("search") val wvypCountHtmlFuture = wvypCountFuture.map(str => views.html.wvyp.wvypCount(str.toInt)) val searchCountHtmlFuture = searchCountFuture.map(str => views.html.wvyp.searchCount(str.toInt)) } } app/controllers/WVYPStream.scala Next, render the data in each Future as Html
  • 137. object WVYPStream extends Controller { def index = Action { val wvypCountFuture = ServiceClient.makeServiceCall("wvyp") val searchCountFuture = ServiceClient.makeServiceCall("search") val wvypCountHtmlFuture = wvypCountFuture.map(str => views.html.wvyp.wvypCount(str.toInt)) val searchCountHtmlFuture = searchCountFuture.map(str => views.html.wvyp.searchCount(str.toInt)) val wvypCountStream = HtmlStream(wvypCountHtmlFuture) val searchCountStream = HtmlStream(searchCountHtmlFuture) } } app/controllers/WVYPStream.scala Convert each Future[Html] to an HtmlStream using the factory methods we created earlier
  • 138. object WVYPStream extends Controller { def index = Action { val wvypCountFuture = ServiceClient.makeServiceCall("wvyp") val searchCountFuture = ServiceClient.makeServiceCall("search") val wvypCountHtmlFuture = wvypCountFuture.map(str => views.html.wvyp.wvypCount(str.toInt)) val searchCountHtmlFuture = searchCountFuture.map(str => views.html.wvyp.searchCount(str.toInt)) val wvypCountStream = HtmlStream(wvypCountHtmlFuture) val searchCountStream = HtmlStream(searchCountHtmlFuture) val body = wvypCountStream.andThen(searchCountStream) Ok.chunked(views.stream.wvypStreaming(body)) } } app/controllers/WVYPStream.scala Finally, combine the streams using andThen and render the streaming template
  • 139. GET @(wvypBody:/mock/:serviceName controllers.Mock.mock(serviceName: String) Html, wvyuBody: Html) GET /wvyp controllers.WVYP.index(embed: Boolean ?= false) GET <html> /wvyu controllers.WVYU.index(embed: Boolean ?= false) GET <head> /aggregate controllers.Aggregator.index GET <link rel="stylesheet" href="/assets/stylesheets/wvyp.css"/> /wvyp/enumerator controllers.WVYPEnumerator.index GET <link rel="stylesheet" href="/assets/stylesheets/wvyu.css"/> /wvyp/stream controllers.WVYPStream.index </head> <body> @wvypBody @wvyuBody </body> </html> app/views/aggregator/aggregator.scala Add a routes entry for the stream-based WVYP controller
  • 140. The page loads almost immediately and we see the WVYP count right away.
  • 141. 2 seconds later, the search count appears.
  • 142. Also, the CSS starts downloading immediately!
  • 143. This is a huge win if the stuff at the top of the page loads quickly. But what if it’s slow?
  • 144. object Mock extends Controller { def mock(serviceName: String) = Action.async { serviceName match { case "wvyp" => respond(data = "56", delay = 2000) // SLOW! case "search" => respond(data = "10", delay = 20) case "likes" => respond(data = "150", delay = 40) case "comments" => respond(data = "14", delay = 20) } } private def respond(data: String, delay: Long) = Promise.timeout(Ok(data), delay) } app/mock/Mock.scala Modify the mock endpoint so wvyp is slow and search is fast
  • 145. Again, the page loads almost immediately, but this time, neither count is visible.
  • 146. 2 seconds later, both counts appear.
  • 147. Fortunately, the CSS still loads right at the beginning.
  • 148. So it’s still a big win, even if the top of the page is slow, but not by as much.
  • 149. Is there a way to stream the data out of order but still render it in order?
  • 151. @(contents: Html, id: String) <script type="text/html-stream" id="@id-contents"> @contents </script> <script type="text/javascript"> document.getElementById("@id").innerHTML = document.getElementById("@id-contents").innerHTML; </script> app/views/ui/pagelet.scala.html Create a “pagelet” template that will take a snippet of HTML and use JS to inject it into the proper spot on the page.
  • 152. object Pagelet { def render(html: Html, id: String): Html = { views.html.ui.pagelet(html, id) } def renderStream(html: Html, id: String): HtmlStream = { HtmlStream(render(html, id)) } def renderStream(htmlFuture: Future[Html], id: String): HtmlStream = { HtmlStream.flatten(htmlFuture.map(html => renderStream(html, id))) } } app/ui/Pagelet.scala Add a Pagelet class with helper methods to wrap Html and Future[Html] in the pagelet template.
  • 153. @(body: ui.HtmlStream) <html> <head> <link rel="stylesheet" href="/assets/stylesheets/wvyp.css"/> </head> <body> <div class="wvyp"> <h2>Who's Viewed Your Profile</h2> <div id="wvypCount"></div> <div id="searchCount"></div> </div> @body </body> </html> app/views/wvyp/wvyp.scala.stream Update the WVYP streaming template to include placholder divs for the WVYP and search counts
  • 154. def index = Action { val wvypCountFuture = ServiceClient.makeServiceCall("wvyp") val searchCountFuture = ServiceClient.makeServiceCall("search") val wvypCountHtmlFuture = wvypCountFuture.map(str => views.html.wvyp.wvypCount(str.toInt)) val searchCountHtmlFuture = searchCountFuture.map(str => views.html.wvyp.searchCount(str.toInt)) } app/controllers/WVYPStream.scala Finally, update the WVYPStream controller. We still make two service calls and render each as HTML.
  • 155. def index = Action { val wvypCountFuture = ServiceClient.makeServiceCall("wvyp") val searchCountFuture = ServiceClient.makeServiceCall("search") val wvypCountHtmlFuture = wvypCountFuture.map(str => views.html.wvyp.wvypCount(str.toInt)) val searchCountHtmlFuture = searchCountFuture.map(str => views.html.wvyp.searchCount(str.toInt)) val wvypCountStream = Pagelet.renderStream(wvypCountHtmlFuture, "wvypCount") val searchCountStream = Pagelet.renderStream(searchCountHtmlFuture, "searchCount") } app/controllers/WVYPStream.scala This time, we convert the Future[Html] into an HtmlStream using the Pagelet.renderStream helper method.
  • 156. def index = Action { val wvypCountFuture = ServiceClient.makeServiceCall("wvyp") val searchCountFuture = ServiceClient.makeServiceCall("search") val wvypCountHtmlFuture = wvypCountFuture.map(str => views.html.wvyp.wvypCount(str.toInt)) val searchCountHtmlFuture = searchCountFuture.map(str => views.html.wvyp.searchCount(str.toInt)) val wvypCountStream = Pagelet.renderStream(wvypCountHtmlFuture, "wvypCount") val searchCountStream = Pagelet.renderStream(searchCountHtmlFuture, "searchCount") val body = HtmlStream.interleave(wvypCountStream, searchCountStream) Ok.chunked(views.stream.wvypStreaming(body)) } app/controllers/WVYPStream.scala Instead of using andThen, we compose the streams using interleave. This way, the Html will stream as soon as it’s ready.
  • 157. The page loads almost immediately, but now we see the search count first
  • 158. 2 second later, the WVYP count appears.
  • 159. We now have the basics for out-of-order, BigPipe style rendering!
  • 160. Wins 1. Much faster time to first byte 2. Static content can start loading much earlier 3. User can see and start interacting with the page almost immediately 4. Out of order rendering with JavaScript allows even deeper optimizations
  • 161. Caveats 1. Once you’ve streamed out the HTTP headers, you can’t change them. This means cookies and error handling may have to be done client-side. 2. Have to be careful with “pop in” and redraws. Client side code should intelligently choose when to insert items into the DOM. 3. Need to handle CSS and JS dependencies differently 4. Testing is harder 5. May need to disable JavaScript rendering for SEO
  • 162. You can find the code from this presentation at: https://github.com/brikis98/ping-play