Add (Syntactic) Sugar To Your Java

Preview:

Citation preview

Add Sugar to your Java“how we architected from the ground up

for testability, and why”

Pascal-Louis Perez – .com

Pascal-Louis Perez, kaChing Group Inc.

VSYNTAC

TI C

.com

Pascal-Louis Perez, kaChing Group Inc.

our system in 30 seconds

Pascal-Louis Perez, kaChing Group Inc.

Overview• Components versus Layers• Type Driven Development

– 1:1 principle– Family Polymorphism

• Annotations– Meta Information– Typing Extensions

• Object Oriented design replaces Conditionals– Delegation– State Pattern

• Declarative Programming– Domain Specific Language– Factories

Pascal-Louis Perez, kaChing Group Inc.

τ @what?

µ-Java

• Imagine Java deprived of all native types (boolean, int, …) and all control-flow constructs (if then else, for, while, …)

• How do you encode booleans using only objects?

• What about integers?• Is µ-Java Turing-complete?

Pascal-Louis Perez, kaChing Group Inc.

µ-Java: boolean

• if (condition) statement1else statement2

• condition.if(statement1, statement2)

• Bool class with True and False subclasses– in True, if computes statement1– In False, if computes statement2

• Statements are instances of Thunk<Void>

Pascal-Louis Perez, kaChing Group Inc.

Growing a Language

Pascal-Louis Perez, kaChing Group Inc.

expressiveness

µ-Java

1 Do not take things for granted

2 Think outside the Language

Testable Code Because…

• It allows quick iterations• It makes it easy to scale the team• It is more cost effective than debugging• It obsoletes the need for functional QA• It facilitates continuous refactoring, allowing

the code to get better with age• It attracts the right kind of engineers

Pascal-Louis Perez, kaChing Group Inc.

It’s a lot of fun!

Pascal-Louis Perez, kaChing Group Inc.

And it can be very geeky!

Pascal-Louis Perez, kaChing Group Inc.

Software is Traditionally Layered

• Examples– Jetty– Apache HTTP client

Pascal-Louis Perez, kaChing Group Inc.

STOP

Think about Components

• Provides Functionality…• given Required Services.• Yields reusable software• Key to testability

Pascal-Louis Perez, kaChing Group Inc.

Wireable Puzzle Pieces

• What if I want only one thread pool in my whole app server?

