• Update: there’s a version of this article that uses bidi instead of silk: No-hashes bidirectional routing in re-frame with bidi and pushy. The content is very similar, only the code changes.

    I recently replaced secretary with silk and pushy in a re-frame project that was created fresh out of leiningen template and this is how I did it, but first, the reason.

    What I like about silk is that it’s bidirectional. It not only parses URLs into data structures but also generates URLs from data structures. This is not unique to silk, bidi also does it and feature-wise they are almost equivalent. On bidi’s website you can find this table comparing various routing libraries:

    LibrarycljcljsSyntaxIsomorphic?Self-contained?Extensible?
    CompojureMacros
    MoustacheMacros
    RouteOneMacros
    PedestalData
    guduData
    secretaryMacros
    silkData
    fnhouseMacros
    bidiData

    I don’t have a strong reason to chose silk over bidi, both seem like excellent choices. I also added pushy to the mix so I could have nice URLs, such as /about  instead of /#/about. The reason for this is that it looks better, follows the semantics of URLs better and allows for server side rendering, to be covered in a future article. It uses HTML5 pushState which by now it’s widely supported.

    Let’s get started

    I’m going to use a fresh project for this article, but the information here is applicable to any similar situation. Let’s get started:

    lein new re-frame projectx +routes

    The first step is to get rid of secretary and include silk and pushy by replacing

    [secretary "1.2.3"]

    with

    [com.domkm/silk "0.1.1"]
    [kibu/pushy "0.3.2"]

    The routes

    The routes.cljs  file will be completely re-written. The namespace declaration will include silk and pushy:

    (ns projectx.routes
      (:require [clojure.set :refer [rename-keys]]
                [domkm.silk :as silk]
                [pushy.core :as pushy]
                [re-frame.core :as re-frame])) 

    The first step is to define the routes we want. One of the designing features of silk is that routes are data structures, not function/macro calls:

    (def routes (silk/routes [[:home [[]]]
                              [:about [["about"]]]]))

    The app-routes function that used to define functions is replaced by one that sets up pushy:

    (defn app-routes []
      (pushy/start! (pushy/pushy dispatch-route parse-url)))

    parse-url  is a very simple function that uses silk/arrive to turn a URL into a data structure representing it:

    (defn- parse-url [url]
      (silk/arrive routes url))

    Then dispatch-route is called with that structure:

    (defn- dispatch-route [matched-route]
      (let [matched-route (sanitize-silk-keywords matched-route)
            panel-name (keyword (str (name (:name matched-route)) "-panel"))]
        (re-frame/dispatch [:set-active-panel panel-name])))

    The :name of the matched-route will be :home or :about and panel-name  is constructed to be :home-panel  or :about-panel so that we can dispatch setting the active panel the same way secretary used to do it.

    sanitize-silk-keywords  just simplifies the namespaced keywords silk produces:

    (defn- sanitize-silk-keywords [matched-route]
      (rename-keys matched-route {:domkm.silk/name    :name
                                  :domkm.silk/pattern :pattern
                                  :domkm.silk/routes  :routes
                                  :domkm.silk/url     :url}))

    And that’s the core of it. You now have to change URLs in the view to be /about  and / instead of /#/about and /#/ respectively.

    Generating URLs

    The whole point of using silk was to not hard-code the URLs, for that I added this function to routes.cljs:

    (def url-for (partial silk/depart routes))

    which allowed me to replace the previous URLs with:

    (routes/url-for :about)

    and

    (routes/url-for :home)

    This works fine until you try to re-load the about page and you get a 404 Not Found error. This is because the server doesn’t know about the /about  URL or any other URL the client-side might support. What you need to do is just send serve the application no matter what the URL and let the client do the dispatching (with any exceptions you might have for APIs and whatnot).

    I’m actually not quite sure how you do it with a figwheel-only project, probably by setting a ring handler. With compojure I ended up creating a route like this:

    (routes (ANY "*" [] (layout/render "app.html")))

    Something else you might consider is passing the whole matched-route  structure to the handler, so that the handler has access to path and query attributes.

    And that’s it! Now you have beautiful bi-directional no-hash client-side routing.

    Summary

    For your reference, the full routes.cljs :

    (ns projectx.routes
      (:require
       [clojure.set :refer [rename-keys]]
       [domkm.silk :as silk]
       [pushy.core :as pushy]
       [re-frame.core :as re-frame]))
    
    (def routes
      (silk/routes
       [[:home [[]]]
        [:about [["about"]]]]))
    
    (defn- parse-url [url]
      (silk/arrive routes url))
    
    (defn- sanitize-silk-keywords [matched-route]
      (rename-keys matched-route
                   {:domkm.silk/name    :name
                    :domkm.silk/pattern :pattern
                    :domkm.silk/routes  :routes
                    :domkm.silk/url     :url}))
    
    (defn- dispatch-route [matched-route]
      (let [matched-route (sanitize-silk-keywords matched-route)
            panel-name    (keyword (str (name (:name matched-route)) "-panel"))]
        (re-frame/dispatch [:set-active-panel panel-name])))
    
    (defn app-routes []
      (pushy/start! (pushy/pushy dispatch-route parse-url)))
    
    (def url-for
      (partial silk/depart routes))
    

    and the full views.cljs:

    (ns projectx.views
        (:require [re-frame.core :as re-frame]
                  [projectx.routes :as routes]))
    
    ;; --------------------
    (defn home-panel []
      (let [name (re-frame/subscribe [:name])]
        (fn []
          [:div (str "Hello from " @name ". This is the Home Page.")
           [:div [:a {:href (routes/url-for :about)} "go to About Page"]]])))
    
    (defn about-panel []
      (fn []
        [:div "This is the About Page."
         [:div [:a {:href (routes/url-for :home)} "go to Home Page"]]]))
    
    ;; --------------------
    (defmulti panels identity)
    (defmethod panels :home-panel [] [home-panel])
    (defmethod panels :about-panel [] [about-panel])
    (defmethod panels :default [] [:div])
    
    (defn main-panel []
      (let [active-panel (re-frame/subscribe [:active-panel])]
        (fn []
          (panels @active-panel))))
  • Learning about macros in Lisps was one of my biggest whoa-moments in my programming career and since then I’ve given presentations about them to audiences ranging from 1 to 100 people. I have a little script that I follow in which I implement a custom form of the if-conditional. Unfortunately, I don’t think I’ve managed to generate many whoa-moments. I’m probably not doing macros justice. It’s not an easy task as they can be complex beasts to play with.

    As we are experimenting with Clojure, I eventually needed a tool that I knew was going to be a macro, and I built a simple version of it. The tool is assert_difference. I don’t know where it first appeared, but Rails ships with one and not satisfied with that one I built one a few years ago. In the simplest case it allows you to do this:

    assert_difference("User.count()", 1) do
      add_user_to_database()
    end
    
    assert_difference("User.count()", 0) do
      modify_user_on_the_database()
    end
    
    assert_difference("User.count()", -1) do
      remove_user_from_the_database()
    end

    The problem

    Do you see what’s wrong there? Well, wrong is a strong word. What’s not as good as it could be? It’s the fact that User.count is expressed as a string and not code, when it is code. The reason for doing that is that we don’t want that code to run, we want to have it in a way that we can run it, run the body of the function (adding users, removing users, etc) and run it again comparing it with the output of the previous one.

    There’s no (nice) way in Ruby or many languages to express code and not run it. Rephrasing that, there’s no (nice) way to have code as data in Ruby as in most languages. I’m not picking on Ruby, I love that language, I’m just using it because it’s the language I’m most familiar with; what I’m saying is probably true about any programming language you chose.

    One of the things you’ll hear repeated over and over in the land of the Lisp, be it Common Lisp, Scheme or Clojure is that code is data. And that’s what we want here, we want to have a piece of code as data. We want this:

    assert_difference(User.count(), 1) do
      add_user_to_database()
    end
    
    assert_difference(User.count(), 0) do
      modify_user_on_the_database()
    end
    
    assert_difference(User.count(), -1) do
      remove_user_from_the_database()
    end

    which in Lisp syntax it would look like this:

    (assert-difference (user-count) 1
      (add-user-to-database))
    
    (assert-difference (user-count) 0
      (modify-user-on-the-database))
    
    (assert-difference (user-count) -1
      (remove-user-from-the-database))

    and this, ladies and gentlemen, is not only easy, it’s good practice.

    Enter the macro

    I achieved it with a simple 4-line macro and here it is:

    (defmacro assert-difference [form delta & body]
      `(let [count# ~form]
         ~@body
         (assert-equal (+ count# ~delta) ~form)))

    If you are not familiar with Clojure that will be very hard to read, so, let me help you:

    The first line defines the macro with the name assert-difference  and getting 3 or more parameters with the first one called form , the second delta  and all other parameters, as a list, in body. So, in this example:

    (assert-difference (user-count) 1
      (add-user-to-database))

    we end up with:

    • form => (user-count)
    • delta => 1
    • body => [(add-user-to-database)]

    Note that the parameters to the macro didn’t get the value of calling (user-count), it got the code itself, unexecuted, represented as data that we can inspect and play with, not an unparsed string.

    The body of the macro is a bit cryptic because it’s a template. The backtick at the beginning just identifies it as a template and ~  means “replace this variable with the parameter”. ~@  is a special version of ~  that we have to use because body contains a list of statements instead of a single one. That means that:

    `(let [count# ~form]
        ~@body 
        (assert-equal (+ count# ~delta) ~form))

    turns into:

    (let [count# (user-count)]
       (add-user-to-database)
       (assert-equal (+ count# 1) (user-count)))

    Is it starting to make sense? count#  is a variable that is set to (user-count), then we execute the body, that is (add-user-to-database) and then we execute  (user-count) again and compare it count#  plus delta. This is the code that’s emitted by the macro, this is the code that actually gets compiled and executed.

    If you are wondering about why the variable name has a hash at the end, imagine that variable was just named count  instead and the macro was used like this:

    (let [count 10]
      (assert-difference (user-count) 1
        (add-users-to-database (generate-users count)))

    That snippet defines count, but then the macro defines count again, by the time you reach (generate-users count) that count  was masked by the macro-generated one. That bug can be very hard to debug. The hash at the ends makes it into a uniquely named variable, something like count__28766__auto__ , that is consistent with the other mentions of count#  within that macro.

    Isn’t that beautiful?

    The real solution

    The actual macro that I’m using for now is:

    (defmacro is-different [[form delta] & body]
      `(let [count# ~form]
         ~@body
         (is (= (+ count# ~delta) ~form))))

    which I’m not going to package and release yet like I did with assert_difference because it’s nowhere near finished and I’m not going to keep on improving it until I see the actual patterns that I like for my tests.

    You might notice that it doesn’t use assert-equal. That’s a function I made up because I believe it was familiar for non-clojurians reading this post. When using clojure.test, you actually do this:

    (is (= a b))

    There’s one and only one thing to remember: is . Think of is  as a generic assert and that’s actually all that you need. No long list of asserts like MiniTest has: assert, assert_block, assert_empty, assert_equal, assert_in_delta, assert_in_epsilon, assert_includes, assert_instance_of, assert_kind_of, assert_match, assert_nil, assert_operator, assert_output, assert_predicate, assert_raises, assert_respond_to, assert_same, assert_send, assert_silent and, assert_throws.

    In a programming language like Ruby we need all those assertions because we want to be able to say things such as “1 was expected to be equal to 2, but it isn’t” which can only be done if you do:

    assert_equal(1, 2)

    but not if you do

    assert(1 == 2)

    because in the second case, assert doesn’t have any visibility into the fact that it was an equality comparison, it would just say something like “true was expected, but got false” which is not very useful.

    Do you see where this is going? is  is a macro, so it has visibility into the code, it can both run the code and use the code as data and thus generate errors such as:

    FAIL in (test-users) (user.clj:12)
    expected: 1
      actual: 2
        diff: - 1
              + 2

    which if you ask me, is a lot of very beautiful detail to come out of just

    (is (= 1 2))

    But language X!

    When talking to people about this, I often get rebuttals that this or that language can do it too and yes, other languages can do some things like this.

    For example, we could argue that this is possible in Ruby if you encase the code in an anonymous function when passing it around, such as:

    assert_difference(->{User.count}, 1) do
      add_user()
    end

    but it’s not as nice and we don’t see it very often. What we see is 20 assert methods like in MiniTest. To have an impact in the language, these techniques need to be easy, nice, first class citizens, the accepted style. Otherwise they might as well not exist.

    An even better syntax for blocks in Ruby might help with the issue and indeed what you are left with is a different approach to incredible flexibility and it already exists. It’s called Smalltalk and there’s some discussion about closures, what you have in Lisp,  and objects, what you have in Smalltalk, being equivalent.

    I’m also aware of a few languages having templating systems to achieve things such as this, like Template Haskell, but they are always quite hard to use and left for the true experts. You rarely see them covered in a book for beginners of the language, like macros tend to be covered for Lisp.

    There are also languages that have a string based macro system, like C and I’ve been told that Tcl does as well. The problem with this is that it’s from hard to impossible to build something that’s of medium complexity, to the point that you are recommended to stay away from it.

    All of the alternative solutions I mention so far have a problem: code is not (nice) data. When a macro in Lisp gets a piece of code such as:

    (+ 1 2)

    that code is received as a list of three elements, containing + , 1  and 2 . If the macro instead received:

    (1 2 +)

    the code would be a list containing 1, 2 and +. Note that it’s not valid Lisp code, it doesn’t have to be because it’s not being compiled and executed. The output of a macro has to be valid Lisp code, the input can be whatever and thus, making a macro that changes the language from prefix notation to suffix notation, like in the last snippet of code, is one of the few first exercises you do when learning to make macros.

    What makes it so easy to get code as data and work with it and then execute the data as code is the fact that Lisp’s syntax is very close to the abstract syntax tree of the language. The abstract syntax tree of Lisp programs is something Lisp programmers are familiar with intuitively while most programmers of other languages have no idea what the AST looks like for their programs. Indeed, I don’t know what it looks like for any of the Ruby code I wrote.

    Most programmers don’t know what an AST actually is, but even the Lisp programmers that don’t know what an AST is have an intuition for what the ASTs of their programs are.

    This is why many claim Lisp to be the most powerful programming language out there. You could start thinking of another programming language that has macros that receive code as data and that their syntax is close to the AST and if you find one of those, congratulations, you found a programming language of the Lisp family because pretty much those properties make it a member of the Lisp family.

  • We tend to be very security conscious at Carousel Apps and one thing we often do is force all our applications to run over TLS (aka SSL), that is, when you go to http://example.com we redirect you to https://example.com. This little article will show you how to do it in a Luminus application.

    First, add Ring SSL to your project by editing project.clj , finding the list of dependencies and adding:

    [ring/ring-ssl "0.2.1"]

    That library provides various Ring middleware functions to deal with SSL. The first one you care about is wrap-ssl-redirect  that will cause an HTTP request to be redirected to the equivalent HTTPS one.

    In your middleware.clj  file, find the function wrap-base  which will look something like:

    (defn wrap-base [handler]
      (-> handler
          wrap-dev
          wrap-auth
          (wrap-idle-session-timeout
            {:timeout          (* 60 30)
             :timeout-response (redirect "/")})
          wrap-formats
          (wrap-defaults
            (-> site-defaults
                (assoc-in [:security :anti-forgery] false)
                (assoc-in [:session :store] (memory-store session/mem))))
          wrap-servlet-context
          wrap-internal-error))
    

    Depending on which options you added, you might have fewer or more middleware functions in your project. You can start simple by adding wrap-ssl-redirect  to it, like this:

    (defn wrap-base [handler]
      (-> handler
          wrap-ssl-redirect
          wrap-dev
          ...))

    Redirecting to SSL should happen as early as possible to avoid leaking any information over a non-secure channel. With that code you’ll immediately run into trouble when running your project locally, because neither your development environment nor your test one are likely to support TLS, so you’ll get redirected to HTTPS and it won’t work.

    That’s easy to solve by creating a function, let’s call it enforce-ssl , that will skip the enforcement when developing or testing:

    (defn enforce-ssl [handler]
      (if (or (env :dev) (env :test))
        handler
        (-> handler
            wrap-ssl-redirect)))

    and then in your middleware configuration:

    (defn wrap-base [handler]
      (-> handler
          enforce-ssl
          wrap-dev
          ...))

    The function wrap-ssl-redirect obviously checks whether you are already accessing the site over SSL and if that’s the case, it doesn’t redirect you; otherwise you’d have a redirect loop.

    If your application is sitting behind a proxy or a load balancer, like in the case of Heroku, Linode’s Load Balance, AWS Elastic Load Balancing, etc. the proxy will be terminating the HTTPS connection and then it’ll issue an HTTP (non-S) connection to your application because since now you are in an internal secure network, encryption is no longer required and HTTP is faster. Thus, your application after forwarding to HTTPS will still receive connections to HTTP and forward again and it’ll be stuck in an infinite forwarding loop.

    The convention for this situation is that those proxies will add the header X-Forwarded-Proto with the original protocol, either http  or https. There’s another middleware function called wrap-forwarded-scheme  that will look at X-Forwarded-Proto (or another header entry of your choosing) and set that as the actual scheme in the request so a simple check for http  or https would suffice:

    (defn enforce-ssl [handler]
      (if (or (env :dev) (env :test))
        handler
        (-> handler
            wrap-ssl-redirect
            wrap-forwarded-scheme)))

    Doing the scheme forwarding should be the first thing you do, so that wrap-ssl-redirect  can use the correct scheme.

    IMPORTANT: if your application is not behind a trusted proxy, or the proxy is using a different header, then blindly applying wrap-forwarded-scheme would be dangerous as your application could be easily deceived into believing a connection is secure which would enable a man‐in‐the‐middle attack.

    One last thing that we do is add wrap-hsts  which makes sure the browser from now on will only use HTTPS for this domain, even if the user types http (which would result in a redirect anyway). The final code looks like this:

    (defn enforce-ssl [handler]
      (if (or (env :dev) (env :test))
        handler
        (-> handler
            wrap-hsts
            wrap-ssl-redirect
            wrap-forwarded-scheme)))

    And that’s it, your application now uses TLS/SSL by default, something that you should always consider and definitely do if there’s any kind of auth at all.

  • You know when after a few months of dating someone, they do something that touches you and fall in love all over again. It just happened to me and Clojure. I was playing with Korma and I had the following namespace declaration:

    (ns carouselapps.db.core
      (:require
        [korma.core :refer :all]
        [korma.db :as db]
        [environ.core :refer [env]]
        [to-jdbc-uri.core :refer [to-jdbc-uri]]))

    which was generating this warning:

    WARNING: update already refers to: #'clojure.core/update in namespace:
                  carouselapps.db.core, being replaced by: #'korma.core/update

    What now? I thought I was going to spend the next two hours figuring out a clean way to deal with this, but nope, it took 5 minutes to figure out I could just rename korma.core/update  as I was requiring it:

    (ns carouselapps.db.core
      (:require
        [korma.core :refer :all :rename {update sql-update}]
        [korma.db :as db]
        [environ.core :refer [env]]
        [to-jdbc-uri.core :refer [to-jdbc-uri]]))

    This is the kind of real world pragmatism that you rarely see in programming languages, specially those rooted in academic practices, like being a Lisp, which Clojure is.

    I fell in love all over again. Sometimes it’s the small things you know!

  • In the past, I never managed to build a web site and feel happy with the process. Every time I finished building a web site I would have a list of things to never do again. Until now! So, I thought I’d share.

    First, by web site I mean content, like watuapp.com or screensaver.ninja, I don’t mean a web app. I’m happy with how I build web apps although I’m constantly improving and learning and trying new things. When it comes to content, you have to balance some opposing forces:

    • It should look amazing.
    • It should be flexible.

    It should look amazing because it’s going to be compared to the ones produced by expert teams of designers at tech companies and if your web site is not indistinguishable from those, your web site will be perceived as unprofessional and as a result, so will you and your product.

    I had web sites that looked very good. A graphic designed was hired to produce a pretty illustration of the web site and then a coder turned that picture into HTML and CSS. New pages were created by hand-coding them in HTML. The process of setting up the web site initially was ok, but after that, the workflow was horrendous.

    Changes to the web site would come from non-coders, like the CEO, people in marketing or sales, copywriters, and they would be given to a developer to execute. Then we would have to prioritize between improving our web site or improving our product. Almost always product wins… only when the web site got the point of being embarrassingly out-of-date or broken we would consider doing something about it. This situation is annoying and frustrating for both developers and content generators.

    The way to solve it is with a Content Management System, where things get flexible. With a CMS suddenly anyone with a browser and the right access can edit the site, add new pages, correct typos, add a FAQ, change a title, write a new blog post, etc. It’s as easy as Microsoft Word and the output is as generic, boring and bland as that of your average Word document. It might be ok for text files, but on the web, that screams unprofessional.

    The problem is a tricky one. You might think there’s a nice separation between design and content but that isn’t true. A content writer might decide to have only one column of text instead of two because there’s not enough copy. But the difference between one and two columns is a big one when it comes to design. The content might call for a picture or even worst, a drawing. The design establishes the palette and style of that drawing.

    A screenshot of Screensaver Ninja's web site
    A screenshot of Screensaver Ninja’s web site at the time of this writing.

    I just finished rebuilding the web site for Screensaver Ninja and for the first time I’m happy with the result. Not only how it looks, but the amount of work and funds require as well as the flexibility and workflow going forward.

    The CMS we are using is WordPress and we host it at wpengine, which I really recommend. Not the cheapest, but if you care about your web site and you can afford it, you should go there.

    One potential approach to having a beautiful site would be to go to 99designs and run a contest for a WordPress theme. My hesitation is around the flexibility of the result. Will the new design be completely hard-coded or will I be able to change the copy? What about changing more involved aspects like the amount of columns or images. I’m not sure and asking around did not reach any useful answers. If you have taken this approach, would you mind sharing how it works with me?

    The approach we took was to use a very flexible and advance WordPress theme called X. We chose one of their many templates for a page that we felt would match our current branding and the message we wanted to communicate. We proceeded to fill it up with our own copy following this tenets:

    • Change as little as possible.
    • Ignore all images, just leave them blank.

    Once copy was done, we hired a designer through a freelancing marketplace and ask her to produce images to fill in the blanks. We showed her our web site with the blank images as well as the original template with sample images and asked her to keep the style and palette. We provided some ideas for the images and she came up with some as well. After a couple of iterations we had all the needed images.

    And that’s it. That’s how we produced that site. Yes, it’s possible that out there there are other sites that look exactly the same, but it’s not a big issue. It’s like worrying that somewhere out there there’s someone with the same t-shirt as you. The chances of you two being seen by the same person in a short period of time is small and even if that happens, whether the t-shirts fits you or not is more important. Nobody will care about your originality of clothing if they look horrible and the same goes for your web site.

    Next time i have to build a web site for a product, I’ll do this exercise again and I recommend it to all entrepreneurs that are working in a small company and need to be efficient.

  • This post is about a better way of creating good habits in your life. I’m going to start with my desire to have the habit of working out. The lessons here can be applied to everything and I’m going to show you some more examples at the end.

    I could track my physical exercise to make sure I keep up. I could use an app like Google Fit. The first day I meet my goal, but eventually, my days will look something like this:

    Google FitI already have two missed goals. It’s very easy to get discouraged by missing a goal one day, or a few days in a row, and then drop out of the plan to improve fitness. This is a very bad way of creating new habits.

    The problem with this, as with recurring to-do items is that the granularity is too low: a day. Google fit is telling me I failed two days out of four and not counting than on those two other days I made up for it. If Google fit was measuring activity in four days intervals that would have been a success, instead of a half success.

    But four days might be too short too. A long weekend and boom! You are out! Maybe we should go for a week or even a month. A month is a nice chunk of time, but it has another problem: it’s so big, you might not know you are actually failing until you are too close to the end to fix it. And even if you fix it, working out like mad on the lat 4 days of every month is not healthy or habit forming.

    What we need is something that won’t punish us for a day of rest, but will still keep pushing us up every day. That is Beeminder. Look at my working out chart:

    Beeminder chart for working out

    Beeminder legend

    The pink line with green dots are my data points, the information about when and how much I worked out. It is measured in Fitocracy points, but it could be time working out, kilometers run, kilocalories burnt or anything else you want.

    The yellow brick road is my goal. I want to always be above it. The yellow brick road keeps going up every day, so I need to keep on working out to reach my goal. Crossing it is called derailment and you can see it actually happened around mid October. When you cross it, the system resets, gives you a week of advantage and then re-starts. What happened around mid October is that I had a trip, but that’s not excuse. You see… if you allow things like a trip to be an excuse, it’s easy to lose a good habit.

    How do you deal with eventualities then? You build up a buffer. Towards the end of November, for example, I did that. Unfortunately then I got a cold and that ate most of my buffer right away, but I’m going up again, building a buffer and staying on the good side of the yellow brick road.

    The beauty of this system is that it doesn’t judge a single day, it judges your progress, but it keeps reminding you that you should be making progress.

    Another advantage of Beeminder is keeping up with good habits without a routine. If you ask most gym-goes when they go to gym, they have a routine: Monday and Wednesdays! or something like that. I have preferred days, but I don’t have a strict routine, my life just doesn’t allow it, it’s too chaotic. When you don’t have a strict routine it’s very easy to forget to go to the gym because our brains are very bad at correctly keeping track of how much we worked out this week.

    You may have noticed the big two numbers on the background of the chart. 10d means 10 days, and that’s how big the buffer is. I could sit on my ass for 10 days and not derail. But then I would be in a very precarious situation in which any eventuality will cause me to derail. I don’t want that to happen, so, I’ll attempt to keep my buffer at 10 days or more. Which leads me to the second number.

    $5 is how much derailing will cost me. Those are real dollars, the ones you have to work for. Talk about an incentive! That’s Beeminder’s business model, that’s how they sustain themselves. And it’s a beautiful system because it only hurts when you do something bad, and that penalty is what makes the system work, so you are paying Beeminder only for doing its job. If you never fail, it’s free.

    And each time it fails, the amount will go up, so, further failures will be more expensive. I been tinkering with my workouts recently, trying to find the right amount to do every week, so I keep reseting the amount to $5, but once things are stable, I’ll let it go up.

    Another thing that I’m doing for my fitness and health is meal tracking. Meal tracking also has this insidious property of an all or nothing system. I started tracking them and one day I forgot. The next day I didn’t forget, but since the data was corrupt already, more corruption wouldn’t be that bad (broken window syndrome?) and the day after that I completely forgot I was doing meal tracking.

    I’m still not sure if incomplete meal tracking data is useful or not, but I know the all-or-nothing situation is not conducive to forming habits. Enter Beeminder! First I tried entering how many meals a week I was tracking, but that allowed every day to be corrupt. It’s easy to track meals, it’s harder to track snacks. Allowing every day to be corrupt means you can just track meals, ignore snacks and be successful in the eyes of Beeminder.

    Right now I’m experimenting with forcing myself to track 2 days a week, and I’m doing well:

     

    Beeminder for meal tracking

    That’s where the angle of the yellow brick line comes from. In that chart is 2 per week. If I continue to do well, I’ll keep increasing it, possibly up to 5 or 6.

    These are just a couple of examples of what I’m tracking right now. Beeminder comes ready packages with many settings for different tasks and they keep adding them. Take a look at the screen for creating a new goal to have an idea:

    Beeminder create goal

    Beeminder is not that easy to use. It’s a power-tool, but I really recommend it. Whenever you want to have a new habit in your life, that’s the way to go.

  • There’s a gem called bundler-audit that checks whether any of the gems in your project have open security advisors against them. A year or so ago there was an infamous month in which Rails itself got three of those. It was terrible and I think bundler-audit is a good idea. My only problem with it is having to remember to run it: it just won’t happen. I need to run it automatically and an easy way to do that is to run it as part of my tests.

    Unfortunately, bundler-audit doesn’t make it easy. It’s designed for the command line and that’s it, but these days it’s easier than a year ago and I recommend everybody to add them to their integration tests. Here’s how we do it at Watu:

    require "test_helper"
    require "bundler/audit/database"
    require "bundler/audit/scanner"
    
    class SecurityTest < ActionDispatch::IntegrationTest
      should "not have any vulnerable gems" do
        Bundler::Audit::Database.update!
        scanner = Bundler::Audit::Scanner.new
        scanner.scan do
          raise "There are vulnerable gems in your Gemfile. Run bundle-audit check to know more"
        end
      end
    end
    

    I don’t try to show the vulnerable gems because I found those methods to not be easily reusable and I didn’t want to copy them because they look like they might change at any moment. It’s not a big problem, if something is wrong, you should run bundle-audit check anyway.

  • First panel of the comic about life and death
    First panel of the comic about life and death

    I recently saw a comic about life and death and it bothered me. The comic shows life and death as two equal figures interacting and I think that’s incorrect. It feels like a false dichotomy. They are not both sides of the same coin. Life is the face of the coin, while death is the side of the coin. Death is limiting life, and the farther away it is, the more life we have.

    The reason why I think this is important is because I people over value death. They say things like “we can’t have life without death”. For me, that’s like saying “We can’t have nice things without also having nice broken things later”. It’s true that a nice broken thing is a byproduct of a nice thing, but it’s not essential for its existence. A nice thing that lasts forever is awesome.

    I think this is mostly bullshit that people make up to be at peace with the prospect of dying. It’s as much bullshit as the after-life or reincarnation, it’s just a non-religious non-spiritual one.

    The big social implication about this is that it ostracises life extension. People enjoy living until they are 80 even though that would have been rare a few of centuries ago, but when people dream of extending it to 800, that’s wrong.

    For example, I can’t believe that more people are not signing up for Alcor or the Cryonics Institute, something that thanks to the trick they play with life insurance is affordable by many, many people. When the OpenWorm project run a Kickstarter it clearly stayed away from the implications of life extension by brain emulation. The only reason why I gave them the biggest donation I ever gave to a anyone is because a friend explained it to me well before the Kickstarter. Actually, if they would have just asked me for money I would have said yes, their campaign made me hesitate.

    I leave you with an interesting old TED talk about life extension:

  • Stop reading if you haven’t seen the movie yet, as obviously this will be a big spoiler.

    I think Star Trek into Darkness should have ended with Kirk dead. I don’t care if they revive them in the next one, that’s fine. A friend told me:

    I didn’t even realize that Kirk was dying, they wouldn’t kill him, it was just a small setback.

    I think story tellers should be bolder and surprise us more.

    I think they should have shown McCoy doing something with the body that can be later, in another movie, revealed as putting it in stasis. I think Spock shouldn’t have chased Kahn and have a fist fight. He should have been busy making sure the good of the many outweigh the revenge of the one by saving the Enterprise and making sure his crew was out of danger.

    Hold on Pablo… you mean you want to end a movie with one of the main characters dead?

    Yes, that would have been brave, although not new. Someone did it before and it might be familiar:

    What about Kahn?

    He should have run away. That’s it. Hold on… even better… he should have fled with his crippled ship.

    But then… the bad guy won?

    Yes. It would have been brave and it would have built a lot of tension and expectations for the next movie. Although, it wouldn’t have been the first franchise to have the bad guys win in one of their movies: