<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Francesco</title>
    <description>The latest articles on DEV Community by Francesco (@fpsd).</description>
    <link>https://dev.to/fpsd</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1066709%2F053e243d-f3da-44a4-9a6c-2919f2630e9d.jpg</url>
      <title>DEV Community: Francesco</title>
      <link>https://dev.to/fpsd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fpsd"/>
    <language>en</language>
    <item>
      <title>Trying out Zola static site generator</title>
      <dc:creator>Francesco</dc:creator>
      <pubDate>Tue, 25 Jul 2023 12:25:17 +0000</pubDate>
      <link>https://dev.to/fpsd/trying-out-zola-static-site-generator-34l7</link>
      <guid>https://dev.to/fpsd/trying-out-zola-static-site-generator-34l7</guid>
      <description>&lt;p&gt;Original post &lt;a href="https://fpsd.codes/blog/migrating-to-zola/"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;Recently I switched from &lt;a href="https://dthompson.us/projects/haunt.html"&gt;Haunt&lt;/a&gt; to &lt;a href="https://www.getzola.org/"&gt;Zola&lt;/a&gt; as the static site generator for&lt;br&gt;
this blog. Main reason was a bit of frustration with Haunt's documentation&lt;br&gt;
and the CommonMark implementation it was using which was holding me back.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why the switch
&lt;/h1&gt;

&lt;p&gt;When starting this blog I wanted something simple and potentially hackable,&lt;br&gt;
in terms of being able to play with the generator like any other Lisp program,&lt;br&gt;
modifying it a runtime and seeing the result of the change right after it happened.&lt;/p&gt;

&lt;p&gt;While Haunt is totally capable of doing so the first roadblock (at least for me)&lt;br&gt;
is that it is written in &lt;a href="https://www.gnu.org/software/guile/"&gt;Guile&lt;/a&gt; which I don't know at all; given that it is a&lt;br&gt;
Lisp I hoped to get into it quickly, but I've never studied it or played with it&lt;br&gt;
too much, and there is only so much time in a day so I cannot play with all the&lt;br&gt;
fun things that there are around and at the same time hope to get some work done!&lt;/p&gt;

&lt;p&gt;So I started looking for alternatives, maybe leaving aside the hackability of the&lt;br&gt;
underlying system in favor of focusing on writing content.&lt;/p&gt;

&lt;p&gt;Don't get me wrong, Haunt is very nice and customizable, it is not just a toy and&lt;br&gt;
for example it is used to build the &lt;a href="https://guix.gnu.org/"&gt;Guix&lt;/a&gt; website (and others); it is possible to&lt;br&gt;
look at that site sources to get an idea on how to write a great website!&lt;br&gt;
The problem is that I did'n manage to learn few fundamental things, Guile and&lt;br&gt;
Haunt internals, quickly enough to be confident with this system and be productive&lt;br&gt;
with it. Better luck next time, maybe.&lt;/p&gt;

&lt;h1&gt;
  
  
  Candidates
&lt;/h1&gt;

&lt;h2&gt;
  
  
  &lt;a href="http://cryogenweb.org/"&gt;Cryogen&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Language: Clojure&lt;br&gt;
Documentation: While complete the feeling is that it does not flow too well&lt;/p&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  You have the engine at your hand and you can hack on it easily while running&lt;/li&gt;
&lt;li&gt;  Easy to start&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Custom front matter format (EDN)&lt;/li&gt;
&lt;li&gt;  Takes some time to get into it, not ideal if you just want a quick blog with your style&lt;/li&gt;
&lt;li&gt;  Documentation could be better&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://getnikola.com/"&gt;Nikola&lt;/a&gt;/&lt;a href="https://getpelican.com/"&gt;Pelican&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Language: Python&lt;br&gt;
Documentation: Complete&lt;/p&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Battle tested&lt;/li&gt;
&lt;li&gt;  Extensible (with lots of extensions)&lt;/li&gt;
&lt;li&gt;  Lots of themes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Custom front matter&lt;/li&gt;
&lt;li&gt;  Too big for my needs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Language: Go&lt;br&gt;
Documentation: Complete&lt;/p&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Battle tested&lt;/li&gt;
&lt;li&gt;  Extensible (with lots of extensions)&lt;/li&gt;
&lt;li&gt;  Lots of themes (I mean LOTS!)&lt;/li&gt;
&lt;li&gt;  Comes packaged in a single binary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  I could not find a clear path to get to my first post quickly&lt;/li&gt;
&lt;li&gt;  Having a lot of features I felt lost in the docs, which caused friction/churn&lt;/li&gt;
&lt;li&gt;  Too big for my needs, the home page says "The world’s fastest framework for building websites"&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.getzola.org/"&gt;Zola&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Language: Rust&lt;br&gt;
Documentation: Complete&lt;/p&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Documentation was feeling just right for my needs&lt;/li&gt;
&lt;li&gt;  The home pages says "Your one-stop static site engine", just what I need&lt;/li&gt;
&lt;li&gt;  Quick time to first post and custom layout&lt;/li&gt;
&lt;li&gt;  Lots of themes (and more are coming to it)&lt;/li&gt;
&lt;li&gt;  Comes packaged in a single binary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Maybe not as feature rich as others (not a problem for me)&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Final decision
&lt;/h1&gt;

&lt;p&gt;Admittedly I did not run a very scientific comparison process, what I did was&lt;br&gt;
to try to run a generator with its defaults, hack it a bit and measure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  time to get to the same layout and a first post&lt;/li&gt;
&lt;li&gt;  level of frustration while doing so&lt;/li&gt;
&lt;li&gt;  documentation&lt;/li&gt;
&lt;li&gt;  …gut feeling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What I did not care about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  speed of generation of content&lt;/li&gt;
&lt;li&gt;  programming language&lt;/li&gt;
&lt;li&gt;  availability of themes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Following the principle of "least resistance path" I went with Zola because&lt;br&gt;
the process to get to that first post was really painless! Some engines were&lt;br&gt;
not properly documented, with other I felt overwhelmed by options or in the&lt;br&gt;
end it did not feel just right.&lt;/p&gt;

&lt;p&gt;It took me 10 minutes to get Zola's approach and file structure, another 30&lt;br&gt;
minutes of grunt work to port the front matter of posts from Haunt (I could&lt;br&gt;
have automated it but it was too hot that day and I was not able to think too&lt;br&gt;
much, but it would have been a nice exercise with Babashka!).&lt;/p&gt;

