Scala in Goozy
Alexey ZlobinE-Legion
Index
1. Goozy overview2. Scala's place3. Lift4. Cake pattern in scale5. Scalaz and other fancy stuff6. Summary
What is Goozy?
A social network built around the concept of sticky note
● A note could be left anywhere in the Web.
● It is associated with particular page element.
Central UI concept: user's related feed with all new notes and comments
Top-level architecture
Scala's place
API server
Main functions:● Storage access● Background tasks (feed writing, e-mails)● Email sending● Text indexing
Why scala?
● Fast● Сoncise● Expressive● Advanced OO● Some functional stuff
○ Simple concurrency● All Java legacy
available
The team
● 2 persons● Strong Java background● Fancy about technologies● Love to try new things
Lift
Utilized features:● REST● JSON serialisation
That's it...
Lift: issuesLocalisation performance
● Hand-made localisation on standard resource bundles gave 4 times throughput improvement.
Very memory-consuming JSON serialisation.● Not so efficient PrettyPrinter is used● Functional-styled string escaping
Poor code style● Extremely long map-match-if hierarchies● Mutable, difficult to debug LiftRules design
Lift: shift from
Some plans about migration to less sophisticated framework...
Ideally small and simple enough to be completely rewritten in case of any issue.
But we have a strong dependency from Boot and configuration
And there is some aspect-like hooks on HTTP processing, which are unportable.
Goozy API logical structure
Application is composed from three layers.
Each layer consists from several similar components. Like UserStorage, GroupStorage, etc.
Conceptual problems
● Components of each level depend from each other● Components most likely have several dependencies
from the previous level● A lot of common stuff inside a level
○ Every storage needs a DB connection○ Every service needs an entire storage system and
access to text indexes○ Etc...
The solution: cake pattern
● Each logically closed piece of functionality is represented as component
● Dependencies are expressed as self-type
● Common features expressed as mix-ins
● Common combinations of functionality are expressed as mix-ins of several components
Cake pattern: consequences
+ All top-level architecture is expressed in one less than 100 LOC file
+ Compile-time dependency checks
+ The biggest file is around 1000 LOC
- Long dependency lists● Poor design?
- Implicit dependency on mix-in order (linearisation strikes back)
● Prefer def and lazy
- A bit unclear how to deal with several dependencies of the same type but different runtime implementation
scalaz.ValidationOne sweet morning I sent a link to the colleague...
On the next morning we had a new dependency and totally refactored request parameters analysis.
Now everything is validated.
Validation: pros and cons+ Comprehensible error aggregation and reporting
+ The only imaginable way to deal with 20+ request parameters with 2-3 constraints on each
+ Unified approach to request validation and runtime error handling
+ Type-level check for correct error handling
- Monads and Applicatives cause massive brain damage
- Complicated error reports from the compiler
- You can't just ignore possibility of runtime exception
Validations and exceptionsProblem: exceptions are here
Solution: catch'em and convert!
Error handling: big picture
Lessons
1. Always prefer simple tools2. Options and Eithers (Validations): they really work
○ It is possible to live with both exceptions and eithers○ Performance consequences are not clear○ Some times I had to use things far behind my
understanding (sequence, traverse)3. Server-side testing is difficult
○ Testing approach should be established before any code is written
References
1. http://www.assembla.com/spaces/liftweb/wiki/REST_Web_Services - REST support in Lift
2. http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di.html - complete cake pattern intro
3. https://gist.github.com/970717 - easy Validation example
Testing
A lot of features
Very quickly evolved at the beginning
We needed to exclude possibility of regression
Testing: solution
● Integration testing from the client point of view● All test deal only with the http interface● Every case is a short (5-10 reqs.) scenario● Every case is wrapped into JUnit test for convenience
Testing: logical architecture
1. JUnit wrapper2. Scenario3. Library of available
operation on http interface4. Groovy's HTTPBuilder
Integration testing: problems
Groovy1. Dynamic typing2. Not obvious ways to do simple things3. One extra language in project
Execution time