From DollarDollar Bill Y'all to finPal: what bad engineering (and bad AI habits) taught me

Before finPal existed, there was a repo called DollarDollar. Yes, like the song. I named it at 1am, deep in a debugging session, and I've never regretted it once. It's still on GitHub, preserved for historical reference, and every so often I go back and look at that code the way you look at an old photo of yourself in a haircut you thought was a good idea at the time.

DollarDollar started the way most of my side projects start: frustration. I was tired of finance apps that wanted my bank credentials, sold my spending patterns to advertisers, or buried the one feature I actually needed behind a paywall. So I built my own. Multi-currency tracking, bill splitting, budgets, the works.

Here's the part I actually want to talk about. DollarDollar was also my first real experiment in AI-assisted development, and it was a genuine wake up call on how not to do it. Here's what I actually did wrong.

I was using local models, qwen2.5 and DeepSeek-V3, alongside Claude, and I let them write a lot of code. Not "generate a function and I'll review it" a lot. More like "describe the feature and accept most of what comes back" a lot. It felt fast. It felt productive. What it actually was, was a codebase accumulating debt I couldn't see because I wasn't the one deciding the architecture anymore, the tool was, one plausible-looking suggestion at a time.

The AI wasn't the problem, exactly. The problem was me treating a coding assistant like a decision maker instead of a very fast, occasionally wrong collaborator. It would write something that ran, that looked reasonable, that passed a quick manual test, and I'd move on. Structure decisions that should have taken real thought got made implicitly, by whatever pattern the model defaulted to, because I never stopped to ask if it was the right one. Migrations got messy. Logic got tangled across files in ways that made sense in the moment and made no sense three weeks later. I was shipping features. I wasn't building a system.

Here's a made-up but honest reconstruction of the pattern, the same conversion logic, written slightly differently, four separate times, because each prompt only ever saw the one file it was editing:

# budgets.py
def to_usd(amount, currency, rate):
    return round(amount * rate, 2)

# transactions.py
def convert_to_usd(amt, cur, exchange_rate):
    return round(amt * exchange_rate, 2)

# splits.py
def usd_amount(value, currency_code, fx_rate):
    return value * fx_rate   # missing round() here, nobody caught it for weeks

# reports.py
def normalize_currency(x, c, r):
    return round(x * r, 2)

Four functions, four names, one of them quietly rounding differently than the other three. None of that was the AI being bad at its job. It did exactly what I asked, one file at a time. I was the one who never asked whether this logic already existed somewhere else.

That's the failure, plainly. What it actually taught me is the part I still carry around. I still believe in AI-assisted development. I use it constantly, on palStack, on data platforms, on this blog. What DollarDollar taught me is the actual discipline required to do it well, and it's not complicated, it's just easy to skip when things feel fast. Review every suggestion like you wrote it yourself, because you're the one who has to live with it. Decide the architecture before you let anything generate code inside it, not after. Treat AI output as a first draft from a very capable, very literal collaborator, not a finished decision.

That's actually become one of the non-negotiables at palStack now: AI suggests, humans review every line. I didn't arrive at that principle from a conference talk. I arrived at it from staring at my own bad migrations at 1am, more than once, wondering how it got that tangled.

That principle is also the reason DollarDollar eventually became something else. I stopped patching it and rebuilt it properly, real architecture decided up front, real review discipline, a modular structure that could actually support the features I wanted to add instead of fighting me every step. That rebuild became finPal, part of palStack now, and the difference isn't cosmetic. It's the difference between code that happened to me and code I actually designed.

Four separate copies of the same logic converging into one shared function budgets.py: to_usd() transactions.py: convert_to_usd() splits.py: usd_amount() reports.py: normalize_currency() conversion.py convert_to_usd() one function, everyone imports it

Four almost-identical functions, one of them rounding wrong, collapsed into one the rebuild made everyone actually share.

My wife endured a lot of those late nights, more debugging sessions than either of us would like to count, and more patience than I probably deserved while I figured this out the hard way. I don't think that part gets said enough when people talk about building software. Somebody's usually there for the version of you that hasn't figured it out yet.

If you're deep in a vibe-coded side project right now and it's starting to feel like it's fighting you, that feeling is information. It was for me. DollarDollar taught me more about actually engineering software than a lot of projects that went smoothly ever did, precisely because it went wrong in ways I had to sit with and understand. I'd rather have that scar tissue than not.

← Previous post Next post →