&lt;p&gt;While others may be more complete solution to build complex websites, what I&lt;br&gt;
really want is a tiny container for my posts, potentially some other pages&lt;br&gt;
like contact section, bio etc. and Zola was able to deliver in just no time.&lt;/p&gt;

&lt;p&gt;Your requirements may be totally different and other engines may work better&lt;br&gt;
for you, all I can suggest is to try (some of) them and see which one sticks&lt;br&gt;
to you!&lt;/p&gt;

</description>
      <category>rust</category>
      <category>buildinpublic</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Clojure Bites - Ring basic auth</title>
      <dc:creator>Francesco</dc:creator>
      <pubDate>Thu, 06 Jul 2023 08:21:54 +0000</pubDate>
      <link>https://dev.to/fpsd/clojure-bites-ring-basic-auth-2jf2</link>
      <guid>https://dev.to/fpsd/clojure-bites-ring-basic-auth-2jf2</guid>
      <description>&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;I am on vacation so I have decided to take it easy and work on small&lt;br&gt;
things on &lt;a href="https://unrefined.one"&gt;Unrefined&lt;/a&gt;; one item in the backlog seemed quite approachable:&lt;br&gt;
adding an admin panel to the project, which requires, among other things,&lt;br&gt;
a way to authenticate users to access those restricted sections.&lt;/p&gt;

&lt;p&gt;Here is a quick intro to how to add Basic Auth support to a &lt;a href="https://github.com/ring-clojure/ring"&gt;Ring&lt;/a&gt; web&lt;br&gt;
application, using &lt;a href="https://git.sr.ht/~rwv/ring-basic-authentication"&gt;ring-basic-authentication&lt;/a&gt; middleware, and, as a bonus,&lt;br&gt;
an intro to &lt;a href="https://github.com/clojure/core.cache"&gt;clojure.core.cache&lt;/a&gt; library.&lt;/p&gt;
&lt;h1&gt;
  
  
  Project setup
&lt;/h1&gt;

