Web Applications for the REST of Us - RainFocus · Web Applications for the REST of Us An...

Preview:

Citation preview

crowdscriber.com

Web Applications for the REST of Us

An Introduction to Ember.js, Akka, and Spray(and Slick)

crowdscriber.com

Craig SeanFounder, Product Managercraig@crowdscriber.com@craiger

Founder, Tech Directorsean@crowdscriber.com

crowdscriber.com

Y etA notherW ebS tack

Presenting...

crowdscriber.com

YOU

crowdscriber.com

ME

crowdscriber.com

Your past has given you the strength and wisdom you have today, so celebrate it. Don’t let it haunt you.

● CGI (C, Perl)● Servlets● JSP● Struts● Wicket● SpringMVC● JSF*● Play*● GWT**

crowdscriber.com

What I was used to...Server-side MVC

Model

Controller

View

<html><%=...</html>

crowdscriber.com

What I didn't like about it...● User Experience

○ Trip to the server to render a page● Not "Designer-friendly"

○ Front-end devs needed to...■ run a servlet container, Database, etc...■ have programming chops■ or rely on developers

● No easy answers to "Can we do this"○ "Can we have an interactive map where users drop pins?"

■ Answer: Derp ● Hands tied

○ Want to use a new Javascript Library?

crowdscriber.com

GWT● This one was different...

○ Everything written in Java○ Concept of Client-side components○ Transliterated Java->Javascript components○ Components made AJAX calls to Server for data

■ i.e. Look Ma! No page reloads!○ "Dev Mode"

■ Debugging/Live-Reload○ Deploys to Google App Engine

● But...○ "Quirky"○ People jumping ship to Angular○ Google no longer spearheads development

crowdscriber.com

Crowdscriber's YAWSFront-end

Ember.js Renders UI, Handles user interaction

Back-endSpray REST API

Akka Async, Concurrency, Scaling

Slick Database Access

crowdscriber.com

Front-endSingle Page Applications

● Popular Frameworks○ Angular○ Ember○ React○ Backbone

● Think Fat-client○ The more things change...

● Server is a glorified datastore

crowdscriber.com

Why Ember?● Active community● Relatively mature

○ Version 2.x currently● Cross-platform (Windows, MacOSX, Linux)● Rapid prototyping

○ Fake out the backend● Opinionated

○ i.e. conventions● Promotes parallel development

○ Front-end Ember Devs○ Back-end API Devs

crowdscriber.com

Ember CLI● Command line tools for...

○ Serving Ember apps (in development)○ Building Ember apps (for production)○ Providing live-reload (think GWT's Dev Mode)○ Generating boilerplate (think Maven archetypes)○ Proxying REST calls (i.e. no CORS.xml)

crowdscriber.com

Ember Concepts● Router

○ Defines URLs in your App● Route

○ Sets up Data for views for a given URL● Components

○ Reusable view logic (Widgets)○ Typically render a Model○ .hbs template + Javascript file

● Ember Data○ ORM for REST APIs○ Provides Models to Routes

● Binding○ Components are notified of changes to Models

crowdscriber.com

Ember Demo

crowdscriber.com

Server-side Stack

Framework Purpose

Spray REST Routing Layer

Akka Scalability and Async

Slick Database Access

crowdscriber.com

Spray● Provides

○ REST Routing DSL spray-routing

○ JSON Serialization spray-json

○ Light-weight server spray-can

crowdscriber.com

Exampletrait ApiRoutes extends HttpService {

// GET /oauth2?code=<someCode>&state=<someState> path("oauth2") {

get {parameters("code", "state") {

(token, userId) => {//handle oauth stuff

}}

}}

}

crowdscriber.com

