Return to the Monolith
lance@lbpaine.com
github @somanythings
twitter @lbpaine
What/why/how?

Tirau

Bio
Text

London
10 years
- hedge funds
- HFT
- banks
- media
Home Office


DRT
Dynamic Response Tool

Major 'Ports


Queues

SLA
Guessperience

FlightStats
MAN, LHR,
BHX, GLG etc
PHP
MySQL
Front End
API
Crunch live
Crunch forecast
Scala
(ish)
DeskStats
PAL
RabbitMq
loader
Configuration


So what to do?
speed of feature change
all ports are NOT the same
shrunken team
Fix It?
Spike!

Backend
- Renjin
- akka-streams
- akka-persistence
Renjin
- easy to setup
- 500x-1000x faster
akka-streams
- Not clear who the documentation is targeting
- Missing some cookbook approaches
- We did spike a pure stream which was pretty
akka-persistence
- gives you PIT views
- exploding mailbox
- thou must snapshot
- choose serialisation wisely
- moving target, but,
- docs are great
scalajs with react
this was very early
object versions {
val scala = "2.11.8"
val scalaDom = "0.9.1"
val scalajsReact = "0.11.1"
val scalajsReactComponents = "0.5.0"
val scalaCSS = "0.4.1"
val autowire = "0.2.6"
val booPickle = "1.2.4"
val diode = "1.0.0"
val uTest = "0.4.3"
val react = "15.1.0"
val jQuery = "1.11.1"
val bootstrap = "3.3.6"
val chartjs = "2.1.3"
val playScripts = "0.5.0"
val sprayVersion: String = "1.3.3"
val json4sVersion = "3.4.0"
}
Teething
pre webpack, sbt
early scalajs-react
scalajs
- mostly just worked
scalajs
- uTest was great,
- but failures a bit weird
scalajs
- autowire
- beware immutable.Seq
scalajs
- lihaoyi
- diode
"io.suzaku" %% "diode" % "1.1.3"


case class Increase(amount: Int) extends Action
case class Decrease(amount: Int) extends Action
case object Reset extends Action
object AppCircuit extends Circuit[RootModel] {
def initialModel = RootModel(0)
override val actionHandler: HandlerFunction =
(model, action) => action match {
case Increase(a) => Some(ModelUpdate(model.copy(counter = model.counter + a)))
case Decrease(a) => Some(ModelUpdate(model.copy(counter = model.counter - a)))
case Reset => Some(ModelUpdate(model.copy(counter = 0)))
case _ => None
}
}
Diode - Circuit
// use an action handler to get composeable handlers
val counterHandler = new ActionHandler(zoomTo(_.counter)) {
override def handle = {
case Increase(a) => updated(value + a)
case Decrease(a) => updated(value - a)
case Reset => updated(0)
}
}
val actionHandler = composeHandlers(counterHandler)
Diode - Circuit
//the view
class CounterView(counter: ModelR[Int], dispatch: Dispatcher) {
def render = {
div(
h3("Counter"),
p("Value = ", b(counter.value)),
button(onclick := { () => dispatch(Increase(2)) }, "Increase"),
button(onclick := { () => dispatch(Decrease(1)) }, "Decrease"),
button(onclick := { () => dispatch(Reset) }, "Reset")
)
}
}
Diode View
val root = document.getElementById("root")
AppCircuit.subscribe(() => render(root))
AppCircuit(Reset)
def render(root: Element) = {
val e = div(
h1("Diode example"),
counter.render
).render
root.innerHTML = ""
root.appendChild(e)
}
Top Render
Original Fan In and Out
Separate instance per 'port
What we used
- architectural decision records
- scalajs
- scalajs-react https://github.com/japgolly/scalajs-react
- diode https://github.com/suzaku-io/diode
- autowire https://github.com/lihaoyi/autowire
- our project
- https://github.com/somanythings/drt-scalajs-spa-exploration
- or what it is now https://github.com/UKHomeOffice/drt-scalajs-spa-exploration
Questions?

lance@lbpaine.com
github @somanythings
twitter @lbpaine
return to monolith
By Lance Paine
return to monolith
- 577