(My) Dart Katas
Quite frankly, I think that this should actually better be named something along the lines of Dart Lab, the examples/exercises below are much more suited to expose experimentation than demonstration. But I won't change anything, if this is shameful, so be it!
The website CodeKata has a wonderful motivation text about programming katas, with which I squarely agree:
How do you get to be a great musician? It helps to know the theory, and to understand the mechanics of your instrument. It helps to have talent. But ultimately, greatness comes from practicing; applying the theory over and over again, using feedback to get better every time.
How do you get to be an All-Star sports person? Obviously fitness and talent help. But the great athletes spend hours and hours every day, practicing.
But in the software industry we take developers trained in the theory and throw them straight in to the deep-end, working on a project. It’s like taking a group of fit kids and telling them that they have four quarters to beat the Redskins (hey, we manage by objectives, right?). In software we do our practicing on the job, and that’s why we make mistakes on the job. We need to find ways of splitting the practice from the profession. We need practice sessions.
It is important to emphasize the fact that katas should be minimalistic units of practice so you can focus on just one topic. This will help us identify mistakes and univocally connect them to their root, with no ambiguity at all. Similarly to what Doug McIlroy mentions in the Bell System Technical Journal from 1978, albeit in a different context and with different intentions:
Make each program do one thing well. To do a new job, build afresh rather than complicate old programs by adding new "features".
Again, CodeKata has a nice description of what katas are:
What makes a good practice session? You need time without
interruptions, and a simple thing you want to try. You need to try it
as many times as it takes, and be comfortable making
mistakes
Code Kata is an attempt to bring this element of practice to software
development. A kata is an exercise in karate
Remember that the point of the kata is not arriving at a correct answer. The point is the stuff you learn along the way. The goal is the practice, not the solution.
Feedback on your craft is very important so you can do the movements or write the code correctly. As Vince Lombardi once famously said, again, in a different context and with different intentions:
Practice does not make perfect. Perfect practice makes perfect.
The Programming Kata's origins are unkown, but the earliest explicit mention comes from Dave "Pragmatic Dave" Thomas' book The Pragmatic Programmer (1999). This practice was further popularized by Robert "Uncle Bob" C. Martin on his blog, in an article called The Programming Dojo.
Personally, I first got in touch with it after reading Uncle Bob's
books
Clean Code
and
The Clean Coder, in which he not only mentions and recommends this practice but also
puts a layer on top: TDD or Test-Driven Development
After mentioning TDD, it's also worth citing Kent Beck, who is
actually its inventor
My most current katas are the ones written in my
Dart Katas Github
repository. These are much longer than the usual expected time of 1
hour to 1 afternoon. On average, mine took an afternoon to a whole
day. The main reason for this is that I was intentionally more careful
with the structure of the code, featuring TDD while also trying to
make it more clean
Some will disagree with my code and I'm not here to say that it is the
best ever or the most correct
One example of practice for which a much more experienced and overall
much better programmer,
Marcelo Glasberg,
criticized me was, in his words, "my systematic obfuscation of the
test answers". For example, in the
Bowling Game Kata, I created a file called fixture_data.dart where I
deposit all of the variables used as the test answers:
final Map<Map<String, int>, int> rollsPinsAndScores = {
gutterGame: 0,
allOnes: 20,
perfectGame: 300,
};
const Map<String, int> gutterGame = {
'rolls': 20,
'pins': 0,
};
const Map<String, int> allOnes = {
'rolls': 20,
'pins': 1,
};
const Map<String, int> perfectGame = {
'rolls': 12,
'pins': 10,
};
His critique was that this was incredibly unnecessary since it doesn't
really add much to so simple a program/problem. He also mentioned that
it makes it harder for other people to read my code because they now
have to manage more files and screens in their heads. I mostly do
agree with his criticism actually, but I left it that way because it
serves to show what I would do if the program got a little bit more
unwieldy
Putting the maps used in each separate test scenario inside another
map was yet another source of his dislike of my code. In this case, I
was trying to avoid the needless repetition of the test setups, which
always had the same heuristics. I still think this makes the reader
better think at a higher level more easily though. Rote repetition of
simpler tests might be easier to read, but its volume will be harder
to memorize and visualize as a whole. Instead of setting up the same
types of tests over and over, you can simply use a
forEach:
test('Test canonical games: gutter, all ones and perfect', () {
rollsPinsAndScores.forEach((Map<String, int> rollsPins, int score) {
_game = BowlingGame();
_rollManyPins(rollsPins['rolls'], rollsPins['pins']);
expect(_game.score(), score);
});
});
Another last warning I must give about my kata code in this particular repository is that I sometimes overparameterized or overgeneralized the problem too much — for practicing purposes —, which is a very easy trap to fall into for programmers. For example, my Tic-Tac-Toe solution can work for any symbol/character and any board size. Not only the board class but also the parser's would be much simpler if I hadn't chosen to implement this overgeneralized solution.
At any rate, in the end, I'll let you be the judge of what practice is
best — if there is one thing I've learned from Go (Baduk or
Weiqi) is that the discussion itself can be much more enlightening
than simply labeling a practice as good or bad