-
Notifications
You must be signed in to change notification settings - Fork 20
Design Rationales
This page describes the rationales for some choices made when designing Trickle
An early version of Trickle used objects with a single method, and a predecessor to Trickle (Shopzilla's PageFlow) used annotations to identify the method to call in a node. We changed that because:
- it allows type-safety, and
- it is forward-compatible with lambdas, making the syntax in Java 8 nicer.
Trickle forces you to have a single sink only. There are use cases for multiple sinks, for instance for calls you want to make asynchronously but that don't return any results you need. We decided to enforce single sinks in order to ensure that any errors in the graph execution will be reported or handled.
The main reason for supporting fallbacks is that they enable graceful degradation in case of failures. So, if some end-user view is made up of data from 5 different services, and one of them fails, it's often much better to display the data from the 4 functioning services than an error page.
There are two types of dependencies between nodes in trickle: the result of node A can be used as an input to node B, or you can specify that node A is a predecessor - must be completed - before node B can run. This is typically useful when coordinating parallel updates. It would be possible to solve the second case by simply passing node A's result to the Function in node B and ignoring it. We chose to introduce the predecessor case primarily to keep the functions executed in the nodes unaware of execution order concerns. That decreases coupling and increases reuse potential, and also makes the code cleaner.
A problem with raw Futures is how to get the value out of them. The easiest way is to simply to a get() on the future - and of course, if that is done before the future is complete, that'll reduce parallelism and introduce a performance bottleneck. In Trickle, while application code almost always returns Futures, it will only be called with plain values. That means that application programmers don't need to worry about interrupting the concurrent flow, and also makes testing individual functions easier.