crowdscriber.com Web Applications for the REST of Us An Introduction to Ember.js, Akka, and Spray (and Slick)
crowdscriber.com
Web Applications for the REST of Us
An Introduction to Ember.js, Akka, and Spray(and Slick)
crowdscriber.com
Craig SeanFounder, Product [email protected]@craiger
Founder, Tech [email protected]
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