Solid and Sustainable 
Development in Scala 
Kazuhiro Sera @seratch 
ScalikeJDBC / Skinny Framework 
Founder & Lead Developer
Ask Me Later! 
• 3 mags for questioners at the end of this 
session! Don’t miss it! 
2
Who Am I 
• Kazuhiro Sera • @seratch on Twitter/GitHub • Scala enthusiast since 2010 • ScalikeJDBC, Skinny Framework, AWScala 
founder & project lead • A web developer at M3, Inc (We’re a Gold 
Sponsor)
Introduce 
My(Our) Products
ScalikeJDBC 
• scalikejdbc.org • “Scala-like JDBC” • Provides Scala-ish APIs • Started as a better querulous / Anorm • “Just write SQL and get things done” • QueryDSL for smoothness & type-safety • Stable enough: lots of companies already 
use it in production
Dependencies 
// build.sbt or project/Build.scala! 
! 
scalaVersion := “2.11.2” // or “2.10.4”! 
! 
libraryDependencies ++= Seq(! 
“org.scalikejdbc” %% “scalikejdbc” % “2.1.1”,! 
“com.h2database” % “h2” % “1.4.181”,! 
“ch.qos.logback” % “logback-classic” % “1.1.2”! 
)
Basic Usage 
import scalikejdbc._! 
! 
ConnectionPool.singleton(! 
“jdbc:h2:mem:matsuri”, ! 
“user”, “secret”)! 
SQL statement! 
(PreparedStatement) 
! 
DB autoCommit { implicit session =>! 
Side effect ! 
with DB connection 
sql”create table attendee (name varchar(32))”.execute.apply()! 
val name = “seratch”! 
sql”insert into attendee (name) values ($name)”.update.apply()! 
}! 
! 
val names: Seq[String] = DB readOnly { implicit s =>! 
sql”select name from attendee”! 
.map(_.string(“name”)).list.apply()! 
} 
execute/update! 
(JDBC operation) 
Extractor
QueryDSL 
import scalikejdbc._! 
case class Attendee(name: String)! 
object Attendee extends SQLSyntaxSupport[Attendee] {! 
def apply(rs: WrappedResultSet, a: ResultName[Attendee]) = ! 
new Attendee(rs.get(a.name)) 
}! 
! 
implicit val session = AutoSession! 
! 
! 
val a = Attendee.syntax(“a”)! 
val seratch: Option[Attendee] = withSQL {! 
QueryDSL! 
(Mostly SQL) 
Actual SQL Query 
select.from(Attendee as a).where.eq(a.name, “seratch”)! 
}.map(rs => new Attendee(rs, a)).single.apply()! 
! 
// select a.name as n_on_a from attendee a where a.name = ?
Skinny Framework 
• skinny-framework.org • “Scala on Rails” • For Rails / Play1 lovers • 1.0.0 was out on 28th March • Already several experiences in production • Full-stack features: Web infrastructure, 
Scaffold generator, ORM, DB migration, 
JSON stuff, HTTP client, Mail sender, Job 
workers, Assets controller, etc..
Boot in 2 minutes 
! 
// install skinny command! 
brew tap skinny-framework/alt! 
brew install skinny! 
! 
// create app and start! 
skinny new myapp! 
cd myapp! 
skinny run! 
! 
// access localhost:8080 from your browser!
Model (DAO) 
import skinny.orm._! 
Entity 
import scalikejdbc._! 
! 
case class User(id: Long, name: Option[String])! 
! 
// companion: data mapper! 
object User extends SkinnyCRUDMapper[User] {! 
def defaultAlias = createAlias(“u”)! 
def extract(rs: WrappedResultSet, u: ResultName[User])! 
= autoConstruct(rs, u) 
}! 
CRUD Mapper Object! 
! 
(No need to be companion) 
User.findById(123)! 
User.count()! 
User.createWithAttributes(‘name -> “Alice”)! 
User.updateById(123).withAttributes(‘name -> “Bob”)! 
User.deleteBy(sqls.eq(u.name, “Bob”)) 
Smooth APIs
Controller + Route 
package controller! 
class UsersController extends ApplicationController {! 
def showUsers = {! 
set(“users”, User.findAll())! 
render(“/users/index”) 
} 
}! 
! 
// Routings! 
object Controllers {! 
Set value in request scope! 
(Visible in views) 
Expects “src/main/webapp/! 
WEB-INF/views/users/index.html.ssp” 
val users = new UsersController with Routes {! 
get(“/users/”)(showUsers).as(‘showUsers) 
}! 
def mount(ctx: ServletContext): Unit = {! 
users.mount(ctx)! 
} 
}
View Template 
// src/main/webapp/WEB-INF/views/users/index.html.ssp! 
! 
<%@val users: Seq[User] %>! 
! 
<table class=“table”>! 
#for (user <- users)! 
<tr>! 
<td>${user.id}</td>! 
<td>${user.name}</td>! 
</tr>! 
#end! 
</table> 
import from request scope 
Loop, if/else syntax! 
in Scalate
Web Development 
• Interactive feedback loop is most 
important especially when changing UI • Actually Scala compilation is so slow that 
waiting view templates compilation makes 
developers much stressed • Skinny doesn’t compile all the view 
templates when developing (unlike Twirl)
My Good Parts 
for Solid and Safe 
Development
My Good Parts 
•Simplified Class-based OOP And 
Immutable Data Structure 
•Working On Problems Without 
Overkill Abstraction 
•Writing Tests Without Question 
•Keep Infrastructure Lightweight 
•No Surprises For Newcomer
Simplified Class-based 
OOP 
And Immutable 
Data Structure
Class-based OOP 
• Already so popular (Java, Ruby, Python ..) • Old style is friendly with mutability (e.g. 
setters, bang methods), but that’s not a 
prerequisite • OOP can be more solid and safer by 
keeping immutability and avoiding 
inheritance anti-patterns
Scala or Java 8? 
• Scala case class is simpler than Java 
beans with (great) Lombok • Scala high-order functions are simpler 
than Java 8 Stream API • Immutability is well-treated in Scala • Fairness: Java decisively beats Scala in 
comparison with compilation speed..
Immutability 
• Do away with mutable states • Re-assignment? No way! Don’t use `var` • Immutability makes your apps not only 
scalable but also more solid • When you modify a case class, call 
#copy() and return new state instead of 
using setters for mutability inside
Immutable Entity 
// entity with behaviors! 
case class User(id: Long, name: Option[String])! 
extends SkinnyRecord[User] {! 
override def skinnyCRUDMapper = User 
}! 
// data mapper! 
object User extends SkinnyCRUDMapper[User] {! 
override def defaultAlias = createAlias(“u”)! 
override def extract(rs: WrappedResultSet, u: ResultName[User])! 
= autoConstruct(rs, u) 
}! 
! 
val noNames: Seq[User] = User.where(‘name -> “”).apply()! 
val anons: Seq[User] = noNames.map { user => ! 
user.copy(name = “Anonymous”).save()! 
} 
Both of “noNames” and 
“anons” are immutable
Trait Chaos 
• Mixing traits can show you terrible chaos • We should have self-discipline • Prefer `override` modifier to detect API 
changes when mixing many traits • Collect the same sort of traits and place 
them in same place to avoid code 
duplication or unwanted complexity
Web Controller 
package controller! 
class MainController extends ApplicationController ! 
with concern.TimeLogging {! 
def index = logElapsedTime { render(“/main/index”) }! 
}! 
! 
// for controllers! 
package controller.concern! 
trait TimeLogging { self: SkinnyController with Logging =>! 
The “concern” just follows Rails style. 
Anyway, naming should be simple and! 
easy-to-understand for anyone 
def millis: Long = System.currentTimeMillis ! 
def logElapsedTime[A](action: => A): A = {! 
val before = millis! 
val result = action! 
logger.debug(“Elapsed time: ${millis - before} millis”)! 
result 
}! 
}
Coding Style Tips 
• Use sbt-scalariform without question 
(similar: go-lang’s fmt) • Don’t toss similar classes or traits into 
single scala file except `sealed` pattern • Don’t place classes under different 
package directory (although it’s possible) • Do you really need cake pattern? • Prefer eloquent method signature than 
explaining a lot in scaladocs
Working On 
Problems Without 
Overkill Abstraction
The Real As-Is 
• Abstraction often improves things, but 
that’s not always the best way to solve 
real-world problems • I/O issue is a typical case that we should 
comprehend problems as-is • Database access / SQL is not a collection 
but just an external I/O operation • Overkill abstraction makes your code 
difficult to maintain for other developers
Don’t Hide the SQL 
• “You don’t need another DSL to access 
relational databases” - Anorm • You must recognize what is working 
effectively in the SQL layer • Utility to write DAO easily is fine but 
hiding SQL is not good • Need to grab the cause from raw queries 
when dealing with troubles (comfortable 
logging also can help)
SQL Ops As-Is 
// A programmer belongs to a company and has several skills! 
! 
implicit val session = AutoSession! 
! 
val p: Option[Programmer] = withSQL {! 
I believe everybody can 
understand this code 
select.from(Programmer as p)! 
.leftJoin(Company as c).on(p.companyId, c.id)! 
.leftJoin(ProgrammerSkill as ps).on(ps.programmerId, p.id)! 
.leftJoin(Skill as s).on(ps.skillId, s.id)! 
.where.eq(p.id, 123).and.isNull(p.deletedAt)! 
}! 
.one(rs => Programmer(rs, p, c))! 
Extracts one-to-many 
.toMany(rs => Skill.opt(rs, s))! 
relationships here 
.map { (programmer, skills) => programmer.copy(skills = skills) }! 
.single! 
.apply()
Skinny ORM 
• ORM built on ScalikeJDBC • Highly inspired by Rails ActiveRecord • SQL queries for CRUD apps are common 
enough, so it’s reasonable to avoid writing 
mostly same code everywhere • Skinny ORM doesn't prevent you from 
using ScaikeJDBC APIs directly • A part of Skinny Framework but you can 
use it in Play apps too
Dependencies 
// build.sbt or project/Build.scala! 
! 
scalaVersion := “2.11.2” // or “2.10.4”! 
! 
libraryDependencies ++= Seq(! 
//“org.scalikejdbc” %% “scalikejdbc” % “2.1.1”,! 
“org.skinny-framework” %% “skinny-orm” % “1.3.1”,! 
“com.h2database” % “h2” % “1.4.181”,! 
“ch.qos.logback” % “logback-classic” % “1.1.2”! 
)
Mappers 
// entities! 
case class Company(id: Long, name: String)! 
case class Employee(id: Long, name: String,! 
companyId: Long, company: Option[Company])! 
! 
// mappers! 
object Company extends SkinnyCRUDMapper[Company] {! 
def extract(rs: WrappedResultSet, rn: ResultName[Company]) =! 
autoConstruct(rs, rn) 
}! 
object Employee extends SkinnyCRUDMapper[Employee] {! 
def extract(rs: WrappedResultSet, rn: ResultName[Employee]) =! 
autoConstruct(rs, rn, “company”)! 
// simple association definition! 
lazy val companyRef = belongsTo[Company](! 
Company, (e, c) => e.copy(company = c)) 
}
Reasonable? 
Right, these CRUD operations are not SQL-ish. However, I believe 
they’re reasonable because these patterns are already common enough. 
! 
! 
val companyId = Company.createWithAttributes(‘name -> “Sun”)! 
val empId = Employee.createWithAttributes(! 
‘name -> “Alice”, ‘companyId -> companyId)! 
! 
val emp: Option[Employee] = Employee.findById(empId)! 
val empWithCompany: Option[Employee] = ! 
Employee.joins(companyRef).findById(123)! 
! 
Company.updateById(companyId).withAttributes(‘name -> “Oracle”)! 
! 
val e = Employee.defaultAlias! 
Employee.deleteBy(sqls.eq(e.id, empId))! 
Using ScalikeJBDC API! 
Company.deleteById(companyId) 
is also possible
Writing Tests 
Without 
Question
Not Only Compiler 
• It’s true that compiler helps you by 
detecting mistakes in coding • Writing tests is a reasonable way to verify 
your code meets requirements / 
specifications as expected • You can’t skip automated tests even if 
your apps are written in Scala
scoverage 
• At this time, the only option available for 
us is scoverage (SCCT inheritor) • Add the dependency into your projects 
right now if you don’t use it yet
Keep 
Infrastructure 
Lightweight
Avoid SBT Hacks 
• sbt is not so easy for Scala newbies, 
upgrading sbt is all the more so • Play depends on sbt version (e.g. Play 2.1 
w/ sbt 0.12), upgrading Play is about not 
only Play API changes but sbt things • Your own sbt plugins/hacks make your 
projects difficult to maintain for a long 
period and involve others • Don’t try to do everything there
Skinny TaskRunner 
• Just want a simple and “rake”-like task 
runner (no sbt plugin) • Simplistic but pragmatic idea: “mainClass” 
of “task” sbt project can be dispatcher of 
task runner system • Tasks are written in Scala (no sbt plugin) • Not only writing code but upgrading 
scala/sbt version become pretty easy
Tasks 
// sbt settings! 
// mainClass := Some("TaskRunner")! 
! 
// task/src/main/scala/TaskRunner.scala! 
object TaskRunner extends skinny.task.TaskLauncher {! 
register("assets:precompile", (params) => {! 
val buildDir = params.headOption.getOrElse(“build")! 
// AssetsPrecompileTask is a Scala object! 
skinny.task.AssetsPrecompileTask.main(Array(buildDir))! 
})! 
}! 
Pure Scala function! 
! 
// skinny task:run assets:precompile [dir] 
task name 
mainClass as the dispatcher
Use Only Essentials 
• The same issue as Ruby gems, what’s 
worse, Scala’s eco-system is still so 
smaller than Ruby’s one • Binary incompatibility makes existing 
libraries outdated every Scala major 
version release • Are you really ready to fork them? • Using Java assets (e.g. commons) 
internally is also worth thinking about
No Surprises 
for Newcomer
Can Feel Welcome? 
• Is joining your Scala projects easy? Can 
newcomer understand overview at once? • Don’t stick to doing on the sbt, don’t 
disfavor using other tools (e.g. Grunt) • Well-known style (e.g. Rails style) is 
preferred for collaborative works • Is asynchronosity really required now? • Indeed, your DSL is very simple but easy 
to modify them (for others)?
Newcomers may not 
know Scala well. 
Attract them to Scala! 
(Don’t scare them)
AMA! #ScalaMatsuri2 
• Unconference tomorrow • “Ask Me Anything” • ScalikeJDBC • Skinny Framework • AWScala • Anything else!
Questions?
Questions?
Questions?
Thanks 
• Amazing “Maturi Urakata” (the 
conference volunteer staff) • Great invited speakers • You all here!

Solid And Sustainable Development in Scala