&lt;p&gt;To show how the middleware works we can create a simple web application with&lt;br&gt;
just one endpoint which later we can protect with basic auth. Start a new&lt;br&gt;
project or use your favorite playground and add the following dependencies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  ring/ring-core 1.10.0&lt;/li&gt;
&lt;li&gt;  ring/ring-jetty-adapter 1.10.0&lt;/li&gt;
&lt;li&gt;  ring-basic-authentication/ring-basic-authentication 1.2.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to use your preferred project and dependency management tool, here I&lt;br&gt;
show how to do that with tools-deps, it is easy to translate it to &lt;a href="https://leiningen.org/"&gt;lein&lt;/a&gt; or &lt;a href="https://boot-clj.github.io/"&gt;boot&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{:paths ["src" "resources"]
 :deps {org.clojure/clojure {:mvn/version "1.11.1"}
        ring/ring-core {:mvn/version "1.10.0"}
        ring/ring-jetty-adapter {:mvn/version "1.10.0"}
        ring-basic-authentication/ring-basic-authentication {:mvn/version "1.2.0"}}
 :aliases
 {:dev/repl {:main-opts ["-m" "nrepl.cmdline" "&amp;amp;#x2013;middleware" "[cider.nrepl/cider-middleware]"]
             :extra-paths ["dev"]
             :extra-deps {cider/cider-nrepl {:mvn/version "0.31.0"}
                          djblue/portal {:mvn/version "0.35.1"}
                          com.github.jpmonettas/clojure {:mvn/version "1.11.1"}
                          com.github.jpmonettas/flow-storm-dbg {:mvn/version "3.3.315"}}
             :jvm-opts ["-Dclojure.storm.instrumentEnable=true"]}
  }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The extra alias &lt;code&gt;:dev/repl&lt;/code&gt; is my usual goto setup for development, it is not required&lt;br&gt;
to run the examples but it can be generally handy; feel free to ignore it if you&lt;br&gt;
have your own way.&lt;/p&gt;

&lt;p&gt;Now we can create a new src/app.clj (or whatever ns you prefer) with the following&lt;br&gt;
content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(ns app
  "A namespace used to show how the basic-authentication middleware works"
  (:require [ring.adapter.jetty :as jetty]))

(defn handler
  "Our basic ring handler function, it takes a request map (unused) and
   return a response map"
  [_request]
  {:status 200
   :headers {"Content-Type" "text/html"}
   :body "Hello World"})

;; We want to hold the server instance in order to close it once done.
;; There are better ways to do it, using life cycle/state management libraries
;; like mount, integrant, component just to name few, but lets keep it simple
(def server-instance (atom nil))

(defn start-server
  "Starts a web server holding its instance in the server-instance atom"
  []
  (reset! server-instance
          (jetty/run-jetty handler {:port 3000
                                    :join? false})))

(defn stop-server
  "If there is a server running, stop it and reset the server-instance atom"
  []
  (swap! server-instance
         (fn [inst]
           (when inst
             (.stop inst)))))

(comment
  (start-server)
  (stop-server)
  ,)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we start a REPL and evaluate the buffer (file) we can start the server by&lt;br&gt;
evaluating the fist form in the &lt;code&gt;comment&lt;/code&gt; form, and pointing a browser to&lt;br&gt;
&lt;a href="http://localhost:3000"&gt;http://localhost:3000&lt;/a&gt; we should be able to see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2iVmtwcW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h469e6pzfelm52nugckp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2iVmtwcW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h469e6pzfelm52nugckp.png" alt="basic handler output" width="414" height="170"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Protecting the route
&lt;/h1&gt;

&lt;p&gt;The library &lt;code&gt;ring-basic-authentication&lt;/code&gt; offers the ring middleware&lt;br&gt;
&lt;code&gt;wrap-basic-authentication&lt;/code&gt; that will call a function accepting a username&lt;br&gt;
and a password and returns a truty value on success (authenticated)&lt;br&gt;
or a falsy value otherwise. On success the next middleware (or handler) will be&lt;br&gt;
called, otherwise it will return a 401 response.&lt;/p&gt;

&lt;p&gt;The first thing we can do is to write a function that will authenticate (or not) a&lt;br&gt;
request based on provided username and password, here is the simplest implementation&lt;br&gt;
we can write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(defn authenticated?
  [username password]
  (and (= "secret-username" username)
       (= "secret-password" password)))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it is time setup ring to use the middleware to autheticate requests. Lets&lt;br&gt;
re-write the &lt;code&gt;start-server&lt;/code&gt; function to do that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(defn gen-app
  []
  (wrap-basic-authentication handler authenticated?))

(defn start-server
  "Starts a web server holding its instance in the server-instance atom"
  []
  (reset! server-instance
          (jetty/run-jetty (gen-app) {:port 3000
                                      :join? false})))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The utility function &lt;code&gt;gen-app&lt;/code&gt; returns a new handler using the &lt;code&gt;wrap-basic-authentication&lt;/code&gt;&lt;br&gt;
middleware to wrap our request handler; start server calls the &lt;code&gt;gen-app&lt;/code&gt; function&lt;br&gt;
when starting the server, to get the application handler function.&lt;/p&gt;

&lt;p&gt;We can see it in action in the following screenshot&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HmL0FzH8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/twltnbgp6g0bi0h16ox2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HmL0FzH8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/twltnbgp6g0bi0h16ox2.png" alt="basic auth form" width="324" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now for each request this is the flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  ring calls the app handler&lt;/li&gt;
&lt;li&gt;  the basic auth middleware is called and&lt;/li&gt;
&lt;li&gt;  if successful it will return the result of calling the wrapped handler&lt;/li&gt;
&lt;li&gt;  if not it will return a 401 without even calling the wrapper handler&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In ring world this is the usual flow; in general we can expect to have chain of&lt;br&gt;
middlewares before the call to the request can even start, common middlewares can&lt;br&gt;
be used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  request routing: given a path call a specific handler&lt;/li&gt;
&lt;li&gt;  request parameter parsing: parsed parameters, coming from query string, body etc are injected for later use&lt;/li&gt;
&lt;li&gt;  response transformation: for example to serialize to JSON, XML or other formats&lt;/li&gt;
&lt;li&gt;  session, authentication and authorization handling&lt;/li&gt;
&lt;li&gt;  request logging and metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are quite a lot of already existing and useful middlewares that can be&lt;br&gt;
used off the shelf.&lt;/p&gt;

&lt;p&gt;Even if this approach can be good enough for some small and private services it&lt;br&gt;
can become unusable or hard to maintain pretty easily if the service grows or must&lt;br&gt;
be exposed to the public internet; few issues that can come to mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Hardcoded credentials: even if the project sources can be private it is easy to leak them, better to load them from another source&lt;/li&gt;
&lt;li&gt;  If we want to change credentials a new build is required; not the end of the world but not really convenient&lt;/li&gt;
&lt;li&gt;  There is no way to have different handlers and URL with or without the basic auth&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  Lets make it flexible
&lt;/h1&gt;

&lt;p&gt;First thing we can do to improve this example is to get rid of those ugly hardcoded&lt;br&gt;
credentials.&lt;/p&gt;

&lt;p&gt;One way could be to load the username and password from environment variables; as one&lt;br&gt;
extra step would be to on the safe side we can avoid having defaults so that if&lt;br&gt;
we forget to set the environment variables no one can access the restricted&lt;br&gt;
resources. Here is one possible way to &lt;code&gt;authenticated?&lt;/code&gt; for our new requirements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(let [secret-username (:basic-auth-username env "")
      secret-password (:basic-auth-password env "")]
  (defn authenticated?
    [username password]
    (and (seq secret-username) ;; making sure this two are set to something
         (seq secret-password) ;; TIL that (seq "") is equivalent to (not (empty? "")), thanks clj-kondo!
         (= secret-username username)
         (= secret-password password))))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait wait wait, where is this &lt;code&gt;env&lt;/code&gt; coming from?&lt;/p&gt;

&lt;p&gt;Even if is possible to get the value of environment variables using Java&lt;br&gt;
interop via &lt;code&gt;System/getenv&lt;/code&gt; I have decided to introduce the library &lt;a href="https://github.com/weavejester/environ"&gt;environ&lt;/a&gt;&lt;br&gt;
because it offers a Clojure only interface and provides more goodies like&lt;br&gt;
reading environment variables from env files or JVM properties and has a&lt;br&gt;
nicer interface (IMHO).&lt;/p&gt;

&lt;p&gt;To be able to use this library all we need to do is&lt;br&gt;
to add it to our &lt;code&gt;deps.edn&lt;/code&gt; (or…you know) and refer the &lt;code&gt;env&lt;/code&gt; symbol in our&lt;br&gt;
namespace. For more details please refer to the library docs, all we need to&lt;br&gt;
know now is that it behaves like a normal map, at least for reading.&lt;/p&gt;

&lt;p&gt;Oh, one more thing, keywords are translated to "UPPERSNAKECASE" when looking&lt;br&gt;
them up, in our case &lt;code&gt;:basic-auth-username&lt;/code&gt; will lookup &lt;code&gt;BASIC_AUTH_USERNAME&lt;/code&gt;&lt;br&gt;
environmental variable.&lt;/p&gt;
&lt;h1&gt;
  
  
  Even more flexible
&lt;/h1&gt;

&lt;p&gt;Now we want to give access to the protected resource to more people and usually&lt;br&gt;
sharing the same credentials is not a good practice; what happens if we want&lt;br&gt;
to invalidate the access for one of the users? We should create new credentials&lt;br&gt;
and share it only with the ones whom should have access to the resource. It is&lt;br&gt;
not really practical, is it? So at this point we may want to have user specific&lt;br&gt;
credentials but handling them with env vars can be too complicated or unpractical.&lt;/p&gt;

&lt;p&gt;An option is to store credentials in a file that we can read at the start of the&lt;br&gt;
application, in case someone leaves our organization we can update our credentials&lt;br&gt;
file and restart the app. For convenience we can read the credentials file path&lt;br&gt;
from an environment variable, we already know how to do it right? Right.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(defn get-credentials
  "Return a username -&amp;amp;gt; password map reading it form the specified file, or an
   empty map it reading fails"
  [credentials-path]
  (try
    (with-open [r (io/reader credentials-path)]
      (edn/read (java.io.PushbackReader. r)))
    (catch Throwable  _ {})))

(defn authenticated?
  [username password]
  (let [credentials (get-credentials (:basic-auth-credentials env "credentials.edn"))]
    (= (get credentials username) password)))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now &lt;code&gt;authenticated?&lt;/code&gt; will read the credentials from an edn file whose path is taken&lt;br&gt;
from the &lt;code&gt;BASIC_AUTH_CREDENTIALS&lt;/code&gt; environment variable (defaulting to some well&lt;br&gt;
known path). If the credentials will ever change we must restart the application&lt;br&gt;
to see the new values, not the end of the world but we can do a bit better.&lt;/p&gt;

&lt;p&gt;The idea is to cache the credentials with a TTL, so when it expires we can read&lt;br&gt;
the file again with possibly new values. Implementing a cache with TTL is a nice&lt;br&gt;
exercise but we can leverage the &lt;a href="https://github.com/clojure/core.cache"&gt;clojure.core.cache&lt;/a&gt; library that implements&lt;br&gt;
this functionality for us. I am not going to write about this library in detail,&lt;br&gt;
the documentation does a great job anyway, so I'll focus on the bare minimum&lt;br&gt;
to get things done.&lt;/p&gt;

&lt;p&gt;Assuming that we have added the library to our dependencies and required it in&lt;br&gt;
our namespace, we can change &lt;code&gt;autheticated?&lt;/code&gt; to make use of it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;;; create a TTL cache with an empty map and a ttl of 60 seconds
(def credentials-cache (cache/ttl-cache-factory {} :ttl 60000))

(defn authenticated?
  [username password]
  (let [credentials (cache/lookup-or-miss
                      credentials-cache
                      :credentials ;; we try to lookup the key :credentials in the cache
                      (fn [_]      ;; if the key is missing or expired we load the credentials file
                        (get-credentials (:basic-auth-credentials env "credentials.edn"))))]
    (= (get credentials username) password)))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a sorts of an hack of the TTL cache; usually you want to cache with TTL different keys,&lt;br&gt;
and load the value of those keys (from DB, external APIs, whatever) when the TTL expires. In our&lt;br&gt;
case we just want to load the whole file so we are using the key &lt;code&gt;:credentials&lt;/code&gt; to hold its&lt;br&gt;
content. The clojure.core.cache implements quite a lot of caching strategies, I encourage everyone&lt;br&gt;
to give it a try!&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusions
&lt;/h1&gt;

&lt;p&gt;If dealing with a simple application, using basic auth can be good enough&lt;br&gt;
and we have explored different ways to achieve that; clearly, as the application&lt;br&gt;
grows, other authentication mechanisms like a full suited identity/role management&lt;br&gt;
solution may be a better fit. Currently I am exploring &lt;a href="https://www.keycloak.org"&gt;Keycloak&lt;/a&gt;, hoping to come&lt;br&gt;
up with a library for Clojure.&lt;/p&gt;

&lt;p&gt;Sources for this little project can be found in my shiny new playground &lt;a href="https://gitlab.com/fpischedda/playground"&gt;repo&lt;/a&gt;,&lt;br&gt;
specifically in the &lt;a href="https://gitlab.com/fpischedda/playground/-/blob/main/src/codes/fpsd/ring_basic_auth.clj"&gt;ring_basic_auth.clj&lt;/a&gt; file&lt;/p&gt;

&lt;h1&gt;
  
  
  Alternatives
&lt;/h1&gt;

&lt;p&gt;Every web server provides a way to protect one (or more) endpoint at the&lt;br&gt;
server configuration level, sometimes it can be even convenient to&lt;br&gt;
leverage that functionality; the only downside I see in this approach is&lt;br&gt;
that it couples the application to the web server serving it.&lt;br&gt;
If the endpoint structure is sufficiently complex it is easy to forget&lt;br&gt;
something in case of a migration to a different web server.&lt;/p&gt;

&lt;p&gt;Another alternative is to use the same authentication/authorization mechanism&lt;br&gt;
used for normal users and play with roles and permissions to enable/disable&lt;br&gt;
access to specific resources. In the longer term this is the approach I&lt;br&gt;
would take given that it reduces special cases and makes role management&lt;br&gt;
more consistent.&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>programming</category>
      <category>beginners</category>
      <category>web</category>
    </item>
    <item>
      <title>Clojure Digressions - Setting up a playground</title>
      <dc:creator>Francesco</dc:creator>
      <pubDate>Fri, 23 Jun 2023 12:49:06 +0000</pubDate>
      <link>https://dev.to/fpsd/clojure-digressions-setting-up-a-playground-1lo0</link>
      <guid>https://dev.to/fpsd/clojure-digressions-setting-up-a-playground-1lo0</guid>
      <description>&lt;p&gt;&lt;a href="https://fpsd.codes/clojure-digressions---setting-up-a-playground.html"&gt;Original post&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Disclaimer
&lt;/h1&gt;

&lt;p&gt;Why a new series named Clojure Digressions?&lt;/p&gt;

&lt;p&gt;Clojure Bites is more suited for short introductions to Clojure&lt;br&gt;
related libraries and tools, instead with digressions I'd like to&lt;br&gt;
talk about more general topics, like development environment setup,&lt;br&gt;
good/bad habits and personal development as a Clojure developer.&lt;/p&gt;

&lt;p&gt;Like a conversation ice breaker, I start by talking about my personal&lt;br&gt;
take on some specific argument, looking forward to get input from&lt;br&gt;
other, possibly more experienced, developers on some specific topic.&lt;/p&gt;

&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;A playground is a safe place aimed at experimentation, without any&lt;br&gt;
legacy background limiting your fantasy and willingness to explore&lt;br&gt;
solutions outside your usual comfort zone i.e. all the code you have&lt;br&gt;
already written for your company/product.&lt;/p&gt;

&lt;p&gt;It is no secret that as professional developers we are expected to reuse&lt;br&gt;
as much as possible of what we have at hand in our code base, being careful&lt;br&gt;
when adding new dependencies, limit experimentation to when it is really&lt;br&gt;
really needed to avoid introducing unforeseen costs but at the same time we&lt;br&gt;
love to try out new things! What if we had a safe place to experiment,&lt;br&gt;
just taking out a small bit of our business domain and test it against&lt;br&gt;
a different approach?&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting from scratch
&lt;/h2&gt;

&lt;p&gt;You want to quickly sketch out something, no REPL is running, the first&lt;br&gt;
thing you can do is to fire up an interactive REPL by running &lt;code&gt;$ clojure&lt;/code&gt;&lt;br&gt;
or, if you want readline support, &lt;code&gt;$ clj&lt;/code&gt;; now you have a prompt where you&lt;br&gt;
con evaluate forms using the rich clojure.core library. Nothing too advanced,&lt;br&gt;
the same is available with the default Python, Ruby and many other prompts.&lt;br&gt;
But it is still something.&lt;/p&gt;

&lt;p&gt;Lets spice up our REPL by replacing the standard readline lib with&lt;br&gt;
&lt;a href="https://github.com/bhauman/rebel-readline"&gt;rebel&lt;/a&gt; that will give us autocompletion,&lt;br&gt;
hints and much more. To try it out quickly:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;clojure -Sdeps "{:deps {com.bhauman/rebel-readline {:mvn/version \"0.1.4\"}}}" -m rebel-readline.main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;-Sdeps\&lt;/code&gt; is used to pull in more dependencies, the &lt;code&gt;-m\&lt;/code&gt; parameter is used to&lt;br&gt;
specify an entry point to be called; this will initialize a REPL session using&lt;br&gt;
rebel readline interface. Learn more &lt;a href="https://github.com/bhauman/rebel-readline"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you'll like it you can create an alias in your &lt;code&gt;~/.clojure/deps.edn\&lt;/code&gt; file in&lt;br&gt;
order to be able to start a rebel REPL without being forced to remember all the&lt;br&gt;
required parameters, here is an example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
 :aliases {:rebel {:extra-deps {com.bhauman/rebel-readline {:mvn/version "0.1.4"}}
                   :main-opts  ["-m" "rebel-readline.main"]}}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And invoke it simply with:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;clojure -M:rebel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;a href="https://asciinema.org/a/160597"&gt;asciinema&lt;/a&gt; of the official docs is worth one&lt;br&gt;
billion words ;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond throw away sessions
&lt;/h2&gt;

&lt;p&gt;Working directly in the REPL prompt is not really ergonomic in some cases and you may&lt;br&gt;
prefer the comfort of your favorite IDE or editor to hack on some code; the first&lt;br&gt;
step is to start a REPL to which you can attach to. As with rebel readline it not&lt;br&gt;
required to to have an alias in your $HOME/.clojure/deps.edn or project's deps.edn:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;clojure -Sdeps "{:deps {nrepl/nrepl {:mvn/version \"1.0.0\"}}}" -m nrepl.cmdline

nREPL server started on port 39435 on host localhost - nrepl://localhost:39435
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now you can connect your IDE to the REPL and start hacking! Please notice that the&lt;br&gt;
port may change at each invocation. Deciding what to work on is left as an exercise&lt;br&gt;
to the reader :)&lt;/p&gt;

