SlideShare uma empresa Scribd logo
1 de 46
Baixar para ler offline
Beginning Scala with
Skinny Framework
Kazuhiro Sera
@seratch
M3, Inc.
Skinny Framework Team
JJUG CCC 2014 Spring
2014/05/18
- What s Skinny -
Skinny?
・ Skinny has a nice ring.
!
・Application should be skinny
・Framework should be skinny
・ su-ki-ni in Japanese means as
you like it
Skinny Framework
・2014/03/28 - version 1.0.0 (latest 1.0.14)
・Concept: Scala on Rails
・Full-stack Web app framework
・MVC、ORM、DB migration、Mail Sender
・scaffold auto generator
・Run on the Servlet containers
・Java 1.6 or higher, Servlet 3.0 or higher
・war packaging, standalone jar file
Full-stack required?
・Full-stack web framework is a dead word?
・Recently they re not uncommon
・Integrating libraries is flexible but costs
・Recommended way to do the same is
important for team building
・Developers time should be used for
creating differentiated features
Scala on Rails?
・Rails and Play1 are optimised for HTML-
based web app development
・Play2 is a new generation framework to
implement servers that have high
performance and solve C10K problem
・JSON API servers、Akka-oriented apps
!
Skinny Structure
・Basically built upon dependable libraries
・Routes, Servlet API DSL from Scalatra
・Default template engine: Scalate
・ORM is built upon ScalikeJDBC
・DB migration: Flyway
・JSON operations: json4s
・Input validations and mailer are original
!
- Beginning Skinny -
Bootstrap (1)
・Required: Only JDK (1.6 or higher)
・Download a zip file from skinny-
framework.org
!
!
!
!
!
Bootstrap (2)
・Unzip it and run skinny run
・Access localhost:8080 from your browser
・Same procedure on Windows OS
!
!
!
!
!
!
Bootstrap (3)
・Recommended sbt project template
・All the jar files are already downloaded
・You don t need learning sbt settings in
detail at this point
・Easy to run on Jenkins
・Using IntelliJ IDEA is recommended
(Community Edition is enough for Scala)
!
- Skinny MVC -
・#set puts value to request scope (can be
accessed in controller/view)
・Returned value will be the response body
!
!
!
!
!
!
First Controller (1)
// src/main/scala/controller/RootController.scala!
!
package controller!
import skinny._!
class RootController extends ApplicationController {!
def index = {!
set(“name”, “JJUG”)!
render(“/root/index”)!
}!
}
・ Hello ${name}! will be Hello JJUG!
!
!
!
!
!
!
!
!
First Controller (2)
! -# src/main/webapp/WEB-INF/views/root/index.html.ssp!
<%@val name: String %>!
<h1>Hello, ${name}!</h1>
・#set can accept various types of values
・In this case, Scala collection object
!
!
!
!
!
!
!
First Controller (3)
// src/main/scala/controller/RootController.scala!
!
package controller!
import skinny._!
class RootController extends ApplicationController {!
def index = {!
set(“numbers”, Seq(1,2,3,4,5))!
render(“/root/index”)!
}!
}!
・Loop/if-else with ${numbers}
!
!
!
!
!
!
!
!
!
First Controller (4)
! -# src/main/webapp/WEB-INF/views/root/index.html.ssp!
!
<%@val numbers: Seq[Int] %>!
#for (n <- numbers)!
#if (n % 2 == 0)!
${n}!
#end!
#end!
・Scalatra s Servlet wrapper API provides
easy-to-use DSL
・e.g.) status = 201, redirect(url), halt(400)
・Also possible to use Servlet API directly
・If you re familiar with Servlet, it s very
easy to understand
!
!
First Controller (5)
・Skinny s Routing uses Scalatra DS (Routes
trait extends a little)
・Substance of controller is Servet s Filter/
Servlet, so just mount it to ServletContext
!
!
!
!
!
First Routing (1)
! // src/main/scala/controller/Controllers.scala!
! object Controllers {!
! object root extends RootController with Routes {!
! val indexUrl = get(“/“)(index).as(‘index)

! }!
! override def mount(ctx: ServletContext): Unit = {!
! root.mount(ctx)!
! }!
! }!
・s.url(Controllers.root.indexUrl) returns
actual URL string
・Avoid embedding URL in view templates
!
!
!
!
!
!
First Routing (2)
! // src/main/scala/controller/Controllers.scala!
! object Controllers {!
! object root extends RootController with Routes {!
! val indexUrl = get(“/“)(index).as(‘index)

! }!
! // …!
! }!
・skinny-validator: input validator DSL
・If errors, they re already put into request
scope, so just show them in the form.
!
!
!
!
!
!
!
SkinnyValidator
! class MembersController extends ApplicationController {!
! protectFromForgery()!
! def createForm = validation(params,!
! paramKey(“name”) is required & maxLength(64),!
! paramKey(“email”) is email!
! )!
! def create = {!
! if (createForm.validate()) {!
! doCreate(params.permit(!
! “name” -> ParamType.String, “email” -> ParamType.String))

! } else {!
! render(“/members/input”)!
! }!
! }!
! }
・Default: Scalate SSP(Scala Server Pages)
・Scalate supports SSP, Scaml(≒Haml),
Jade and Mustache
・If you use other templates, just change file
extension (e.g. show.html.ssp ->
show.html.jade)
・FreeMarker and Thymeleaf are also
supported (optional)
First View
・DB access example with Skinny ORM
・case class: entity, object: DAO
!
!
!
!
!
!
First Model (1)
! sql”create table member (id serial, name varchar(64))”!
! ! .execute.apply()! !
!
! // src/main/scala/model/Member.scala!
! case class Member(id: Long, name: Option[String])!
!
! object Member extends SkinnyCRUDMapper[Member] {!
! lazy val defaultAlias = createAlias(“m”)!
! def extract(rs: WrappedResultSet, m: ResultName[Member]) =!
! new Member(rs.get(m.id), rs.get(m.name))!
! }
・DB migration by using Flyway is handy to
setup local dev environment
!
!
!
!
!
!
!
First Model (2)
! ./skinny g migration createMember!
! // src/main/resources/db/migration/V20140514141738__createMember.sql!
! // Write DDL to V20140514141738__createMember.sql!
!
! // “development” ENVB!
! ./skinny db:migrate!
!
! // “test” ENV!
! ./skinny db:migrate test
・That s all, now you can use APIs
!
!
!
!
!
!
!
!
First Model (3)
! // Insert!
! val id: Long = Member.createWithAttributes('name -> “JJUG")!
! // insert into member (name) values ('JJUG')!
!
! // Finder API!
! val ms: Seq[Member] = Member.findAll()!
! // select m.id as i_on_m, m.name as n_on_m from member m order by m.id;!
!
! // Querying API!
! val ms: Seq[Member] = Member.where(‘name -> “JJUG").apply()!
! // from member m where m.name = ‘JJUG'!
!
! // ScalikeJDBC QueryDSL!
! val m = Member.defaultAlias!
! val mopt: Option[Member] = Member.findBy(sqls.eq(m.name, "JJUG"))!
! // from member m where m.name = ‘JJUG'
・Add country" table
!
!
!
!
!
!
!
First Model (4)
! case class Member(id: Long, name: Option[String])!
! object Member extends SkinnyCRUDMapper[Member] {!
! lazy val defaultAlias = createAlias(“m”)!
! def extract(rs: WrappedResultSet, m: ResultName[Member] =!
! new Member(rs.get(m.id), rs.get(m.name))!
! }!
!
! // create table country(id serial, name varchar(128) not null);!
! object class Country(id: Long, name: String)!
! object Country extends SkinnyCRUDMapper[Country] {!
! lazy val defaultAlias = createAlias(“m”)!
! def extract(rs: WrappedResultSet, c: ResultName[Country] =!
! new Country(rs.get(c.id), rs.get(c.name))!
! }
・Add a belongsTo replationship
!
!
!
!
!
!
!
!
First Model (5)
! case class Member(!
! id: Long, !
! name: Option[String]!
! countryId: Option[Long],!
! country: Option[Country] = None)!
!
! object Member extends SkinnyCRUDMapper[Member] {!
! val defaultAlias = createAlias(“m”)!
! def extract(rs: WrappedResultSet, m: ResultName[Member] =!
! new Member(rs.get(m.id), rs.get(m.name), rs.get(m.countryId))!
!
! val country = belongsTo[Country](Country, !
! (member, country) => member.copy(country = country)!
! )!
! }
・Calling #joins resolves associations
!
!
!
!
!
!
!
!
First Model(6)
! // Insert!
! val countryId: Long = Country.createWithAttributes('name -> “Japan”)!
! val id = Member.createWithAttributes(!
! ‘name -> “JJUG”, ‘countryId -> countryId)!
!
! // member だけ!
! val m = Member.findById(id)!
! // from member m where m.id = ?!
!
! // country も!
! Member.joins(Member.country).findById(id)!
! // from member m left join country c on m.country_id = c.id where m.id = ?!
・#byDefault allows fetching associations
without calling #joins
!
!
!
!
!
!
!
!
First Model (7)
! case class Member(!
! id: Long, !
! name: Option[String]!
! countryId: Option[Long],!
! country: Option[Country] = None)!
!
! object Member extends SkinnyCRUDMapper[Member] {!
! val defaultAlias = createAlias(“m”)!
! def extract(rs: WrappedResultSet, m: ResultName[Member] =!
! new Member(rs.get(m.id), rs.get(m.name), rs.get(m.countryId))!
!
! val country = belongsTo[Country](Country, !
! (member, country) => member.copy(country = country)!
! ).byDefault!
! }
・AutoSession is the simplest way
・Transaction is provided by ScalikeJDBC s
localTx blocks or it s fine to use
TxPerRequestFilter(thread-local)
!
!
!
!
!
!
First Model (8)
! DB.localTx { implicit session =>!
! // will be rolled back when exception is thrown here!
! Member.findById(id).map { member =>!
! member.copy(name = newName).save() // SkinnyRecord!
! MemberStatus.setAsActive(member)

! }.getOrElse {!
! val id = Member.createWithAttributes(‘name -> newName)!
! MemberStatus.addNewMemberAsActive(id)

! }!
! }
・Just use in controllers
・Avoid fat controller
!
!
!
!
!
!
!
First Model (9)
! // src/main/scala/controller/MembersController.scala!
!
! import model.Member!
! class MembersController extends ApplicationController {!
! def showAll = {!
! set(“members”, Member.findAll())!
! render(“/members/showAll”)!
! }!
! }!
!
FactoryGirl
・Highly inspired by thoughtbot/factory_girl
・Not YAML but typesafe-config s HOCON
・Scala code can be executed
!
!
!
!
!
!
! member {!
! name=“JJUG”!
! luckyNumber="${scala.util.Random.nextInt(64)}"!
! }
! val member: Member = FactoryGirl(Member).create()!
! val member = FactoryGirl(Member).create(‘name -> “ScalaJP”)
- Other Features -
scaffold (1)
・CRUD admin pages by scaffold
・Test code also generated
!
!
!
!
!
!
!
! ./skinny g scaffold members member name:String birthday:Option[LocalDate] active:Boolean!
!
! *** Skinny Generator Task ***!
!
! "src/main/scala/controller/ApplicationController.scala" skipped.!
! "src/main/scala/controller/MembersController.scala" created.!
! "src/main/scala/controller/Controllers.scala" modified.!
! "src/test/scala/controller/MembersControllerSpec.scala" created.!
! "src/test/scala/integrationtest/MembersController_IntegrationTestSpec.scala" created.!
! "src/test/resources/factories.conf" modified.!
! "src/main/scala/model/Member.scala" created.!
! "src/test/scala/model/MemberSpec.scala" created.!
! "src/main/webapp/WEB-INF/views/members/_form.html.ssp" created.!
! "src/main/webapp/WEB-INF/views/members/new.html.ssp" created.!
! "src/main/webapp/WEB-INF/views/members/edit.html.ssp" created.!
! "src/main/webapp/WEB-INF/views/members/index.html.ssp" created.!
! "src/main/webapp/WEB-INF/views/members/show.html.ssp" created.!
! "src/main/resources/messages.conf" modified.!
! "src/main/resources/db/migration/V20140514173530__Create_members_table.sql" created.
scaffold (2)
! ./skinny db:migrate !
! ./skinnny run!
!
! ./skinny db:migrate test!
! ./skinny test
・Validation code is also generated
!
!
!
!
!
!
!
!
scaffold (3)
・flash is also available
!
!
!
!
!
!
!
!
scaffold (4)
・pagination also implemented
!
!
!
!
!
!
!
!
scaffold (5)
reverse-scaffold
・scaffold generation from existing DB
・Simple primary key is required
!
!
!
!
!
!
!
! ./skinny g reverse-scaffold members members member!
!
! *** Skinny Reverse Engineering Task ***!
!
! Table : members!
! ID : id:Long!
! Resources : members!
! Resource : member!
!
! Columns:!
! - name:String:varchar(512)!
! - birthday:Option[LocalDate]!
! - createdAt:DateTime!
! - updatedAt:DateTime!
!
! *** Skinny Generator Task ***!
!
! "src/main/scala/controller/ApplicationController.scala" skipped.!
! "src/main/scala/controller/MembersController.scala" created.!
! "src/main/scala/controller/Controllers.scala" modified.
・JavaMail DSL
・Available for not only Skinny apps
!
!
!
!
!
!
!
!
SkinnyMailer
! val config = SkinnyMailerConfig.default.copy(!
! // JavaMail, SMTP configuration !
! )!
! val mailer = SkinnyMailer(config)!
! mailer!
! .to(“seratch@example.com”)!
! .cc(“users-ml@example.com”)!
! .subject(“Skinny talk at JJUG CCC”)!
! .body {“””Hi all,!
! |I’ll give a talk on Skinny next Sunday.!
! |”””.stripMargin}!
! .deliver()
Assets (1)
・Converts CoffeeScript, React JS, Scala.js,
Sass, LESS to JS/CSS
・Everything but Sass works on the JVM =
Windows OS friendly
・Source Maps with native compilers
・CoffeeScript under src/main/webapp/
WEB-INF/assets/coffee will be converted
under src/main/webapp/assets/js
Assets(2)
・Scala.js is pretty interesting though it s
stilll in the alpha stage
!
!
!
!
!
!
!
! ./skinny run!! ! ! // Terminal A!
! ./skinny scalajs:watch! // Terminal B!
! vim src/main/webapp/WEB-INF/assets/scala/Sample.scala! // Terminal C
Deployment
・ skinny package generates war file
・package task compiles all the Scalate
templates
・ skinny package:standalone generates
jar file which has an embedded Jetty server
・Heroku deployment is also ready
!
!! ./skinny package!
! ./skinny package:standalone
- Conclusion -
Skinny for You
・Skinny is the best framework when you
need Play1/Rails in Scala
・Much simpler code than Java apps
・Skinny ORM + ScalikeJDBC is so useful
・I think negative things about Scala
development are too long compilation time,
learning tools and styles. Skinny resolves or
reduces in a pragmatic way
Not Only Reactive
・Reactive applications is the most exciting
trend in the Scala community
・OTOH, statically-typed Ruby-like code or
Java compatible and simpler code is much
desired by lots of people
・You can use Skinny(Scalatra)with Akka
but Skinny s features focuses on Better
Java convenience
Roadmap
・Skinny 1.1 - Scala 2.10/2.11 cross build,
deps major version up
・We ll keep compatible APIs
・We d like to challenge non-blocking APIs
too, we hope doing that with http4s or
something similar

Mais conteúdo relacionado

Mais procurados

Future on Servlet #scala_ks
Future on Servlet #scala_ksFuture on Servlet #scala_ks
Future on Servlet #scala_ksKazuhiro Sera
 
What's a macro?: Learning by Examples / Scalaのマクロに実用例から触れてみよう!
What's a macro?: Learning by Examples / Scalaのマクロに実用例から触れてみよう!What's a macro?: Learning by Examples / Scalaのマクロに実用例から触れてみよう!
What's a macro?: Learning by Examples / Scalaのマクロに実用例から触れてみよう!scalaconfjp
 
Xitrum @ Scala Matsuri Tokyo 2014
Xitrum @ Scala Matsuri Tokyo 2014Xitrum @ Scala Matsuri Tokyo 2014
Xitrum @ Scala Matsuri Tokyo 2014Ngoc Dao
 
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory Course
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory CourseRuby on Rails 101 - Presentation Slides for a Five Day Introductory Course
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory Coursepeter_marklund
 
FITC - Here Be Dragons: Advanced JavaScript Debugging
FITC - Here Be Dragons: Advanced JavaScript DebuggingFITC - Here Be Dragons: Advanced JavaScript Debugging
FITC - Here Be Dragons: Advanced JavaScript DebuggingRami Sayar
 
Modularize JavaScript with RequireJS
Modularize JavaScript with RequireJSModularize JavaScript with RequireJS
Modularize JavaScript with RequireJSMinh Hoang
 
Ruby on Rails Training - Module 1
Ruby on Rails Training - Module 1Ruby on Rails Training - Module 1
Ruby on Rails Training - Module 1Mark Menard
 
Develop realtime web with Scala and Xitrum
Develop realtime web with Scala and XitrumDevelop realtime web with Scala and Xitrum
Develop realtime web with Scala and XitrumNgoc Dao
 
Ror Seminar With agilebd.org on 23 Jan09
Ror Seminar With agilebd.org on 23 Jan09Ror Seminar With agilebd.org on 23 Jan09
Ror Seminar With agilebd.org on 23 Jan09Shaer Hassan
 
Ruby on Rails workshop for beginner
Ruby on Rails workshop for beginnerRuby on Rails workshop for beginner
Ruby on Rails workshop for beginnerUmair Amjad
 
From Ruby to Scala
From Ruby to ScalaFrom Ruby to Scala
From Ruby to Scalatod esking
 
O que há de novo no Rails 3
O que há de novo no Rails 3O que há de novo no Rails 3
O que há de novo no Rails 3Hugo Baraúna
 
Java 7 Whats New(), Whats Next() from Oredev
Java 7 Whats New(), Whats Next() from OredevJava 7 Whats New(), Whats Next() from Oredev
Java 7 Whats New(), Whats Next() from OredevMattias Karlsson
 
Scala Frameworks for Web Application 2016
Scala Frameworks for Web Application 2016Scala Frameworks for Web Application 2016
Scala Frameworks for Web Application 2016takezoe
 
Ruby on Rails Penetration Testing
Ruby on Rails Penetration TestingRuby on Rails Penetration Testing
Ruby on Rails Penetration Testing3S Labs
 
Web a Quebec - JS Debugging
Web a Quebec - JS DebuggingWeb a Quebec - JS Debugging
Web a Quebec - JS DebuggingRami Sayar
 
Frontend Application Architecture, Patterns, and Workflows
Frontend Application Architecture, Patterns, and WorkflowsFrontend Application Architecture, Patterns, and Workflows
Frontend Application Architecture, Patterns, and WorkflowsTreasure Data, Inc.
 
Picking gem ruby for penetration testers
Picking gem ruby for penetration testersPicking gem ruby for penetration testers
Picking gem ruby for penetration testersPaolo Perego
 

Mais procurados (20)

Future on Servlet #scala_ks
Future on Servlet #scala_ksFuture on Servlet #scala_ks
Future on Servlet #scala_ks
 
What's a macro?: Learning by Examples / Scalaのマクロに実用例から触れてみよう!
What's a macro?: Learning by Examples / Scalaのマクロに実用例から触れてみよう!What's a macro?: Learning by Examples / Scalaのマクロに実用例から触れてみよう!
What's a macro?: Learning by Examples / Scalaのマクロに実用例から触れてみよう!
 
Xitrum @ Scala Matsuri Tokyo 2014
Xitrum @ Scala Matsuri Tokyo 2014Xitrum @ Scala Matsuri Tokyo 2014
Xitrum @ Scala Matsuri Tokyo 2014
 
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory Course
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory CourseRuby on Rails 101 - Presentation Slides for a Five Day Introductory Course
Ruby on Rails 101 - Presentation Slides for a Five Day Introductory Course
 
FITC - Here Be Dragons: Advanced JavaScript Debugging
FITC - Here Be Dragons: Advanced JavaScript DebuggingFITC - Here Be Dragons: Advanced JavaScript Debugging
FITC - Here Be Dragons: Advanced JavaScript Debugging
 
Modularize JavaScript with RequireJS
Modularize JavaScript with RequireJSModularize JavaScript with RequireJS
Modularize JavaScript with RequireJS
 
Ruby on Rails Training - Module 1
Ruby on Rails Training - Module 1Ruby on Rails Training - Module 1
Ruby on Rails Training - Module 1
 
Develop realtime web with Scala and Xitrum
Develop realtime web with Scala and XitrumDevelop realtime web with Scala and Xitrum
Develop realtime web with Scala and Xitrum
 
Ror Seminar With agilebd.org on 23 Jan09
Ror Seminar With agilebd.org on 23 Jan09Ror Seminar With agilebd.org on 23 Jan09
Ror Seminar With agilebd.org on 23 Jan09
 
Ruby on Rails workshop for beginner
Ruby on Rails workshop for beginnerRuby on Rails workshop for beginner
Ruby on Rails workshop for beginner
 
Introduction to CQ5
Introduction to CQ5Introduction to CQ5
Introduction to CQ5
 
From Ruby to Scala
From Ruby to ScalaFrom Ruby to Scala
From Ruby to Scala
 
O que há de novo no Rails 3
O que há de novo no Rails 3O que há de novo no Rails 3
O que há de novo no Rails 3
 
Java 7 Whats New(), Whats Next() from Oredev
Java 7 Whats New(), Whats Next() from OredevJava 7 Whats New(), Whats Next() from Oredev
Java 7 Whats New(), Whats Next() from Oredev
 
Scala Frameworks for Web Application 2016
Scala Frameworks for Web Application 2016Scala Frameworks for Web Application 2016
Scala Frameworks for Web Application 2016
 
Play framework
Play frameworkPlay framework
Play framework
 
Ruby on Rails Penetration Testing
Ruby on Rails Penetration TestingRuby on Rails Penetration Testing
Ruby on Rails Penetration Testing
 
Web a Quebec - JS Debugging
Web a Quebec - JS DebuggingWeb a Quebec - JS Debugging
Web a Quebec - JS Debugging
 
Frontend Application Architecture, Patterns, and Workflows
Frontend Application Architecture, Patterns, and WorkflowsFrontend Application Architecture, Patterns, and Workflows
Frontend Application Architecture, Patterns, and Workflows
 
Picking gem ruby for penetration testers
Picking gem ruby for penetration testersPicking gem ruby for penetration testers
Picking gem ruby for penetration testers
 

Semelhante a Beginning Scala with Skinny Framework #jjug_ccc

Solid and Sustainable Development in Scala
Solid and Sustainable Development in ScalaSolid and Sustainable Development in Scala
Solid and Sustainable Development in Scalascalaconfjp
 
Solid And Sustainable Development in Scala
Solid And Sustainable Development in ScalaSolid And Sustainable Development in Scala
Solid And Sustainable Development in ScalaKazuhiro Sera
 
BP-6 Repository Customization Best Practices
BP-6 Repository Customization Best PracticesBP-6 Repository Customization Best Practices
BP-6 Repository Customization Best PracticesAlfresco Software
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Racksickill
 
From Hacker to Programmer (w/ Webpack, Babel and React)
From Hacker to Programmer (w/ Webpack, Babel and React)From Hacker to Programmer (w/ Webpack, Babel and React)
From Hacker to Programmer (w/ Webpack, Babel and React)Joseph Chiang
 
Intro to node.js - Ran Mizrahi (27/8/2014)
Intro to node.js - Ran Mizrahi (27/8/2014)Intro to node.js - Ran Mizrahi (27/8/2014)
Intro to node.js - Ran Mizrahi (27/8/2014)Ran Mizrahi
 
Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)Ran Mizrahi
 
Modern Front-End Development
Modern Front-End DevelopmentModern Front-End Development
Modern Front-End Developmentmwrather
 
Ruby on Rails survival guide of an aged Java developer
Ruby on Rails survival guide of an aged Java developerRuby on Rails survival guide of an aged Java developer
Ruby on Rails survival guide of an aged Java developergicappa
 
Sparkling Water 5 28-14
Sparkling Water 5 28-14Sparkling Water 5 28-14
Sparkling Water 5 28-14Sri Ambati
 
Practical JavaScript Programming - Session 1/8
Practical JavaScript Programming - Session 1/8Practical JavaScript Programming - Session 1/8
Practical JavaScript Programming - Session 1/8Wilson Su
 
Using Sinatra to Build REST APIs in Ruby
Using Sinatra to Build REST APIs in RubyUsing Sinatra to Build REST APIs in Ruby
Using Sinatra to Build REST APIs in RubyLaunchAny
 
Introduction to Spark
Introduction to SparkIntroduction to Spark
Introduction to SparkLi Ming Tsai
 
Compiler2016 by abcdabcd987
Compiler2016 by abcdabcd987Compiler2016 by abcdabcd987
Compiler2016 by abcdabcd987乐群 陈
 
Yang in ODL by Jan Medved
Yang in ODL by Jan MedvedYang in ODL by Jan Medved
Yang in ODL by Jan MedvedOpenDaylight
 
Yang in OpenDaylight
Yang in OpenDaylightYang in OpenDaylight
Yang in OpenDaylightGunjan Patel
 

Semelhante a Beginning Scala with Skinny Framework #jjug_ccc (20)

Solid and Sustainable Development in Scala
Solid and Sustainable Development in ScalaSolid and Sustainable Development in Scala
Solid and Sustainable Development in Scala
 
Solid And Sustainable Development in Scala
Solid And Sustainable Development in ScalaSolid And Sustainable Development in Scala
Solid And Sustainable Development in Scala
 
BP-6 Repository Customization Best Practices
BP-6 Repository Customization Best PracticesBP-6 Repository Customization Best Practices
BP-6 Repository Customization Best Practices
 
Building web framework with Rack
Building web framework with RackBuilding web framework with Rack
Building web framework with Rack
 
From Hacker to Programmer (w/ Webpack, Babel and React)
From Hacker to Programmer (w/ Webpack, Babel and React)From Hacker to Programmer (w/ Webpack, Babel and React)
From Hacker to Programmer (w/ Webpack, Babel and React)
 
Intro to node.js - Ran Mizrahi (27/8/2014)
Intro to node.js - Ran Mizrahi (27/8/2014)Intro to node.js - Ran Mizrahi (27/8/2014)
Intro to node.js - Ran Mizrahi (27/8/2014)
 
Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)
 
Modern Front-End Development
Modern Front-End DevelopmentModern Front-End Development
Modern Front-End Development
 
Ruby on Rails survival guide of an aged Java developer
Ruby on Rails survival guide of an aged Java developerRuby on Rails survival guide of an aged Java developer
Ruby on Rails survival guide of an aged Java developer
 
JavaScript ES6
JavaScript ES6JavaScript ES6
JavaScript ES6
 
Sparkling Water 5 28-14
Sparkling Water 5 28-14Sparkling Water 5 28-14
Sparkling Water 5 28-14
 
Practical JavaScript Programming - Session 1/8
Practical JavaScript Programming - Session 1/8Practical JavaScript Programming - Session 1/8
Practical JavaScript Programming - Session 1/8
 
Avatar 2.0
Avatar 2.0Avatar 2.0
Avatar 2.0
 
Using Sinatra to Build REST APIs in Ruby
Using Sinatra to Build REST APIs in RubyUsing Sinatra to Build REST APIs in Ruby
Using Sinatra to Build REST APIs in Ruby
 
Introduction to Spark
Introduction to SparkIntroduction to Spark
Introduction to Spark
 
Compiler2016 by abcdabcd987
Compiler2016 by abcdabcd987Compiler2016 by abcdabcd987
Compiler2016 by abcdabcd987
 
Yang in ODL by Jan Medved
Yang in ODL by Jan MedvedYang in ODL by Jan Medved
Yang in ODL by Jan Medved
 
Yang in OpenDaylight
Yang in OpenDaylightYang in OpenDaylight
Yang in OpenDaylight
 
DSLs in JavaScript
DSLs in JavaScriptDSLs in JavaScript
DSLs in JavaScript
 
ECMAScript 6
ECMAScript 6ECMAScript 6
ECMAScript 6
 

Mais de Kazuhiro Sera

All I learned while working on a Scala OSS project for over six years #ScalaM...
All I learned while working on a Scala OSS project for over six years #ScalaM...All I learned while working on a Scala OSS project for over six years #ScalaM...
All I learned while working on a Scala OSS project for over six years #ScalaM...Kazuhiro Sera
 
Contributing to Scala OSS from East Asia #ScalaMatsuri
 Contributing to Scala OSS from East Asia #ScalaMatsuri Contributing to Scala OSS from East Asia #ScalaMatsuri
Contributing to Scala OSS from East Asia #ScalaMatsuriKazuhiro Sera
 
Skinny Meetup Tokyo 2 日本語スライド
Skinny Meetup Tokyo 2 日本語スライドSkinny Meetup Tokyo 2 日本語スライド
Skinny Meetup Tokyo 2 日本語スライドKazuhiro Sera
 
Seasar ユーザだったプログラマが目指す OSS の世界展開 #seasarcon
Seasar ユーザだったプログラマが目指す OSS の世界展開 #seasarconSeasar ユーザだったプログラマが目指す OSS の世界展開 #seasarcon
Seasar ユーザだったプログラマが目指す OSS の世界展開 #seasarconKazuhiro Sera
 
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageek
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageekJava エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageek
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageekKazuhiro Sera
 
Servlet と Future の関わり方 #scala_ks
Servlet と Future の関わり方 #scala_ksServlet と Future の関わり方 #scala_ks
Servlet と Future の関わり方 #scala_ksKazuhiro Sera
 
マイクロサービス運用の所感 #m3dev
マイクロサービス運用の所感 #m3devマイクロサービス運用の所感 #m3dev
マイクロサービス運用の所感 #m3devKazuhiro Sera
 
Scala が支える医療系ウェブサービス #jissenscala
Scala が支える医療系ウェブサービス #jissenscalaScala が支える医療系ウェブサービス #jissenscala
Scala が支える医療系ウェブサービス #jissenscalaKazuhiro Sera
 
Scala on Rails #rakutentech
Scala on Rails #rakutentechScala on Rails #rakutentech
Scala on Rails #rakutentechKazuhiro Sera
 
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24Kazuhiro Sera
 
Skinny Framework 1.0.0
Skinny Framework 1.0.0Skinny Framework 1.0.0
Skinny Framework 1.0.0Kazuhiro Sera
 
Skinny Framework 進捗どうですか? #fud_scala
Skinny Framework 進捗どうですか? #fud_scalaSkinny Framework 進捗どうですか? #fud_scala
Skinny Framework 進捗どうですか? #fud_scalaKazuhiro Sera
 
テストの運用について #m3dev
テストの運用について #m3devテストの運用について #m3dev
テストの運用について #m3devKazuhiro Sera
 
めんどくさくない Scala #kwkni_scala
めんどくさくない Scala #kwkni_scalaめんどくさくない Scala #kwkni_scala
めんどくさくない Scala #kwkni_scalaKazuhiro Sera
 
歌舞伎座.tech 1 LT - ScalikeJDBC Async & Skinny Framework #kbkz_tech
歌舞伎座.tech 1 LT - ScalikeJDBC Async & Skinny Framework #kbkz_tech歌舞伎座.tech 1 LT - ScalikeJDBC Async & Skinny Framework #kbkz_tech
歌舞伎座.tech 1 LT - ScalikeJDBC Async & Skinny Framework #kbkz_techKazuhiro Sera
 
Kabukiza.tech 1 LT - ScalikeJDBC-Async & Skinny Framework #kbkz_tech
Kabukiza.tech 1 LT - ScalikeJDBC-Async & Skinny Framework #kbkz_techKabukiza.tech 1 LT - ScalikeJDBC-Async & Skinny Framework #kbkz_tech
Kabukiza.tech 1 LT - ScalikeJDBC-Async & Skinny Framework #kbkz_techKazuhiro Sera
 
テストを書くのが嫌いな君へ #m3dev
テストを書くのが嫌いな君へ #m3devテストを書くのが嫌いな君へ #m3dev
テストを書くのが嫌いな君へ #m3devKazuhiro Sera
 
Skinny Controllers, Skinny Models
Skinny Controllers, Skinny ModelsSkinny Controllers, Skinny Models
Skinny Controllers, Skinny ModelsKazuhiro Sera
 
ScalikeJDBC Tutorial for Beginners
ScalikeJDBC Tutorial for BeginnersScalikeJDBC Tutorial for Beginners
ScalikeJDBC Tutorial for BeginnersKazuhiro Sera
 

Mais de Kazuhiro Sera (20)

All I learned while working on a Scala OSS project for over six years #ScalaM...
All I learned while working on a Scala OSS project for over six years #ScalaM...All I learned while working on a Scala OSS project for over six years #ScalaM...
All I learned while working on a Scala OSS project for over six years #ScalaM...
 
Contributing to Scala OSS from East Asia #ScalaMatsuri
 Contributing to Scala OSS from East Asia #ScalaMatsuri Contributing to Scala OSS from East Asia #ScalaMatsuri
Contributing to Scala OSS from East Asia #ScalaMatsuri
 
Skinny Meetup Tokyo 2 日本語スライド
Skinny Meetup Tokyo 2 日本語スライドSkinny Meetup Tokyo 2 日本語スライド
Skinny Meetup Tokyo 2 日本語スライド
 
Skinny 2 Update
Skinny 2 UpdateSkinny 2 Update
Skinny 2 Update
 
Seasar ユーザだったプログラマが目指す OSS の世界展開 #seasarcon
Seasar ユーザだったプログラマが目指す OSS の世界展開 #seasarconSeasar ユーザだったプログラマが目指す OSS の世界展開 #seasarcon
Seasar ユーザだったプログラマが目指す OSS の世界展開 #seasarcon
 
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageek
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageekJava エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageek
Java エンジニアチームが始めやすい Scala コーディングスタイル #ichigayageek
 
Servlet と Future の関わり方 #scala_ks
Servlet と Future の関わり方 #scala_ksServlet と Future の関わり方 #scala_ks
Servlet と Future の関わり方 #scala_ks
 
マイクロサービス運用の所感 #m3dev
マイクロサービス運用の所感 #m3devマイクロサービス運用の所感 #m3dev
マイクロサービス運用の所感 #m3dev
 
Scala が支える医療系ウェブサービス #jissenscala
Scala が支える医療系ウェブサービス #jissenscalaScala が支える医療系ウェブサービス #jissenscala
Scala が支える医療系ウェブサービス #jissenscala
 
Scala on Rails #rakutentech
Scala on Rails #rakutentechScala on Rails #rakutentech
Scala on Rails #rakutentech
 
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24
 
Skinny Framework 1.0.0
Skinny Framework 1.0.0Skinny Framework 1.0.0
Skinny Framework 1.0.0
 
Skinny Framework 進捗どうですか? #fud_scala
Skinny Framework 進捗どうですか? #fud_scalaSkinny Framework 進捗どうですか? #fud_scala
Skinny Framework 進捗どうですか? #fud_scala
 
テストの運用について #m3dev
テストの運用について #m3devテストの運用について #m3dev
テストの運用について #m3dev
 
めんどくさくない Scala #kwkni_scala
めんどくさくない Scala #kwkni_scalaめんどくさくない Scala #kwkni_scala
めんどくさくない Scala #kwkni_scala
 
歌舞伎座.tech 1 LT - ScalikeJDBC Async & Skinny Framework #kbkz_tech
歌舞伎座.tech 1 LT - ScalikeJDBC Async & Skinny Framework #kbkz_tech歌舞伎座.tech 1 LT - ScalikeJDBC Async & Skinny Framework #kbkz_tech
歌舞伎座.tech 1 LT - ScalikeJDBC Async & Skinny Framework #kbkz_tech
 
Kabukiza.tech 1 LT - ScalikeJDBC-Async & Skinny Framework #kbkz_tech
Kabukiza.tech 1 LT - ScalikeJDBC-Async & Skinny Framework #kbkz_techKabukiza.tech 1 LT - ScalikeJDBC-Async & Skinny Framework #kbkz_tech
Kabukiza.tech 1 LT - ScalikeJDBC-Async & Skinny Framework #kbkz_tech
 
テストを書くのが嫌いな君へ #m3dev
テストを書くのが嫌いな君へ #m3devテストを書くのが嫌いな君へ #m3dev
テストを書くのが嫌いな君へ #m3dev
 
Skinny Controllers, Skinny Models
Skinny Controllers, Skinny ModelsSkinny Controllers, Skinny Models
Skinny Controllers, Skinny Models
 
ScalikeJDBC Tutorial for Beginners
ScalikeJDBC Tutorial for BeginnersScalikeJDBC Tutorial for Beginners
ScalikeJDBC Tutorial for Beginners
 

Último

Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessPixlogix Infotech
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 

Último (20)

Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 

Beginning Scala with Skinny Framework #jjug_ccc

  • 1. Beginning Scala with Skinny Framework Kazuhiro Sera @seratch M3, Inc. Skinny Framework Team JJUG CCC 2014 Spring 2014/05/18
  • 2. - What s Skinny -
  • 3. Skinny? ・ Skinny has a nice ring. ! ・Application should be skinny ・Framework should be skinny ・ su-ki-ni in Japanese means as you like it
  • 4. Skinny Framework ・2014/03/28 - version 1.0.0 (latest 1.0.14) ・Concept: Scala on Rails ・Full-stack Web app framework ・MVC、ORM、DB migration、Mail Sender ・scaffold auto generator ・Run on the Servlet containers ・Java 1.6 or higher, Servlet 3.0 or higher ・war packaging, standalone jar file
  • 5. Full-stack required? ・Full-stack web framework is a dead word? ・Recently they re not uncommon ・Integrating libraries is flexible but costs ・Recommended way to do the same is important for team building ・Developers time should be used for creating differentiated features
  • 6. Scala on Rails? ・Rails and Play1 are optimised for HTML- based web app development ・Play2 is a new generation framework to implement servers that have high performance and solve C10K problem ・JSON API servers、Akka-oriented apps !
  • 7. Skinny Structure ・Basically built upon dependable libraries ・Routes, Servlet API DSL from Scalatra ・Default template engine: Scalate ・ORM is built upon ScalikeJDBC ・DB migration: Flyway ・JSON operations: json4s ・Input validations and mailer are original !
  • 9. Bootstrap (1) ・Required: Only JDK (1.6 or higher) ・Download a zip file from skinny- framework.org ! ! ! ! !
  • 10. Bootstrap (2) ・Unzip it and run skinny run ・Access localhost:8080 from your browser ・Same procedure on Windows OS ! ! ! ! ! !
  • 11. Bootstrap (3) ・Recommended sbt project template ・All the jar files are already downloaded ・You don t need learning sbt settings in detail at this point ・Easy to run on Jenkins ・Using IntelliJ IDEA is recommended (Community Edition is enough for Scala) !
  • 13. ・#set puts value to request scope (can be accessed in controller/view) ・Returned value will be the response body ! ! ! ! ! ! First Controller (1) // src/main/scala/controller/RootController.scala! ! package controller! import skinny._! class RootController extends ApplicationController {! def index = {! set(“name”, “JJUG”)! render(“/root/index”)! }! }
  • 14. ・ Hello ${name}! will be Hello JJUG! ! ! ! ! ! ! ! ! First Controller (2) ! -# src/main/webapp/WEB-INF/views/root/index.html.ssp! <%@val name: String %>! <h1>Hello, ${name}!</h1>
  • 15. ・#set can accept various types of values ・In this case, Scala collection object ! ! ! ! ! ! ! First Controller (3) // src/main/scala/controller/RootController.scala! ! package controller! import skinny._! class RootController extends ApplicationController {! def index = {! set(“numbers”, Seq(1,2,3,4,5))! render(“/root/index”)! }! }!
  • 16. ・Loop/if-else with ${numbers} ! ! ! ! ! ! ! ! ! First Controller (4) ! -# src/main/webapp/WEB-INF/views/root/index.html.ssp! ! <%@val numbers: Seq[Int] %>! #for (n <- numbers)! #if (n % 2 == 0)! ${n}! #end! #end!
  • 17. ・Scalatra s Servlet wrapper API provides easy-to-use DSL ・e.g.) status = 201, redirect(url), halt(400) ・Also possible to use Servlet API directly ・If you re familiar with Servlet, it s very easy to understand ! ! First Controller (5)
  • 18. ・Skinny s Routing uses Scalatra DS (Routes trait extends a little) ・Substance of controller is Servet s Filter/ Servlet, so just mount it to ServletContext ! ! ! ! ! First Routing (1) ! // src/main/scala/controller/Controllers.scala! ! object Controllers {! ! object root extends RootController with Routes {! ! val indexUrl = get(“/“)(index).as(‘index)
 ! }! ! override def mount(ctx: ServletContext): Unit = {! ! root.mount(ctx)! ! }! ! }!
  • 19. ・s.url(Controllers.root.indexUrl) returns actual URL string ・Avoid embedding URL in view templates ! ! ! ! ! ! First Routing (2) ! // src/main/scala/controller/Controllers.scala! ! object Controllers {! ! object root extends RootController with Routes {! ! val indexUrl = get(“/“)(index).as(‘index)
 ! }! ! // …! ! }!
  • 20. ・skinny-validator: input validator DSL ・If errors, they re already put into request scope, so just show them in the form. ! ! ! ! ! ! ! SkinnyValidator ! class MembersController extends ApplicationController {! ! protectFromForgery()! ! def createForm = validation(params,! ! paramKey(“name”) is required & maxLength(64),! ! paramKey(“email”) is email! ! )! ! def create = {! ! if (createForm.validate()) {! ! doCreate(params.permit(! ! “name” -> ParamType.String, “email” -> ParamType.String))
 ! } else {! ! render(“/members/input”)! ! }! ! }! ! }
  • 21. ・Default: Scalate SSP(Scala Server Pages) ・Scalate supports SSP, Scaml(≒Haml), Jade and Mustache ・If you use other templates, just change file extension (e.g. show.html.ssp -> show.html.jade) ・FreeMarker and Thymeleaf are also supported (optional) First View
  • 22. ・DB access example with Skinny ORM ・case class: entity, object: DAO ! ! ! ! ! ! First Model (1) ! sql”create table member (id serial, name varchar(64))”! ! ! .execute.apply()! ! ! ! // src/main/scala/model/Member.scala! ! case class Member(id: Long, name: Option[String])! ! ! object Member extends SkinnyCRUDMapper[Member] {! ! lazy val defaultAlias = createAlias(“m”)! ! def extract(rs: WrappedResultSet, m: ResultName[Member]) =! ! new Member(rs.get(m.id), rs.get(m.name))! ! }
  • 23. ・DB migration by using Flyway is handy to setup local dev environment ! ! ! ! ! ! ! First Model (2) ! ./skinny g migration createMember! ! // src/main/resources/db/migration/V20140514141738__createMember.sql! ! // Write DDL to V20140514141738__createMember.sql! ! ! // “development” ENVB! ! ./skinny db:migrate! ! ! // “test” ENV! ! ./skinny db:migrate test
  • 24. ・That s all, now you can use APIs ! ! ! ! ! ! ! ! First Model (3) ! // Insert! ! val id: Long = Member.createWithAttributes('name -> “JJUG")! ! // insert into member (name) values ('JJUG')! ! ! // Finder API! ! val ms: Seq[Member] = Member.findAll()! ! // select m.id as i_on_m, m.name as n_on_m from member m order by m.id;! ! ! // Querying API! ! val ms: Seq[Member] = Member.where(‘name -> “JJUG").apply()! ! // from member m where m.name = ‘JJUG'! ! ! // ScalikeJDBC QueryDSL! ! val m = Member.defaultAlias! ! val mopt: Option[Member] = Member.findBy(sqls.eq(m.name, "JJUG"))! ! // from member m where m.name = ‘JJUG'
  • 25. ・Add country" table ! ! ! ! ! ! ! First Model (4) ! case class Member(id: Long, name: Option[String])! ! object Member extends SkinnyCRUDMapper[Member] {! ! lazy val defaultAlias = createAlias(“m”)! ! def extract(rs: WrappedResultSet, m: ResultName[Member] =! ! new Member(rs.get(m.id), rs.get(m.name))! ! }! ! ! // create table country(id serial, name varchar(128) not null);! ! object class Country(id: Long, name: String)! ! object Country extends SkinnyCRUDMapper[Country] {! ! lazy val defaultAlias = createAlias(“m”)! ! def extract(rs: WrappedResultSet, c: ResultName[Country] =! ! new Country(rs.get(c.id), rs.get(c.name))! ! }
  • 26. ・Add a belongsTo replationship ! ! ! ! ! ! ! ! First Model (5) ! case class Member(! ! id: Long, ! ! name: Option[String]! ! countryId: Option[Long],! ! country: Option[Country] = None)! ! ! object Member extends SkinnyCRUDMapper[Member] {! ! val defaultAlias = createAlias(“m”)! ! def extract(rs: WrappedResultSet, m: ResultName[Member] =! ! new Member(rs.get(m.id), rs.get(m.name), rs.get(m.countryId))! ! ! val country = belongsTo[Country](Country, ! ! (member, country) => member.copy(country = country)! ! )! ! }
  • 27. ・Calling #joins resolves associations ! ! ! ! ! ! ! ! First Model(6) ! // Insert! ! val countryId: Long = Country.createWithAttributes('name -> “Japan”)! ! val id = Member.createWithAttributes(! ! ‘name -> “JJUG”, ‘countryId -> countryId)! ! ! // member だけ! ! val m = Member.findById(id)! ! // from member m where m.id = ?! ! ! // country も! ! Member.joins(Member.country).findById(id)! ! // from member m left join country c on m.country_id = c.id where m.id = ?!
  • 28. ・#byDefault allows fetching associations without calling #joins ! ! ! ! ! ! ! ! First Model (7) ! case class Member(! ! id: Long, ! ! name: Option[String]! ! countryId: Option[Long],! ! country: Option[Country] = None)! ! ! object Member extends SkinnyCRUDMapper[Member] {! ! val defaultAlias = createAlias(“m”)! ! def extract(rs: WrappedResultSet, m: ResultName[Member] =! ! new Member(rs.get(m.id), rs.get(m.name), rs.get(m.countryId))! ! ! val country = belongsTo[Country](Country, ! ! (member, country) => member.copy(country = country)! ! ).byDefault! ! }
  • 29. ・AutoSession is the simplest way ・Transaction is provided by ScalikeJDBC s localTx blocks or it s fine to use TxPerRequestFilter(thread-local) ! ! ! ! ! ! First Model (8) ! DB.localTx { implicit session =>! ! // will be rolled back when exception is thrown here! ! Member.findById(id).map { member =>! ! member.copy(name = newName).save() // SkinnyRecord! ! MemberStatus.setAsActive(member)
 ! }.getOrElse {! ! val id = Member.createWithAttributes(‘name -> newName)! ! MemberStatus.addNewMemberAsActive(id)
 ! }! ! }
  • 30. ・Just use in controllers ・Avoid fat controller ! ! ! ! ! ! ! First Model (9) ! // src/main/scala/controller/MembersController.scala! ! ! import model.Member! ! class MembersController extends ApplicationController {! ! def showAll = {! ! set(“members”, Member.findAll())! ! render(“/members/showAll”)! ! }! ! }! !
  • 31. FactoryGirl ・Highly inspired by thoughtbot/factory_girl ・Not YAML but typesafe-config s HOCON ・Scala code can be executed ! ! ! ! ! ! ! member {! ! name=“JJUG”! ! luckyNumber="${scala.util.Random.nextInt(64)}"! ! } ! val member: Member = FactoryGirl(Member).create()! ! val member = FactoryGirl(Member).create(‘name -> “ScalaJP”)
  • 33. scaffold (1) ・CRUD admin pages by scaffold ・Test code also generated ! ! ! ! ! ! ! ! ./skinny g scaffold members member name:String birthday:Option[LocalDate] active:Boolean! ! ! *** Skinny Generator Task ***! ! ! "src/main/scala/controller/ApplicationController.scala" skipped.! ! "src/main/scala/controller/MembersController.scala" created.! ! "src/main/scala/controller/Controllers.scala" modified.! ! "src/test/scala/controller/MembersControllerSpec.scala" created.! ! "src/test/scala/integrationtest/MembersController_IntegrationTestSpec.scala" created.! ! "src/test/resources/factories.conf" modified.! ! "src/main/scala/model/Member.scala" created.! ! "src/test/scala/model/MemberSpec.scala" created.! ! "src/main/webapp/WEB-INF/views/members/_form.html.ssp" created.! ! "src/main/webapp/WEB-INF/views/members/new.html.ssp" created.! ! "src/main/webapp/WEB-INF/views/members/edit.html.ssp" created.! ! "src/main/webapp/WEB-INF/views/members/index.html.ssp" created.! ! "src/main/webapp/WEB-INF/views/members/show.html.ssp" created.! ! "src/main/resources/messages.conf" modified.! ! "src/main/resources/db/migration/V20140514173530__Create_members_table.sql" created.
  • 34. scaffold (2) ! ./skinny db:migrate ! ! ./skinnny run! ! ! ./skinny db:migrate test! ! ./skinny test
  • 35. ・Validation code is also generated ! ! ! ! ! ! ! ! scaffold (3)
  • 36. ・flash is also available ! ! ! ! ! ! ! ! scaffold (4)
  • 38. reverse-scaffold ・scaffold generation from existing DB ・Simple primary key is required ! ! ! ! ! ! ! ! ./skinny g reverse-scaffold members members member! ! ! *** Skinny Reverse Engineering Task ***! ! ! Table : members! ! ID : id:Long! ! Resources : members! ! Resource : member! ! ! Columns:! ! - name:String:varchar(512)! ! - birthday:Option[LocalDate]! ! - createdAt:DateTime! ! - updatedAt:DateTime! ! ! *** Skinny Generator Task ***! ! ! "src/main/scala/controller/ApplicationController.scala" skipped.! ! "src/main/scala/controller/MembersController.scala" created.! ! "src/main/scala/controller/Controllers.scala" modified.
  • 39. ・JavaMail DSL ・Available for not only Skinny apps ! ! ! ! ! ! ! ! SkinnyMailer ! val config = SkinnyMailerConfig.default.copy(! ! // JavaMail, SMTP configuration ! ! )! ! val mailer = SkinnyMailer(config)! ! mailer! ! .to(“seratch@example.com”)! ! .cc(“users-ml@example.com”)! ! .subject(“Skinny talk at JJUG CCC”)! ! .body {“””Hi all,! ! |I’ll give a talk on Skinny next Sunday.! ! |”””.stripMargin}! ! .deliver()
  • 40. Assets (1) ・Converts CoffeeScript, React JS, Scala.js, Sass, LESS to JS/CSS ・Everything but Sass works on the JVM = Windows OS friendly ・Source Maps with native compilers ・CoffeeScript under src/main/webapp/ WEB-INF/assets/coffee will be converted under src/main/webapp/assets/js
  • 41. Assets(2) ・Scala.js is pretty interesting though it s stilll in the alpha stage ! ! ! ! ! ! ! ! ./skinny run!! ! ! // Terminal A! ! ./skinny scalajs:watch! // Terminal B! ! vim src/main/webapp/WEB-INF/assets/scala/Sample.scala! // Terminal C
  • 42. Deployment ・ skinny package generates war file ・package task compiles all the Scalate templates ・ skinny package:standalone generates jar file which has an embedded Jetty server ・Heroku deployment is also ready ! !! ./skinny package! ! ./skinny package:standalone
  • 44. Skinny for You ・Skinny is the best framework when you need Play1/Rails in Scala ・Much simpler code than Java apps ・Skinny ORM + ScalikeJDBC is so useful ・I think negative things about Scala development are too long compilation time, learning tools and styles. Skinny resolves or reduces in a pragmatic way
  • 45. Not Only Reactive ・Reactive applications is the most exciting trend in the Scala community ・OTOH, statically-typed Ruby-like code or Java compatible and simpler code is much desired by lots of people ・You can use Skinny(Scalatra)with Akka but Skinny s features focuses on Better Java convenience
  • 46. Roadmap ・Skinny 1.1 - Scala 2.10/2.11 cross build, deps major version up ・We ll keep compatible APIs ・We d like to challenge non-blocking APIs too, we hope doing that with http4s or something similar