Expanding the (cyber-)dojo: Making room for even more deliberate practice

Millard Ellingsworth
6 min readNov 23, 2016

Mastery of any craft requires intentioned practice and an openness to learning. My friend Chris Sharp introduced me to cyber-dojo as an easy way to run code retreats and I’ve also found it a fun place to practice with different programming problems and languages and tools, all installed and ready to go when I am.

My part in this story is very small (but told in excruciating detail below). Credit where it is due, first. cyber-dojo is the brain-child of Jon Jagger. It’s a learning environment created to promote deliberate practice among software developers. I find it’s origin story quite interesting. It’s delightfully Dockerized architecture makes it easy to extend (and host). With a rather modest amount of effort, you can have it hosted on your laptop. If you do code retreats or programming workshops (and of course you do, right?), you should get to know cyber-dojo.

cyber-dojo supports almost 30 different programming languages with at least 1 testing framework for each (more popular environments like Java, Javascript and Python offer several choices for writing tests). There are at least 40 different exercises. With a few choices and mouse clicks you can choose a language, test framework and exercise to work on and have a fully hosted environment ready to go. So go use it and hone your craft. And support Jon for giving us something so cool.

cyber-dojo provides many language and test framework options

But even with all of those choices, it didn’t have the one I wanted (Python with Behave/Cucumber). I could use Java with Cucumber, but not everyone knows Java and I wanted to have some options for my code retreats. I keep thinking a fun exercise would be to have something completely working, covered with Cucumber tests, and your job is to port it to another language with only the feature files as your starting point…but I digress.

Having poked around cyber-dojo some, I knew it was possible to extend it with new languages and test frameworks. I also knew it would take some effort as all the information was likely there, just spread across various blog posts and GitHub README files. In case you are interested or may want to do this yourself some day, the rest of this piece explains the steps I figured out to add a new test framework for an existing language at cyber-dojo. If that doesn’t interest you, that cyber-dojo Bowling exercise is kinda fun…

I’m sure there’s more than one path through the forest; this is the one I took and it brought me to the meadow of pythonic behave-ness I was seeking. I was only adding a new test framework to an existing language though I don’t think adding a whole new language would be particularly more difficult (and you’d still need to do these parts anyway).

Start by getting cyber-dojo to run locally on your system. Choose your environment from this page: http://blog.cyber-dojo.org/2014/09/setting-up-your-own-cyber-dojo-server.html I used a Mac (Sierra) and Docker 1.12.1 — any following screen shots or other comments are related to that environment. Make sure it comes up and you can see the working site locally. When it’s up, run docker ps from your terminal. You should see containers for -web, -runner, -differ and -nginx running.

Since everything is Dockerized, the first thing I did was create a Docker image for Python+Behave using the instructions here: http://blog.cyber-dojo.org/2016/08/adding-new-language-and-unit-test.html Of course, the first step was to fork and clone the cyber-dojo/Dockerfiles repo.

Since I was only adding a test framework, I started with step 2. I navigated to Dockerfiles/Python and created a /behave directory there. I then copied the files from Dockerfiles/Python/pytest as a starting point. Only two changes were required: (1) change the Dockerfile to install behave instead of pytest and (2) change the build-docker-image.sh file to name the new image cyberdojofoundation/python_behave. After building it, I was able to change to some directories that had some Python and Behave code and test the new docker image against them (i.e., docker run --rm -v “$PWD”:/usr/src/myapp -w /usr/src/myapp cyberdojofoundation/python_behave behave). This work is in https://github.com/cyber-dojo/Dockerfiles/pull/6

The next step was to let the cyber-dojo web application know about my Python_Behave configuration by adding a new start point and starter exercise. All sessions begin with a version of this same starter (hat tip to the Hitchhiker).

To create a new starter exercise and configuration for Python_Behave, the first step was to fork and clone the cyber-dojo/start-points-languages repo. Similar to the Dockerfiles update above, this involved navigating to the Python directory, adding a /behave directory, then building the required bits. This wasn’t quite as simple as the previous case, so let’s unpack it…

Three things need to be in this directory: (1) a manifest.json file describing your environment, (2) a cyber-dojo.sh file that is used to run tests against the code in this project and (3) the files necessary to represent the starter exercise. I also added a README file to describe some important aspects of the environment (which really are important).

The link above reasonably explains the manifest.json file contents. I had to tweak the “red_amber_green” entry to properly identify behave output, change the “image_name” to match the name of the Docker image built earlier, change the “display_name” and set of “visible_filenames”. The last one was the only sticker — every time I renamed or removed a file, I had to make sure I updated the list of filenames or the build would fail (more on how to build it later).

The cyber-dojo.sh file turned out to be more interesting than you’d expect — and that’s where the README comes in. In the simplest case, for example with Python and py.test, the cyber-dojo.sh has only “python -m pytest *test*.py” in it. That’s all that’s necessary to run pytest against the source in the folder. As best I can tell, Behave is very picky and *requires* that the files that implement the steps for the features must be in a subdirectory named /steps. [Not picking on Behave, I think the convention makes sense.] Problem is that cyber-dojo only supports flat file systems for the exercises (and it turns out that works in every other language/framework implemented so far). Jumping past some hair pulling and cursing that was involved before I figured that out, my cyber-dojo.sh has to create a /steps subdirectory and copy *_steps.py to it before running behave. This works, though is a slight hack — and it’s why the README explains this and tells the user that if they want to add any additional steps files, that they need to use the convention above to make them work as intended.

The last part is the working starter exercise. You can see the pull request for details. It only involves three files: hiker.py (the code under test), hiker.feature (the feature file describing the first scenario) and hiker_steps.py (the implementation of the scenario steps).

A practice session starts with a failing test — though in the form of a busted requirement

To test that locally (usually a good idea before submitting a pull request), you have to understand most of what is described here about languages and start points. The cyber-dojo web app will read (or create) its default collections for languages and exercises. Very similar to the example in the link above, all I had to do to get cyber-dojo to pick up my changes (note: start-points-languages/ is the name of the repo cloned for this segment) was:

./cyber-dojo down
./cyber-dojo start-point rm languages
./cyber-dojo start-point create languages --dir=start-points-languages/
./cyber-dojo up

And I could test all of my changes locally before submitting the pull requests.

I think I’m going to work on a Javascript/Cucumber update next — then there will be at least three languages you can use Cucumber-BDD with. But I have also been playing around with Elm (which isn’t at cyber-dojo yet) and there is an issue Jon could use some help with. Maybe you can take that one?

--

--

Millard Ellingsworth

Scrum Master, DevOps+Agile Coach, Developer, handyman and occasional musician. All content represents my own opinions. #Agile #DevOps