&lt;p&gt;Like we did for rebel readline, we can add an alias to our $HOME/.clojure/deps.edn&lt;br&gt;
file to make it easier in future to start a REPL we can attach to:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  :aliases {:rebel {:extra-deps {com.bhauman/rebel-readline {:mvn/version "0.1.4"}}
                    :main-opts  ["-m" "rebel-readline.main"]}
            :nrep  {:extra-deps {nrepl/nrepl {:mvn/version "1.0.0"}}
                    :main-opts  ["-m" "nrepl.cmdline"]}}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Starting it with:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;clojure -M:nrepl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;At this point I encourage you to test this setup with your own IDE to get a real feel&lt;br&gt;
of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some more spices
&lt;/h2&gt;

&lt;p&gt;Being able to run a REPL on demand is already something useful but we can get more&lt;br&gt;
out of it, for example being able to pull in new dependencies on demand in the&lt;br&gt;
currently running process using the upcoming &lt;a href=""&gt;add-lib&lt;/a&gt; in the &lt;a href=""&gt;repl.deps&lt;/a&gt;&lt;br&gt;
module.&lt;/p&gt;

&lt;p&gt;Add a new alias to our clojure deps file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  :aliases {:rebel {:extra-deps {com.bhauman/rebel-readline {:mvn/version "0.1.4"}}
                    :main-opts  ["-m" "rebel-readline.main"]}
            :add-libs {:extra-deps {clojure.org/clojure {:mvn/version "1.12.0-alpha3"}}}
            :nrep  {:extra-deps {nrepl/nrepl {:mvn/version "1.0.0"}}
                    :main-opts  ["-m" "nrepl.cmdline"]}}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now we can add this capability to either rebel or nrepl alias, for example, running:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;clojure -M:add-libs:rebel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;will start a new REPL pulling in both the new Clojure version with support to dynamically&lt;br&gt;
