Dave's No Tests Challenge
I've mentioned before my difficulties in the 2014 IPSC. But taking one beating is no reason not to try again. The first loss just showed me that the contest still had more to teach me.
A buddy of mine has spent some time with the crossword problem and told me that he enjoyed it. I didn't try this problem during the actual event, but I was a little familiar with it from my friend's description.
To add to the fun, I decided this would be a great excuse to take up the recent challenge Dave Thomas gave to the Ruby Rogues: "Stop writing tests."
Step 1: Feedback Loops
Without tests to guide me, I really want to see what's going on. One of the biggest advantages of tests, in my opinion, is the feedback loop it provides. So I set out to provide my own feedback.
Since the problem at hand involves filling in a crossword board, the easiest feedback loop I could think of was to see the board as it fills in. The final board is also the required output. Therefor, I decided a good first step would just be to read the board into some data structure and write it back out. Once I had that, I could insert code between those steps to fill it in. And constantly seeing the board evolve would let me eyeball things for obvious mistakes.
One Programmer's Library
I have always enjoyed the posts where people list out all of the books they think are important, given some subject. They vary wildly. For example, some are very to-the-point while others are rich in detail (and Danielle makes one of those each year).
I began to wonder what my list would look like. Below I've tried to make those decisions. I was surprised by just how hard it is to restrict myself to the bare essentials. A lot of things that I read influence me in some way.
I'll start with the super obvious titles you've likely heard mentioned before.
- Refactoring: Improving the Design of Existing Code is probably the classically great programming text that had the biggest effect on me. This book teaches you how to turn the code you have into the code you want. It doesn't get much more essential than that.
- Smalltalk Best Practice Patterns is the book I learned a new language just to read. It's worth that. This is The Field Manual of Object-Oriented Tactics and it helps you know what to do line-by-line.
- Patterns of Enterprise Application Architecture is the book you should read so you can see how much great knowledge we've had about building programs for over a decade. Odds are that this book can teach you multiple strategies for problems you face regularly.
- The Pragmatic Programmer: From Journeyman to Master is one of those rare books that can make you a better person, in addition to a better programmer. Advice like "Fix Broken Windows" and "Make Stone Soup" have universal scope. This is a must read.
- Programming Pearls (2nd Edition) is a book about algorithms and, eventually, all programmers need to learn some algorithms. The upside of this title is that it's fun from page one. That helps to keep you interested in what can be a dry topic.
- Growing Object-Oriented Software, Guided by Tests is almost surely the single biggest influence on how I do Test-Driven Development. There are other schools of thought but pick one and dig deep enough into TDD until you're confident about when and how to use it. This is a tool everyone needs in their toolbox.
IPSC 2014 Postmortem
I decided to give the Internet Problem Solving Contest (IPSC) a go this year, with a couple of friends. I've done it in the past and enjoyed it. I like how it only eats a few hours one day and I like how the variety in the problems they give you keeps things interesting.
That said, my performance in the IPSC this year is probably best described as, "Three strikes and you're out!" I did terrible.
I solved one very simple problem. I spent the rest of the contest chasing after a much harder challenge that I couldn't complete in the time allowed.
The worst part is that I made some silly mistakes that I've learned to avoid in the past. As penance, I offer up this article, mainly as a reminder to myself, but hopefully also as a tool that could save others from some of my folly.
Let's start with a simple mistake I made…
Not All Problems are Programming Problems
The IPSC does a great job each year of reminding us that some problems are trivial to solve without programming. It's a good thing they do too, because I seem to need a lot of reminding.
I got another thing out of my recent conversation with Katrina Owen: a will-not-let-go itch to try a programming exercise that she mentioned. I'm such a sucker for a challenge.
Katrina spoke of an assignment that her and Sandi Metz have used in their object orientation trainings. She said that they build an OO implementation of the 99 Bottles of Beer song, "mainly removing
ifs and such." There may be more to the actual task than this, but I ran with that brief explanation.
As I often say, you'll probably learn more by trying the exercise for yourself before you read through my thoughts about it. Give it a go if you can spare the time.
Diff Driven Development
I decided to throw some scaffolding into the master branch of a Git repository. I figured I could then branch off of that with each idea, to keep trying things out.
I started by constructing a trivial framework for running and verifying the song. That consisted of an executable:
#!/usr/bin/env ruby -w require_relative "../lib/bottles_of_beer" verses = ARGV.first =~ /\A\d+\z/ ? ARGV.shift.to_i : 99 BottlesOfBeer::Song.new(verses).sing($stdout)
Are We Teaching the Best Things?
I'm in Denver right now, mostly to see family. Being the geek that I am though, you know I snuck a little time for the local Rubyists. One of those Rubyists that I was lucky enough chat with is Katrina Owen.
I always love getting a chance to talk with Katrina. She's so thoughtful that she raises the level of discourse and makes me feel smarter. Plus, it turns out that Katrina and I have been thinking about similar things lately.
For my part, I've been thinking about the various students that I've taught to program over the years. I have taught many and because they all learned from me, they learned roughly the same way. What's interesting to me is how different the results have been from that technique. In some cases my students were all set after our lessons and they just began coding up a storm. Other students didn't seem to feel they were ready yet though. They had more of a "Now what do I do?" attitude at this stage.
Katrina raised a similar point from her time teaching in a developer school. When they would get to teaching language basics, they would show several constructs and how they are used. This is similar to how I teach. Just as I have observed, this works for some students. They can just take what they know and run from here. But they also found other students felt a little lost at this point.
A Library in One Day
I was super inspired by Darius Kazemi's recent blog post on small projects, so I've been looking for ways to speed up my process.
Today, I tried an experiment: develop a library in one day. I wanted to go from an empty repository to a published gem that I could start using.
Obviously, I had to select a pretty simple idea to use. I wouldn't have time to do a huge project.
I think this may be the killer feature of this technique.
On one hand, you could argue that what I built may not be very library worthy. It's around 50 lines of code. It has ten specs and they really cover what it does. This isn't a complex beast and you could pretty easily hand roll a solution to replace it.
But in some ways that's the best part. I've dropped a 50 line pattern that I like down to a one line
Gemfileinclude. I'm making it even easier for myself to get some mileage out of experimenting with this code. I can mix and match this new library with other small tools to build up the ecosystem that I want for a project. Plus, if it turns out to be something I regret, it's not like I'm tied down to a huge dependency when I go to rip it out. This thinking actually has me wanting to keep this library minimal, at least for now.
Proof of Life
As many of you noticed, and some of you regularly messaged me about, this blog has been offline for quite some time. There are many reasons for this: I was rewriting the software this blog runs on, the host that served it closed their doors, I had to take an extended break in working on it for multiple reasons, and, when I got back to it, my half-complete rewrite had enough bit rot that I decided to start fresh. The good news is that all of that mess has finally passed. As you can see, that means this blog is back is business.
If you are a long time reader and you have a good memory, you'll notice that I changed the name of my blog. That's because the old name was a not-so-clever play on my name that was later appropriated for a rather different collection of writing. I think that's worth resetting the Google credit counter to get away from.
Oh and there have been a few upgrades…
All of my posts are back. Some content is a bit dated and I've tried to add clarifying notes where they were needed, but I was pleasantly surprised to see that much of it is still useful today. I believe my coverage of Character Encodings is what readers missed the most and it's fully restored.
Decorators Verses the Mix-in
It is a neat time to be involved in the Ruby community, if you ask me. A large portion of us are currently studying the techniques for doing good object oriented development. We are looking at the ideas that have come before and trying to decide the best ways to apply those ideas to our favorite language. This leads to blog posts, forum threads, and conference talks about what we are learning. No matter what, we all gain from explorations like this. Everybody wins as our collective knowledge grows. We all deserve gold stars.
So far, there's one point pretty much everyone agrees on: composition should typically be preferred to inheritance. The trickier part of that discussion though is deciding what composition looks like in Ruby. Generally you see Rubyists comparing the merits of decorators and mix-ins. [Note: the comments correctly pointed out that this was a bad use of the word "composition" on my part, to describe mix-ins.] There's a very representative thread on the excellent Objects on Rails mailing list.
I love playing with Ruby's
Hash. I think it has a neat API and experimenting with it can actually help you understand how to write good Ruby. Let's dig into this idea to see what I mean.
The nil Problem
In Destroy All Software #9 Gary chooses to show an example in Python because, unlike Ruby's
Hash, it will raise an error for a non-existent key. Ruby just returns
nil, he explains.
What Gary said isn't really true, but I'm guessing he just didn't know that at the time. He was in the process of switching to Ruby from Python and I'm guessing he just didn't have a deep enough understanding of Ruby's
Hashyet. I bet he does know how it works now.
But assume he was right. What's he saying and why does it matter? Consider some code like this:
class SearchesController < ApplicationController def show terms = params[:terms] SomeModel.search(terms) # ... end end
This is what Gary doesn't like, and rightfully so. Because I indexed into
paramshere with the
()method, I will indeed get a
:termskey wasn't in
Single Method Classes
[Update: I've changed my mind about some of the following due to this excellent counter argument.]
In the words of Dennis Miller, "I don't want to get off on a rant here, but…"
There's something that drives me crazy and I see it in so much Ruby code. I see it in the documentation for our key projects; I see Rubyists of all skill levels doing it; it's just everywhere.
Let's talk about when the use of a
Classis and is not appropriate.
The Chained new()
Here's an example of one form of code that bugs me:
class Adder def add(n) 40 + n end end p Adder.new.add(2)
The problem here is that a
Classhas been used, probably because as Rubyists that's always our default choice, but it's the wrong fit for this code. A
Classis for state and behavior. The example above is just using behavior. No state is maintained.
A handy tip for sniffing out this problem is watching for a call to
new()in the middle of method chaining as we have here. If you always use a
Classlike that, it's not really a
Class. Put another way, if an instance never gets assigned to a variable, something has likely gone wrong with the design.