full stack scala
Post on 21-Apr-2017
6.808 Views
Preview:
TRANSCRIPT
Full Stack ScalaScala in the backend and frontend!
Ramnivas LaddadFounder, Paya Labs
@ramnivas
@ramnivas
• Spring framework and Cloud Foundry contributor
• Main interests • Scala and functional programming • Cloud computing
• Author of books and articles • AspectJ in Action (1st and 2nd edition)
• Speaker at many professional conferences • JavaOne, ScalaDays, JavaPolis, SpringOne, Software
Development, No Fluff Just Stuff, OSCON etc.
A Quick Demo
High-level Architecture
API Server Static Page Server
html, js, css, …
GET, PUT, POST, DELETE
{ "name" : ...}
Backend Stack
API Server
API Server Static Page Server
html, js, css, …
GET, PUT, POST, DELETE
{ "name" : ...}
API Server
API Server Static Page Server
html, js, css, …
GET, PUT, POST, DELETE
{ "name" : ...}
Backend Structure
Backend Structure
Database
Backend Structure
DatabaseSendgrid
Backend Structure
DatabaseSendgridS3
Backend Structure
DatabaseSendgridS3
Backend Structure
DatabaseSendgridS3
Backend Structure
DatabaseSendgridS3
Backend Structure
Database
Data Access Layer
SendgridS3
Backend Structure
Database
Data Access Layer
SendgridS3
Talk by Rob NorrisPrograms as Values: JDBC Programming with Doobie
Backend Structure
Database
Data Access Layer
SendgridS3
Backend Structure
Database
Data Access Layer
SendgridS3
ApacheCommons
Backend Structure
Database
Data Access Layer
SendgridS3
ApacheCommons
AWSSDK
Backend Structure
Database
Data Access Layer
Service Layer
SendgridS3
ApacheCommons
AWSSDK
Backend Structure
Database
Data Access Layer
Service Layer
HTTP Layer
SendgridS3
ApacheCommons
AWSSDK
Frontend Stack
High-level Architecture
Static Page Server
html, js, css, …
API Server
GET, PUT, POST, DELETE
{ "name" : ...}
High-level Architecture
Static Page Server
html, js, css, …
API Server
GET, PUT, POST, DELETE
{ "name" : ...}
Serving static contentsvar express = require('express');var fs = require('fs');
var app = express();var port = process.env.PORT || 4000;
var devMode = process.env.SERVE_MODE != "SERVE_PROD";
var serveInfo = { dir: __dirname + ‘/dev-bin', maxAge: 0}if (!devMode) {
var oneHour = 60*60*1000;serveInfo = { dir: __dirname + ‘/prod-bin', maxAge: oneHour}
}
app.use(express.static(serveInfo.dir, { maxAge: serveInfo.maxAge }));
app.get('*', function(request, response, next) { response.sendFile(serveInfo.dir + '/index.html');});
app.listen(port, function() {console.log("Started on " + port + " (dev mode = " + devMode + ")\n");
});
High-level Architecture
API Server Static Page Server
html, js, css, …
GET, PUT, POST, DELETE
{ "name" : ...}
High-level Architecture
API Server Static Page Server
html, js, css, …
GET, PUT, POST, DELETE
{ "name" : ...}
Why Scala.js?
Why Scala.js?
Why Scala.js
Scala!
Why Scala.js
Static Types
Why Scala.js
Functional Programming
Why Scala.js
Isomorphism
Why Scala.js
Maturity!
Why Scala.js
Eco-system
UI Framework
Choosing a UI Framework
Choosing a UI FrameworkSimple
Mental Model
Choosing a UI FrameworkSimple
Mental ModelImmutable
Data
Choosing a UI FrameworkSimple
Mental ModelFunctional
programmingImmutable
Data
Choosing a UI FrameworkSimple
Mental Model
Mobile
Functionalprogramming
Immutable Data
Choosing a UI FrameworkSimple
Mental Model
Mobile
Functionalprogramming
Immutable Data
Isomorphism
Choosing a UI FrameworkSimple
Mental Model
CommunityMobile
Functionalprogramming
Immutable Data
Isomorphism
Choosing a UI FrameworkSimple
Mental Model
CommunityMobile
Functionalprogramming
Immutable Data
Isomorphism
What is React?• “A JavaScript library for building user interfaces” by
• Focuses just on the UI• Uses virtual DOM• One-way data-flow
Frontend Overview
Frontend Overview
Router
Frontend Overview
Router
Frontend Overview
Router Flux Component
Frontend Overview
Router Flux Component
Frontend Overview
Router
Store
Flux Component
Frontend Overview
Router
Store
Flux Component
Frontend Overview
Router
Store
Flux Component
Rest Client
Frontend Overview
Router
Store
Flux Component
Rest Client
Frontend Overview
Router
Store
Flux Component
Rest Client
Frontend Overview
Router
Store
Flux Component
Rest Client
Frontend Overview
ComponentRouter
Store
Flux Component
Rest Client
Frontend Overview
ComponentRouter
Store
Flux Component
Rest Client
Scala.js with React
• Statically-typed wrapper around React• Fluent, builder API to create components• Well-implemented router (v2)
scalajs-react
Simple Mental Model
View
PropertiesState
Composition
Composition
Composition
Composition
Composition
Real World Composition
Real World Composition
Real World Composition
Mostly Immutable
ComponentRouter
Store
Flux Component
Rest Client
Taking advantage of immutability
def shouldComponentUpdate(scope: ScopeType, nextProps: P, nextState: S) = { scope.props != nextProps || scope.state != nextState}
Flux
Flux Componentobject ArtistRegistrationWrapper extends FluxComponent[String, ArtistEditDto](Seq(ArtistStore, InstrumentStore)) {
def onArtistChange(artist: ArtistEditDto): Unit = { ArtistUpdated(artist).dispatch() }
...
def element(props: String) = { ... div( ArtistRegistration( ArtistRegistrationProps( artist, allInstruments, onArtistChange, onArtistCoverPhotoChange, onArtistProfilsePhotoChange) ) ) }}
Component
object ArtistRegistration extends Component[ArtistRegistrationProps] {
def element(props: ArtistRegistrationProps): ReactTag = { div(…) }}
Responding to events
override def receive = { case ArtistUpdated(newValue) => artist = newValue emitChange() case ArtistSaved => save() emitChange() ...
No sweat undo/redotrait CompositionStore extends AbstractStore { val compositionStack = new UndoStack[Composition]() override def receive = { case NewComposition => compositionStack.clear() loaded() case LoadComposition(c) => compositionStack.clear() compositionStack.push(c) loaded() case UpdateComposition(c) => compositionStack.push(c) emitChange() case UndoComposition => compositionStack.undo() emitChange() case RedoComposition => compositionStack.redo() emitChange() ...}
Mobile: React Native
Mobile: React Native
https://facebook.github.io/react-native
Mobile: React Native
https://github.com/chandu0101/scalajs-react-native
https://facebook.github.io/react-native
Using external components
Bridging Native React Components• Problem:
• You got to use components developed in the wild
• Requires significant boilerplate to make it work from scalajs-react
• Solution: Some macro magic!
Bridging Native React Components• Problem:
• You got to use components developed in the wild
• Requires significant boilerplate to make it work from scalajs-react
• Solution: Some macro magic!
github.com/payalabs/scalajs-react-bridge
Example Bridge Component
case class TagsInput(id: js.UndefOr[String] = js.undefined, className: js.UndefOr[String] = js.undefined, ref: js.UndefOr[String] = js.undefined, key: js.UndefOr[Any] = js.undefined, defaultValue: js.UndefOr[Seq[String]] = js.undefined, value: js.UndefOr[Array[String]] = js.undefined, placeholder: js.UndefOr[String] = js.undefined, onChange: js.UndefOr[js.Array[String] => Unit] = js.undefined, validate: js.UndefOr[String => Boolean] = js.undefined, transform: js.UndefOr[String => String] = js.undefined) extends ReactBridgeComponent
Using TagsInput
div( TagsInput( defaultValue = Seq(“foo","bar"), onChange = printSequence _ ))
Using MDL in React• Problem:
• Components need to be “upgraded”
• Solution:• React wrapper component around a ReactTag• Upgrades element upon mounting• Implicits to avoid noise
Using MDL in React• Problem:
• Components need to be “upgraded”
• Solution:• React wrapper component around a ReactTag• Upgrades element upon mounting• Implicits to avoid noise
github.com/payalabs/scalajs-react-mdl
Example MDL Use
a(className := "mdl-button mdl-js-button mdl-button--raised mdl-button—colored mdl-js-ripple-effect", onClick --> saveAction())("Save").material
Example MDL Use
a(className := "mdl-button mdl-js-button mdl-button--raised mdl-button—colored mdl-js-ripple-effect", onClick --> saveAction())("Save").material
Things on the Horizon
• GraphQL?• Stitch?• Relay?• Falcor?
?Ramnivas Laddad
@ramnivas
top related