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.