Coding in the Dark
Programming is a craft… You work small miracles every day.
- Andy Hunt and David Thomas, The Pragmatic Programmer
Even in a seemingly straightforward game such as tic-tac-toe, a key challenge that I have faced is figuring out how to navigate uncertainty.
In a different context, this would be no problem. For instance, think of scheduling a hangout. If I had to coordinate brunch with my friends, I would typically wait to hear from invited friends about their general availability and preferred location (which may depend on where they live or their origin/destination). I would have a general idea about where I’d like to go based on my own availability and location, as well as restaurant recommendations that I’ve heard about from other friends. But really — the restaurant and day and time of our hangout is TBD until I hear back from my friends. Until then, don’t expect me to send out a calendar invite for an arbitrary date of my own choosing.
The process of writing a tic-tac-toe game has been primarily the same. The point that I’ve been struggling with is figuring out how to execute the game’s overall design. This is the equivalent of me trying to figure out whether I should prioritize two conflicting preferences for the brunch time (e.g. 11am versus 1pm). Or, figuring out a middle ground if someone is coming from Orange County and someone else is coming from the Westside. What do I prioritize? Getting caught in the details of scheduling brunch, similar to figuring out the architecture of a game, can be particularly straining.
While I won’t extend the brunch metaphor to the concepts below (hopefully it wasn’t too much of a stretch), I will be elaborating on their applicability to building software and its application to navigating uncertainty.
Tracer Bullets
According to The Pragmatic Programmer, tracer bullets are “loaded at intervals on the ammo belt alongside regular ammunition. When they’re fired, their phosphorous ignites and leaves a pyrotechnic trail… if the tracers are hitting the target, then so are the regular bullets.” In the context of software, tracer bullets apply to an approach in new projects, particularly ones that have not yet been built. Factors are not only up in the air, but bound to change over time. Andy Hunt and David Thomas, authors of the book, suggest moving toward to the final system in such as way that is quick and visible.
What tracer code can mean in terms of software is developing the individual parts and then bringing it all together to see if it works. The initial build can be a very simple build that shows the interconnected parts. Over time, the basic structure will be fleshed out to resemble something more sophisticated and closer to the final product. The code is not meant to be disposable. It is not functional until everything is connected and once that occurs, adding functionality and changing its requirement are considered easy.
To be fair, this is how I built my tic-tac-toe game. I worked on the smallest parts (writing unit tests and reusable code that are meant to be preserved) and moved up to bringing it together. When I first brought my game together, it was not initially a full-fledged game. Rather, I made sure that I was able to print a welcome command and the board. Then, I kept building it until it was closer to the game’s requirements.
Prototyping
Another way of navigating the unknown is through prototyping. The purpose in building software prototypes is to test viability (which is cheaper and faster than production) and to analyze any potential risks. (Granted, I have always associated prototyping with UX designers whose mock-ups get tested by end users).
In prototyping, code gets thrown away. Actually, prototyping doesn’t even require code; according Hunt and Thomas, you can very well use some kind of prototyping tool and then code based on any logic that has been acquired. This can also be applied to algorithms and lead to coding the algorithm in its final environment after trying it a high-level programming language first. It is something that is built to be “good enough,” but is meant to test a very specific aspect of the final product. Tracer code is more concerned about how the entire application is held together. Prototyping is used to solicit information and intelligence that is necessary for a tracer bullet to be fired.
Estimates
When first trying my hand at freelance work, I wasn’t perfectly sure about how long tasks would take me. If I never worked in a certain environment, how sure would I be that I’d accomplish the task in x hours? How long would it take me to troubleshoot and resolve issues? Similarly, providing more exact estimates is one of my current goals. In a professional context as a consultant, it will lead to less surprises and better outcomes. Here are some tips that Hunt and Thomas have shared:
- Think about the “scope of the domain.” That is, understand what is being asked and about the various factors that will influence how long certain tasks will take. Address the assumptions behind your estimate.
- Break out the various components and assign each one a value. Determine which one will have the most impact on the result and focus on getting that right.
- Track your estimation — what turned out according to what you predicted, and even what deviated. Understanding what went wrong can help your next estimate be better.
- Iterate the schedule with the code. With each iteration, the schedule becomes refined. I think this applies to how I’ve been approaching the tic-tac-toe game with my mentors. Each week, I have a better sense of where I’m at with my game — rather than designating a timeline out of thin air. The more code I write, the more progress, the better the estimate.
- Get back to people. Slow down the process and spend some time thinking about the various factors and employing the above tips. Giving an answer at another time can lead to better results in the future.