Wide Awake Developers

« April 2010 | Main

Glue Fleet and Compojure Together Using Protocols

Inspired by Glenn Vanderburg's article on Clojure templating frameworks, I decided to try using Fleet for my latest pet project. Fleet has a very nice interface. I can call a single function to create new Clojure functions for every template in a directory. That really makes the templates feel like part of the language. Unfortunately, Glenn's otherwise excellent article didn't talk about how to connect Fleet into Compojure or Ring. I chose to interpret that as a compliment, springing from his high esteem of our abilities.

My first attempt, just calling the template function directly as a route handler resulted in the following:

java.lang.IllegalArgumentException: No implementation of method: :render of protocol: #'compojure.response/Renderable found for class: fleet.util.CljString

Ah, you've just got to love Clojure errors. After you understand the problem, you can always see that the error precisely described what was wrong. As an aid to helping you understand the problem... well, best not to dwell on that.

The clue is the protocol. Compojure knows how to turn many different things into valid response maps. It can handle nil, strings, maps, functions, references, files, seqs, and input streams. Not bad for 22 lines of code!

There's probably a simpler way that I can't see right now, but I decided to have CljString support the same protocol.

Take a close look at the call to extend-protocol on lines 12 through 15. I'm adding a protocol--which I didn't create--onto a Java class--which I also didn't create. My extension calls a function that was created at runtime, based on the template files in a directory. There's deep magic happening beneath those 3 lines of code.

Because I extended Renderable to cover CljString, I can use any template function directly as a route function, as in line 17. (The function views/index was created by the call to fleet-ns on line 10.)

So, I glued together two libraries without changing the code to either one, and without resorting to Factories, Strategies, or XML-configured injection.

Metaphoric Problems in REST Systems

I used to think that metaphor was just a literary technique, that it was something you could use to dress up some piece of creative writing. Reading George Lakoff's Metaphors We Live By, though has changed my mind about that.

I now see that metaphor is not just something we use in writing; it's actually a powerful technique for structuring thought. We use metaphor when we are creating designs. We say that a class is like a factory, that an object is a kind of a thing. The thing may be an animal, it may be a part of a whole, or it may be representative of some real world thing.

All those are uses of metaphor, but there is a deeper structure of metaphors that we use every day, without even realizing it. We don't think of them as metaphors because in a sense these are actually the ways that we think. Lakoff uses the example of "The tree is in front of the mountain." Perfectly ordinary sentence. We wouldn't think twice about saying it.

But the mountain doesn't actually have a front, neither does the tree. Or if the mountain has a front, how do we know it's facing us? What we actually mean, if we unpack that metaphor is something like, "The distance from me to the tree is less than the distance from me to the mountain." Or, "The tree is closer to me than the mountain is." That we assign that to being in front is actually a metaphoric construct.

When we say, "I am filled with joy." We are actually using a double metaphor, two different metaphors related structurally. One, is "A Person Is A Container," the other is, "An Emotion Is A Physical Quantity." Together it makes sense to say, if a person is a container and emotion is a physical thing then the person can be full of that emotion. In reality of course, the person is no such thing. The person is full of all the usual things a person is full of, tissues, blood, bones, other fluids that are best kept on the inside.

But we are embodied beings, we have an inside and an outside and so we think of ourselves as a container with something on the inside.

This notion of containers is actually really important.

Because we are embodied beings, we tend to view other things as containers as well. It would make perfect sense to you if I said, "I am in the room." The room is a container, the building is a container. The building contains the room. The room contains me. No problem.

It would also make perfect sense to you, if I said, "That program is in my computer." Or we might even say, "that video is on the Internet." As though the Internet itself were a container rather than a vast collection of wires and specialized computers.

None of these things are containers, but it's useful for us to think of them as such. Metaphorically, we can treat them as containers. This isn't just an abstraction about the choice of pronouns. Rather the use of the pronouns I think reflects the way that we think about these things.

We also tend to think about our applications as containers. The contents that they hold are the features they provide. This has provided a powerful way of thinking about and structuring our programs for a long time. In reality, no such thing is happening. The program source text doesn't contain features. It contains instructions to the computer. The features are actually sort of emergent properties of the source text.

Increasingly the features aren't even fully specified within the source text. We went through a period for a while where we could pretend that everything was inside of an application. Take web systems for example. We would pretend that the source text specified the program completely. We even talked about application containers. There was always a little bit of fuzziness around the edges. Sure, most of the behavior was inside the container. But there were always those extra bits. There was the web server, which would have some variety of rules in it about access control, rewrite rules, ways to present friendly URLs. There were load balancers and firewalls. These active components meant that it was really necessary to understand more than the program text, in order to fully understand what the program was doing.

The more the network devices edged into Layer 7, previously the domain of the application, the more false the metaphor of program as container became. Look at something like a web application firewall. Or the miniature programs you can write inside of an F5 load balancer. These are functional behavior. They are part of the program. However, you will never find them in the source text. And most of the time, you don't find them inside the source control systems either.

Consequently, systems today are enormously complex. It's very hard to tell what a system is going to do once you put into production. Especially in those edge cases within hard to reach sections of the state space. We are just bad at thinking about emergent properties. It's hard to design properties to emerge from simple rules.

I think we'll find this most truly in RESTful architectures. In a fully mature REST architecture, the state of the system doesn't really exist in either the client or the server, but rather in the communication between the two of them. We say, HATEOAS "Hypertext As The Engine Of Application State," (which is a sort of shibboleth use to identify true RESTafarian's from the rest of the world) but the truth is: what the client is allowed to do is to hold to it by the server at any point in time, and the next state transition is whatever the client chooses to invoke. Once we have that then the true behavior of the system can't actually be known just by the service provider.

In a REST architecture we follow an open world assumption. When we're designing the service provider, we don't actually know who all the consumers are going to be or what their individual and particular work flows maybe. Therefore we have to design for a visible system, an open system that communicates what it can do, and what it has done at any point in time. Once we do that then the behavior is no longer just in the server. And in a sense it's not really in the client either. It's in the interaction between the two of them, in the collaborations.

That means the features of our system are emergent properties of the communication between these several parts. They're externalized. They're no longer in anything. There is no container. One could almost say there's no application. The features exists somewhere in the white space between those boxes on the architecture diagram.

I think we lack some of the conceptual tools for that as well. We certainly don't have a good metaphorical structure for thinking about behavior as a hive-like property emerging from the collaboration of these relatively, independent and self-directed pieces of software.

I don't know where the next set of metaphors will come from. I do know that the attempt to force web-shaped systems in to the application is container metaphor, simply won't work anymore. In truth, they never worked all that well. But now it's broken down completely.

Metaphoric Problems in REST Systems (audio)

Metaphoric problems in rest systems by mtnygard