Scala in a wild enterpriseRafael Bagmanov ( Grid Dynamics )
the?
In what use cases (types of applications) does Scala make the least sense?
"Database front end, CRUD apps.
Most of the boring apps that are built with Struts and Spring"
David Pollak "Barriers to scala adoption" Infoq.com
OpenGenesisgithub.com/griddynamics/OpenGenesis
● open source - open-genesis.org
● 2 years of development
● > 50 KLOC of scala code
● successfully deployed to production in one
large american financial institution
● Buzzwords: continuous deployment, cloud,
chef, devops, aws, openstack
OpenGenesisDeployment orchestration tool
● Integration with legacy apps and data (lots of
SOAP and xml)
● sophisticated security policies
● IT department separated from development
team
● J2EE Containers everywhere
● Risk averse
Enterprise characteristics
Typical "lightweight" j2ee stack
Web layer
Service layer
Data access layer
DB
Spring MVC
Spring
JPA
j2ee stack. Scala edition
Web layer
Service layer
Data access layer
DB
Spring MVC + scala magic
Spring + scala implicits
JPA Squeryl
j2ee stack. Scala edition
Web layer
Service layer
Data access layer
DB
Spring MVC
Spring
Squeryl
WAR
j2ee stack. Scala edition + scala goodness
Web layer
Service layer
Data access layer
DB
Spring MVC
Spring
Squeryl
Workflow distributed engine
Akka
WAR
Service layer: Spring
● DI fits almost nicely with scala
Spring with scala
● DI fits almost nicely with scalaclass GenesisRestController {
@Autowired var genesisService: GenesisService = _
}
class GenesisRestController {
@BeanProperty var genesisService: GenesisService = _
}
class GenesisRestController (genesisService: GenesisService) {}
Spring with scala
● DI fits almost nicely with scala○ "Everything is a trait" approach can't be done
Spring with scala
● DI fits almost nicely with scala○ "Everything is a trait" approach can't be done
○ Be aware of type inference in @Configuration beantrait Service
class ServiceImpl extends Service
@Configuration
class ServiceContext {
@Bean def service = new ServiceImpl
}
Spring with scala
● DI fits almost nicely with scala○ "Everything is a trait" approach can't be done
○ Be aware of type inference in @Configuration beantrait Service
class ServiceImpl extends Service
@Configuration
class ServiceContext {
@Bean def service: Service = new ServiceImpl
}
Spring with scala
● DI fits almost nicely with scala
● Rich spring templates libraries.
Spring with scala
● DI fits almost nicely with scala
● Rich spring templates libraries.
springLdapTemplate.authenticate("user", "*", "password", new
AuthenticationErrorCallback {
def execute(e: Exception) {log.error(e)}
})
Spring with scala
● DI fits almost nicely with scala
● Rich spring templates libraries.
springLdapTemplate.authenticate("user", "*", "password", new
AuthenticationErrorCallback {
def execute(e: Exception) {log.error(e)}
})
Spring with scala
● DI fits almost nicely with scala
● Rich spring templates libraries.
springLdapTemplate.authenticate("user", "*", "password", new
AuthenticationErrorCallback {
def execute(e: Exception) {log.error(e)}
})
springLdapTemplate.authenticate("user", "*", "password", log.error(_))
Spring with scala
● DI fits almost nicely with scala
● Rich spring templates libraries.
springLdapTemplate.authenticate("user", "*", "password", log.error(_))
implicit def authErrorCallbackWrapper(func:(Exception) => Any) = { new AuthenticationErrorCallback { def execute(exception: Exception): Unit = func(exception) } }
Spring with scala
● DI fits almost nicely with scala
● Rich spring templates libraries.
● AOP for free (almost)
Spring with scala
● DI fits almost nicely with scala
● Rich spring templates libraries.
● AOP for free (almost)○ Be aware of naming in debug info def findUsers(projectId: Int) {
dao.findUsers(projectId)
}
def findUsers2(projectId: Int) {
dao.allUsers().filter(_.projectId == projectId)
}
Spring with scala
● DI fits almost nicely with scala
● Rich spring templates libraries.
● AOP for free (almost)○ Be aware of naming in debug info def findUsers(projectId: Int) { // debugIfo: name "projectId" dao.findUsers(projectId)
}
def findUsers2(projectId: Int) { // debugInfo: name "projectId$" dao.allUsers().filter(_.projectId == projectId)
}
Spring with scala
● DI fits almost nicely with scala
● Rich spring templates libraries.
● AOP for free (almost)
● Spring security just works
Spring with scala
Persistence layer: Squeryl
● Lightweight ORM written in scala
Squeryl
● Lightweight ORM written in scala
Squeryl
class Workflow(override val id: Int) extends KeyedEntity[Int]
● Lightweight ORM written in scala
Squeryl
class Workflow(override val id: Int) extends KeyedEntity[Int]
object GS extends Schema {
val workflows = table[Workflow]
}
● Lightweight ORM written in scala
Squeryl
class Workflow(override val id: Int) extends KeyedEntity[Int]
object GS extends Schema {
val workflows = table[Workflow]
}
def find(workflowId: Int) = from(GS.workflows)(w =>
where(w.id === workflowId)
select (w)
orderBy(w.id desc)
)
● Lightweight ORM written in scala○ First class support for scala collections, options, etc
Squeryl
● Lightweight ORM written in scala○ First class support for scala collections, options, etc
○ Integrates with spring transaction management
(not out of the box)
Squeryl
● Lightweight ORM written in scala○ First class support for scala collections, options, etc
○ Integrates with spring transaction management
(not out of the box)
Squeryl
@Transactional(propagation = REQUIRES_NEW)
def find(workflowId: Int) = from(GS.workflows)(w =>
where(w.id === workflowId)
select (w)
orderBy(w.id desc)
)
Squeryl
● Lightweight ORM written in scala
○ Likes heap in the same proportion as Hibernate does
hibernate squeryl
● Lightweight ORM written in scala
○ Likes heap in the same proportion as Hibernate does
○ Lot's of "black magic" in source code
Squeryl
● Lightweight ORM written in scala
● Internal scala DSL for writing queries○ Type safe queries - compile time syntax check
Squeryl
● Lightweight ORM written in scala
● Internal scala DSL for writing queries○ Lot's of "black magic" in source code
Squeryl
● Lightweight ORM written in scala
● Internal scala DSL for writing queries○ Lot's of "black magic" in source code
○ Fallback on native sql is not easy
Squeryl
● Lightweight ORM written in scala
● Internal scala DSL for writing queries○ Lot's of "black magic" in source code
○ Fallback on native sql is not easy
○ Lots of implicits drives IDE crazy and increases compilation time
Squeryl
● Lightweight ORM written in scala
● Internal scala DSL for writing queries○ Lot's of "black magic" in source code
○ Fallback on native sql is not easy
○ Lots of implicits drives IDE crazy and increase compilation time
○ The approach is somewhat flawed (opinion)
Squeryl
Web layer: Spring MVClift-json
scala magic
● RESTfull web services
Web layer
case class User (
@NotBlank username: String,
@Email @Size(min = 1, max = 256) email: String,
password: Option[String]
)
@Controller
@RequestMapping(Array("/rest/users"))
class UsersController {
@RequestMapping(method = Array(RequestMethod.POST))
@ResponseBody
def create(@RequestBody @Valid request: User): User = userService.create(request)
}
● RESTfull web services
● Easy to make Hypermedia REST with
implicits
Web layer
@Controller
@RequestMapping(Array("/rest/users"))
class UsersController {
import com.griddynamics.genesis.rest.links.Hypermedia._
@RequestMapping(method = Array(RequestMethod.POST))
@ResponseBody
def create(@RequestBody @Valid request: User): Hypermedia[User] = {
userService.create(request).withLink("/rest/users", LinkType.SELF)
}
Couple of words aboutAKKA
Ехал Акка через Акка
Смотрит Акка в Акка Акка
Сунул Акка Акка в Акка
Акка Акка Акка Акка *
* Ode to Akka in russian
Greatest challenge:
Greatest challenge:People
● Hiring is hard
Challenges
● Hiring is hard○ Scala is a talent attraction
Challenges
● Hiring is hard○ Scala is a talent attraction
○ In avg: 0.5 interview per month
Challenges
● Hiring is hard
● Settling team standards and code
convention
Challenges
● Hiring is hard
● Settling team standards and code
convention○ Tools are not there yet
Challenges
● Hiring is hard
● Settling team standards and code
convention○ Tools are not there yet
○ Between "OCaml" and "Java" fires
Challenges
● Hiring is hard
● Settling team standards and code
convention○ Tools are not there yet
○ Between "OCaml" and "Java" fires
○ "Effective scala" by Twitter and "Scala style guide"
might help (a bit)
Challenges
The greatest code-review mystery of all times
if (option.isDefined) {
..
}
option.foreach { .. }
option match { case Some(x) => .. case None => ..}
How to deal with scala.Option
?
The greatest code-review mystery of all times
if (option.isDefined) {
..
}
option.foreach { .. }
option match { case Some(x) => .. case None => ..}
How to deal with scala.Option
?
Recruiting java developers
aka
5 stages of grief
1. Denial
2. Anger
3. Bargaining
4. Depression
5. Acceptance
5 stages of grief
1. Denial
2. Anger
3. Bargaining
4. Depression
5. Acceptance
5 stages of grief
1. Denial
2. Anger
3. Bargaining
4. Depression
5. Acceptance
5 stages of grief
1. Denial
2. Anger
3. Bargaining
4. Depression
5. Acceptance
5 stages of grief
1. Denial
2. Anger
3. Bargaining
4. Depression
5. Acceptance
5 stages of grief
1. Denial
2. Anger
3. Bargaining
4. Depression
5. Acceptance
5 stages of grief