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.

Reply via email to