Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Building Startups on Scala

Building Startups on Scala

buildo's talk at Scala Italy 2015

buildo is a software company enabling startups execute on their vision. In this talk we present our experience in building a solid stack based on Scala for working with multiple startup projects.

buildo

May 08, 2015
Tweet

More Decks by buildo

Other Decks in Programming

Transcript

  1. B U I L D I N G S TA

    R T U P S O N S C A L A T U R N I D E A S I N T O R E A L I T Y @ B U I L D O H Q @ U TA A L @ G A B R O 2 7
  2. W H O A R E Y O U ?

    buildo, a young italian company we help startups everywhere 
 execute on their vision
  3. L E T ’ S TA K E A S

    T E P B A C K
  4. A L O N G T I M E A

    G O I N A G A L A X Y FA R FA R AWAY • a wild scary large project appears!
  5. F L A S H B A C K :

    N O T L O N G B E F O R E • Intern at Google, MongoDB • Freelancer • C++ • Python (programming is fun again) • Java (university) • Haskell • Scala
  6. F L A S H B A C K :

    N O T L O N G B E F O R E • Startupper and freelance dev • Java (university) • Objective-C <3 • “blocks? That’s confusing…” • intrigued by Haskell • Scala (Martin’s online course)
  7. T H E R E S T O F T

    H E ( I N I T I A L ) C R E W
  8. R E C E N T LY B U R

    N E D B Y … • a new startup, for hosting and serving videos • a year of work • countless refactors • …node.js
  9. B A C K T O O U R S

    C A RY P R O J E C T • we wanted • type safety • expressiveness • flexibility
  10. B U I L D O , T O D

    AY • startups, in scala?! • everybody knows rails/node/php is the hipster startup language! • waxed mustache for extra points
  11. S TA RT U P T E C H N

    O L O G I E S 07/08/2014 - source: http://codingvc.com/which-technologies-do-startups-use-an-exploration-of-angellist
  12. P E R C E P T I O N

    • “Do you know Scala?” • “Isn’t it that thing Twitter uses?”
  13. P E R C E P T I O N

    ( C O N T ’ D ) • “developing in scala is slow” • “the learning curve is steep” • “is it worth it for a startup?”
  14. S C A L I N G S C A

    L A D O W N • we started with a large project • and applied what we learned to startups
  15. W H Y ? • well, we liked it :-)

    • small team • the final S in “startups” is not silent
  16. O K , W H Y D O Y O

    U L I K E I T ? • it takes more time to ship code • it takes less time to ship code that works
  17. O K , W H Y D O Y O

    U L I K E I T ? ( C O N T ’ D ) • intrinsic correctness and clarity • easy to write testable code • refactor with confidence • JVM is nice
  18. “Scala trusts the programmer to ‘do the right thing’” Martin

    Odersky (6 hours ago) “We don’t have enough material on how to get practical on scala” Phil Calçado (short after)
  19. H O W D O W E D O T

    H I S ? 1. dealing with a diverse and evolving set of requirements 2. akka 3. controllers 4. open problems
  20. 1 . D E A L I N G W

    I T H A D I V E R S E S E T O F R E Q U I R E M E N T S
  21. M I X - M AT C H I N

    F R A S T R U C T U R E
  22. cake pattern trait UserService extends DataModule { trait UserServiceDef {

    def login(username: String, password: String): Option[Token] } def userService: UserServiceDef }
  23. cake pattern trait UserService extends DataModule { trait UserServiceDef {

    def login(username: String, password: String): Option[Token] } def userService: UserServiceDef } trait DataModule { type Token trait DataModuleDef { def getUserByName(username: String): Option[User] def storeToken(user: User, token: Token): Boolean } def dataModule: DataModuleDef }
  24. trait MemoryDataModule { self: DataModule => type Token = String

    object dataModule extends DataModuleDef { val users = new scala.collection.mutable.Map[String, User] val tokens = new scala.collection.mutable.Map[User, Token] def getUserByName(username: String): Option[User] = users.get(username) def storeToken(user: String, token: Token): Boolean = tokens += user -> token } } trait DataModule { type Token trait DataModuleDef { def getUserByName(username: String): Option[User] def storeToken(user: User, token: Token): Boolean } def dataModule: DataModuleDef }
  25. trait MemoryDataModule { self: DataModule => … } trait AppUserService

    { self: UserService => … } object app extends MemoryDataModule with AppUserService println(app.login("utaal", "secretpassword"))
  26. // POST /consultation/15/confirm (post & path(“consultations” / IntNumber / “confirm”))

    { consultationId => complete(confirmConsultation(consultationId)) } ~ typesafe router
  27. • cake pattern • tests • type safety 1 .

    D E A L I N G W I T H A D I V E R S E S E T O F R E Q U I R E M E N T S
  28. • use akka for dispatching requests
 (in spray) • Futures

    for business logic • Akka for async tasks
 (notifications, elasticsearch updates) 2 . A K K A
  29. typesafe router trait ConsultationControllerDef { def confirmConsultation(consultationId: Int): Future[ControllerResponse[Unit]] }

    // POST /consultation/15/confirm (post & path(“consultations” / IntNumber / “confirm”)) { consultationId => complete( (confirmConsultation(consultationId)) : Future[ControllerResponse[Unit]] ) } ~
  30. sealed trait ControllerResponse[+T] object ControllerResponse { sealed trait ControllerError case

    object NotFound extends ControllerError case class InvalidOperation(desc: String) extends ControllerError case class Forbidden(desc: String) extends ControllerError … … … case class Ok[T](value: T) extends ControllerResponse[T] case class UserError(err: ControllerError) extends ControllerResponse[Nothing] } response semantics
  31. def confirmConsultation(consultationId: Int, user: User): Future[ControllerResponse[Unit]] = checkRole(user, UserRole.Patient) {

    checkConsultationExists(consultationId) { c => checkConsultationOwner(c, user) { checkConsultationPending(c) { consultationData.updateStatus( consultationId, ConsultationStatus.Confirmed) map ( throwOnUnmatched { case DataActionResult.Ok(_) => OkEmpty }) } } } } controller workflow
  32. def confirmConsultation(consultationId: Int, user: User): Future[ControllerResponse[Unit]] = checkRole(user, UserRole.Patient) {

    checkConsultationExists(consultationId) { c => checkConsultationOwner(c, user) { checkConsultationPending(c) { consultationData.updateStatus( consultationId, ConsultationStatus.Confirmed) map ( throwOnUnmatched { case DataActionResult.Ok(_) => OkEmpty }) } } } } controller workflow CALLBACK HELL
  33. sealed trait ControllerResponse[+T] object ControllerResponse { sealed trait ControllerError case

    object NotFound extends ControllerError case class InvalidOperation(desc: String) extends ControllerError case class Forbidden(desc: String) extends ControllerError … … … case class Ok[T](value: T) extends ControllerResponse[T] case class UserError(err: ControllerError) extends ControllerResponse[Nothing] } response semantics
  34. monadic controllers type CtrlFlow[A] = CtrlError \/ A sealed trait

    CtrlError object CtrlError { case class InvalidOperation(desc: String) extends CtrlError case class Forbidden(desc: String) extends CtrlError case object NotFound extends CtrlError … … … }
  35. def confirmConsultation(consultationId: Int, user: User): FutureCtrlFlow[Unit] = for { _

    <- eitherT(checkRole(user, UserRole.Patient).point[Future]) c <- checkConsultationExists(consultationId) _ <- checkConsultationOwner(c, user) _ <- checkConsultationPending(c) res <- eitherT(consultationData.updateStatus(consultationId, ConsultationStatus.Confirmed).map(_.point[CtrlFlow])) } yield { throwIfNotOk(res) Ok(()) } monadic controllers type FutureCtrlFlow[B] = EitherT[Future, CtrlError, B]
  36. • monad! • non-trivial to design,
 straightforward to use 3

    . C O M P L E X C O N T R O L L E R L O G I C
  37. M O D U L A R I T Y

    • modularity comes with a cost • boilerplate to translate between internal and external representations • we can’t trace a request across different layers
  38. P E O P L E • you can’t throw

    developers at this • you need good programmers • scala is (still) a good hiring signal
  39. Good programmers are up to 30 times better than mediocre

    programmers, according to “individual differences” research. Given that their pay is never commensurate, they are the biggest bargains in the software field. Robert L. Glass