load libraries and a rebel readline prompt; the same would apply if replacing rebel with&lt;br&gt;
nrepl, i.e. we would have a nrepl session with the add-libs support.&lt;/p&gt;

&lt;p&gt;It is useful to be able to combine more functionalities coming from different aliases when&lt;br&gt;
starting a new REPL process. Again I encourage everyone to play with it and come with a setup&lt;br&gt;
the covers your requirements.&lt;/p&gt;

&lt;p&gt;Other useful tools worth considering for your personal toolbox:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://github.com/djblue/portal"&gt;Portal&lt;/a&gt;: A clojure tool to navigate through your data.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/jpmonettas/flow-storm-debugger"&gt;FlowStorm&lt;/a&gt;: A tracing debugger for Clojure and ClojureScript.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://jpmonettas.github.io/flow-storm-debugger/user_guide.html#_clojurestorm"&gt;ClojureStorm&lt;/a&gt;: Companion FlowStorm Clojure implementation that automatically instruments your code to be used with FlowStorm.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It can be seen as a safe place to play with unknown possible solutions,&lt;br&gt;
in an isolated environment, collect useful information and then decide&lt;br&gt;
if we can introduce them to our daily stack.&lt;/p&gt;

&lt;p&gt;How can it be useful?&lt;/p&gt;

&lt;p&gt;Which tools should I include in mine?&lt;/p&gt;

&lt;p&gt;Is there something obvious that I am missing?&lt;/p&gt;

&lt;h2&gt;
  
  
  Are we playground yet?
&lt;/h2&gt;

&lt;p&gt;We have learned how to setup an interactive or a nREPL to connect to from an&lt;br&gt;
IDE and we have added some useful tools to improve our developer experience&lt;br&gt;
but where do we put the results of our experiments? I usually start a new&lt;br&gt;
project each time I want try out something and honestly it is a straight&lt;br&gt;
forward process especially if using tools like &lt;a href="https://github.com/seancorfield/clj-new"&gt;clj-new&lt;/a&gt;, taking from the project&lt;br&gt;
README:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# one-off to install clj-new as a tool:
clojure -Ttools install com.github.seancorfield/clj-new '{:git/tag "v1.2.399"}' :as clj-new

# commands to create new projects:

# create a new app:
clojure -Tclj-new app :name myname/myapp
# create a new library:
clojure -Tclj-new lib :name myname/mylib
# create a new template:
clojure -Tclj-new template :name myname/mytemplate
# create a new project from a public template:
clojure -Tclj-new create :template electron-app :name myname/myelectron-app#+END_SRC
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Recently maybe I have created too many throw away projects and creating a full&lt;br&gt;
fledged project structure each time feels like a waste of time; ideally I'd like&lt;br&gt;
to open a new file, connect to a fully capable REPL (or start a new one) and&lt;br&gt;
start hacking. When finished commit the new file or changes to existing ones and&lt;br&gt;
move one.&lt;/p&gt;

&lt;p&gt;One advantage I see with this approach is that I can keep all these small projects&lt;br&gt;
in one place, accumulating knowledge that can be easily reused later. An added&lt;br&gt;
benefit is that it is easy to add another powerful tool like &lt;a href="https://github.com/nextjournal/clerk"&gt;Clerk&lt;/a&gt; to generate&lt;br&gt;
playbooks to interact with and document the code; two months from now you may&lt;br&gt;
want to get back to your experiment and easily get back to it and its conclusions&lt;br&gt;
without spending too much time.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;We started from a simple REPL, added some tasty juice to it and ended up creating&lt;br&gt;
a safe place to play and experiment. I want to point out that this is just my personal&lt;br&gt;
take and not a default in the Clojure community (or if that is, it is just a coincidence).&lt;/p&gt;

&lt;p&gt;I am curious to learn how others are addressing the same problem, if it is a problem anyway.&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Clojure Bites - Render HTML, introducing selmer templating library</title>
      <dc:creator>Francesco</dc:creator>
      <pubDate>Thu, 08 Jun 2023 19:33:58 +0000</pubDate>
      <link>https://dev.to/fpsd/clojure-bites-render-html-introducing-selmer-templating-library-3bh8</link>
      <guid>https://dev.to/fpsd/clojure-bites-render-html-introducing-selmer-templating-library-3bh8</guid>
      <description>&lt;p&gt;Sometimes all we need is a way to render HTML out of a template, &lt;a href="https://github.com/yogthos/Selmer"&gt;selmer&lt;/a&gt; is a great library for that, lets have a look at it! &lt;a href="https://fpsd.codes/clojure-bites---rendering-html.html"&gt;https://fpsd.codes/clojure-bites---rendering-html.html&lt;/a&gt;&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>programming</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Coding live session starting 3PM CEST, come and join me for a chat!</title>
      <dc:creator>Francesco</dc:creator>
      <pubDate>Sun, 28 May 2023 09:17:08 +0000</pubDate>
      <link>https://dev.to/fpsd/coding-live-session-starting-3pm-cest-come-and-join-me-for-a-chat-5b1o</link>
      <guid>https://dev.to/fpsd/coding-live-session-starting-3pm-cest-come-and-join-me-for-a-chat-5b1o</guid>
      <description>&lt;p&gt;For the first time in my life, today I am going to stream while I work on one of my side projects.&lt;/p&gt;

&lt;p&gt;I want to invite you all to join me, today May 28 at 15:00 CEST, on Twitch &lt;a href="https://www.twitch.tv/fpsd_codes"&gt;https://www.twitch.tv/fpsd_codes&lt;/a&gt; !&lt;/p&gt;

&lt;p&gt;Why I am doing this? Because I think that having a potential audience would help me to stay focuses on the code without (too many) distractions and because building a side project it is easy to feel alone :)&lt;/p&gt;

&lt;p&gt;I will keep notes on &lt;a href="https://dynalist.io/d/y47HRsd9pjyqYR8JaPYE9pnO"&gt;Dynalist&lt;/a&gt;, if you want to have edit access to the document to contribute, please ping me!&lt;/p&gt;

&lt;p&gt;See you later!&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>programming</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>Clojure Bites - Structured logging with mulog</title>
      <dc:creator>Francesco</dc:creator>
      <pubDate>Wed, 24 May 2023 20:01:33 +0000</pubDate>
      <link>https://dev.to/fpsd/clojure-bites-structure-logging-with-mulog-2id3</link>
      <guid>https://dev.to/fpsd/clojure-bites-structure-logging-with-mulog-2id3</guid>
      <description>&lt;p&gt;Full post &lt;a href="https://fpsd.codes/blog/clojure-bites-mulog/"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looking forward your comments!&lt;/p&gt;

&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;Logging is a fundamental tool to monitor and debug a running system.&lt;br&gt;
Even if we can use logs to gather metrics about our system, these are&lt;br&gt;
often written with the assumption that humans are going to consume them,&lt;br&gt;
which make it hard to extract meaning information from log messages.&lt;/p&gt;

&lt;p&gt;Log messages are rarely consistent or even meaningful if read few days&lt;br&gt;
after writing them during your emergency debug session. Writing good log&lt;br&gt;
messages is hard! Almost as hard as naming things and cache invalidation.&lt;/p&gt;

&lt;p&gt;Another overlooked problem is that often logs are are context less, what&lt;br&gt;
can we infer by a message like "Failed to process user payment" if we don't&lt;br&gt;
know what triggered the payment process, the affected user or product?&lt;/p&gt;

&lt;h2&gt;
  
  
  Structured logging
&lt;/h2&gt;

&lt;p&gt;Structured logging aims to provide query-able, consistent, information rich&lt;br&gt;
logs that can be used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Business intelligence: derive business relevant data from logged events&lt;/li&gt;
&lt;li&gt;  Monitoring: understand the current state of a system&lt;/li&gt;
&lt;li&gt;  Debugging: understand the context in which an error has been reported&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>clojure</category>
      <category>logging</category>
      <category>beginners</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Clojure bites - dynamically add depencencies at runtime!</title>
      <dc:creator>Francesco</dc:creator>
      <pubDate>Fri, 12 May 2023 17:34:51 +0000</pubDate>
      <link>https://dev.to/fpsd/clojure-bites-dynamically-add-depencencies-at-runtime-6di</link>
      <guid>https://dev.to/fpsd/clojure-bites-dynamically-add-depencencies-at-runtime-6di</guid>
      <description>&lt;p&gt;&lt;a href="https://fpsd.codes/clojure-bites---dynamically-add-depencencies-at-runtime.html"&gt;Full article&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;One pain point of REPL driven development is that even if it is possible to&lt;br&gt;
