How To Make Better, Faster Decisions With Lean Experiments

As many of you know by now, I strongly believe in the effectiveness of using the scientific method to validate business ideas.

Earlier this year, I began running a bunch of experiments for my ideas and ventures. But, quickly, my experiments became too much to handle on a white-board with stickies. I switched to a Google Sheet but that didn’t have the usability and speed that I loved from using stickies.

So I decided to build a simple experiment tracking system for myself.

Keeping Track of Ventures, Experiments and Costs

I would say it’s pretty basic and covers exactly what I need to keep track of:

  • My Ventures which are a sequential list of experiments and their Pivot-or-Persevere decision. Ventures can also be aborted if there is no encouraging signal.
  • Experiments, which comprise of:
    • Theory
    • Riskiest Assumption
    • Method
    • Prediction
    • Outcome
    • Decision
    • Cost
    • Learnings
  • Cost tracking
    • Per Experiment
    • Per Venture
    • Overall

Types Of Experiments:

I templated the main three experiment types that I usually run:

  • Market Experiment – Usually an overview how big the market is, how much traffic there is, how the market has grown so far.
  • Customer/Problem Experiment – If the market is attractive, I ask myself, what problems do these people really have? Depending on my theory and riskiest assumption I might do interviews or keyword research or – something I’ve fallen in love with – analyze Amazon customer reviews.
  • Problem/Solution Experiment – Knowing the problem, can I come up with a solution that is attractive to the customer segment?

Once I have nailed those three, I start running custom experiments for Acquisition, Activation, Retention and Revenue (but not earlier.)

If you look at my dashboard below, I’ve run 43 Experiments for 14 Ventures. As you’ll see, based on my learnings I aborted more than 2/3rds of my Ventures and continued on only a few promising ones.

I think that’s been a huge value for me. To know and to be sure when to persevere and when not.

So far, I’m quiet happy with it. It’s rudimentary but works.

And since the Venture Board was, in itself, an experiment for myself (My theory was that I’ll consistently use it to track my progress and costs) –

I’m persevering.

Thanks for reading!

How To Get Better At What You Do Every Day With Retrospectives

I mentioned the Retrospectives I have been doing for the past years.

Retros are great fun. I use them to improve myself and my work week-over-week. I love them.

In case you’re every interested in doing one, here are three templates that I use regularly. Both, by yourself and as a team.

They’re a lot of fun.

“Happy, Meh, Sad + Action Items”

The simplest one is “Happy, Meh, Sad + Action Items” (The one I told you about yesterday)

On a piece of paper, make the 4 columns, and for 10 minutes just write down what went well (Happy), what was so-so (Meh) and what isn’t going well (Sad). Then, go through the lists and think out loud what you can do to improve on it. Usually, that’s for the “Sad” column items.

“Start, Stop, More, Less, Keep”

On a piece of paper, draw the star and fill in the blanks around each piece. “What should I start doing, stop doing, do more of, do less of and what should I just keep doing?”

I love this one because almost all of it is super actionable.

“Sailboat to Paradise”

Great fun, helps figure out short-term and long-term goals.

Draw the picture on a piece of paper, and fill out the sections “Island: Where do I want to be? “, “Wind: What’s pushing me forward?”, “Anchor: What’s holding me back?”

It’s that simple. And, if you do them regularly and work on your action-items, you’ll see tremendous improvements for yourself and your team.

Calculating Nonces That Result In Zero-Padded SHA256 Hashes

Build Status

Full Github Repo here

Yesterday I watched Anders Brownworth’s awesome Blockchain demo and got inspired to follow along in Clojure.

I had to play around with implementing a toy (read: unoptimized!) algorithm to “mine” for nonces that, when added to the hashing input, produces n zeros at the beginning of the hash:

I came up with make-nonce-for-zeros-finder, a function which takes the numbers of zeros you want to have at the beginning and a maximum search-depth and returns a function that will calculate the right nonce for your inputs.

What I personally enjoyed about this little exercise was to express an iterative process in a simple recursive function. And to make a function-maker once I wanted to play around with different types of hashes/nonces I wanted to find.

(with-test
  (defn make-nonce-for-zeros-finder [z-count]
    (fn
      ([num data]
       ((make-nonce-for-zeros-finder z-count) num data 0))
      ([num data nonce]
       (cond (= (generate-zeros-string z-count) (subs (generate-hash num data nonce) 0 z-count)) nonce
             :else (recur num data (inc nonce))))))

  (is (= ((make-nonce-for-zeros-finder 1) nil nil) 39))
  (is (= ((make-nonce-for-zeros-finder 1) 1 nil) 25))
  (is (= ((make-nonce-for-zeros-finder 1) 1 1) 11))
  (is (= ((make-nonce-for-zeros-finder 1) "foo" "bar" 0) 20))
  (is (= ((make-nonce-for-zeros-finder 2) nil nil) 286))
  (is (= ((make-nonce-for-zeros-finder 4) nil nil) 88484))
  (is (= ((make-nonce-for-zeros-finder 4) 1 1) 64840))
  (is (= ((make-nonce-for-zeros-finder 4) "foo" "bar") 42515)))

With it, I can quickly create finders for different lengths of zero paddings:

(def find-nonce-for-one-zero-padded-hash
  (make-nonce-for-zeros-finder 1))

(def find-nonce-for-two-zeros-padded-hash
  (make-nonce-for-zeros-finder 2))

(def find-nonce-for-three-zeros-padded-hash
  (make-nonce-for-zeros-finder 3))

(def find-nonce-for-four-zeros-padded-hash
  (make-nonce-for-zeros-finder 4))

(def find-nonce-for-five-zeros-padded-hash
  (make-nonce-for-zeros-finder 5))

(def find-nonce-for-six-zeros-padded-hash
  (make-nonce-for-zeros-finder 6))

;; and so on...

With these guys set up, we can now calculate the nonce for hashes with 1, 2, 3, 4 and 5 zeros padded. Let’s see how that looks:

(find-nonce-for-one-zero-padded-hash "foo" "bar")
;; => 20
;; takes less than a millisecond

;; we can verify that the hash has one zero at the beginning:
(generate-hash "foo" "bar" 20)
;; => "0fdc57809f5917eba08907d2805e43ce83f4c933a090b4a2b2549923a35e43d7"

