Discussing the first draft of my new hobby app PureBlog implemented for the purpose of getting some practice and feedback from Eric Normand (PurelyFunctional.tv). It also was my first attempt to use Duct/Integrant micro-frameworks for building a real Clojure app.
I’m a subscriber of PurelyFunctional.tv and I think it’s the best online resource for learning Clojure that is available out there. As part of the membership, Eric Normand (the man behind PurelyFunctional.tv) offers a free 30-min coaching session where you can discuss your Clojure learning strategy - issues, challenges, approaches, etc.
A while ago, during my coaching call, I mentioned that feedback from a real Clojure expert is one of the most important things for learning and that I’d lacked this type of feedback during my Clojure learning journey. To my surprise, Eric immediately offered his help in reviewing my code. What a great opportunity!
So we agreed upon creating a simple side-project - blog implementation in Clojure (Eric has a nice list of 10 Weekend projects to spruce up your functional resume on his website).
I decided to make it a bit harder and take this as an opportunity to learn a bit about Duct and Integrant and use them in a real application (instead of a usual ring + compojure combo). Although it took significantly longer than it could, it was fun and I’ve learned quite a bit about Duct and Integrant.
Eric published his code review as Blog in Clojure Code Review youtube video.
Following is my summary of Eric’s review, but please, watch the full video to make your own conclusion.
I definitely agree with the idea of moving the translation logic ("readable" functions) to the db namespace.
The namespaced maps: Now I really think that they are an unnecessary clutter for such a simple CRUD app. Initially, I was inspired by Fogus modeling a domain with namespaced maps and some other people suggesting them. I guess they could be more useful in a richer domain model. I’m curious to hear if you ever use them and what other factors you take into account when making that decision.
Separating protocol definitions and getting rid of some functions (update-post et al.) in features namespace is an interesting idea:
I agree that protocol definitions should be separated from the db implementation
As regards to the removal of functions in features/posts.clj I think they still might have some value - perhaps, not right now.
I was inspired by Paul Stadig’s Clojure Polymorphism book where he frequently uses client namespace for protocol functions - maybe the benefits of doing so are not so obvious in my case but I’ll probably leave them there. The protocol itself could be moved to completely separate namespace (Paul uses "protocol.clj" for this purpose). Perhaps the protocol should be kept in boundary/db.clj, but the implementations moved to boundary/sql.clj or something similar. I admit that it may well be a bit of overengineering for the sake of this app, though.
I think that at least the
preview function should probably be kept in "features" namespace as opposed to the db namespace.
Using select-keys instead of dissoc in update-post function is probably good advice. I couldn’t make up my mind which approach is better because I was worried that I’d have to change the update-post implementation every time I decide to add a new field to the post. I expect that (generally speaking) I’ll want to make new fields updatable and (hopefully) only the user_id and created_date will remain the ones that should not be updated (that is they are used only in create-post function). I guess there’s a bit of conflict because I try to reuse readable->db-post function for both update-post and create-post but there’s a small difference between them. Maybe I could just duplicate the logic and move on.
calling now() twice & using remove instead of (filter (complement …) - nice catch!
You can find the source code in pure-blog GitHub repo. The version that Eric reviewed is tagged as *mvp-1.0*. A read-only version of the PureBlog application is available at http://pureblog.curiousprogrammer.net:3000/.
I’m happy to hear your comments and additional feedback! Feel free to comment on the Github issue *Initial Feedback*.
I haven’t had time to move this project beyond the initial version but I do plan to do more work, implement Eric’s suggestions and add more features. However, this app isn’t intended to be really practical/useful; just "whimsical" :).
Some more features/things I’d like to do in the future:
Authentication and login
It might include a proper user-registration process as well
Datomic as a persistence layer
May be used for features like Post edits history
Tags & Comments