You are on page 1of 55

Dynamic Languages: the

next big thing for the JVM or


an evolutionary dead end?

Chris Richardson
Author of POJOs in Action
y
Founder of Cloud Tools and Cloud Foundry
Chris Richardson Consulting, Inc
www.chrisrichardson.net
Overall p
presentation g
goal

Dynamic languages have many


benefits
But
Static languages,
languages which have the
safety net of compile-time
checking can be just as expressive
checking,

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 2
About Chris
• Grew up in England and live in Oakland, CA
• Over 20+ years of software development
experience including 12 years of Java
• Author of POJOs in Action
• Speaker at JavaOne, SpringOne, NFJS,
JavaPolis, Spring Experience, etc.
• Chair of the eBIG Java SIG in Oakland
(www.ebig.org)
• Run the Groovy/Grails meetup
(http://java.meetup.com/161)
• Run
u a consulting
co su t g and
a d training
t a g company
co pa y that
t at
helps organizations reduce development costs
and increase effectiveness
• Founder of Cloud Tools, an open-source project
for deploying Java applications on Amazon EC2:
http://code google com/p/cloudtools
http://code.google.com/p/cloudtools
• Founder of a startup that provides outsourced,
automated, and Java-centric datacenter
management on the cloud:
y
www.cloudfoundry.com

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 3
Agenda
g
The fall and rise of dynamic
languages
Favorite Groovy features
The frustration of using Groovy
Scala: expressiveness
p and compile-
p
time checking

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 4
Dynamic vs. static languages

Dynamic (run-time) Static (compile-time)


Types associated with Types associated with
values rather than variables
variables Compile-time
Ability to define new checking of language
program elements at elements and types
runtime Not a new idea
Not a new idea: either:
Lisp – 1958! Algol 60
SmallTalk - 1980
anObject.someMethod(someArgs)

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 5
LISP/CLOS – an early (late 1980s)
y
dynamic language
g g
(defclass Account ()
((account-id :accessor account-id :initarg :account-id)
(balance :accessor account-balance :initarg :balance)) Develop by adding and
) g gp
changing program
g
elements in a running VM
(defmethod debit ((Account account) amount)
(decf (account-balance account) amount))

(defmethod credit ((Account account) amount)


(incf (account-balance
(account balance account) amount))

CL-USER 5 > (setq a (make-instance 'account :account-id "abc123" :balance 10.0))


#<ACCOUNT 200C05AF>

CL-USER 6 > (describe a)

#<ACCOUNT 200C05AF> is an ACCOUNT


ACCOUNT-ID "abc123"
BALANCE 10.0

CL-USER
CL USER 7 > (debit a 5)
5.0

CL-USER 8 > (describe a)

#<ACCOUNT 200C05AF> is an ACCOUNT


ACCOUNT ID
ACCOUNT-ID ""abc123"
b 123"
BALANCE 5.0

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


6
… a very
y dynamic
y language
g g

((defclass Account ()
((account-id :accessor account-id :initarg :account-id) Existing instances
(balance :accessor account-balance :initarg :balance) are updated when
(description :accessor account-description :initarg :description)) the class is redefined
)

CL-USER 9 > (describe a)

#<ACCOUNT 2168DCBF> is an ACCOUNT


ACCOUNT-ID "abc123"
BALANCE 10.0
DESCRIPTION #<unbound slot>

CL-USER 10 > (setf (account-description a) "checking account")


"checking account"

CL-USER 11 > (describe a)

#<ACCOUNT 2168DCBF> is an ACCOUNT


ACCOUNT-ID "abc123"
BALANCE 10.0
DESCRIPTION "checking account"

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


7
Ruby
y on Rails woke up
p Java
Ruby on Rails:
Significantly more productive
Simplicity of Convention over
C fi
Configuration
ti
Motivated the Java community to
improve
Reopened the debate about
programming
i llanguages

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 8
Dynamic
y languages
g g on the JVM
JRuby
http://jruby.codehaus.org
p //j y g
Ruby on the JVM
Jython
http://www.jython.org/Project
p // jy g/ j
Python on the JVM
Clojure
http://clojure.org/
p j g
Functional programming language
Software Transactional Memory

Groovy
http://groovy.codehaus.org/
Java-compatible, dynamic language

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 9
Small…

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 10
… but growing
g g

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 11
Agenda
g
The fall and rise of dynamic
languages
Favorite Groovy features
The frustration of using Groovy
Scala: expressiveness
p and compile-
p
time checking

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 12
About Groovy
y
Object-oriented, dynamic language
Java compatible
Runs on the JVM
Made popular by the Grails
framework:
Rails-like productivity
Usingg robust Java frameworks including
g
Spring and Hibernate

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 13
Things
g I like: Java compatible
p
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

class EC2RequestExecutor { Java-like syntax


Use Java libraries
Log logger = LogFactory.getLog(getClass())

public String calculateRFC2104HMAC(String data, String key) {


try {
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes("UTF8"),
HMAC_SHA1_ALGORITHM)
M mac = Mac.getInstance(HMAC_SHA1_ALGORITHM)
Mac M tI t (HMAC SHA1 ALGORITHM)
mac.init(signingKey)
byte[] rawHmac = mac.doFinal(data.getBytes())
return new String(Base64.encodeBase64(rawHmac))
}
catch (Exception e) {
throw new RuntimeException("Failed to generate HMAC : ", e)
}
}

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 14
Groovy
y is concise and expressive
p
def configureAsMaster() {
writeFile fileName: "/etc/my.cnf", templateName: "/templates/master.my.cnf"

restartService "mysqld"

exec command: "mysql -u root",


templateName: "/templates/createSchema.sql",
/templates/createSchema.sql , No parens
templateArgs: [schemaSpec: schemaSpec] Keyword parameters

executeSchemaScripts()
}

class TomcatServer { tomcatServer.contexts


N get…()
No t ()
def getContexts() {
webApps.context
}
}

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 15
Literals for lists and maps
p

def myList = [“a”, “b”, “c”]

def params = ['Action': 'RunInstances',


'MinCount': n.toString(), 'MaxCount': n.toString(),
' ImageId': awsProperties."imageId.${instanceType}",
'KeyName': awsProperties.keyName,
' InstanceType': instanceType] + extraParams
def response = requestor.executeRequest(params)
requestor executeRequest(params)

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 16
GStrings
g

def schemaScript = """


DROP SCHEMA IF EXISTS ${schemaSpec.name};
CREATE SCHEMA ${schemaSpec.name};
"""

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 17
Closures

public EC2Server findInstance(String instanceId) {


d f server = servers.find
def fi d {instanceId
{i t Id == it.instanceId}
it i t Id}
if (server)
return server
else throw new RuntimeException(….)
RuntimeException( )
}

Simplified collection processing

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 18
Closures – new control structures
public class Ssh {

public Object
p j withTunnel(String
( gppublicDnsName,, int localPort,, int remotePort,, Closure closure)) {
SshConnection sshConnection = makeSshConnection(publicDnsName);
try {
sshConnection.connect()

return closure.call()
} finally
fi ll {
sshConnection.close()
}
}
}

class EC2 {

String snapshotEbsVolume(String hostName, EbsVolume ebsVolume, String schemaName) {


int localPort = PortUtil.allocatePort()
def result = ssh.withTunnel(hostName,
( , localPort,, 3306)
){

}
return (String)result
}

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 19
An interactive shell

Great for experimentation and learning

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 20
Simple
p reusable code
interface Quackable {
void q
quack();
();
Java:
} complexity
l it off
class QuackableContainer<T extends Quackable>
generics

void add(T element) {


element.quack();

}

}

class
c ass Quac
QuackableContainer
ab eCo ta e { Groovy: just assume that
void add(T element) { there is a quack()
element.quack()

method
}

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 21
Groovy
y metaclasses
public class StringMetaclassExampleTest extends GroovyTestCase {

void testAddMethodToString() {
String.metaClass.doubleString = { -> delegate + delegate }
String.metaClass.static.makePowerString = { String s, int n ->
def result = s
n.times { result = result.doubleString() }
result
}
assertEquals "CommunityOne EastCommunityOne East",
"CommunityOne
CommunityOne East
East".doubleString()
doubleString()
assertEquals "NewYorkNewYorkNewYorkNewYork",
String.makePowerString("NewYork", 2)
}
}

Runtime definition of p
program
g elements

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 22
Method Missing
g
public class ClassWithMissingMethods {

Object methodMissing(String name, args) {


Closure method = makeMethodImplementation(name)
if (method) {
method(args)
} else {
throw new MissingMethodException(name, getClass(), args)
}
}

def makeMethodImplementation(String name) {


….
}

def foo = new ClassWithMissingMethods()


g ()
foo.nonExistentMethod()

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 23
XML and GPath expressions
p
<RunInstancesResponse>

<instancesSet>
<item>
<instanceId>i-4ef21327</instanceId>
<imageId>ami-3795705e</imageId>
<instanceState>
<code>0</code>
def client = new HttpClient() <name>pending</name>
… </instanceState>
def responseStream = <dnsName/>
getMethod getResponseBodyAsStream()
getMethod.getResponseBodyAsStream() …
</RunInstancesResponse>
def parser = new XmlParser(false, false)
def response = parser.parseText(responseStream)

def newServers = response.instancesSet.item.collect


response instancesSet.item collect {
new EC2Server(this, awsProperties, ssh,
it.instanceId.text(),
it.instanceState.name.text())
}

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 24
Builders
def report(String path, hosts, cpuCount, threadCount) {
def builder = new groovy.xml.MarkupBuilder(new OutputStreamWriter(new FileOutputStream(path)))
builder.performanceReport {
cpus cpuCount
threads threadCount
hosts.entrySet().each { hostEntry ->
host {
name hostEntry.key <performanceReport>
cpuUtil hostEntry.value.getAverageBusy()
hostEntry value getAverageBusy() <cpus>1</cpus>
} <threads>10</threads>
} <host>
requests {
<name>database</name>
timings.entrySet().sort{ a, b-> a.key <=> b.key}.each{ pair ->
request { <cpuUtil>3.27</cpuUtil>
name pair.key
pair key </host>
art pair.value.average() <host>
errors pair.value.errorPercentage() <name>tomcat0</name>
}
<cpuUtil>94.32</cpuUtil>
}
} </host>
d f durationValue
def d ti V l = ((float)(endTime
((fl t)( dTi - startTime))/1000.0
t tTi ))/1000 0 …
duration durationValue <duration>557.943</duration>
def tpsValue = transactionCount/ durationValue <tps>10.753786677133686</tps>
tps tpsValue
<art>916.6578333333</art>
art averageResponseTime()
} </performanceReport>
}

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved. Slide 25
Grails/GORM
/ p
persistence methods
class Customer { Implemented using
String
g name metaclasses and method
} missing

C t
Customer c = new Customer("John
C t ("J h Doe")
D ")

if (!c.save())
fail "validation failed: ${c.errors}"

Customer c2 = Customer.get(c.id)

c2.delete()

assertNull Customer.get(c.id)

def customers = Customer.findAllByName(


Customer findAllByName(“Fred”)
Fred )

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 26
Agenda
g
The fall and rise of dynamic
languages
Favorite Groovy features
The frustration of using Groovy
Scala: expressiveness
p and compile-
p
time checking

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 27
Getting Groovy code to work can
g
be frustrating
Dynamic language = less information
for IDE:
Limited compile-time checking
Limited refactorings
Limited completion

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 28
Groovy fans say "write unit tests“
BUT…

Groovy

When you have typos


versus

Java

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 29
Unit tests don't always
y catch errors
void testPollStatus_discoveringNewServer() {
mockEC2RequestExecutor.demand.executeRequest {params ->
….
}
def mockEC2Server = new MockFor(EC2Server.class)
….
mockEC2Server.use {
mockEC2RequestExecutor.use {
ec2 = new EC2(awsProperties)
ec2.pollStatus() public class EC2 {
assertEquals 1, ec2.servers.size()
} public pollStatus() {
} def params = ['Action':
} 'DescribeInstances']
def p =
requestor executeRequest(params)
requestor.executeRequest(params)
class EC2RequestExecutor { …
}
public Node executeEc2Request(Map …
parameters) { } Method signature changes are
… often
ft missed
i d
}

Slide 30
4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.
The trouble with duck typing
yp g
Interface between components not
defined in a single place
It is scattered throughout caller
Difficult to understand
Difficult to change
g

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 31
The outcome: fear of change
g

Did my tests
catch all
the obvious errors?

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 32
Writing
g Java becomes frustrating
g
Importing the obvious, e.g. java.util
Tedious collection manipulation
Painful XML processing
p g
Repetitive type declarations

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 33
Agenda
g
The fall and rise of dynamic
languages
Favorite Groovy features
The frustration of using Groovy
Scala: expressiveness
p and
compile-time checking

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 34
Distilling
g a language
g g

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 35
Scala – a modern (2003) static
g g
language
Object-oriented
Pure object-oriented language
All values are objects
Class-based
Traits support "multiple inheritance"
Functional
Functions are values
Higher-order functions
Currying
Statically typed
Expressive
Type inference
E t
Extensible
ibl tto supportt d
domain
i specific
ifi languages
l
Methods as infix and postfix operators
Automatic closure construction
Fully interoperable with Java

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 36
Simple
p example
p
object StringFunctions {

def reverseSentence(sentence : String) = sentence.split(" ").reverse.mkString(" ")

import org.junit._
import Assert._

@Test
class StringFunctionsTest {

@Test
def testReverseSentence() = {
val input = "Hello New York"
val expected = "York New Hello"
assertEquals(expected, StringFunctions.reverseSentence(input))
}
}

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 37
Collection literals example
p
@Test
class ScalaCollectionExamplesTest {

@Test
def listExample() = {
val myList = List(1, 2, 3)
assertEquals(3, myList.length)
assertEquals(List(0 1
assertEquals(List(0, 1, 2
2, 3),
3) 0::myList)
assertEquals(List(2, 3), myList.tail)
assertEquals(1, myList.head)
}

@Test
def testMapExampleList() : Unit = {
val myMap = Map( "x" -> 1, "y" -> 2, "z" -> 3)
assertEquals(1, myMap("x"))
}
}

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 38
Closure example
p

@Test
class ScalaCollectionExamplesTest {

@Test
def testMapList()
p () = {
val myList = List(1, 2, 3)
assertEquals(List(2,4,6), myList.map ( x => x * 2))
assertEquals(List(2,4,6), myList.map ( _ * 2))
}

@Test
def testFilterList() = {
val myList = List(1, 2, 3)
assertEquals(List(1, 3), myList.filter( _ % 2 == 1));
}

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 39
Pattern matching
g
case class Organization(name: String,
industry: Industry.Value, revenue: Double, assets: Double, liabilities: Double) {

object Industry extends Enumeration {


val Banking, GreenEnergy, IT, Other = Value

class LoanApprovalPolicy {

def isLoanApproved(organization : Organization) = organization match {


case Organization(_, Industry.GreenEnergy, _, _, _) => true
case Organization(_, Industry.Banking, _, assets, liabilities)
if liabilities < assets * 1.5 => true
case Organization(_,
O i ti ( Industry.Banking,
I d t B ki _, _, _)) => false
f l
case Organization(_, _, _, assets, liabilities) if assets > liabilities => true
case _ => false
}

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 40
XML generation
g
@Test
class ScalaXmlExampleTest {

@Test
def xmlLiterals() {
val now = new Date()
val loanRequestor =
new Organization("Community Bank, Inc", Industry.Banking, 10, 10, 5)

val doc = <loanRequest>


<time>{now.getTime()}</time>
<requester>{loanRequestor.name}</requester>
<industry>{loanRequestor.industry}</industry>
<revenue>{loanRequestor.revenue}</revenue>
<assets>{loanRequestor.assets}</assets>
<liabilities>{loanRequestor.liabilities}</liabilities>
</l
</loanRequest>
R t>

val docAsString : String = doc.toString()


println(docAsString)
}

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 41
XML parsing
p g
class ScalaXmlExampleTest {

@Test
def xmlProcessing() {
val doc = xml.XML.loadString(docAsString)
assertEquals ("Community Bank, Inc", (doc \ "requester").text)

node match {
case <loanRequest>{children @ _* }</loanRequest> =>
for (x <- children if !x.isInstanceOf[scala.xml.Text]) {
processChildren(x)
}
}
}

def processChildren(node : scala.xml.Node ) = {


node
d match
t h{
case <time>{value}</time> => println(value.text)
case <requester>{value}</requester> => println(value.text)

}
}

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 42
DSL Example
p
class OrganizationDslTest {
val o : Organization = (Organization
called "Bernie
Bernie Madoff & Associates"
Associates
in Industry.Banking
withRevenuesOf (10 million)
withAssetsOf (10 billion)
withLiabilitiesOf (30 billion))

} object Organization {
def called(name : String) = new OrganizationBuilder(name)

class OrganizationBuilder(name
g ( : String)
g) {
var industry : Industry.Value = null
def in(industry : Industry.Value) = { this.industry = industry; this }
def withRevenuesOf(…) = …

def make()= new Organization(name
Organization(name, industry
industry, revenue
revenue, assets,
assets liabilities)
}

implicit def organizationBuilderToOrganization(builder : OrganizationBuilder)


= builder.make
}

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 43
Constructing
g object
j hierarchies
object ExampleSwingApp extends SimpleGUIApplication {

def top = new MainFrame {


title = "Example Swing App"

val button = new Button {


text = "press"
press
}

contents = button

var countt = 0
listenTo(button)
reactions += {
case ButtonClicked(b) =>
count = count + 1
Console.println(count);
b.text = "press: " + count
}
}

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 44
Scala command line

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 45
Traits
Consist of members
methods
fields
types
The members can be abstract
Multiple traits can be mixed into a
class
Alternative to multiple inheritance
Class must define abstract members

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 46
Dependency
p y injection
j in Scala
Dependency injection = component
definition and composition
Traditional approach
Metadata: XML, annotations
Framework: Spring, Guice, EJB3
Scala: use traits and other language
features

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 47
Dependency injection –
p g/
Spring/Java example
p
Names a
@Component("organizationRepository")
component
p and class OrganizationRepositoryImpl extends OrganizationRepository {
specifies it's …
implementation }

@Component("loanProcessingService")
class LoanProcessingServiceImpl extends LoanProcessingService{

Expresses a @Autowired
dependency private OrganizationRepository organizationRepository;

void processLoan(….)
processLoan( ) {
}

}

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 48
Dependency
p y injection
j - repository
p y
trait OrganizationRepositoryComponent {
Names a
component
p val organizationRepository : OrganizationRepository
and defines
it's interface trait OrganizationRepository {
def findByName(name : String) : Organization
}
}
Specifies the
implementation

trait OrganizationRepositoryComponentImpl extends OrganizationRepositoryComponent {

val organizationRepository = new OrganizationRepositoryImpl()

class OrganizationRepositoryImpl extends OrganizationRepository {


d f findByName(name
def fi dB N ( : String)
S i )={
… Access the database here…
}
}
}

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 49
Dependency
p y injection
j - service
trait LoanProcessingServiceComponent {
val loanProcessingService : LoanProcessingService Expresses a
trait LoanProcessingService { dependency
def processLoan(organizationName : String )
}
}
trait LoanProcessingServiceComponentImpl extends LoanProcessingServiceComponent
{ this : OrganizationRepositoryComponent =>

val loanProcessingService = new LoanProcessingServiceImpl()


val policy = new LoanApprovalPolicy()

class LoanProcessingServiceImpl extends LoanProcessingService {

def processLoan(organizationName : String ) = {


val organization = organizationRepository.findByName(organizationName)
if (policy.isLoanApproved(organization))
( li i L A d( i i )) {
// process the loan
} else {
throw new LoanRequestRejectedException()
….
}

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 50
Dependency
p y injection
j - application
pp

object LoanProcessingApplication
extends LoanProcessingServiceComponentImpl
with OrganizationRepositoryComponentImpl {

LoanProcessingApplication.loanProcessingService.processLoan("Green Co")

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 51
Dependency
p y injection
j – testing
g
class LoanProcessingApplicationTest {

trait OrganizationRepositoryComponentStub extends OrganizationRepositoryComponent {


val organizationRepository = new OrganizationRepositoryStubImpl()
class OrganizationRepositoryStubImpl extends OrganizationRepository {
def findByName(name : String) = {
name match {
case "Bernie Madoff & Associates" => new Organization(…)

}
}
}
}

object LoanProcessingApplicationWithStub extends


LoanProcessingServiceComponentImpl
g p p with OrganizationRepositoryComponentStub
g p y p {
}

@Test
def testProcessLoanOk() = {
LoanProcessingApplicationWithStub loanProcessingService processLoan("Green
LoanProcessingApplicationWithStub.loanProcessingService.processLoan( Green Co")
Co )
}

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 52
The bad news about Scala
IDEs are rough around the edges
Expressiveness comes from complex
language features
Generics are better than Java but still
complex
BUT
The investment in learning these
features is repaid with every
pp
application you
y write

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 53
Summary
y
Today’s interest in dynamic
languages is natural reaction to Java
Not evolving sufficiently
Showing its age
But many benefits of those languages
are due to good language design
Scala = expressiveness + static
typing

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 54
Final thoughts
g
Download or contribute to Cloud
Tools today
y:
www.cloudtools.org
Checkout Cloud Foundry:
www cloudfoundry com
www.cloudfoundry.com
Buy my book ☺
Send email:
chris@chrisrichardson.net
Visit my website:
www.chrisrichardson.net
Talk to me about consulting and
training
Phone: 510 904 9832

4/8/2009 Copyright (c) 2009 Chris Richardson. All rights reserved.


Slide 55