Coding dojos
One of the things that I love the most about working at Travelex is the culture of continuous improvement, knowledge sharing and learning.
In addition to Hack Days, regular tech talks and this blog, we recently tried our first coding dojo so I thought I’d share a little about how it went.
What is a coding dojo?
A coding dojo is where a number of engineers come together to collectively solve a programming challenge. The goal is that the participants improve their skills by engaging in deliberate practice — seeking out different experiences to those encountered in your day-to-day work that stretch you and provide feedback. It’s also quite a lot of fun!
The format
The dojo should last in the region of 2 hours depending on the complexity of the challenge.
The engineers are grouped into teams of around 4. The leader of the session introduces the challenge to the participants, and provides any necessary tools or materials (e.g. a starter project or language/framework cheat sheets).
Each team shares a single computer and works on the challenge as follows:
- At any one time, there are two people pairing on the exercise.
- Every 5–7 minutes, the team members rotate by one — one of the pair steps down and one of the other team members takes their place.
After about about 90 minutes, the teams then share their solutions with each other and then discuss how they compare and what was learnt.
The challenge
For our first dojo we selected the following challenge, courtesy of codekata.com:
Given a file containing one word per line, print out all the combinations of words that are anagrams; each line in the output contains all the words from the input that are anagrams of each other. For example, your program might include in its output:
kinship pinkish
enlist inlets listen silent
boaster boaters borates
fresher refresh
sinks skins
knits stink
rots sortIf you run this on the provided word list you should find 20683 sets of anagrams (a total of 48162 words), including all-time favorites such as
crepitus cuprites pictures piecrust
paste pates peats septa spate tapes tepas
punctilio unpolitic
sunders undressFor added programming pleasure, find the longest words that are anagrams, and find the set of anagrams containing the most words (so “parsley players replays sparely” would not win, having only four words in the set).
We also decided to give each team a new programming language to try out — Scala, Kotlin and Go respectively.
The solutions
Team Go got the furthest and completed the main part of the challenge. Unfortunately, they were so excited that their code worked that they forgot about the extension.
Their complete solution is as follows:
package mainimport (
"bufio"
"fmt"
"os"
"sort"
"strings"
)// Sort a string in ascending character order
func SortStringByCharacter(s string) string {
rs := []rune(s)
sort.Slice(rs, func(i, j int) bool {
return rs[i] < rs[j]
})
return string(rs)
}// Pretty print a slice of strings
func PrintSlice(s []string) string {
return strings.Trim(fmt.Sprint(s), "[]")
}func main() {
// Open file
fileHandle, err := os.Open(“wordlist.txt”)
if err != nil {
fmt.Println(err.Error())
return
}
defer fileHandle.Close()
fileScanner := bufio.NewScanner(fileHandle) // Insert words into map, using the keys to group anagrams
m := make(map[string][]string)for fileScanner.Scan() {
var word = fileScanner.Text()
var sorted = SortStringByCharacter(word)
m[sorted] = append(m[sorted], word)
} // Print out anagrams and find longest words
var longest string
var most string
for k, v := range m {
if len(v) > 1 {
fmt.Println(PrintSlice(v)) // Track whether this is the longest anagram we've seen
if len(k) > len(longest) {
longest = k
} // Track whether this is the most anagrams we've seen
if len(v) > len(m[most]) {
most = k
}
}
} fmt.Println("Longest anagrams: " + PrintSlice(m[longest]))
fmt.Println("Most anagrams: " + PrintSlice(m[most]))
}
Team Kotlin originally took a procedural approach to solving the problem and were minutes away of a working solution. The next day they came up with the following functional approach:
fun main(args: Array<String>) { val anagrams = File(“wordlist.txt”)
.readLines()
.map {
word -> word to String(word.toCharArray().sortedArray())
}
.groupBy { it.second }
.filter {entry -> entry.value.size > 1 }
.mapValues { pairValue -> pairValue.value.map { it.first } } val mostAnagrams = anagrams.entries.reduce {
first, second ->
if (first.value.size > second.value.size) first
else second
} val longestAnagram = anagrams.entries.reduce {
first, second ->
if (first.key.length > second.key.length) first
else second
} anagrams.forEach {
entry -> println(entry.value.joinToString(“, ”))
} println(“Most anagrams: ” + mostAnagrams.value
.joinToString(“, “))
println(“Longest anagrams: ” + longestAnagram.value
.joinToString(“, “))
}
Lastly, Team Scala had a few issues with their development environment and then, being software engineers, thoroughly debated the different approaches they could take. With their approach decided, they were well on their way to solving the problem however needed a bit more time. A solution in Scala is given below:
object Anagrams {
def main(args: Array[String]): Unit = {
val wordMap = Source.fromInputStream(
getClass.getResourceAsStream("/anagrams"))
.getLines().toList
.map(word => word.toCharArray.sorted.mkString -> word)
.groupBy(_._1)
val anagrams = wordMap mapValues (_.size) filter (_._2 > 1) val most = anagrams.maxBy(_._2)
val longest = anagrams
.reduceLeft((x, y) => if (x._1.length > y._1.length) x else y)
println("Anagrams = ")
anagrams.keysIterator
.foreach(anagram => println(wordMap(anagram) map (_._2))) println("Longest anagrams:" + wordMap(longest._1) map (_._2))
println("Most anagrams:" + wordMap(most._1) map (_._2))
}
}
Lessons learnt
Allow plenty of time. Things take longer when you’re working with engineers who you don’t work with on a regular basis, or if you’re using an unfamiliar language, framework or another engineer’s computer.
Don’t underestimate the difficulty of the challenge. Make sure the main part of the challenge is achievable, and provide a few follow up extensions in case the teams finish in good time.
It’s not a competition. The purpose is to learn something new, not to see who can get the furthest in the shortest space of time. If there has to be a winner, then it is the team that comes away having learnt the most.
Preparation is key. Provide the teams with whatever resources would enable them to get the most from the exercise. Make sure that any tools or development environments are tested and working.
Use the language in the way it is intended to be used. The primary insight that came from trying some different languages in this dojo was that you should embrace the different paradigms and features that each language brings. The Kotlin solution was so much more simple and elegant when written using the language’s functional programming constructs.
Will we run another coding dojo at Travelex? Absolutely! In fact, planning for it is already well under way.
Further reading
If you’re thinking about running a coding dojo at your company or amongst friends, then the following links may be useful: