Scala @ PayPal: Cascade
I recently wrote about a Scala Style Guide that my team and I at PayPal recently released.
I’m following up here about Cascade, an Scala project that I open sourced a while ago (this post has been a long time coming!)
Cascade started way back I was at StackMob as a bunch of utilities thrown together ad-hoc. It grew over time into a big disorganized repository called “stackmob-common.”
When I joined PayPal, my team and I started bringing it over to an internal repository one piece at a time. We wanted to make sure its new home was clean, simple and organized.
Fast forward to today. We’ve (obviously) open sourced it and divided it into 4 major pieces.
I also created a set of goals that everything has to follow. I want Cascade to stay simple and focused, because that’s how it’s stayed useful for us.
Each piece must:
- Work well with Scala and the Typesafe libraries.
- Work independently from each other.
- Be well defined in their functionality.
- Minimize the number of external dependencies.
- Related to (4) - use the features of the Scala standard library before building their own.
Both at PayPal and StackMob, we wrote a lot of REST servers. Previous incarnations of the library grew organically with primarily JSON & HTTP in mind, so naturally Cascade is also focused primarily around HTTP and JSON.
Over time, we’ve built utilities for:
- JSON encoding/decoding
- Building and serving Netty pipelines
- Building Finagle filters & pipelines - after we moved from Netty to Finagle
- Scalamachine - when we were in our super FP phase
- Spray routes and managing Akka actors - after we switched to building Spray/Akka services at StackMob
Notice the Scalamachine bullet in the list - that was an entire HTTP server library based on the Webmachine HTTP state machine.
When we switched to Spray at StackMob, we built a rough re-implementation of the state machine, and when we came to PayPal, we ported it over and simplified it a lot. We trimmed it down to expose only the states that we use the most in practice.
We don’t have any Scalamachine, Netty or Finagle utilities in Cascade.
The library ships only with the simplified implementation of the HTTP state machine and we call it the resource model.
Finagle and Netty are good choices in some cases, so if you’re considering using Cascade, check out the example code to see if the resource model is right for you.
The Resource Model
Building services in this model lets us reason about collections of Spray routes instead of one at a time. A single resource can be responsible for one or more routes, and we get some useful and powerful guarantees from Cascade’s implementation:
- The library exposes all state transitions as actor messages
- Each HTTP request spawns a new actor to execute the HTTP state machine. The resource actor can store state, manage computation & IO, spawn new actors, etc… The actor is spawned in addition to the Spray connection actor.
- Failure modes (e.g. timeouts or exceptions) are all handled by the library (thanks to Akka actor supervision).
For example, one of the states in all resources is authentication and authorization (“auth”). In the auth state, you can execute your logic and send an appropriate message back to
sender. If auth succeeded, Cascade will send a message back to transition to the next state (processing the actual request). Otherwise it will shut down your state actor and return a
401 Unauthorized to the client.
Today at PayPal, we have resource-based services in production. It achieves my original goals for Cascade’s success (listed above), and it’s also very easy to read, understand and teach. All great things to have when 20+ people are sharing a codebase.
Cascade is useful and powerful for my team and I because it’s small. Almost all the other benefits are derived from that one:
- it has good test coverage - we fail builds internally when coverage goes under 90%
- it’s easy to test
- it has thorough, quality documentation (that link is broken, I need to fix it!)
- it’s easy to learn - new hires usually learn enough to use it effectively in a day
Right now, Cascade is so core to what we do that my team and I take it for granted. When we find something we want to add, we just go through the process to add it and it’s that simple.
We’ll continue to grow Cascade carefully according to the goals, and I want to share it with the community now too.
File an issue, submit a PR, or tweet/email me if you have ideas/feedback, and definitely let me know if you’re using it.
I’m looking forward to hearing what you think!