change an application while it is running, if you want to experiment with a&lt;br&gt;
new library it is need to add a new dependency to your project and restart the&lt;br&gt;
REPL to use it, possibly breaking your flow.&lt;/p&gt;

&lt;p&gt;Fortunately a new set of functions to alleviate this pain are in the &lt;a href="https://clojure.atlassian.net/browse/CLJ-2761"&gt;works&lt;/a&gt;&lt;br&gt;
and ready to be tested since Clojure &lt;a href="https://clojure.org/releases/devchangelog#v1.12.0-alpha2"&gt;1.12.0-alpha2&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;add-lib: Given a lib that is not yet on the repl classpath, make it available by downloading the library if necessary and adding it to the classloader.&lt;/li&gt;
&lt;li&gt;add-libs: Given lib-coords, a map of lib to coord, will resolve all transitive deps for the libs together and add them to the repl classpath, unlike separate calls to add-lib.&lt;/li&gt;
&lt;li&gt;sync-deps: Calls add-libs with any libs present in deps.edn but not yet present on the classpath.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Get the full content
&lt;/h1&gt;

&lt;p&gt;This time the content of the post is be available on my &lt;a href="https://fpsd.codes/clojure-bites---dynamically-add-depencencies-at-runtime.html"&gt;site&lt;/a&gt;, especially to avoid editing it in too many places. Please let me know it is a deal breaker! If that is the case, I'll replicate it here.&lt;/p&gt;

&lt;p&gt;Looking forward your feedback!&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>buildinpublic</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Data driven unit tests with Clojure</title>
      <dc:creator>Francesco</dc:creator>
      <pubDate>Tue, 02 May 2023 06:10:54 +0000</pubDate>
      <link>https://dev.to/fpsd/data-driven-unit-tests-with-clojure-22l</link>
      <guid>https://dev.to/fpsd/data-driven-unit-tests-with-clojure-22l</guid>
      <description>&lt;p&gt;&lt;a href="https://fpsd.codes/clojure-bites---clojuretestare.html"&gt;original article + updates&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;Clojure's &lt;a href="https://clojuredocs.org/clojure.test/are"&gt;clojure.test/are&lt;/a&gt; provides a data driven approach to unit testing.&lt;br&gt;
Lets start with a practical example, implementing the most important function&lt;br&gt;
in the history of computer science, FizzBuzz! (But only because all of my&lt;br&gt;
binary search trees are already balanced).&lt;/p&gt;
&lt;h2&gt;
  
  
  FizzBuzz
&lt;/h2&gt;

&lt;p&gt;It is (was?) common that, during an interview, to be asked to implement the&lt;br&gt;
logic of the FizzBuzz game, Wikipedia has a nice &lt;a href="https://en.wikipedia.org/wiki/Fizz_buzz"&gt;article&lt;/a&gt; about it.&lt;/p&gt;

&lt;p&gt;It can be summarized as follows:&lt;/p&gt;

&lt;p&gt;Write a function that takes a numerical argument and returns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The string Fizz if the number is divisible by 3&lt;/li&gt;
&lt;li&gt;  The string Buzz if the number is divisible by 5&lt;/li&gt;
&lt;li&gt;  The string FizzBuzz if the number is divisible by both 3 and 5&lt;/li&gt;
&lt;li&gt;  The argument if none of the previous conditions are met&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The implementation
&lt;/h2&gt;

&lt;p&gt;Lets start by defining the test suite using the usual clojure.test/is macro.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    (ns fizzbuzz.core-test
      (:require [clojure.test :refer [deftest is testing]]
                [fizzbuzz.core :as sut]))

    (deftest OMG-FizzBuzz
      (testing "Should return the numerical argument"
        (is (= 1 (sut/fizz-buzz 1))))

      (testing "Should return Fizz"
        (is (= "Fizz" (sut/fizz-buzz 3))))
      (testing "Should return Buzz"
        (is (= "Buzz" (sut/fizz-buzz 5))))
      (testing "Should return FizzBuzz"
        (is (= "FizzBuzz" (sut/fizz-buzz 15))))
      )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please note that sut stands for system under test; I've seen it being used&lt;br&gt;
here and there but I am not sure it is a best practice or not.&lt;/p&gt;

&lt;p&gt;The test will clearly fail because there is no fizz-buzz function or even a&lt;br&gt;
fizzbuzz.core namespace. Lets start with a trivial implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    (ns fizzbuzz.core)

    (defn fizz-buzz [n]
      (cond
        (= 0 (mod n 15)) "FizzBuzz"
        (= 0 (mod n 3)) "Fizz"
        (= 0 (mod n 5)) "Buzz"
        :else n))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now all tests are passing, the interviewer is more than happy but you&lt;br&gt;
want to show off your skills and ask to improve both code and tests&lt;/p&gt;
&lt;h2&gt;
  
  
  Improvements
&lt;/h2&gt;

&lt;p&gt;First thing to notice is that if a number is not a multiple of 3 or 5 then&lt;br&gt;
we run 4 divisions and return n. A slightly improvement can be the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    (ns fizzbuzz.core)

    (defn fizz-buzz
      [n]
      (cond
        (= 0 (mod n 3)) (if (= 0 (mod n 5)) "FizzBuzz" "Fizz")
        (= 0 (mod n 5)) "Buzz"
        :else n))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test are passing so we are confident that the function is working as expected,&lt;br&gt;
and it is a bit more performing! Yes, we are not solving the world's energy&lt;br&gt;
crisis but it is something.&lt;/p&gt;
&lt;h2&gt;
  
  
  Data driven tests
&lt;/h2&gt;

&lt;p&gt;Looking at the tests we can notice that we are calling the same function with&lt;br&gt;
different input values and expecting a specific result. User of other testing&lt;br&gt;
libraries, for example &lt;a href="https://docs.pytest.org/en/7.3.x/"&gt;Pytest&lt;/a&gt; may be familiar with the &lt;a href="https://docs.pytest.org/en/7.3.x/how-to/parametrize.html#pytest-mark-parametrize"&gt;parametrize&lt;/a&gt; decorator&lt;br&gt;
that takes tuples of data and calls the test case with that data as parameters.&lt;br&gt;
In Clojure we can achieve that with clojure.test/are macro, here is the docstring:&lt;/p&gt;

&lt;p&gt;"Checks multiple assertions with a template expression.&lt;br&gt;
See clojure.template/do-template for an explanation of&lt;br&gt;
templates."&lt;/p&gt;

&lt;p&gt;A bit cryptic but an example can help us understand better.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    (ns fizzbuzz.core-test
      (:require [clojure.test :refer [deftest are]]
                [fizzbuzz.core :as sut]))

    (deftest OMG-FizzBuzz
      (are [argument expected] (= expected (sut/fizz-buzz argument))
        1 1
        2 2
        3 "Fizz"
        6 "Fizz"
        5 "Buzz"
        10 "Buzz"
        15 "FizzBuzz"))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And voila, we have a data driven test suite for our implementation!&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing words
&lt;/h2&gt;

&lt;p&gt;I hope this will encourage exploring Clojure's core library, to spot little&lt;br&gt;
gems like this one, and to have added a new tool to your toolbox!&lt;/p&gt;

&lt;p&gt;Code for this post can be found &lt;a href="https://gitlab.com/fpischedda/fp-site/-/merge_requests/8/diffs"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>clojure</category>
      <category>unittest</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Segmenting my audience</title>
      <dc:creator>Francesco</dc:creator>
      <pubDate>Thu, 27 Apr 2023 16:21:50 +0000</pubDate>
      <link>https://dev.to/fpsd/segmenting-my-audience-5hbd</link>
      <guid>https://dev.to/fpsd/segmenting-my-audience-5hbd</guid>
      <description>&lt;p&gt;Hi everyone!&lt;/p&gt;

&lt;p&gt;After a long time reading DevTo contents I've started posting about my projects but soon after that I've realized that my writings were not a good fit for the community, which looks more interested in tech other than products (but if I am wrong, happy the learn that!).&lt;/p&gt;

&lt;p&gt;From now on I'll try sharing only tech related topic here, which is a perfect fit, because you know, we have soooo much to learn from each other!&lt;/p&gt;

&lt;p&gt;That said, here is my latest post, hoping to find Lisp/Scheme/Guile enthusiasts around the corner :) &lt;a href="https://fpsd.codes/random-bits.html"&gt;https://fpsd.codes/random-bits.html&lt;/a&gt;&lt;/p&gt;

</description>
      <category>community</category>
      <category>webdev</category>
      <category>buildinpublic</category>
      <category>programming</category>
    </item>
    <item>
      <title>My project got a shiny new Chrome Extension!</title>
      <dc:creator>Francesco</dc:creator>
      <pubDate>Mon, 24 Apr 2023 12:13:29 +0000</pubDate>
      <link>https://dev.to/fpsd/my-project-got-a-shiny-new-chrome-extension-i04</link>
      <guid>https://dev.to/fpsd/my-project-got-a-shiny-new-chrome-extension-i04</guid>
      <description>&lt;p&gt;I have few days off at work, so a good opportunity to work on my projects!&lt;/p&gt;

&lt;p&gt;Today's post is about the new Unrefined's Chrome Extension, which should streamline the job of EMs.&lt;/p&gt;

&lt;p&gt;Get it here &lt;a href="https://fpsd.codes/announcing-unrefineds-chrome-extension.html"&gt;https://fpsd.codes/announcing-unrefineds-chrome-extension.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;p.s. It is exciting to build in public, I feel more encouraged to make progress and I am procrastinating way less than usual! &lt;/p&gt;

</description>
      <category>clojure</category>
      <category>buildinpublic</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Updates on my #buildinpublic effort</title>
      <dc:creator>Francesco</dc:creator>
      <pubDate>Fri, 21 Apr 2023 17:59:05 +0000</pubDate>
      <link>https://dev.to/fpsd/updates-on-my-buildinpublic-effort-1agi</link>
      <guid>https://dev.to/fpsd/updates-on-my-buildinpublic-effort-1agi</guid>
      <description>&lt;p&gt;Hi Everyone!&lt;/p&gt;

&lt;p&gt;I have a new update on my projects' roadmap, why I haven't published much content this week and next steps.&lt;br&gt;
&lt;a href="https://fpsd.codes/updates-on-projects.html"&gt;https://fpsd.codes/updates-on-projects.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Question: anyone interested attending a live coding session? It would be fun to get realtime feedback and getting in touch with other devs!&lt;/p&gt;

&lt;p&gt;All my projects are build in public (sources included, of course), but this happens post-facto, I think it would be an interesting experience to share the design/development process, while it is happening! (plus, I've never streamed before so it can become quite ridiculous...) &lt;/p&gt;

&lt;p&gt;Let me know what do you think.&lt;/p&gt;

&lt;p&gt;p.s. I have tagged the post with #clojure and #javascript because these are the main languages for my current project ;)&lt;/p&gt;

</description>
      <category>buildinpublic</category>
      <category>clojure</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Introduce yourself, take 2</title>
      <dc:creator>Francesco</dc:creator>
      <pubDate>Mon, 17 Apr 2023 19:27:05 +0000</pubDate>
      <link>https://dev.to/fpsd/introduce-yourself-take-2-2p3d</link>
      <guid>https://dev.to/fpsd/introduce-yourself-take-2-2p3d</guid>
      <description>&lt;p&gt;And hello again dev.to community!&lt;/p&gt;

&lt;p&gt;I have no followers so I will be talking to myself most probably but anyway I think it is important for me, as a new member, to share as much as possible since the beginning of my presence here.&lt;/p&gt;

&lt;p&gt;Recently I have started a new website, to keep track of the progress of my projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tools or products&lt;/li&gt;
&lt;li&gt;learning new things, like programming languages, tools, recipes, whatever&lt;/li&gt;
&lt;li&gt;communication &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is no clear path yet, but I'll be happy to share everything in the process, hoping to be useful for others as well as for myself.&lt;/p&gt;

&lt;p&gt;It is all for now, if curious point your browser to &lt;a href="https://fpsd.codes"&gt;https://fpsd.codes&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It be great to get any kind of feedback, see you soon!&lt;/p&gt;

</description>
      <category>buildinpublic</category>
      <category>webdev</category>
      <category>clojure</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
