Damon Snyder <drsny...@gmail.com> writes:

> One of the decisions I wasn't sure about was whether to use a protocol
> or a struct map for the (socket, reader, writer) tuple. I started
> using a struct-map and then switched over to defprotocol/defrecord.
> See 
> https://github.com/drsnyder/beanstalk/blob/82f301f1f825bb05aa14d85a220ec57c1dea61b2/src/beanstalk/core.clj#L117
> for the definition.

Struct maps were in the language for a long time before defrecord was
added.  Records are supposed to replace them for most purposes.  So if
in doubt between the two use a defrecord.  The decision tree is
basically:

* Am I implementing a data structure (like a hash-map or vector)?
  => Use deftype.

* Do I need to use polymorphism?
  => Use defrecord.

* Otherwise
  => Use a normal hash-map instance.

I'd probably also try to implement basic functionality against an
existing Java or Clojure interface where possible.  For example for 
close you could use the java.io.Closeable interface.  If possible (I'm
not familiar with beanstalk's model) I'd also try to implement parts of
java.util.Queue.  That way you could use the object with existing code
that knows how to use those interfaces.

You can still have Clojure helper functions to avoid clients having to
do type-hinting and so the functions can be used first-class.  Just
define the helpers against the interface: 

  (defn close [^java.io.Closeable closeable] (.close closeable))

What you've got seems pretty reasonable though.  If I were writing
client code using your library, I guess I'd consume it something like
this:

  (ns myapp
    (:require [beanstalk.core :as bs]))

  (def *running* true)

  (with-open [q (bs/new-beanstalk ...)]
    (while *running*
      (let [[id len] (bs/reserve q)]
        (do-some-work (bs/peek q id))
        (bs/bury q id)))

I wonder if there's room for some higher-level helpers in your library?
For example if the above pattern is really common would something along
these lines be useful:

  (defn do-work
    "Grabs work items from the queue and processes them with f.  Stops
    when f returns false."
   [queue f]
   (while (let [[id len] (reserve queue)
                result (f (peek queue id))]
            (bury queue id)
            result)))

Perhaps in a new thread?  Perhaps you need a try/catch to release failed
jobs or something?  Whatever makes sense for the normal beanstalk usage
pattern.

Would it make sense to implement clojure.lang.Seqable for a pull-style
interface?

  (map f queue)
  (doseq [job queue] (f job))
  (let [some-jobs (take 10 queue)] ...)

-- 
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

Reply via email to