I set out to build a list of the knitting needles I own. What I actually built was a compatibility engine, because the honest answer to "what do I have?" is "it depends on what you're trying to make."
This isn't a hypothetical persona. I knit, and I own a lot of needles. Most of them are interchangeable: a set is a bag of tips, cables, and small connecting parts that combine into a finished needle. The recurring frustration is small, specific, and mine. I'm standing in a yarn store, holding a pattern that calls for a US 8 at 32 inches, and I cannot remember whether I already own the pieces to make one. I have genuinely bought duplicates I didn't need because I couldn't remember which pieces were already in my collection, and I've also gone home empty-handed only to find I'd had it all along. The whole project started from that lived frustration, which is the strongest kind of product knowledge to build from: I am the user.
The obvious fix is an inventory app. List what you own, check the list at the store. I started there, and the model fell apart almost immediately.
Most inventory tools assume items are atomic: you own a thing, you list the thing, you look it up. Interchangeable needles break that assumption. A fixed circular is atomic. But an interchangeable set isn't a list of needles at all. It's a set of components that combine, and only some combinations are legal. "What do I own?" is the wrong question. The real one is "what can I build right now?" That's not a lookup. It's a computation.
The tempting first schema is one flat table of needles: size, length, brand, done. It fails on contact with a real collection, for three reasons that only surface when you try to answer a real question.
Components combine, so a needle isn't a row. A finished interchangeable needle is a tip plus a cable. The same tip makes a different needle on a different cable. Storing "needles" means either duplicating every possible combination as a row, which explodes, or storing the wrong unit entirely.
Compatibility is a real constraint, not a detail. A tip only fits a cable if their join sizes match. A US 8 tip and a 32-inch cable are useless together if one is a small join and the other is large. So the model has to know join sizes and enforce them, or it will confidently tell you to build things you physically cannot.
Ownership and availability are different questions. If your US 8 tips are currently on a half-finished sweater, you own them but you can't use them. "Do I own it" and "can I build it today" diverge, and the second question is the one that sends people to the store to buy a duplicate.
Rather than guess at compatibility, I modeled it on ChiaoGoo's published interchangeable systems guide. Two rules from that document ended up driving the entire engine, and both corrected assumptions I had made on my first pass.
The guide states it plainly: TWIST and SPIN parts interchange whenever the join sizes are the same. My first model had treated the product lines as separate systems, which quietly hid legal combinations from the user. The fix was to collapse them into one family and let a single property, the join size (mini, small, or large), govern everything. Fewer concepts, more correct answers.
This is the detail I could never have guessed. A needle's join size depends not just on its US size but on its tip length. Short 2-inch and 3-inch tips split the size bands differently from standard 4-inch and 5-inch tips. The consequence: a US 2 needle is a mini join as a 2-inch Shortie, but a small join as a 4-inch tip. Same size, different join, depending on a property most inventory apps would never track.
That second rule is the clearest example of why reading the spec beats assuming. A model that looks obviously correct can be quietly wrong in a way no amount of staring at your own needles reveals, and only surfaces when you check it against the source. The app now computes join size from both US size and tip length, and I verified every band against the published ranges.
A related trap: cables are sold by cable length, not by the length of the needle they make. The finished needle is the cable plus both tips. An 8-inch cable with 4-inch tips is the familiar 16-inch circular. Shorter Shortie tips on the same cable produce a shorter needle. So "length" is a derived value, and the store lookup has to compute it rather than read it off a label. Getting this wrong would mean telling someone they own a 32-inch needle when they actually own a 30-inch one, which is exactly the kind of quiet error that erodes trust in a tool you consult under time pressure.
Once the data model was right, the interface question became interesting. I realized the app is used in two completely different moods, and forcing one screen to serve both would compromise each.
One hand free, fifteen seconds, maybe bad signal. The only question is "do I already have this?" So this screen is a size-and-length picker with a big yes or no, and a note on what's tied up in a project.
At home, unhurried, adding and tidying. This is the full catalog, grouped by category, with the build panel showing every configuration the collection can produce.
Both modes read the same items and the same compatibility engine. The difference is entirely in the question each screen is built to answer.
Recognizing that "look something up fast" and "organize a collection" are different jobs, deserving different screens over shared data, is the part of this project I'd point a hiring manager to first. It's a small product decision, but it's the kind that separates a tool people actually reach for from one they abandon after setup.
The compatibility engine started simple: a tip fits a cable when their join sizes match. Then two real-world mechanics turned pairing into a small pathfinding problem.
Adapters let a tip connect to a cable one join size away. Own the right adapter and combinations that were impossible become buildable. Connectors join two cables end to end into one longer composite cable. And the two compose: a connector plus an adapter chains two cables of different join sizes into a single longer run, with the adapter bridging the junction.
That chain is the whole engine. A tip reaches a cable directly, or through an adapter. Two cables join through a connector, and if their joins differ, through an adapter at the junction. The build panel walks these paths, computes the finished length of each result, and flags exactly which adapters and connectors a given configuration depends on, so you know what the answer rests on.
This is the moment an "inventory app" quietly became a constraint solver. The value stopped living in the items and moved into the relationships between them, which is the same lesson that runs through my QA work: the interesting failures and the interesting capabilities both live between components, not inside them.
Naming cuts is as much a part of the design as naming features, so here are the ones I made on purpose.
A prototype that only runs on my laptop doesn't solve the store problem, so I built it as an installable, offline Progressive Web App. It installs to a phone home screen, works with no signal after the first load, and keeps all data on the device. That last point isn't incidental: yarn-store reception is genuinely unreliable, so the local copy has to be the source of truth, not a cache waiting on a server.
Where it goes next, in the order I'd build it and the reasoning for that order.
| Next | Why it comes when it does |
|---|---|
| Barcode scan to add | Capture a cable or set at the store by scanning it, instead of typing it in later. Serves the exact away-from-home moment the store lookup was built for. |
| Cross-device sync | Optional login so the list follows you from laptop to phone. Offline stays the source of truth; last-write-wins is enough for one person's own devices. |
| Crochet hooks | Track hooks with quantity, so duplicates are visible. Same "do I already own this?" question, different tool. Broadens the product from needles to fiber tools. |
| Tunisian hooks | Interchangeable Tunisian sets share the exact combinatorial structure this app already models: hook plus cable, by join size. The engine is already most of the way there. |
Scan-to-add and sync both deepen the core loop the store lookup created. Crochet and Tunisian hooks are a broader bet, expanding the product's scope rather than sharpening it, and that's worth making only after the core loop proves it earns its keep. Sequencing by "sharpen before you broaden" is a judgment call, and stating the judgment is the point.
The résumé work shows product thinking inside a company. This shows it end to end and on my own: I found a real problem I have, resisted the obvious-but-wrong data model, grounded the hard rules in primary-source documentation, designed for the two contexts of actual use, built and tested a working compatibility engine, shipped it as something installable, and drew a roadmap with reasoned priorities and honest cuts. It's a small product. But every decision in it is one I can defend, which is the only kind worth putting in front of a hiring manager.