Background: I'm in the process of translating a fairly low-level and messy C networking library. The original involves lots of bit-twiddling and global variables.
My first pass (which has been in the "real soon now" state for months now...in hind-sight, I have some regrets about starting this at all, much less trying to go straight from C to clojure) tried to stick fairly close to the original as I figured out what it was doing. I also used this project as an excuse to start learning about spec. Right now, I'm basically just using it to document parameters and return values. I've started doing a little generative testing, but that part's just icing, really. I wound up with some uncomfortably large top-level maps. So I have specs like ::server/state, ::client/state, and ::ioloop/state. Those in turn contain maps like ::log/state and ::flow-control/state. There's nothing really exciting/surprising about any of that. There are a couple of places where the tree gets 3 or 4 layers deep, but it doesn't seem awful. In my original version, I basically just passed the top-level state maps around everywhere. A function takes that as one of its parameters, and it probably returns the same thing where 1 or 2 of the values have been updated. Now I think I want to get more specific about the spec for each of those functions so I have a better feel for what each is doing. And I almost feel like I'm dealing with java checked exceptions. Say I have (-> x foo bar baz qux), and qux is the hairy part that actually uses all the complicated values (and there are also plenty of byte-arrays, just to make life really interesting) stored in x. The details don't matter, but just to make the problem a little more concrete: foo, bar, and baz have their own hairiness. In the specific scenario that I'm looking at right now, foo is the boundary-function event handler that pulls byte buffers off the network socket, bar is the function that decides how to handle each incoming packet, baz is the function that handles this particular packet type, and then qux is the part that opens the encryption box that contains the actual payload. I decided last night to extend some ongoing refactoring to qux. It now uses a new key that I recently introduced. Except that I don't seem to have added it to the top-level state map that I'm passing around everywhere. In disgust, I started dabbling with the idea of being explicit about which keys it actually needs. In order to make that work, it seems like I need to update the specs for baz and bar to specify their exact parameters/return values. And possibly exactly which members of the top-level state I expect to change. So when the spec for one changes, it trickles up to everything that calls it. I wouldn't mind too terribly much making them as tightly coupled as this implies. They already are, really, and they're all so specialized that they really don't make any sense in isolation. I really just broke them into smaller pieces out of a single gigantic main() function for the sake of my own sanity. And this is strictly internal. The library interface is just a function/callback thing to read/write. How do other people approach the sort of big-picture problem I'm describing? Thanks in advance, James -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.