I'm very new to Clojure/ClojureScript and have a question regarding a "proper" way to express something.
This code sends a mail using nodemailer on nodejs:
(defn send-mail [some-id]
(try
(let [clj-props (:mail (config/config-file)) ; get the mail server cofiguration
mail-address (mail-adress-from-props clj-props) ; get the mail address
mail (clj->js (create-mail mail-address some-id)) ; create a mail to send
transporter (.createTransport nodemailer (clj->js clj-props))] ; create a transporter using nodemailer
(.sendMail transporter mail on-mail-sent)) ; send mail using nodemailer
(catch js/Error e
(logging/error (.toString e)))))
It is working, but looks completely out of place in ClojureScript. I woud like for a more idiomatic way to do this, so any feedback is welcome.
-
1\$\begingroup\$ Welcome to Code Review! Could you please tell me if you use an online clojure compiler, or if you run this locally? (I'm interested as I want to test some Clojure, but I don't want to install it on my computer... ) \$\endgroup\$holroy– holroy2015年12月15日 16:25:41 +00:00Commented Dec 15, 2015 at 16:25
-
\$\begingroup\$ Thanks! I'm running everything locally, but if you don't want to install anything, then docker is your friend, I guess \$\endgroup\$clojure-learner– clojure-learner2015年12月15日 17:03:12 +00:00Commented Dec 15, 2015 at 17:03
1 Answer 1
In my opinion the code looks great. What in particular looks out of place? When dealing with interop, there is no need to get hung up style, you are going to have to match the model exposed to you. I don't think there is any more proper way than as you have done.
Just as a matter of style I would make these suggestions based on my personal tastes:
Lean toward functions that take arguments over looking things up from the environment. Consider passing the result of
create-mail
tosend-mail
as an argument. Consider passing on-mail-sent to send-mail as an argument. Your functions will be more flexible this way.Consider putting the try catch log around the call to send-mail, instead of inside it. Functions tend to be more reusable when they allow the caller to handle errors either by returning a result or possibly throwing.
Don't bother with comments that repeat the code.
nodemailer
appears to be a global; should this be called like (js/nodemailer.createTransport)? Or is it a def?clj-props
doesn't convey meaning. Considermail-config
?What does
mail-adress-from-props
do? is it just a keyword lookup? If so consider just using the direct lookup instead.
-
\$\begingroup\$ Thanks, I agree with all your suggestions. The problem with the code is that it looks somehow too imperative to me, but this is just a feeling. \$\endgroup\$clojure-learner– clojure-learner2015年12月17日 16:35:03 +00:00Commented Dec 17, 2015 at 16:35
-
\$\begingroup\$ gotcha - I don't think you have anything to worry about :) \$\endgroup\$Timothy Pratley– Timothy Pratley2015年12月17日 18:30:54 +00:00Commented Dec 17, 2015 at 18:30