3
\$\begingroup\$

It has been mentioned in the Clojure Style guide to avoid functions longer than 10 SLOC but mine has more than 10 (47 to be exact).

The code is an web api implementation and follows like this:

(defn classify
  "Sends a text to a classifier and returns a classification"
  [keys texts classifier & user-name]
  {:pre [(check-keys? keys)]}
  (let [textbase64-tag (map #(make-xml-node :textBase64
                                            {:id (str "Text" (str (index-of % texts)))}
                                            (String. (encode (.getBytes %)) )) texts)
        texts-tag (make-xml-node :texts {} textbase64-tag)
        user-attribute (if (> (count user-name) 0)
                         { :username (first user-name) })
        classify-tag (if (= (count user-name) 0)
                       (map #(make-xml-node :classify
                                            {:id (str "Classify" %)
                                             :classifierName classifier
                                             :textId (str "Text" %)
                                             })
                            (range (count texts)))
                       (map #(make-xml-node :classify
                                            {:id (str "Classify" %)
                                             :classifierName classifier
                                             :textId (str "Text" %)
                                             :username (first user-name)})
                            (range (count texts))))
        read-calls (make-xml-node :readCalls
                                  {:readApiKey (keys :read-key)}
                                  classify-tag)
        uclassify-response (raw-post-request
                            (xml/emit-str
                             (xml-append-elements uclassify
                                                  (list texts-tag read-calls))))]
    (if (check-response
         (get-response uclassify-response))
      (readable-list
       (list
        (x/xml-> uclassify-response
                 :readCalls :classify
                 :classification (x/attr :textCoverage))
        (map vector
             (x/xml-> uclassify-response
                      :readCalls :classify
                      :classification :class
                      (x/attr :className))
             (x/xml-> uclassify-response
                      :readCalls :classify
                      :classification :class
                      (x/attr :p)))))
      false ;; Will never reach here
      )))

The code initially builds all the associated xml tags within let and after building them sends a request to the server and then checks out the response to see if it succeeded.

Why I didn't handle the response in a separate function is because that it won't be reused again. Is this a good practice, any suggestions ?

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

There's value in factoring the logic out into one or more new functions, even if those functions are only used in a single place, because it can make the code easier to understand and modify.

In a situation like that (when the logic won't be used elsewhere) I often use letfn. The letfn could be either internal or external to the function itself but I see that as a purely stylistic decision.

Here's the ClojureDocs page on letfn. See Pedestal's dataflow logic for a few examples of letfn in use.

On the other hand, there's really no problem with having a top level function that's only used in one place. I like that letfn implicitly communicates the function's scope of relevance, but I don't think either way is objectively superior to the other.

\$\endgroup\$
1
  • \$\begingroup\$ While it used to be accepted style to extract functions only for reuse, I find myself more often than not doing so to break up logic. Every function you extract removes the need for a comment explaining what's going on when you use a descriptive function name. And you're more likely to update a function name when changing the logic as compared to a comment. \$\endgroup\$ Commented Aug 23, 2013 at 2:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.