I've just watched this wonderful practical demonstration of using connascence to guide the refactoring step of TDD by James Jeffries and Kevin Rutherford:
These are the slides.
These other slides explain more about each type of connascence.
Record of experiments, readings, links, videos and other things that I find on the long road.
Registro de experimentos, lecturas, links, vídeos y otras cosas que voy encontrando en el largo camino.
Sunday, May 31, 2015
Friday, May 29, 2015
Interesting Talk: "Integrated Tests Are A Scam"
I've just watched a newer version of this wonderful talk by J. B. Rainsberger:
Compare it with this old version of the same talk
Thursday, May 28, 2015
Interesting Talk: "The New New Software Development Game"
I've just watched this wonderful talk by Mary Poppendieck:
Tuesday, May 26, 2015
Interesting Talk: "Functional Programming Design Patterns"
I've just watched this wonderful talk by Scott Wlaschin:
Monday, May 25, 2015
Interesting Talk: "Design Patterns in Dynamic Languages"
I've just watched this great talk by Neal Ford:
Wednesday, May 20, 2015
Exercism: "Queen Attack in Clojure"
I solved the Queen Attack problem in Clojure.
This is my solution:
I think that the can-attack function should be called can-attack?. I've kept its original name because it's being exercised from the tests given by Exercism.
You can nitpick the solution here and/or see all the exercises I've done so far in this repository.
This is my solution:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns queen-attack | |
(:require [clojure.string :as clj-str])) | |
(def ^:private empty-board | |
(vec (repeat 8 (vec (repeat 8 "O"))))) | |
(defn- add-to-board [position representation board] | |
(if position | |
(assoc-in board position representation) | |
board)) | |
(defn- board [{white-queen-position :w black-queen-position :b}] | |
(->> empty-board | |
(add-to-board white-queen-position "W") | |
(add-to-board black-queen-position "B"))) | |
(defn board-string [queens] | |
(str (clj-str/join | |
"\n" | |
(map #(clj-str/join " " %) (board queens))) | |
"\n")) | |
(defn- in-same-rank? [[white-queen-rank _] [black-queen-rank _]] | |
(= white-queen-rank black-queen-rank)) | |
(defn- in-same-column? [[_ white-queen-col] [_ black-queen-col]] | |
(= white-queen-col black-queen-col)) | |
(defn- in-same-diagonal? [[white-queen-rank white-queen-col] | |
[black-queen-rank black-queen-col]] | |
(= 1 (quot (- white-queen-rank black-queen-rank) | |
(- white-queen-col black-queen-col)))) | |
(defn can-attack [{white-queen-pos :w black-queen-pos :b}] | |
(or (in-same-column? white-queen-pos black-queen-pos) | |
(in-same-rank? white-queen-pos black-queen-pos) | |
(in-same-diagonal? white-queen-pos black-queen-pos))) |
You can nitpick the solution here and/or see all the exercises I've done so far in this repository.
Exercism: "Robot Simulator in Clojure"
I solved the Robot Simulator problem in Clojure.
This is my solution:
I think that the turn-right and turn-left functions aren't necessary. I've kept them because they are being exercised from the tests given by Exercism.
You can nitpick the solution here and/or see all the exercises I've done so far in this repository.
This is my solution:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns robot-simulator) | |
(defn robot [coordinates bearing] | |
{:coordinates coordinates | |
:bearing bearing}) | |
(def ^:private turns | |
{:right {:north :east | |
:east :south | |
:south :west | |
:west :north} | |
:left {:north :west | |
:east :north | |
:south :east | |
:west :south}}) | |
(defn- turn [direction current-bearing] | |
(get-in turns [direction current-bearing])) | |
(defn turn-right [bearing] | |
(turn :right bearing)) | |
(defn turn-left [bearing] | |
(turn :left bearing)) | |
(def ^:private displacements | |
{:north [0 1] | |
:east [1 0] | |
:south [0 -1] | |
:west [-1 0]}) | |
(defn- advance [{{:keys [x y]} :coordinates bearing :bearing}] | |
(let [displacement (get displacements bearing [0 0]) | |
[x y] (map + [x y] displacement)] | |
(robot {:x x :y y} bearing))) | |
(defn- right [{bearing :bearing :as rb}] | |
(assoc rb :bearing (turn-right bearing))) | |
(defn- left [{bearing :bearing :as rb}] | |
(assoc rb :bearing (turn-left bearing))) | |
(def ^:private commands | |
{\R right | |
\A advance | |
\L left}) | |
(defn simulate [[first-msg & rest-msg] rb] | |
(if-let [comm (get commands first-msg)] | |
(recur rest-msg (comm rb)) | |
rb)) |
You can nitpick the solution here and/or see all the exercises I've done so far in this repository.
Tuesday, May 19, 2015
Exercism: "Kindergarten Garden in Clojure"
I solved the Kindergarten Garden problem in Clojure.
This is my solution:
You can nitpick this solution here and/or see all the exercises I've done so far in this repository.
This is my solution:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns kindergarten-garden) | |
(def ^:private plants | |
{\R :radishes \C :clover \G :grass \V :violets}) | |
(def ^:private default-children | |
[:alice :bob :charlie :david | |
:eve :fred :ginny :harriet | |
:ileana :joseph :kincaid :larry]) | |
(def ^:private get-plants | |
(partial map #(get plants %))) | |
(defn- plants-rows [diagram] | |
(map #(vec (get-plants %)) | |
(clojure.string/split diagram #"\n"))) | |
(defn- plants-per-child-in-rows [child-index rows] | |
(vec | |
(flatten | |
(map #(vector (get % child-index) (get % (inc child-index))) | |
rows)))) | |
(defn- plants-per-child [diagram] | |
(let [num-cols (.indexOf diagram "\n")] | |
(map #(plants-per-child-in-rows (* 2 %) (plants-rows diagram)) | |
(range 0 (quot num-cols 2))))) | |
(def ^:private lowercase-all | |
(partial map #(clojure.string/lower-case %))) | |
(def ^:private strs->keys | |
(partial map #(keyword %))) | |
(defn- children-keys [children-strs] | |
(->> children-strs | |
lowercase-all | |
sort | |
strs->keys)) | |
(defn- make-garden [children diagram] | |
(zipmap children (plants-per-child diagram))) | |
(defn garden | |
([diagram] | |
(make-garden default-children diagram)) | |
([diagram children-strs] | |
(make-garden (children-keys children-strs) diagram))) |
Saturday, May 16, 2015
Exercism: "Crypto Square in Clojure"
I solved the Crypto Square problem in Clojure.
This is my solution:
You can nitpick this solution here or see all the exercises I've done so far in this repository.
This is my solution:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns crypto-square | |
(:require [clojure.string :as clj-str])) | |
(defn- no-punctuation [c] | |
(or (Character/isLetter c) | |
(Character/isDigit c))) | |
(defn- remove-punctuation [text] | |
(clj-str/join "" (filter no-punctuation text))) | |
(defn normalize-plaintext [text] | |
(clj-str/lower-case (remove-punctuation text))) | |
(defn square-size [text] | |
(int (Math/ceil (Math/sqrt (count text))))) | |
(defn plaintext-segments [text] | |
(let [normalized-text (normalize-plaintext text) | |
segment-size (square-size normalized-text)] | |
(map clj-str/join (partition-all segment-size normalized-text)))) | |
(defn- pad-segments [segments segments-size] | |
(map #(format (str "%-" segments-size "s") %) segments)) | |
(defn- segments-in-columns [text] | |
(let [segments (plaintext-segments text) | |
segment-size (count (first segments))] | |
(apply map | |
#(clj-str/trim (apply str %&)) | |
(pad-segments segments segment-size)))) | |
(defn- remove-spaces [text] | |
(clj-str/replace text " " "")) | |
(defn normalize-ciphertext [text] | |
(->> text | |
segments-in-columns | |
(clj-str/join " "))) | |
(defn ciphertext [text] | |
(remove-spaces (normalize-ciphertext text))) |
Wednesday, May 13, 2015
Exercism: "Bank Account in Clojure"
In the last event of Clojure Developers Barcelona, we practiced mob programming to solve the Bank Account problem in Clojure.
This is our solution:
You can nitpick our solution here or see all the exercises I've done so far in this repository.
This is our solution:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns bank-account) | |
(defn open-account [] | |
(atom 0)) | |
(defn close-account [_]) | |
(defn get-balance [acct] | |
@acct) | |
(defn update-balance [account amount] | |
(swap! account + amount)) |
Monday, May 11, 2015
Friday, May 8, 2015
Interesting Panel: "TDD and Software Design"
I've just watched this wonderful discussion between Sandro Mancuso and J. B. Rainsberger about the relationship between TDD and Software Design which was organized by Carlos Blé:
Tuesday, May 5, 2015
Kata: String Calculator in Clojure
Last week we started working on the String Calculator kata at the Clojure Developers Barcelona meetup.
Finally, this week I found some time to finish it.
These are the tests using Midje:
The resulting code which is divided in several name spaces.
The string-calculator.core name space:
The string-calculator.numbers-parser which is where most of the logic lives:
The string-calculator.numbers-validation name space:
Finally, the string-calculator.numbers-filter name space:
I used a mix of TDD and REPL-driven development to code it.
To document the process I committed the code after every passing test and every refactoring.
This time I didn't commit the REPL history because I used Cursive and I didn't find how to save it. Apart from that, I really enjoyed the experience of using Cursive.
You can find the commits step by step here and the code in this repository in GitHub.
Finally, this week I found some time to finish it.
These are the tests using Midje:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns string-calculator.core-test | |
(:use midje.sweet) | |
(:use [string-calculator.core])) | |
(facts | |
"about string-calculator" | |
(fact | |
"It returns 0 for an empty string" | |
(add "") => 0) | |
(fact | |
"It returns the number itself when the string contains only a number" | |
(add "1") => 1 | |
(add "2") => 2) | |
(fact | |
"It adds strings containing several numbers separated by commas" | |
(add "1,2") => 3 | |
(add "1,2,3") => 6) | |
(fact | |
"It adds numbers separated by new lines and/or commas" | |
(add "1\n2,3") => 6) | |
(fact | |
"It can also use any given delimiter" | |
(add "//;\n1;2,3") => 6) | |
(fact | |
"It throws and exception when trying to add negative numbers" | |
(add "1,-2,3,-4") => (throws Exception | |
"Detected negative numbers: -2, -4")) | |
(fact | |
"It ignores any number greater than 1000" | |
(add "4,5,1001,3") => 12) | |
(fact | |
"It can use delimiters of any length" | |
(add "//[***]\n1***2***3") => 6) | |
(fact | |
"It can use multiple delimiters of any length" | |
(add "//[***][%%]\n1***2%%3,4") => 10)) |
The string-calculator.core name space:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns string-calculator.core | |
(:require [string-calculator.numbers-parser :as numbers-parser] | |
[string-calculator.numbers-validation :as numbers-validation] | |
[string-calculator.numbers-filter :as numbers-filter])) | |
(def ^:private sum (partial apply +)) | |
(defn add [input-str] | |
(-> input-str | |
numbers-parser/parse | |
numbers-validation/validate | |
numbers-filter/remove-too-big-numbers | |
sum)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns string-calculator.numbers-parser | |
(:require [clojure.string :as string])) | |
(def ^:private default-delimiters ["," "\n"]) | |
(def ^:private escaped-chars-by-metachar | |
(let [esc-chars "()*&^%$#!"] | |
(zipmap esc-chars | |
(map #(str "\\" %) esc-chars)))) | |
(defn- escape-meta-characters [delimiters-str] | |
(reduce str (map #(get escaped-chars-by-metachar % %) | |
delimiters-str))) | |
(defn- get-matches [pattern string] | |
(mapcat (partial drop 1) (re-seq pattern string))) | |
(defn- extract-delimiters [delimiters-str] | |
(let [delimiters (get-matches #"\[(.*?)\]" delimiters-str)] | |
(if (empty? delimiters) | |
delimiters-str | |
delimiters))) | |
(defn- create-delimiters-pattern [delimiters-str] | |
(->> delimiters-str | |
extract-delimiters | |
(concat default-delimiters) | |
(string/join "|") | |
escape-meta-characters | |
re-pattern)) | |
(defn- numbers-and-delimiters-pattern [input] | |
(let [delimiters-and-numbers (get-matches #"//(.+)\n(.*)" input)] | |
[(or (second delimiters-and-numbers) input) | |
(create-delimiters-pattern | |
(or (first delimiters-and-numbers) ""))])) | |
(defn- extract-nums-str [input-str] | |
(apply string/split | |
(numbers-and-delimiters-pattern input-str))) | |
(defn parse [input-str] | |
(if (string/blank? input-str) | |
[0] | |
(map #(Integer/parseInt %) | |
(extract-nums-str input-str)))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns string-calculator.numbers-validation) | |
(def ^:private any-negative? | |
(partial not-every? #(>= % 0))) | |
(defn- throw-negative-numbers-exception [numbers] | |
(throw | |
(Exception. | |
(str "Detected negative numbers: " | |
(clojure.string/join ", " (filter neg? numbers)))))) | |
(defn validate [numbers] | |
(if (any-negative? numbers) | |
(throw-negative-numbers-exception numbers) | |
numbers)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns string-calculator.numbers-filter) | |
(defn remove-too-big-numbers [numbers] | |
(remove #(> % 1000) numbers)) |
To document the process I committed the code after every passing test and every refactoring.
This time I didn't commit the REPL history because I used Cursive and I didn't find how to save it. Apart from that, I really enjoyed the experience of using Cursive.
You can find the commits step by step here and the code in this repository in GitHub.
Subscribe to:
Posts (Atom)