(find-nonce-for-two-zeros-padded-hash "foo" "bar")
;; => 102
;; takes less than a millisecond

;; we can verify that the hash has two zeros at the beginning:
(generate-hash "foo" "bar" 102)
;; => "006668bba91b7e2d5b5357b56600784edb77a72ecf86dc09d515853a841485f6"

(find-nonce-for-three-zeros-padded-hash "foo" "bar")
;; => 4663
;; takes less than a millisecond

;; we can verify that the hash has three zeros at the beginning:
(generate-hash "foo" "bar" 4663)
;; => "0005d9cd6c13fe6bf56e169fd2a7008003fc3a4c6539f8a1cf7d82975d00210e"

And that’s really all there is to it. Once you cross 6 padded zeros, you’ll notice an increase in time it takes to compute.

How to test

I’ve been a huge fan of the with-test macro. Because of that, you’ll find all test-coverage in core.clj instead of a separate “_test.clj” file.

To run all tests, use lein test

The Little Schemer in Clojure – Recap Chapter 6

Shadows

Using helper functions increases readability and helps abstract away representations.

In particular, the example is a simple calculating function value such as (value '(1 + (7 + 11)) ;; => 19

We can implement this with standard procedures and recursion:

(with-test
  (def value
    (fn [u] 
      (cond (atom? u) u
            (eq? (car (cdr u)) '+) (+ (value (car u))
                                          (value (car (cdr (cdr u)))))
            (eq? (car (cdr u)) '*) (- (value (car u))
                                           (value (car (cdr (cdr u)))))
            :else (int (java.lang.Math/pow (value (car u))
                                           (value (car (cdr (cdr u)))))))))

  (is (= (value 13) 13))
  (is (= (value '(1 + 3)) 4))
  (is (= (value '(1 + (3 pow 4))) 82)))

Now, you can already see a lot of visual noise. There is a lot of car-ing and cdr-ing about. If you squint your eyes a little, you’ll also notice that they all look similar. in fact, there is a lot of repetition in this function:

We see this pattern three times and each it’s along the lines of:

((eq? (car (cdr u)) 'OPERATOR) (OPERATOR (value (car u)) (value (car (cdr (cdr u))))))

Since we know that our “language” right now is infix arithmetic expressions such as

(1 + 2) and (1 + (4 * 999))

…we can extract helper functions that get the operator, the first sub expression - 1 and the second sub expression - 2 like so:

(with-test
  (def operator
    (fn [aexp]
      (car (cdr aexp))))

  (is (= (operator '()) nil))
  (is (= (operator '(1)) nil))
  (is (= (operator '(1 + )) '+))
  (is (= (operator '(1 + 2)) '+)))

(with-test
  (def first-sub-exp
    (fn [aexp]
      (car aexp)))

  (is (= (first-sub-exp '()) nil))
  (is (= (first-sub-exp '(1)) 1))
  (is (= (first-sub-exp '(1 + 2)) 1))
  (is (= (first-sub-exp '(2 + 1)) 2)))

(with-test
  (def second-sub-exp
    (fn [aexp] (car (cdr (cdr aexp)))))

  (is (= (second-sub-exp '()) nil))
  (is (= (second-sub-exp '(1)) nil))
  (is (= (second-sub-exp '(1 +)) nil))
  (is (= (second-sub-exp '(1 + 2)) 2))
  (is (= (second-sub-exp '(1 + 3)) 3)))

And then, since we have test-coverage already, refactor our value function to be…

(with-test
  (def value
    (fn [u] 
      (cond (atom? u) u
            (eq? (operator u) '+) (+ (value (first-sub-exp u))
                                          (value (second-sub-exp u)))
            (eq? (operator u) '*) (- (value (first-sub-exp u))
                                           (value (second-sub-exp u)))
            :else (int (java.lang.Math/pow (value (first-sub-exp u))
                                           (value (second-sub-exp u)))))))

  (is (= (value 13) 13))
  (is (= (value '(1 + 3)) 4))
  (is (= (value '(1 + (3 pow 4))) 82)))

Dandy. The new help functions help read this much better.

Changing Your Mind

Now, say, you wake up today and would like to change your newly-born arithmetic language to be written in prefix notation, such as (+ 1 2). In a way, I want to say:

I’ve changed my mind. Now, I want have (+ 1 2) express the common arithmetic expression that evaluates to 4.

The changes needed to make this happen are now trivial since we have used help functions to hide the representation of operator, first sub expression and second sub expression.

Simply changing the helper functions as follows implements the prefix notation without having to change our value function.

You have to adjust your tests accordingly, of course, and, in a way, doing so is as much as saying

“I want to change this and it should work as follows…”

(with-test
  (def operator
    (fn [aexp]
      (car aexp)))

  (is (= (operator '()) nil))
  (is (= (operator '(+)) '+))
  (is (= (operator '(+ 1)) '+)))

(with-test
  (def first-sub-exp
    (fn [aexp]
      (car (cdr aexp))))

  (is (= (first-sub-exp '()) nil))
  (is (= (first-sub-exp '(+)) nil))
  (is (= (first-sub-exp '(+ 1)) 1))
  (is (= (first-sub-exp '(+ 1 2)) 1)))

(with-test
  (def second-sub-exp
    (fn [aexp]
      (car (cdr (cdr aexp)))))

  (is (= (second-sub-exp '()) nil))
  (is (= (second-sub-exp '(+)) nil))
  (is (= (second-sub-exp '(+ 1)) nil))
  (is (= (second-sub-exp '(+ 1 2)) 2))
  (is (= (second-sub-exp '(+ 1 2 3)) 2)))

(with-test
  (def value-prefix
    (fn [nexp]
      (cond (atom? nexp) nexp
            (eq? (operator nexp) '+) (+ (value-prefix (first-sub-exp nexp))
                                         (value-prefix (second-sub-exp nexp)))
            (eq? (operator nexp) '*) (* (value-prefix (first-sub-exp nexp))
                                        (value-prefix (second-sub-exp nexp)))
            :else (int (java.lang.Math/pow (value-prefix (first-sub-exp nexp))
                                           (value-prefix (second-sub-exp nexp)))))))

  (is (= (value-prefix 1) 1))
  (is (= (value-prefix '(+ 1 3)) 4))
  (is (= (value-prefix '(+ 1 (* 2 2))) 5))
  (is (= (value-prefix '(+ 1 (pow 3 4))) 82)))

This is nice. We have changed values language by changing the helper functions without changing its own structure.

This way, we are able to demonstrate that we can represent the arithmetic expression 1 + 1 in several ways:

  • (+ 1 1) to make it feel lispy
  • (1 + 1) to make it feel ‘normal’ and
  • (1 1 +) if we wanted to accommodate friends that read from right to left more naturally

After all, they mean the same thing but in different ways.

Parental Controls – Braces as Numbers

Now, another example: Let’s say we wanted to represent numbers differently but wanted, as reasonable human beings, to maintain the idea of plus, minus, multiplication and division.

So, instead of using the numeral…

  • 0, I would like to use () (a list of zero items)
  • 1, I would like to use (()) (a list of one items)
  • 2, I would like to use (() ()) (a list of two items)
  • 3, I would like to use (() () ()) (a list of three items)
  • and so on…

In terms of API, I would like then to be able to write 1 + 1 as follows:

(+ '( () ) '( () ))
;; => 2

Clearly, the idea of addition or subtraction doesn’t change just because I’ve changed how I represent my numbers, right?

Our function to represent the operator + was

  (def + (fn [n m] 
                (cond (zero? m) n
                      :else (add1 (+ n (sub1 m))))))

To make our dream of (fairly unreadable) parenthesis number crunching real, all we have to do is rewrite our helper functions zero?, add1 and sub1 and we’re off to the races:

(with-test
  (def zero? 
    (fn [n] (null? n)))

  (is (= (zero? '()) true))
  (is (= (zero? '(())) false)))

(with-test
  (def add1
    (fn [n]
      (cons '() n)))
  (is (= (add1 '()) '(())))
  (is (= (add1 '(())) '(() ())))
  (is (= (add1 '(() ())) '(() () ()))))

(with-test
  (def sub1
    (fn [n] (cdr n)))

  (is (= (sub1 '()) '()))
  (is (= (sub1 '(())) '()))
  (is (= (sub1 '(() ())) '(()))))

(with-test
  (def + (fn [n m] 
            (cond (zero? m) n
                  :else (add1 (+ n (sub1 m))))))

  (is (= (+ '() '()) '()))
  (is (= (+ '(()) '())) '(()))
  (is (= (+ '(() ()) '(())) '(() () ()))))

Anyways, that’s what I’ve taken away from the chapter.

My Journey Into Deep Work – Retrospective Week 17

I spent this week in Mallorca with my parents. Stil I got to take time to sit down and get 13 (!) hours of deep work done.

Here’s my recap:

What went well

  • Still very inspired by “Amateurs vs. Pros
  • Feel like I’ve made good progress
  • 1 Focus for the week: Work through “The Little Schemer” in Clojure. Finished Chapter 1 – 4.
  • Wrote and published 4 blogposts
  • Daily Yoga and especially Pranayama exercises
  • Had an idea for a meditation video
  • Very happy with my Psycho-Cybernetic Imagineering script rehearsals
  • Cooking good food with the family
  • Have a fireplace at home
  • Have a minimal but functional work-space set up

What went okay

  • Didn’t spend a lot of time outside, especially when there’s the mediterranean just across from me.
  • “Give and Take” is getting harder to read
  • Access to internet only sometimes
  • Still jumping a lot from idea to idea
  • Didn’t celebrate/appreciate/acknowledge my progress
  • Didn’t edit the blogposts
  • Lost interest in RedditGrowth while it still could become something valuable

What went bad

  • Have procrastinated on writing the meet up summary
  • Too reserved talking about my feelings with my parents

Action items

  • Take a daily walk
  • Celebrate successes and progress more often
  • Edit posts before publishing
  • Make a decision if I want to continue reading “Give and Take”

My Journey Into Deep Work – Retrospective Week 16

I managed to work deeply for 9.5 hours. I also traveled over the weekend, so my week was a bit shot.

Also, I have decided to extend my retros to look at my overall life not just deep work. Since I am independent right now, I want to make sure I maximize my time spent and minimize distractions.
I figured that “Life Retro” combined with action items to improve myself every week is a good idea.

What went well

  • Using my Psycho-Cybernetics Imagineering script
  • It was easy to get into work-flow
  • With everything considered, 9.5 hours is still great!
  • Traveled to Mallorca to see my parents 🙂
  • Had good insight into my “stop-and-go” way of working
  • Had a good mentoring session with my friend Philip on Friday
  • Overall, I have a more positive outlook on my life than last week
  • Inspired by reading “Give and Take” [1]
  • Inspired by “Amateurs vs. Pros” [2]
  • Got up most days before 9am
  • Getting back into a daily Yoga and Meditation routine
  • I fixed my vaporizer myself
  • Feeling less distracted
  • Got to hang out with Nina for an afternoon 🙂
  • Went out to a cool bar on Friday with friends
  • Made bubbles again
  • Cooked delicious food with my father

What went okay

  • I didn’t follow up on my Whiteboard experiment
  • I haven’t followed up on the Meetup idea I had
  • There was a lot of organizational stuff this week
  • Waiting for my accountant on paperwork
  • The dating-pool in Berlin is rough. Didn’t do well to my self-image
  • Didn’t hear back from someone I needed information from

What went bad

  • I still don’t have one specific idea/topic that I want to deep-dive into. Instead I jump around from idea to idea.
  • Jumping between tasks and ideas is exhausting.

Action Items

  • Choose 1 main point of focus for coming week
  • Buy a yoga mat while in Mallorca to continue practice there
  • Create a visible backlog of tasks

[1] https://www.amazon.com/dp/B00AFPTSI0/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1
[2] https://medium.com/the-mission/the-7-differences-between-professionals-and-amateurs-f8efc4840861

Thinking and Sleeping Better With Clojure

To prioritize a list of todo-items, as in my Prioritization-app I recently launched, I needed to get a list of the unique combinations for the user to choose from:

It goes a little bit like this:

Which is more important: A or B?
Which is more important: A or C?
Which is more important: B or C?

I wrote a version in Ruby for the app and then a sketch in Clojure to compare readability and expressiveness.

In my opinion, the Clojure version is much more readable and was far easier to reason about.

Probably because I’m not good to solve problems in Ruby but there might be more than meets the eye here.

Creating Comparisons

Let’s say I have a todo-list of A, B, C and D.

The list of comparisons I want is A ↔ B, A ↔ C, A ↔ D, B ↔ C, B ↔ D and C ↔ D to use later in my app.

From the matrix below, you can see, I want only the unique comparisons (A ↔ B and B ↔ A are interchangeable for my purposes) and skip dupes that compare an element with itself (A ↔ A, B ↔ B, C ↔ C, D ↔ D)

To demonstrate, I only want the top-right triangle of comparisons:

× A B C D
A skip (dupe) A ↔ B A ↔ C A ↔ D
B skip skip (dupe) B ↔ C B ↔ D
C skip skip skip (dupe) C ↔ D
D skip skip skip skip (dupe)

Thinking, Testing and Implementing in Ruby

Now, since I started the app in Ruby, I translated the behavior above as follows:

describe '.unique_combinations' do
    context 'input list is empty' do
      it 'returns an empty list' do
        result = Combinator.unique_combinations([])
        expect(result).to eq([])
      end
    end

    context 'input list only has one element' do
      it 'returns an empty list' do
        result = Combinator.unique_combinations([1])
        expect(result).to eq([])
      end
    end

    context 'input list only has two elements' do
      it 'returns a list with combination a' do
        result = Combinator.unique_combinations([1, 2])
        expect(result).to eq([[1,2]])
      end

      it 'returns a list with combination b' do
        result = Combinator.unique_combinations([:foo, :bar])
        expect(result).to eq([[:foo, :bar]])
      end
    end

    context 'input list only has three elements' do
      it 'returns a list with 3 combinations' do
        result = Combinator.unique_combinations([1, 2, 3])
        expect(result).to eq([[1, 2], [1, 3], [2, 3]])
      end
    end

    context 'input list only has four elements' do
      it 'returns a list with 6 combinations' do
        result = Combinator.unique_combinations([1, 2, 3, 4])
        expect(result).to eq([[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]])
      end
    end
  End
end

…and wrote, after several failed attempts and one sleepless night, the following, working but not very elegant solution. I felt weird about it, because even looking at it now, I can’t fully explain it well. It works, it has reasonable test-coverage. But I’m not proud of it.

def self.unique_combinations(ids)
    return [] if ids.length < 2

    all_combinations = []

    for i1 in ids
      for i2 in ids
        if i1 != i2
          contains = false
          for c in all_combinations
            if c[1] == i1 and c[0] == i2
              contains = true
            end
          end
          unless contains
            all_combinations << [i1, i2]
          end
        end
      end
    end

    return all_combinations
  end

Okay, fine I thought. How would I solve this issue in Lisp?

Thinking, Testing and Implementing in Clojure

I don’t know why but thinking in terms of lists and recursion instead of iteration made it simpler for me.

The top-level function works as follows:

(final-combinations '(A B C D)) 
;; => '((A B) (A C) (A D) (B C) (B D) (C D))

Yup, that’s the list I want.
Thinking about it I had an idea to break the problem further down:

The complete list of unique comparisons, the one I want, is…

  1. the union of each row of one element combined with all the others. That’s A combined with B, C and D
  2. Each row has an increasing offset from the left that starts at 0 for row 1 and increases by 1 for each following row.
  3. I have to subtract the dupes such as A ↔ A because I don’t need them.

For illustration purposes, here is the table again:

× A B C D
A skip (dupe) A ↔ B A ↔ C A ↔ D
B skip skip (dupe) B ↔ C B ↔ D
C skip skip skip (dupe) C ↔ D
D skip skip skip skip (dupe)

Given the above 3 steps, I basically just wrote them out as functions.

I derived the first function, combine which takes x and l and returns a list of all possible combinations, including the ones we’ll later skip.

(with-test 
  (defn combine 
    ([x l] 
     (combine x l '()))
    ([x l acc]
     (cond (empty? l) (reverse acc)
           :else (recur x (rest l) (conj acc (list x (first l)))) )))

  (is (= (combine 1 '()) '()))
  (is (= (combine 1 '(1)) '((1 1))))
  (is (= (combine 1 '(2)) '((1 2))))
  (is (= (combine 1 '(1 2)) '((1 1) (1 2))))
  (is (= (combine 1 '(1 2 3)) '((1 1) (1 2) (1 3)))))

Then, I use combine to create basically the table above but with nothing yet removed.

(with-test
  (defn combine-lists 
    ([l1 l2] 
     (combine-lists l1 l2 '()))
    ([l1 l2 acc]
     (cond (empty? l1) (reverse acc)
           :else (recur (rest l1) l2 (cons (combine (first l1) l2) acc)) )))

  (is (= (combine-lists '() '()) '()))
  (is (= (combine-lists '(1) '(1)) '(((1 1)))))
  (is (= (combine-lists '(1 2) '(1 2)) '(((1 1) (1 2)) 
                                         ((2 1) (2 2))))))

Then I introduce the idea of an offset. To only take those elements in a list that are after a certain offset.

(with-test
  (defn take-rest
    ([offset l]
     (cond (= offset 0) l
           :else (recur (dec offset) (rest l)))))

  (is (= (take-rest 0 '()) '()))
  (is (= (take-rest 1 '()) '()))
  (is (= (take-rest 0 '(1)) '(1)))
  (is (= (take-rest 0 '(1 2)) '(1 2)))
  (is (= (take-rest 1 '(1 2)) '(2)))
  (is (= (take-rest 1 '(1 2 3)) '(2 3)))
  (is (= (take-rest 2 '(1 2 3)) '(3)))
  (is (= (take-rest 2 '(1 2 3 4)) '(3 4))))

Now I can use take-rest and apply it to each row in my matrix…

(defn unique-combinations 
  ([offset ll] 
   (unique-combinations offset ll '()))
  ([offset ll acc]
   (cond (empty? ll) (reverse acc)
         :else (recur (inc offset) (rest ll) (cons (take-rest offset (first ll)) acc)))))

And finally remove the identity items such as A ↔ A

(with-test
  (defn final-combinations 
    [l]
    (filter #((= (first %) (second %)))) (partition 2 (flatten (unique-combinations 1 (combine-lists l l)))))

  (is (= (final-combinations '()) '()))
  (is (= (final-combinations '(1)) '()))
  (is (= (final-combinations '(1 2)) '((1 2))))
  (is (= (final-combinations '(1 2 3)) '((1 2) (1 3) (2 3))))
  (is (= (final-combinations '(1 2 3 4)) '((1 2) (1 3) (1 4) (2 3) (2 4) (3 4)))))

Granted, this code is not yet refactored and in total more lines than the Ruby version, but here is the rub:

It took me 20 minutes to think up and implement the solution in Clojure and 2 days including a sleepless night to do it in Ruby.

I don’t know what that means but I’ll probably use a Lisp like Clojure for problems like this in the future. Just to make sure I get some sleep.

Set Your Priorities Straight In 2 Minutes Without Thinking Hard

“I have so much to do but I’m not sure which of the things I should do first.”

If you, like me, have struggled with figuring out what should be my #1 priority, then I have good news.

Prioritizing is hard, especially when your items can be important and/or urgent. The app that I just released gives you the answer to:

What’s the most important and urgent thing I should do next? (The answer might surprise you!)

I would like to have someone help me with this and say to me:

Your most important and urgent next step is… Make a balance sheet

Now, I just released a simple web-app that helps you (and me) prioritize a list (a todo-list, a list of chores, whatever you want) by two measures:

Importance and Urgency. Some things are important, some are urgent. And some are both. Make sure you tackle the one that’s both first.

The app guides you through comparing each item with each other based on both measures and comes up with the math and sorting automatically.

Here’s the result for the tasks I had on my list today:

Clearly, I need to create my balance sheet. After that I can do the other stuff.

The process is simple.

Go to the homepage and click the start button

Then, insert your list of tasks like so:

Then, the app will guide you through comparing each item with each other. This is called a binary sort and will make sure that what item is at the top is really the most important and urgent one.

Finally, you’ll see your result.

Now, what are you waiting for? Get your priorities straight in a few short minutes and tackle your next, most important and urgent task right away.

Click here: https://prioio.herokuapp.com

Have fun!

Alexis

*

PS: You can check out the source at https://github.com/akaalias/prio in case you want to poke around a bit.

PPS: Let me know if you, too, have found a surprising result of your top priority after sorting.

The Little Schemer in Clojure – Recap Chapter 5

Oh My Gawd, It’s Full Of Stars

Dealing With Nested Lists

Learned how to deal with nested lists by asking at least 3 questions:

  • Is the list null? If so, return the empty element (an empty list if the value of the function is to be a list, or 0 if you’re evaluating to a number)
  • Is the first element in the list an atom? – If so, operate on that atom and cons it onto the natural recursion of the function.
  • Else, cons the natural recursion of the function of car list onto the natural recursion of the function of cdr list

You can see this pattern in action on rember* which removes any occurrence of a in l regardless of how deep as are hidden in the nested list. (*, or star is added to the function name to denote that it’s recurring on both, car and cdr.)

(with-test
  (def rember* 
    (fn [a l]
      (cond (null? l) '()
            (atom? (car l)) (cond (eq? (car l) a) (rember* a (cdr l))
                                  :else (cons (car l)
                                              (rember* a (cdr l))))
            :else (cons (rember* a (car l))
                        (rember* a (cdr l))))))

  (is (= (rember* 'cup '()) '()))
  (is (= (rember* 'cup '(coffee)) '(coffee)))
  (is (= (rember* 'cup '(cup)) '()))
  (is (= (rember* 'cup '(coffee cup)) '(coffee)))
  (is (= (rember* 'cup '((cup))) '(())))
  (is (= (rember* 'cup '(coffee (cup) and (another) cup)) '(coffee () and (another))))
  (is (= (rember* 'sauce '(((tomato sauce)) ((bean) sauce) (and ((flying)) sauce))) '(((tomato)) ((bean)) (and ((flying)))))))

The same applies to insertR and insertL* which respectively return a new list with new inserted next to to old in l.

The questions are again:

  • null? – return an empty list that can be cons-ed onto from previous calls
  • atom? – checks if car l is what we’re looking for and if so, adds a new element
  • else – recurs on both car l and cdr l
(with-test
  (def insertR*
    (fn [new old l]
      (cond (null? l) '()
            (atom? (car l)) (cond (eq? (car l) old) (cons old 
                                                          (cons new (insertR* new old 
                                                                              (cdr l))))

                                  :else (cons (car l) 
                                              (insertR* new old 
                                                        (cdr l))))
            :else (cons (insertR* new old (car l))
                        (insertR* new old (cdr l))))))

  (is (= (insertR* 'new 'old '()) '()))
  (is (= (insertR* 'new 'old '(old)) '(old new)))
  (is (= (insertR* 'new 'old '((old))) '((old new))))
  (is (= (insertR* 'new 'old '((these) old ((shoes old) perfume))) '((these) old new ((shoes old new) perfume)))))
(with-test
  (def insertL*
    (fn [new old l] 
      (cond (null? l) '()
            (atom? (car l)) (cond (eq? (car l) old) (cons new (cons old (insertL* new old (cdr l))))
                                  :else (cons (car l) (insertL* new old (cdr l))))
            :else (cons (insertL* new old (car l))
                        (insertL* new old (cdr l))))))

  (is (= (insertL* 'new 'old '()) '()))
  (is (= (insertL* 'new 'old '(old)) '(new old)))
  (is (= (insertL* 'new 'old '((old))) '((new old))))
  (is (= (insertL* 'new 'old '((these) old ((shoes old) perfume))) '((these) new old ((shoes new old) perfume)))))

Then, the same pattern applies to subst* which substitutes new with old in l

(with-test 
  (def subst*
    (fn [new old l] 
      (cond (null? l) '()
            (atom? (car l)) (cond (eq? (car l) old) (cons new (subst* new old (cdr l)))
                                  :else (cons (car l) (subst* new old (cdr l))))
            :else (cons (subst* new old (car l))
                        (subst* new old (cdr l))))))

  (is (= (subst* 'orange 'banana '()) '()))
  (is (= (subst* 'orange 'banana '(banana)) '(orange)))
  (is (= (subst* 'orange 'banana '((banana))) '((orange))))
  (is (= (subst* 'cup 'mug '((a mug) in the (((kitchen (mug)))))) '((a cup) in the (((kitchen (cup))))))))

Then, member* returns true if a can be found in l, otherwise it returns false:

Note that instead of returning a list on (null l) it returns false which represents that the element couldn’t be found and we’ve reached the end where we can’t look no further.

(with-test
  (def member* 
    (fn [a l] 
      (cond (null? l) false
            (atom? (car l)) (or (eq? (car l) a)
                                (member* a (cdr l)))
            :else (or (member* a (car l))
                      (member* a (cdr l))))))

  (is (= (member* 'foo '()) false))
  (is (= (member* 'foo '(foo)) true))
  (is (= (member* 'foo '(bar)) false))
  (is (= (member* 'foo '((foo))) true))
  (is (= (member* 'foo '((the quick) ((((brown (springy foo)) jumps over)) the dog))))))

Traversing a Tree

A personal favorite of mine is leftmost which returns the left-most element in l. It’s a bit simpler than the functions before. It recurs only on (car l) unless it is an atom:

(with-test
  (def leftmost 
    (fn [l]
      (cond (null? l) nil
            (atom? (car l)) (car l)
            :else (leftmost (car l)))))

  (is (= (leftmost '()) nil))
  (is (= (leftmost '(apple)) 'apple))
  (is (= (leftmost '((apple))) 'apple))
  (is (= (leftmost '(((hot cider) with (green) tea))) 'hot)))

Testing equality

At the end of the chapter, the authors use recurring on a nested list to test for equality of any s-expression:

(with-test
  (def eqlist?
    (fn [l1 l2] 
      (cond (and (null? l1) (null? l2)) true
            (or (null? l1) (null? l2)) false
            :else (and (equal? (car l1) (car l2))
                       (eqlist? (cdr l1) (cdr l2))))))

  (is (= (eqlist? '() '()) true))
  (is (= (eqlist? '() '(foot)) false))
  (is (= (eqlist? '(foot) '()) false))
  (is (= (eqlist? '(foot) '(foot)) true))
  (is (= (eqlist? '(foot rub) '(foot sub)) false))
  (is (= (eqlist? '(strawberry ice cream) '(strawberry ice cream)) true))
  (is (= (eqlist? '(strawberry ice cream) '(strawberry cream ice)) false))
  (is (= (eqlist? '((coffee) (cup)) '((coffee) (cup))) true)))

(with-test
  (def equal? 
    (fn [s1 s2]
      (cond (and (atom? s1) (atom? s2)) (equan? s1 s2)
            (or (atom? s1) (atom? s2)) false
            :else (eqlist? s1 s2))))

  (is (= (equal? 'a 'a) true))
  (is (= (equal? 'a 'b) false))
  (is (= (equal? 'a '(a)) false))
  (is (= (equal? '(a) 'a) false))
  (is (= (equal? '(a) '(a)) true))
  (is (= (equal? '(a) '(b)) false)))

I am starting to realize how great it is to have a set of tests right away with any function definition. Refactoring will be easy and give me confidence that everything still works. Pretty stoked!

The Little Schemer in Clojure – Chapter 4 Recap

Number Games

I’ve enjoyed working through chapter 4. It’s simpler and more dense at the same time since it’s all about numbers. Over the course of this chapter I (re)implemented several arithmetic basic functions such as add1, sub1 – Those were rather helper functions – and moved on to implementing pluss and minuss, multiply and divide (I added the extra “s” to pluss and minuss to avoid redefining built-in functions).

The cool thing about this chapter is that I was able to implement these functions only in terms of very simple operations (add1, sub1) and recursion.

For example, pluss works as follows:

Given n and m, I want to evaluate their sum. For that to happen, I need to ask two questions:

  • Is m equal to 0? If so, return n. This would make an addition such as 1 + 0 work straight away.
  • Else, add1 to the natural recursion of pluss with n and (sub1 m). This counts m down with each recursion until it reaches 0.

If we were to add 1 and 3, the result of 4 would be calculated as:

(pluss 1 3)
1 + (pluss 1 2)
1 + 1 + (pluss 1 1)
1 + 1 + 1 (pluss 1 0)
1 + 1 + 1 + 1

Pretty cool.

(with-test
  (def pluss
    (fn [n m]
      (cond (zero? m) n
            :else (add1 (pluss n (sub1 m))))))

  (is (= (pluss 0 0) 0))
  (is (= (pluss 1 0) 1))
  (is (= (pluss 0 1) 1))
  (is (= (pluss 1 1) 2))
  (is (= (pluss 1 2) 3))
  (is (= (pluss 46 12) 58)))

For every function I write, I also make sure I start with the smallest possible test-case and then only add the code necessary to fix that test. I quiet enjoy it because it gives me confidence that, once I refactor, the functions still work.

For example, take occur which takes an atom a and a list lat as its arguments and returns the count of a in lat.

To build the simple algorithm, I start out writing the bare minimum setup for the first, smallest test:

(with-test
  (def occur
    (fn [a lat]))

  (is (= (occur 'a '()) 0)))

Running the test will fail since the function currently, and intentionally, only returns nil and not 0 when given 'a and '() as its inputs.

I can fix this situation by writing the smallest possible solution which is to return 0, hardcoded:

(with-test
  (def occur
    (fn [a lat] 0))

  (is (= (occur 'a '()) 0)))

Our first test will now pass. We could, if we wanted to, make a commit at this point. On to the next.

(with-test
  (def occur
    (fn [a lat] 0))

  (is (= (occur 'a '()) 0))
  (is (= (occur 'a '(a)) 1)))

Running the tests will now fail for scenario 2 when we expect to receive 1 as the value and not 0. The smallest fix to solve for this is to introduce a conditional.

(with-test
  (def occur
    (fn [a lat]
      (cond (null? lat) 0
            :else 1)))

  (is (= (occur 'a '()) 0))
  (is (= (occur 'a '(a)) 1)))

Great! All tests are passing now. Now, on to the next, simplest test-case where (occur 'a '(b)) should evaluate to 0.

(with-test
  (def occur
    (fn [a lat]
      (cond (null? lat) 0
            :else 1)))

  (is (= (occur 'a '()) 0))
  (is (= (occur 'a '(a)) 1))
  (is (= (occur 'a '(b)) 0)))

The third test fails naturally. To fix it, I now have to introduce a new condition to check if (car lat) is equal to a:

(with-test
  (def occur
    (fn [a lat]
      (cond (null? lat) 0
            (equan? (car lat) a) 1
            :else 0)))

  (is (= (occur 'a '()) 0))
  (is (= (occur 'a '(a)) 1))
  (is (= (occur 'a '(b)) 0)))

Now, let’s test for multiple occurrences of a in lat: (is (= (occur 'a '(a a)) 2))

(with-test
  (def occur
    (fn [a lat]
      (cond (null? lat) 0
            (equan? (car lat) a) 1
            :else 0)))

  (is (= (occur 'a '()) 0))
  (is (= (occur 'a '(a)) 1))
  (is (= (occur 'a '(b)) 0))
  (is (= (occur 'a '(a a)) 2)))

The test will fail when run. Now we have to fix it by introducing adding 1 to the natural recursion of the function as follows: (add1 (occur a (cdr lat)))

(with-test
  (def occur
    (fn [a lat]
      (cond (null? lat) 0
            (equan? (car lat) a) (add1 (occur a (cdr lat)))
            :else 0)))

  (is (= (occur 'a '()) 0))
  (is (= (occur 'a '(a)) 1))
  (is (= (occur 'a '(b)) 0))
  (is (= (occur 'a '(a a)) 2)))

Splendid, all tests are passing.

Now, I want to make sure that we get the right result, when the list is mixed, such as (is (= (occur 'a '(a b c a)) 2))

(with-test
  (def occur
    (fn [a lat]
      (cond (null? lat) 0
            (equan? (car lat) a) (add1 (occur a (cdr lat)))
            :else 0)))

  (is (= (occur 'a '()) 0))
  (is (= (occur 'a '(a)) 1))
  (is (= (occur 'a '(b)) 0))
  (is (= (occur 'a '(a a)) 2))
  (is (= (occur 'a '(a b c a)) 2)))

Adding the test makes it fail of course, since we’re not accounting for this scenario. It’s a simple fix, we need to allow our :else branch to continue searching for as with (occur a (cdr lat)). The final solution to occur is

(with-test
  (def occur
    (fn [a lat]
      (cond (null? lat) 0
            (equan? (car lat) a) (add1 (occur a (cdr lat)))
            :else (occur a (cdr lat)))))

  (is (= (occur 'a '()) 0))
  (is (= (occur 'a '(a)) 1))
  (is (= (occur 'a '(b)) 0))
  (is (= (occur 'a '(a a)) 2))
  (is (= (occur 'a '(a b c a)) 2)))

I think this is pretty cool. We’ve got a first set of reasonable inputs and outputs covered. This would be a great time to run the full test-suite with lein test, and if everything passes, make a commit and push to master. For this I usually make myself a tiny script named ship.sh that runs the test-suite one final time and does the git push for me:

ship.sh

#!/bin/bash

lein test && git push origin master

Nothing fancy, but it keeps me from habitually doing a git push origin master without running all tests beforehand.

Anyways, I enjoyed showing you how I build my functions with TDD and baby-steps to arrive at a good place to commit and push. The full listing of my (un-refactored) chapter 4 is as follows:

(ns the-little-clojurian.chapter4
  (:require [clojure.test :refer :all]
            [the-little-clojurian.chapter1 :refer :all]
            [the-little-clojurian.chapter2 :refer :all]
            [the-little-clojurian.chapter3 :refer :all]))

(with-test 
  (def add1 
    (fn [x] (+ x 1)))

  (is (= (add1 0) 1))
  (is (= (add1 67) 68))
  (is (= (add1 68) 69)))

(with-test
  (def sub1
    (fn [x] (- x 1)))

  (is (= (sub1 0) -1))
  (is (= (sub1 1) 0))
  (is (= (sub1 2) 1))
  (is (= (sub1 3) 2)))

(with-test
  (def pluss
    (fn [n m]
      (cond (zero? m) n
            :else (add1 (pluss n (sub1 m))))))

  (is (= (pluss 0 0) 0))
  (is (= (pluss 1 0) 1))
  (is (= (pluss 0 1) 1))
  (is (= (pluss 1 1) 2))
  (is (= (pluss 1 2) 3))
  (is (= (pluss 46 12) 58)))

(with-test
  (def minuss 
    (fn [n m]
      (cond 
       (zero? m) n
       :else (sub1 (minuss n (sub1 m))))))

  (is (= (minuss 0 0) 0))
  (is (= (minuss 1 1) 0))
  (is (= (minuss 2 1) 1))
  (is (= (minuss 3 2) 1))
  (is (= (minuss 100 1) 99)))

(with-test
  (def tup?
    (fn [l] 
      (cond (null? l) true
            (not (number? (car l))) false
            :else (tup? (cdr l)))))

  (is (= (tup? '()) true))
  (is (= (tup? '(a)) false))
  (is (= (tup? '(1)) true))
  (is (= (tup? '(1 a)) false))
  (is (= (tup? '(1 2)) true))
  (is (= (tup? '(2 11 3 79 47 6))))
  (is (= (tup? '(8 55 5 555))))
  (is (= (tup? '(1 2 8 apple 4 3)) false))
  (is (= (tup? '(3 (7 4) 13 9)) false)))

(with-test
  (def addtup 
    (fn [tup] 
      (cond (null? tup) 0
            :else (pluss (car tup) (addtup (cdr tup))))))

  (is (= (addtup '()) 0))
  (is (= (addtup '(1)) 1))
  (is (= (addtup '(1 2)) 3))
  (is (= (addtup '(1 2 3)) 6))
  (is (= (addtup '(3 5 2 8)) 18))
  (is (= (addtup '(15 6 7 12 3)) 43)))

(with-test
  (def multiply 
    (fn [n m]
      (cond (zero? m) 0
            :else (pluss n (multiply n (sub1 m))))))

  (is (= (multiply 0 0) 0))
  (is (= (multiply 1 1) 1))
  (is (= (multiply 1 0) 0))
  (is (= (multiply 5 3) 15))
  (is (= (multiply 13 4) 52)))

(with-test
  (def tup+ 
    (fn [tup1 tup2]
      (cond (null? tup1) tup2
            (null? tup2) tup1
            :else (cons (pluss (car tup1) (car tup2)) 
                        (tup+ 
                         (cdr tup1) (cdr tup2))))))

  (is (= (tup+ '() '()) '()))
  (is (= (tup+ '(1) '(1)) '(2)))
  (is (= (tup+ '(2 3) '(4 6)) '(6 9)))
  (is (= (tup+ '(3 6 9 11 4) '(8 5 2 0 7)) '(11 11 11 11 11)))
  (is (= (tup+ '(3 7) '(4 6 8 1)) '(7 13 8 1))))

(with-test
  (def greater-than
    (fn [n m] false
      (cond (zero? n) false
            (zero? m) true
            :else (greater-than (sub1 n) (sub1 m)))))

  (is (= (greater-than 0 0) false))
  (is (= (greater-than 1 0) true))
  (is (= (greater-than 12 133) false))
  (is (= (greater-than 120 11) true))
  (is (= (greater-than 4 6) false)))

(with-test
  (def smaller-than
    (fn [n m] 
      (cond (zero? m) false
            (zero? n) true
            :else (smaller-than (sub1 n) (sub1 m)))))

  (is (= (smaller-than 0 0) false))
  (is (= (smaller-than 0 1) true))
  (is (= (smaller-than 4 6))))

(with-test
  (def equal 
    (fn [n m] 
      (cond (smaller-than n m) false
            (greater-than n m) false
            :else true)))

  (is (= (equal 0 0) true))
  (is (= (equal 0 1) false))
  (is (= (equal 1 1) true))
  (is (= (equal 44 44) true)))

(with-test
  (def expt 
    (fn [n m]
      (cond (zero? m) 1
            :else (multiply n (expt n (sub1 m))))))

  (is (= (expt 1 1) 1))
  (is (= (expt 2 2) 4))
  (is (= (expt 2 3) 8))
  (is (= (expt 5 3) 125)))

(with-test
  (def divide
    (fn [n m]
      (cond (zero? m) (throw (IllegalArgumentException.))
            (smaller-than n m) 0
            :else (add1 (divide (minuss n m) m)))))
  (is (= (divide 0 1) 0))
  (is (thrown? IllegalArgumentException (divide 1 0)))
  (is (= (divide 15 4) 3))
  (is (= (divide 15 3) 5))
  (is (= (divide 100 10) 10)))

(with-test
  (def length 
    (fn [lat] 
      (cond (null? lat) 0
            :else (add1 (length (cdr lat))))))

  (is (= (length '()) 0))
  (is (= (length '(hotdogs)) 1))
  (is (= (length '(hotdogs with mustard sauerkraut and pickles)) 6))
  (is (= (length '(ham and cheese on rye)) 5)))

(with-test 
  (def pick 
    (fn [n lat] 
      (cond (zero? n) nil
            (one? n) (car lat)
            :else (pick (sub1 n) (cdr lat)))))

  (is (= (pick 0 '(apple)) nil))
  (is (= (pick 1 '()) nil))
  (is (= (pick 1 '(apple)) 'apple))
  (is (= (pick 2 '(apple bananas)) 'bananas))
  (is (= (pick 4 '(apple)) nil)))

(with-test
  (def rempick 
    (fn [n lat]
      (cond (zero? n) nil
            (one? n) (cdr lat)
            :else (cons (car lat) 
                        (rempick (sub1 n) 
                                 (cdr lat))))))

  (is (= (rempick 0 '()) nil))
  (is (= (rempick 1 '(apple)) '()))
  (is (= (rempick 2 '(apple bananas gin)) '(apple gin))))


(with-test 
  (def no-nums 
    (fn [lat]
      (cond (null? lat) '()
            (number? (car lat)) (no-nums (cdr lat))
            :else (cons (car lat) 
                        (no-nums 
                         (cdr lat))))))

  (is (= (no-nums '()) '()))
  (is (= (no-nums '(1)) '()))
  (is (= (no-nums '(apple)) '(apple)))
  (is (= (no-nums '(5 pears 6 prunes 9 dates)) '(pears prunes dates))))

(with-test
  (def all-nums
    (fn [lat]
      (cond (null? lat) '()
            (number? (car lat)) (cons (car lat)
                                      (all-nums (cdr lat)))
            :else (all-nums (cdr lat)))))

  (is (= (all-nums '()) '()))
  (is (= (all-nums '(1)) '(1)))
  (is (= (all-nums '(apple)) '()))
  (is (= (all-nums '(1 apple 2 pears 3 bananas)) '(1 2 3))))

(with-test
  (def equan?
    (fn [a1 a2]
      (cond (and (number? a1) (number? a2)) (equal a1 a2)
            (or (number? a1) (number? a2)) false
            :else (eq? a1 a2))))

  (is (= (equan? 0 0) true))
  (is (= (equan? 0 1) false))
  (is (= (equan? 0 'a) false))
  (is (= (equan? 'a 'a) true))
  (is (= (equan? 'a 'b) false)))

(with-test
  (def occur
    (fn [a lat] 
      (cond (null? lat) 0
            (equan? (car lat) a) (add1 (occur a (cdr lat)))
            :else (occur a (cdr lat)))))

  (is (= (occur 'a '()) 0))
  (is (= (occur 'a '(a)) 1))
  (is (= (occur 'a '(b)) 0))
  (is (= (occur 'a '(a a)) 2))
  (is (= (occur 'a '(a b c a)) 2))
  (is (= (occur 'a '(b c d e)) 0)))

(with-test
  (def one?
    (fn [x] (equal x 1)))

  (is (= (one? 0) false))
  (is (= (one? 1) true))
  (is (= (one? 2) false)))