We only say this because we care :)
For myself, I feel that the main feed could use a lot more whitespace and have less information about each story. For example, I wouldn't mind being able to toggle off the social quotes completely and perhaps even the images (images are nice for some sources, but not others).
The first idea is to take a complex system and express the set of components and their relationships declaratively, rather than procedurally. This is an old idea, and makes it possible to reason about the system, mock out components for testing, map over the components for monitoring, and more.
The second idea is simplicity. By making this declarative language as simple as possible, it becomes trivially easy to do all the things I just mentioned using the existing tools in the language, without needing to write complex library functions to support each use case.
For another example of a declarative system for composition you could look at 'react' in JS, which can be used in similar ways to Graph (and also supports things like async composition): https://github.com/jeffbski/react
Here's a stupid simple js implementation of their example:
https://gist.github.com/3874826
Edit: Loaded the page and got interrupted by lunch. Shows me for not refreshing.
DI frameworks then build upon the pattern offering a declarative DSL to declare dependencies and wiring. They also offer a selection of alternatives to build dependent objects (e.g. build a fresh one when needed or supply a global instance for every dependee) and a smidgen of generic functionality via impersonation (e.g. monitoring, logging, timing, transaction acquisition/release).
Interesting that untyped functional programming and macros allow for a lighter expression of the same basic idea.
Also interesting that maps of functions are a fundamental part of the solution. There are definitions of object-orientation that amount to basically records-of-lambdas. I've long thought that there is a lot to gain by using this basic abstraction as it naturally provides seams for testing/observability/auditing/etc.
It seems like this fits a similar purpose to Nathan Marz' Storm framework. Could you do a bit of a compare/contrast thing between Graph and Storm?
The main similarity between this and Nathan Marz's Storm framework is that they both rely on a declarative expression of the structure of the computation graph.
However, beyond that there are many key differences. Storm is a graph computation framework, which compiles your specification into a distributed real-time computation pipeline. In contrast, Graph is just a library for expressing composition structure, but says nothing about execution strategy.
In principle (with a lot more code and some more annotations), one could compile Graphs into distributed real-time topologies like Storm. For now we've been using Graph in-process for real-time processing. But because Graph is so simple and close to the language, it's very easy to apply to new situations and build new abstractions on top of. For example, we also find Graph useful for expressing the composition structure of our production services, which are built up from many components.
Storm requires some manual intervention because you need direct control over how things are distributed.
Also, has this at all been inspired by SecDB's powerful graph oriented features?
I haven't heard of SecDB, but I'll definitely check it out -- thanks!
P.S. As I understand it all the graphs are dags. In my line of work (which involves doing stuff at the interface of probability and statistics) there are quite a few recursive functions that are difficult to unroll explicitly, or are otherwise undesirable to unroll for the purposes of readability. Can we expect to see circular dependencies at some point. Well, I know, the halting problem and all, but still...
http://cl.ly/image/241X1C2D3O35
I'm on 10.8 with the latest version of safari.
In other news, this looks pretty cool.
Nit, defnk? what about def-kw-func or something? not wholly readable as defnk.
Point taken about the names, thanks for the feedback. Since Clojure already uses defn and fn, defnk and fnk seemed natural. But maybe defn-keyword and fn-keyword would be better.
I like to have fully expanded names, ala Common Lisp. My editor will autocomplete those on demand after I use a name once, so it's not a hindrance to reading or writing.
My goal for identifiers is that I can read without consulting my internal lookup table.