Why Clojure?
medium.com
medium.com
Instead, I will try to give some reasons why Clojure is a good fit for high-performance stream fusion, which I presume AppsFlyer has to do a lot of:
- [Onyx](https://github.com/onyx-platform/onyx) for distributed, masterless, fault-tolerant data processing
- [core.async](https://github.com/clojure/core.async) for CSP-style events through a channel abstraction. I miss core.async so much in every other language, I generally end up implementing a subset of the semantics.
- [Transducers](https://clojure.org/reference/transducers) for composable transformations, e.g.
(filter odd?) ;; returns a transducer that filters odd
(map inc) ;; returns a mapping transducer for incrementing
(take 5) ;; returns a transducer that will take the first 5 values of a sequence
(def xf
(comp
(filter odd?)
(map inc)
(take 5)))
(into [] xf (range 100)) ;; => [2 4 6 8 10]
Note that no intermediate data structures are created during these transformations, so it's super fast.- [Specter](https://github.com/nathanmarz/specter) decomplects navigation and transformation, pulling apart the "where" from the "how". In most imperative languages whenever the shape or performance characteristics your data structures change, you also have to update all the code that transforms it. Not with Specter.
- Zach Tellman's [Manifold](https://github.com/ztellman/manifold) provides event-streaming abstractions on top of async workflows like lazy sequences, core.async and Java's BlockingQueues.
Being new to Clojure I've been avoiding some concepts until later, but if they hadn't renamed old concepts, ie: higher order functions to transducers, maybe newbies wouldn't get scared.
Simple HOFs wouldn’t prevent the elements to be traversed in each subsequent function call.
(disclaimer: I am the author of aiochan)