Test Driven Epiphany

So, when I first started formally learning to write code, and do programming, we were taught the only and true method of it, a method now known as Waterfall.  It doesn’t work, and it causes more problems than it helps with.  I understand why it was done that way at one time, but with the way we use computers now, it doesn’t work at all.  With “waterfall” all the testing was done at the end of the project. There was some expected unit testing by the developer, but they were supported by the supposed safety net of QA at the end. They would do the real testing and go through that cycle.

That worked okay; the real problem with waterfall is that it took too long, the business would change in the interim, and the users’ needs and expectations would drift in the nine months it took to make a waterfall project.  Also, it depended on getting the user requirements right, and that’s actually the hardest part of any project.  Most users don’t know what they want until they see something that’s not quite that. Which, again, takes months in waterfall.

I started learning about Agile methods, which have faster cycles and different methodologies when I worked for a bank in Charlotte.  We were trying to do better, but most of us weren’t properly trained in it. We were never going to do some of the things (like pair programming) and so wound up primarily doing fast cycles and user stories, because we were the most comfortable with that.  As the Agile-guru of our team, I was trying to figure out how to implement it and get it working. I was pretty stoked by this idea about testing, and test-driven code, but I couldn’t wrap my head around it.

Some of it I got, certainly. I’d naturally come to a place where I worked backwards from outputs to inputs. This was mostly laziness, since I didn’t want to write the parts of the program that no one was going to use — let’s start with the end product and build things that make that. [One of the things that frustrates me about the C# development I’m doing at my current job is the amount of what feels like boilerplate and structural code that ‘has’ to exist. It feels like trying to do surgery with a mace.]

But there are things I didn’t get.  How do you start? How do you really test each function? How do you test UI elements (still don’t have a good idea about that.) I couldn’t figure out how to start.  Starting on code was easy, I could focus in on one thing and build it and it worked. Most of my private projects were small and I didn’t need to do much more than that. I probably wasn’t going to finish them anyway.

But with my focus on Making Things this year I want to finish things.  I want to share them, and some of the things — like an IF Parser– should be fairly testable. I mean, I can take a script and pipe it into tads and get the game script out.  At least at some level, that should be completely testable.  So I started up a nodejs project for my parser, Mydas, and set to work.

I knew that I would be having a set of command strings, and I wanted to isolate what were  verbs, direct objects, and prepositions, etc. So I had a parser object, that was going to have some private functions to  parse the syntax. I’d found pos.js which had been ported to Node by Darius Kazemi. I pulled the parts, stopped myself and said, “Wait, don’t I need to write some tests first?”

I started digging around with mocha, and seeing how to write the tests, but I couldn’t figure out how to test my code. I mean, I knew what I was going to call it with, and what I expected out, but it wasn’t working. Part of it, of course, was that I was trying to test a private function. It was private because I know after 20+ years that’s where it’ll wind up, it’s not a public API, it should be a private function.  But you can’t test it.

You can, actually, there’s ways listed on Stack Overflow if you look hard enough.  But you shouldn’t.

Because I was doing it all wrong.

Not completely wrong, of course, my instinct was to focus in on the hardest bit of code and see if I could pound that out, get it working.  But that code won’t exist in a vacuum. It’ll be called from somewhere, with a particular goal in mind.  The truth is, I didn’t know if I was right when I was so certain that I was going to need this f unction, that it was going to be private, etc.  Probably, but I didn’t know.

The only way to know was to start with some use cases/user stories.  What does this thing do, and for whom? Then to slowly back up into writing the needed functions as you moved from the outputs to the inputs.  And that private function? When there’s a test for the public function that calls it, then you can refactor it to a private one, because it will still be tested. Starting with private functions risks code that’s never tested, and that’s decidedly not the goal.

And of course this makes sense. Only write code for the uses that the program will be written for. Figure those out first, and then write the code that does that. And then that because another user of code, which calls back and back until you’ve got the whole processing chain written and tested.  And I realized that I had at least two different kinds of users in Mydas — we’ve got the player who I had been focusing on, but you also have the author who is writing code. All of this has to work for both of them, and what does that mean anyway?

But, again, the advantage of this project is that I can specify the whole thing. I can write the Author’s inputs, and the player’s inputs as text files (perhaps) and input them both to the program, and be completely certain of what the output should be.  And that’s where I should start writing my use cases. And there will be more detailed ones as I go and worry about the how, and the what.

For the first time I feel like I might know what I’m doing with this.  Of course defining the what is turning out to be a harder task than I thought at the time, which makes me glad I started on it.

2 comments

  1. At this point, I believe that if C# seems to require a lot of boilerplate there is a library you are missing or you have an abstraction problem (too much or too little)…

    Anyway, Corpus testing is a very tried and true testing mechanism for parsers: here’s a giant sample of things that should parse and all the example edge cases that I can find that should not parse. I remember quite fondly how useful a corpus was to identify tweaking issues to a parser I once wrote…

    1. On C#: I’m very sure we’re doing stuff wrong. Unfortunately, I can’t separate out the parts that are C# and the parts that are unenlightened design. I’ve mostly learned form the code I’ve been given how to do things, and I think it’s both over-engineered for the task it’s been given. With our system, I’ve got to write a stored proc to get our data, then create a repository object, a manager object and a service object as well as interface versions of all of them. Then I’ve got to map the service to our main project, and create model objects which call the service, create the objects I need, and I still haven’t written the controller methods or created the view I need to display the data. Compare this to Cake.PHP or Yii, where I don’t write any SQL (I don’t mind writing the SQL, but it’s just not necessary). Cake does reflection to the database at runtime, so when you’re just starting you don’t even need to make model objects (it’s faster if you do). Yii generates that, but it creates a lot of useless boilerplate code, too.

      The other part of it is the sort of MS way of doing things that isn’t how I think or build software. I’m even more productive without the IDE, but part of that is that I’m horribly slow in C#, but don’t need to think about how to do stuff in PHP or JavaScript, really. Again, a good portion of that is how I learned them (and I was a pretty poor PHP programmer 20 years ago:) (yes that’s the right number)

      I’ll take a look at Corpus testing, I’m actually working on the other end right now, about how the game is defined and instantiated by the engine. I did find a cool parts of speech project for node (called pos, unsurprisingly). I know I need more than that, but it’s a start and something I don’t have to build myself.

Leave a Reply

Your email address will not be published. Required fields are marked *