• In Scala ( http://www.scala-lang.org)

new JettyServer with MyThreadPool;

new ParallelRpc with MyThreadPool;

Pascal-Louis Perez, kaChing Group Inc.

Dependency Injection to the Rescue

class UserServiceImpl

implements UserService {

@Inject

UserServiceImpl(HttpClient, …) { …

}

Pascal-Louis Perez, kaChing Group Inc.

required services

functionality

τ

Add Retrying Logic

class MyExtendedUserServiceImpl implements UserService {

@Inject UserServiceImpl(UserServiceImpl) …

User getUser(Id<User> id) { User u = null; for (int i=0; i<5 && u == null; i++) u = delegate.getUser(id); return u; }

Pascal-Louis Perez, kaChing Group Inc.

QueryEngine

• Software platform to build services quickly• Unit of work is a Query– query constructors define input parameters– queries can request dependencies at run-time– queries do work and produce a value which is

then post-processed (serialized, stored, …)

• Soon open-sourced http://code.google.com/p/queryengine/

Pascal-Louis Perez, kaChing Group Inc.

Shell’s “everything is a process”

process

stdin args

stdoutstderr return code

Pascal-Louis Perez, kaChing Group Inc.

Shell is a plumbing language

if echo $name | grep –q “Jack”; then

echo

$name

$name

grep

-q

return code

if

return code

Pascal-Louis Perez, kaChing Group Inc.

Queries

query

dependencies

exception

arguments

value

Pascal-Louis Perez, kaChing Group Inc.

Query Constructors

• Similar to dependency injection, you ask for the arguments you need rather than fetch them from the environment

• Type safe regardless of input format

Pascal-Louis Perez, kaChing Group Inc.

Query Constructors

AddToWatchlist(Id<User>, Symbol)

AddToGroup(Id<User>, Id<Group>, @Optional boolean)

PlaceOrder(Id<User>, Action, Symbol, @Positive int)

PostMessage(Id<User>, Id<Wall>, Text<Plain>)

Pascal-Louis Perez, kaChing Group Inc.

HelloWorld Query

class HelloWorld extends AbstractQuery<String> {

HelloWorld(String name) { …

@Inject DateTime now;

String process() {

return now + “: Hello ” + name;

}

}

Pascal-Louis Perez, kaChing Group Inc.

QueryDriver

Pascal-Louis Perez, kaChing Group Inc.

query

mon

itorin

g

retr

ying

tran

sact

ing

inje

ctin

g

scop

ing

V

Lazy

Man

ager

@

Adapt Queries

• Backend servers• Frontend server for GWT• Command-line tools• Tests

Pascal-Louis Perez, kaChing Group Inc.

Conditionals Complicate Testingif (a) { if (b) { section 1 } else { section 2 }} else { if (b) { section 3 } else { section 4 }}

• Branch coverage requires a lot of tests

• Typically, deep conditionals require a lot of obscure setup in tests

• Ties more closely the test and the implementation

Pascal-Louis Perez, kaChing Group Inc.

Thunk<T>

abstract class Thunk<T> {

private boolean evaluated = false;

private T value;

public T get() {

if (!evaluated) {

value = compute();

evaluated = true;

}

return value;

}

abstract protected T compute();

}

Pascal-Louis Perez, kaChing Group Inc.

Thunk<T> without conditional

abstract class Thunk<T> {

private Getter value = new Getter<T>() {

public T get() {

final T v = compute();

value = new Getter<T>() {

T get() { return v; }

};

return value.get();

}

};

public T get() { return value.get(); }

Pascal-Louis Perez, kaChing Group Inc.

JsonMarshaller

• Marshalling library converting Java POJOs into JSON and vice-versa.

• Annotations and persistence ideas inspired by Hibernate

• “kaChing’s proto buffers”• http://code.google.com/p/jsonmarshaller/

Pascal-Louis Perez, kaChing Group Inc.

JsonMarshaller

@Entityclass Googler {

@ValueList<Cafe> favoriteCafes;

}

createMarshaller(Googler.class).marshall(…);

produces

{“favoriteCafes”:[“150”, “Charlie’s”]}

Pascal-Louis Perez, kaChing Group Inc.

JsonMarshaller

@Value ABC enumAbc;

@Value(ordinal = true) ABC enumAbc;

• dedicated code is wired at creation time• (almost) no conditionals at run-time

Pascal-Louis Perez, kaChing Group Inc.

@

JsonMarshaller

Conditionals

if(annotation.ordinal)

marshallOrdinal()

else

marshallName()

Delegation

marshall()

Pascal-Louis Perez, kaChing Group Inc.

kaChing’s API REST path parsing

• REST API with paths such as/users/:id:/users/:id:/portfolio/trades/:tradeId:/communities/everyone/insight

• HTTP parameters• Headers (X-KaChing-ApiKey, X-KaChing-

RemoteKey)• GET, PUT, POST, DELETE

Pascal-Louis Perez, kaChing Group Inc.

Express “what” instead of Coding “how”

path(

"users",

path(

FetchUser.class,

path(

"watchlist",

QuerySpec.of(

FetchUser.class,

asList(UserPart.WATCHLIST)),

path(immutableMap(

PUT, AddToWatchlist.class,

DELETE, RemoveFromWatchlist.class)))),

Pascal-Louis Perez, kaChing Group Inc.

/users/:id: handled by FetchUser.class

/users/:id:/watchlist handled by FetchUser.class with the extra paramater WATCHLIST

PUT /users/:id:/watchlist handled by AddToWatchlist.class

what?

τ

I’ll have a big boilerplate for lunch

Portfolio p = new Portfolio(…);

Stock ko = new Stock(…);

p.executeTrade(

new BuyStockTrade(ko, …));

p.executeTrade(new Interest(…));

p.executeTrade(

new SellStockTrade(ko, …));

Pascal-Louis Perez, kaChing Group Inc.

… or maybe not

Pascal-Louis Perez, kaChing Group Inc.

portfolio(now, 90) .buyStock(now, "KO", 10, 1) .payInterest(later, fedRateRepository) .sellStock(latest, "KO", 10, 1) .get()

what?

Find Managers

Pascal-Louis Perez, kaChing Group Inc.

order

constraint

Constraint, Index, Selector

• Constraint: search criteria on one dimension– e.g. age = 4

• Index: search structure– can handle only one kind of

constraint

• Selector: constraint template used to find appropriate index– e.g. age = ?

Pascal-Louis Perez, kaChing Group Inc.

dimension 1

dimension 2

orde

r 1

orde

r 2

Practice Safe Programming: Use Types

Pascal-Louis Perez, kaChing Group Inc.

Selector

createIndex : Index

Index

search(Constraint)

Constraint

getSelector : Selector

Practice Safe Programming: Use Types

Pascal-Louis Perez, kaChing Group Inc.

Selector<M>

createIndex : Index<M>

Index<M>

search(Constraint<M>)

Constraint<M>

getSelector : Selector<M>

τ

Summary of the Examples

Pascal-Louis Perez, kaChing Group Inc.

τ @what?

dependency injection

query constructors

query driver

thunk

JsonMarshaller

API paths parsing

builder pattern

family polymorphism

✓ ✓✓ ✓

✓ ✓✓ ✓

✓ ✓✓

µ-Java ✓

Key Takeaways

• Build components instead of providing extension points

• Apply the 1:1 principle• Simplify your life with annotations• Use delegation instead of conditionals• Languages are conveniences, not barriers

Pascal-Louis Perez, kaChing Group Inc.

Further Readings• TotT: Too Many Tests• http://googletesting.blogspot.com/2008/02/in-movie-amadeus-austrian-emperor.html• TotT: The Invisible Branch• http://googletesting.blogspot.com/2008/05/tott-invisible-branch.html• JsonMarshaller

http://code.google.com/p/jsonmarshaller/• Real-World Scala: Dependency Injection

http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di/• Scalable Component Abstraction

http://lamp.epfl.ch/~odersky/papers/ScalableComponent.pdf• Unifying Type Parameters in Java

http://blog.kaching.com/index.php/2009/01/16/unifying-type-parameters-in-java/• Japex: Micro-Benchmarking

https://japex.dev.java.net/

• The Testability Explorer, Misko Heveryhttp://misko.hevery.com

• Growing a Language, by Guy Steelehttp://video.google.com/videoplay?docid=-8860158196198824415

• Type-Safe Builder Pattern in Scalahttp://blog.rafaelferreira.net/2008/07/type-safe-builder-pattern-in-scala.html

Pascal-Louis Perez, kaChing Group Inc.

Recommended