Or more condensed...trait ApiRoutes extends HttpService {

path("oauth2" & get & parameters("code", "state")) {(token, userId) => {

//handle oauth stuff}

}}

crowdscriber.com

spray-jsonpath("user" & post) {

entity(as[RegistrationDto]) { reg =>complete(

userService.registerUser(reg.email, reg.password))

}}

crowdscriber.com

Akka● Actors framework● Asynchronous● Stateless

○ Promotes concurrency● Scalable● Spray is built on Akka

crowdscriber.com

Actors● Typically thread-per-Actor● Each actor can queue requests (mailbox)● Only one request (message) at a time is processed● Spray uses an Actor as the Route

○ You can use Akka to load-balance○ Multiple instances of your route○ Otherwise requests pile up in the queue

crowdscriber.com

Scalable● Why are Actor Frameworks Scalable?

○ Elastic○ Distributed○ Light-weight

crowdscriber.com

Scaling● How would you scale a traditional JEE app?

○ Connection pool○ Caching○ I know! Increase the thread pool!

■ Ah, that didn't work. Let's Load-balance

crowdscriber.com

Request Threads

t1 t2 t3

r1 r3r2 r4

What you don't want to happen...

f1 c1

f2 c2

f3 c3

f4 c4f4

r4 ✅

t1 t2 t3

f3

f2

f1

r1 r3r2

What you want to happen...

crowdscriber.com

Load Balancing● Balance requests (load) across App Containers

○ Strategy: Round-robin, Random, Sticky...● But what if it's only certain requests that cause load?

○ Do we actually want to scale entire containers?○ What if we could Scale from within our app?

● Akka lets us Scale internally○ Costly requests are balanced across Actors○ Freeing up request threads to handle more requests○ Actors may be remotely distributed across process/network boundaries

crowdscriber.com

Internal Actors● Subtitle Actor

○ Built-in serialization of our requests● Chunker Actor

○ Time-intensive algorithm○ Distribute load across Actor systems

crowdscriber.com

Load Balancing vs Actor Pools

Server 1 Server 2

Requests Requests

crowdscriber.com

● Loosely Coupled○ Replace any layer with something else

● Rapid Prototyping○ Develop Ember with Mock Data○ Same app you'll deliver to the Client

● Parallel Development○ Two different developers can develop Front-end/Back-end

● Reusable API○ Open it up to customers○ Use it for a batch jobs

● Close to the Metal front-end○ HTML/CSS/JS○ Designer can iterate their design

Why our YAWS?

crowdscriber.com

Do we have time for Slick?● Scala RDMS ORM● Access database tables like collections● Connection pooling● Transaction management● Code Generator● Schema Generator● Query DSL

crowdscriber.com

Slick DSLval subQuery =

for {

uc <- UserContentTable.query if uc.userId === userId.toString

c <- ContentTable.query if uc.contentId === c.id

} yield (uc, c)

val query =

UserTable.query.filter(_.id === userId.toString)

.joinLeft(subQuery).on { case (u, (uc, c)) => u.id === uc.userId}

.map { case (u, sub) => (u, sub.map{ case (uc, c) => c }) }

SELECT s17.s112, s17.s113, s90.`user_id`, s91.`id`, s91.`title`, s91.`source`, s91.`source_id`, s91.`content_type`, s91.`duration`, s91.`privacy_status`, s91.`thumbnail_url`, s91.`publisher`FROM (SELECT `id` AS s112, `email` AS s113 FROM `user` WHERE `id` = 'c504073a-bcf2-410b-9d88-3e81531374e5') s17LEFT OUTER JOIN (`user_content` s90 INNER JOIN `content` s91 ON (s90.`user_id` = 'c504073a-bcf2-410b-9d88-3e81531374e5') AND (s90.`content_id` = s91.`id`)) ON s17.s112 = s90.`user_id`

crowdscriber.com

Is the Grass Truly Greener?● Learning Curve● You have to like Javascript● Prepare to upgrade often● Slick Upgrade was tough

crowdscriber.com

Craig Seancraig@crowdscriber.com@craiger

sean@crowdscriber.com

Thank you