Gen AI in Software Development, Not Coding 1
August 31, 2025
Gen AI in Software Development, Not Coding 1
I feel like I want to do a “stop talking about Gen AI generating code” series. Maybe I’ll just drop a few of these out ad-hoc, see how folks respond.
Today’s thing is managing decisions. Here’s a pattern I use.
I often have something like a plan document in my repositories. It’s usually ephemeral, that is it exists for a while until the plan is done, then I delete it.
Imagine you were doing XP and just tossing brainstorming stickies on a new feature all over the whiteboard. That’s how my plan starts. Get all the perspectives in the room, everyone writes down their top-of-the-head concerns. Scrunch up and bin the bad ones, clarify, you know regular brainstorming kind of stuff. Leave the room with some consensus on the core things.
From that input (maybe you took a picture and asked a visual model to record those to a markdown file) I generally let the LLM do it’s generalized knowledge correlative magic, something real simple like:
Read BRAINSTORM.md carefully. Identify themes and organize this into a specification in SPEC.md.
This is speculative. It will produce a document, but in the beginning it will likely be of questionable value. This becomes your first feedback loop. It will come up with weird things, and those weird things will probably indicate assumptions or gaps in your brainstorming.
You can iterate the SPEC.md itself, or you can go back to add items to the BRAINSTORM.md. I might start adding to BRAINSTORM.md and have a brand new SPEC.md generated. It probably is organized differently, maybe I adjust my prompt to explicitly outline the sections I want. Maybe the sections don’t matter so much to me right now. Maybe I’ll start to get invested in them sooner or later.
Now, it’s a behaviour of various LLMs to get all wishy washy.
- Generate a 256-bit random token (os.urandom(32) -> base64url or hex).
- Store only its hash (SHA-256 or Argon2id). Never persist the raw token.
- Return the raw token exactly once in POST /jobs response.
- Require token for GET /jobs/{id} and /jobs/{id}/result via header or query param.
- Use constant-time comparison on hashes. Return 403 for mismatches.
This was neat for me, I hadn’t been tracking Argon2 as a hashing algorthm. This is the kind of thing that the security geek on my team might have tossed on the board as a brainstorming idea, and I’d have loved them for it.
But look at all the “or”s in there. We need to make some decisions. This is a bit tricky though - you might be inclined to say something like “Let’s use base64url to encode our tokens.” - sounds reasonable right? You just made the decision.
But then you get…
- Representation: base64url (RFC 4648 URL-safe), unpadded. Do not use hex.
And then you get a little frustrated and follow up with something like “Don’t state what not to do, there’s no end to things we aren’t going to do, it’s pointless and confusing to the reader.”
Finally you get to…
- Generation: 256-bit random bytes (os.urandom(32)) -> base64url, strip any ’=’ padding (43 chars).
Effectively what you’re on here, and you can do it organically or build out a more formal prompt, is making and recording your decisions.
Now you’re iterating on and targeting your SPEC.md into something more actionable.
You could take a fairly direct approach too…
Go through SPEC.md, identify outstanding decisions, number them and add them to the bottom of the file.
I like this because then I can refer to them one by one, like…
- The token may be provided with the X-Authorization-Header or as a Bearer token under Authorization, or as a parameter to the URL like ?t=[token]
Decision #12, we will expect the token as a Bearer token in the Authorization header. Update the document to reflect this decision, remove references to other options, and mark this item complete.
Anyways, I hope this is interesting to you. It’s an aspect of software development that must happen, before we write code, as we’re writing code, it happens different ways in different circumstances, but the decision was the work, and the code was just the codification of the decision.
I’ll leave you with one final thought. If you believe that all of the decisions can be extracted and chosen before code starts to get written, I’m afraid I have some bad news for you. This has never been the case. Code is code because it, and only it, precisely specifies what the computer must do. We certainly didn’t eliminate all of the decisions yet to be made in this example, though it might seem like we did.
You can’t program a computer in the english language. It lacks precision, and people lack precision when they wield it.