  • 1.
    Solid and Sustainable Development in Scala Kazuhiro Sera @seratch ScalikeJDBC / Skinny Framework Founder & Lead Developer
  • 2.
    Ask Me Later! • 3 mags for questioners at the end of this session! Don’t miss it! 2
  • 3.
    Who Am I • Kazuhiro Sera • @seratch on Twitter/GitHub • Scala enthusiast since 2010 • ScalikeJDBC, Skinny Framework, AWScala founder & project lead • A web developer at M3, Inc (We’re a Gold Sponsor)
  • 4.
  • 5.
    ScalikeJDBC • scalikejdbc.org• “Scala-like JDBC” • Provides Scala-ish APIs • Started as a better querulous / Anorm • “Just write SQL and get things done” • QueryDSL for smoothness & type-safety • Stable enough: lots of companies already use it in production
  • 6.
    Dependencies // build.sbtor project/Build.scala! ! scalaVersion := “2.11.2” // or “2.10.4”! ! libraryDependencies ++= Seq(! “org.scalikejdbc” %% “scalikejdbc” % “2.1.1”,! “com.h2database” % “h2” % “1.4.181”,! “ch.qos.logback” % “logback-classic” % “1.1.2”! )
  • 7.
    Basic Usage importscalikejdbc._! ! ConnectionPool.singleton(! “jdbc:h2:mem:matsuri”, ! “user”, “secret”)! SQL statement! (PreparedStatement) ! DB autoCommit { implicit session =>! Side effect ! with DB connection sql”create table attendee (name varchar(32))”.execute.apply()! val name = “seratch”! sql”insert into attendee (name) values ($name)”.update.apply()! }! ! val names: Seq[String] = DB readOnly { implicit s =>! sql”select name from attendee”! .map(_.string(“name”)).list.apply()! } execute/update! (JDBC operation) Extractor
  • 8.
    QueryDSL import scalikejdbc._! case class Attendee(name: String)! object Attendee extends SQLSyntaxSupport[Attendee] {! def apply(rs: WrappedResultSet, a: ResultName[Attendee]) = ! new Attendee(rs.get(a.name)) }! ! implicit val session = AutoSession! ! ! val a = Attendee.syntax(“a”)! val seratch: Option[Attendee] = withSQL {! QueryDSL! (Mostly SQL) Actual SQL Query select.from(Attendee as a).where.eq(a.name, “seratch”)! }.map(rs => new Attendee(rs, a)).single.apply()! ! // select a.name as n_on_a from attendee a where a.name = ?
  • 9.
    Skinny Framework •skinny-framework.org • “Scala on Rails” • For Rails / Play1 lovers • 1.0.0 was out on 28th March • Already several experiences in production • Full-stack features: Web infrastructure, Scaffold generator, ORM, DB migration, JSON stuff, HTTP client, Mail sender, Job workers, Assets controller, etc..
  • 10.
    Boot in 2minutes ! // install skinny command! brew tap skinny-framework/alt! brew install skinny! ! // create app and start! skinny new myapp! cd myapp! skinny run! ! // access localhost:8080 from your browser!
  • 11.
    Model (DAO) importskinny.orm._! Entity import scalikejdbc._! ! case class User(id: Long, name: Option[String])! ! // companion: data mapper! object User extends SkinnyCRUDMapper[User] {! def defaultAlias = createAlias(“u”)! def extract(rs: WrappedResultSet, u: ResultName[User])! = autoConstruct(rs, u) }! CRUD Mapper Object! ! (No need to be companion) User.findById(123)! User.count()! User.createWithAttributes(‘name -> “Alice”)! User.updateById(123).withAttributes(‘name -> “Bob”)! User.deleteBy(sqls.eq(u.name, “Bob”)) Smooth APIs
  • 12.
    Controller + Route package controller! class UsersController extends ApplicationController {! def showUsers = {! set(“users”, User.findAll())! render(“/users/index”) } }! ! // Routings! object Controllers {! Set value in request scope! (Visible in views) Expects “src/main/webapp/! WEB-INF/views/users/index.html.ssp” val users = new UsersController with Routes {! get(“/users/”)(showUsers).as(‘showUsers) }! def mount(ctx: ServletContext): Unit = {! users.mount(ctx)! } }
  • 13.
    View Template //src/main/webapp/WEB-INF/views/users/index.html.ssp! ! <%@val users: Seq[User] %>! ! <table class=“table”>! #for (user <- users)! <tr>! <td>${user.id}</td>! <td>${user.name}</td>! </tr>! #end! </table> import from request scope Loop, if/else syntax! in Scalate
  • 14.
    Web Development •Interactive feedback loop is most important especially when changing UI • Actually Scala compilation is so slow that waiting view templates compilation makes developers much stressed • Skinny doesn’t compile all the view templates when developing (unlike Twirl)
  • 15.
    My Good Parts for Solid and Safe Development
  • 16.
    My Good Parts •Simplified Class-based OOP And Immutable Data Structure •Working On Problems Without Overkill Abstraction •Writing Tests Without Question •Keep Infrastructure Lightweight •No Surprises For Newcomer
  • 17.
    Simplified Class-based OOP And Immutable Data Structure
  • 18.
    Class-based OOP •Already so popular (Java, Ruby, Python ..) • Old style is friendly with mutability (e.g. setters, bang methods), but that’s not a prerequisite • OOP can be more solid and safer by keeping immutability and avoiding inheritance anti-patterns
  • 19.
    Scala or Java8? • Scala case class is simpler than Java beans with (great) Lombok • Scala high-order functions are simpler than Java 8 Stream API • Immutability is well-treated in Scala • Fairness: Java decisively beats Scala in comparison with compilation speed..
  • 20.
    Immutability • Doaway with mutable states • Re-assignment? No way! Don’t use `var` • Immutability makes your apps not only scalable but also more solid • When you modify a case class, call #copy() and return new state instead of using setters for mutability inside
  • 21.
    Immutable Entity //entity with behaviors! case class User(id: Long, name: Option[String])! extends SkinnyRecord[User] {! override def skinnyCRUDMapper = User }! // data mapper! object User extends SkinnyCRUDMapper[User] {! override def defaultAlias = createAlias(“u”)! override def extract(rs: WrappedResultSet, u: ResultName[User])! = autoConstruct(rs, u) }! ! val noNames: Seq[User] = User.where(‘name -> “”).apply()! val anons: Seq[User] = noNames.map { user => ! user.copy(name = “Anonymous”).save()! } Both of “noNames” and “anons” are immutable
  • 22.
    Trait Chaos •Mixing traits can show you terrible chaos • We should have self-discipline • Prefer `override` modifier to detect API changes when mixing many traits • Collect the same sort of traits and place them in same place to avoid code duplication or unwanted complexity
  • 23.
    Web Controller packagecontroller! class MainController extends ApplicationController ! with concern.TimeLogging {! def index = logElapsedTime { render(“/main/index”) }! }! ! // for controllers! package controller.concern! trait TimeLogging { self: SkinnyController with Logging =>! The “concern” just follows Rails style. Anyway, naming should be simple and! easy-to-understand for anyone def millis: Long = System.currentTimeMillis ! def logElapsedTime[A](action: => A): A = {! val before = millis! val result = action! logger.debug(“Elapsed time: ${millis - before} millis”)! result }! }
  • 24.
    Coding Style Tips • Use sbt-scalariform without question (similar: go-lang’s fmt) • Don’t toss similar classes or traits into single scala file except `sealed` pattern • Don’t place classes under different package directory (although it’s possible) • Do you really need cake pattern? • Prefer eloquent method signature than explaining a lot in scaladocs
  • 25.
    Working On ProblemsWithout Overkill Abstraction
  • 26.
    The Real As-Is • Abstraction often improves things, but that’s not always the best way to solve real-world problems • I/O issue is a typical case that we should comprehend problems as-is • Database access / SQL is not a collection but just an external I/O operation • Overkill abstraction makes your code difficult to maintain for other developers
  • 27.
    Don’t Hide theSQL • “You don’t need another DSL to access relational databases” - Anorm • You must recognize what is working effectively in the SQL layer • Utility to write DAO easily is fine but hiding SQL is not good • Need to grab the cause from raw queries when dealing with troubles (comfortable logging also can help)
  • 28.
    SQL Ops As-Is // A programmer belongs to a company and has several skills! ! implicit val session = AutoSession! ! val p: Option[Programmer] = withSQL {! I believe everybody can understand this code select.from(Programmer as p)! .leftJoin(Company as c).on(p.companyId, c.id)! .leftJoin(ProgrammerSkill as ps).on(ps.programmerId, p.id)! .leftJoin(Skill as s).on(ps.skillId, s.id)! .where.eq(p.id, 123).and.isNull(p.deletedAt)! }! .one(rs => Programmer(rs, p, c))! Extracts one-to-many .toMany(rs => Skill.opt(rs, s))! relationships here .map { (programmer, skills) => programmer.copy(skills = skills) }! .single! .apply()
  • 29.
    Skinny ORM •ORM built on ScalikeJDBC • Highly inspired by Rails ActiveRecord • SQL queries for CRUD apps are common enough, so it’s reasonable to avoid writing mostly same code everywhere • Skinny ORM doesn't prevent you from using ScaikeJDBC APIs directly • A part of Skinny Framework but you can use it in Play apps too
  • 30.
    Dependencies // build.sbtor project/Build.scala! ! scalaVersion := “2.11.2” // or “2.10.4”! ! libraryDependencies ++= Seq(! //“org.scalikejdbc” %% “scalikejdbc” % “2.1.1”,! “org.skinny-framework” %% “skinny-orm” % “1.3.1”,! “com.h2database” % “h2” % “1.4.181”,! “ch.qos.logback” % “logback-classic” % “1.1.2”! )
  • 31.
    Mappers // entities! case class Company(id: Long, name: String)! case class Employee(id: Long, name: String,! companyId: Long, company: Option[Company])! ! // mappers! object Company extends SkinnyCRUDMapper[Company] {! def extract(rs: WrappedResultSet, rn: ResultName[Company]) =! autoConstruct(rs, rn) }! object Employee extends SkinnyCRUDMapper[Employee] {! def extract(rs: WrappedResultSet, rn: ResultName[Employee]) =! autoConstruct(rs, rn, “company”)! // simple association definition! lazy val companyRef = belongsTo[Company](! Company, (e, c) => e.copy(company = c)) }
  • 32.
    Reasonable? Right, theseCRUD operations are not SQL-ish. However, I believe they’re reasonable because these patterns are already common enough. ! ! val companyId = Company.createWithAttributes(‘name -> “Sun”)! val empId = Employee.createWithAttributes(! ‘name -> “Alice”, ‘companyId -> companyId)! ! val emp: Option[Employee] = Employee.findById(empId)! val empWithCompany: Option[Employee] = ! Employee.joins(companyRef).findById(123)! ! Company.updateById(companyId).withAttributes(‘name -> “Oracle”)! ! val e = Employee.defaultAlias! Employee.deleteBy(sqls.eq(e.id, empId))! Using ScalikeJBDC API! Company.deleteById(companyId) is also possible
  • 33.
  • 34.
    Not Only Compiler • It’s true that compiler helps you by detecting mistakes in coding • Writing tests is a reasonable way to verify your code meets requirements / specifications as expected • You can’t skip automated tests even if your apps are written in Scala
  • 35.
    scoverage • Atthis time, the only option available for us is scoverage (SCCT inheritor) • Add the dependency into your projects right now if you don’t use it yet
  • 36.
  • 37.
    Avoid SBT Hacks • sbt is not so easy for Scala newbies, upgrading sbt is all the more so • Play depends on sbt version (e.g. Play 2.1 w/ sbt 0.12), upgrading Play is about not only Play API changes but sbt things • Your own sbt plugins/hacks make your projects difficult to maintain for a long period and involve others • Don’t try to do everything there
  • 38.
    Skinny TaskRunner •Just want a simple and “rake”-like task runner (no sbt plugin) • Simplistic but pragmatic idea: “mainClass” of “task” sbt project can be dispatcher of task runner system • Tasks are written in Scala (no sbt plugin) • Not only writing code but upgrading scala/sbt version become pretty easy
  • 39.
    Tasks // sbtsettings! // mainClass := Some("TaskRunner")! ! // task/src/main/scala/TaskRunner.scala! object TaskRunner extends skinny.task.TaskLauncher {! register("assets:precompile", (params) => {! val buildDir = params.headOption.getOrElse(“build")! // AssetsPrecompileTask is a Scala object! skinny.task.AssetsPrecompileTask.main(Array(buildDir))! })! }! Pure Scala function! ! // skinny task:run assets:precompile [dir] task name mainClass as the dispatcher
  • 40.
    Use Only Essentials • The same issue as Ruby gems, what’s worse, Scala’s eco-system is still so smaller than Ruby’s one • Binary incompatibility makes existing libraries outdated every Scala major version release • Are you really ready to fork them? • Using Java assets (e.g. commons) internally is also worth thinking about
  • 41.
  • 42.
    Can Feel Welcome? • Is joining your Scala projects easy? Can newcomer understand overview at once? • Don’t stick to doing on the sbt, don’t disfavor using other tools (e.g. Grunt) • Well-known style (e.g. Rails style) is preferred for collaborative works • Is asynchronosity really required now? • Indeed, your DSL is very simple but easy to modify them (for others)?
  • 43.
    Newcomers may not know Scala well. Attract them to Scala! (Don’t scare them)
  • 44.
    AMA! #ScalaMatsuri2 •Unconference tomorrow • “Ask Me Anything” • ScalikeJDBC • Skinny Framework • AWScala • Anything else!
  • 45.
  • 46.
  • 47.
  • 48.
    Thanks • Amazing“Maturi Urakata” (the conference volunteer staff) • Great invited speakers • You all here!