Different ways I start writing new code
I’ve been to a bunch of technical job interviews this year and one of them sparked me to think about different practical approaches I have for starting new code. It sparked those thoughts mainly because I did a rather bad job with it during that interview (but managed to pull myself together towards the end). Didn’t end up getting an offer though.
Here are my five approaches. I don’t have a good framework for when I choose one but I usually end up starting with one of these.
Start with tests
Test-Driven Development is a practice where you
- write a failing test
- write the minimal solution that passes the test
- refactor
In addition to a test being something that helps (to some extent) guarantee the code does what it’s supposed to but by writing tests first, they drive the design of the interface, ie. how the code is used. It drives the design and development with small increments that are at each step tested.
I often do this when I have a clear idea of what I’m doing or if I’m fixing a bug. Especially in the latter case, I want to make sure I can capture the problem in question, reproduce it reliably and have a tight feedback cycle that informs me if I’ve managed to fix the bug.
Another benefit in the context of this blog post is that I can run the code on very small intervals and iterations.
Start with the interface
The second approach is to write the code “outside in”. What it means is that I might write the equivalent of a main function and write how I’d like that to look like: what objects am I initiating or what functions I’m calling. None of it will work, which hinders the ability to run and verify that things are working.
The benefits with design are similar to writing tests: instead of writing individual bits of code as they come to mind, I build a coherent interface to the code.
Once I’m done with the first layer (the main function), I then start implementing the classes and functions based on what I’m missing. These layers follow the same iterative approach: I call functions that don’t exist, based on how I feel the interface would make the code easier to read.
My experience with this approach – which is often the one I enjoy the most – is that in the end, I get to a result that is really good. A major downside however is the lack of immediate feedback cycle.
Start with the models
The third approach is where I start by modeling the classes and data structures based on the problem statement or spec. It probably originates from me learning object-oriented programming in the university during my formative years as a developer.
It feels very good because it helps me form some structure in the chaos. However, my experience is that it often leads to way worse design/architecture than the two previous approaches. I often end up modelling individual bits and pieces and the resulting design is not often very coherent. So it needs a lot of refactoring and improving and sometimes it’s hard.
It is sometimes the right solution to a problem, especially if I end up doing database tables as part of the solution.
Start with documentation
One of my favourite approaches and then one I use for example when I develop my 235 app is documentation-driven development. With it, I start by writing the documentation: it could be user guide, manual, library usage docs or however the software is being used.
It is similar approach to the interface-driven or test-driven development that you start by designing how the code is being used. But it takes it to a new level by explicitly starting with the user in mind. Not only in terms of code and technical implementations but by focusing on what the full user experience is. If you’re building a command-line tool, what are the arguments, subcommands and flags? Do they make sense and are they in line with your existing ones?
Start by randomly poking around
The first four are the optimal cases but let’s be real: sometimes we just poke around and try to make something happen. I’ve written about my iterative approach earlier and sometimes (to be fair, often) I don’t know enough at the beginning so I just start writing something to learn where the “goal line” is and then move back and forth, improving and refactoring the code as I move forward.
Bob wrote about how his creative process sometimes requires “closing the door” and I feel this is the part in coding where I want to be alone, until I reach the first iteration and gain more confidence in knowing I can solve the issue or build the feature.