Documentation is difficult in the best of situations. I've encountered lots of bad documentation. Bad because it's unclear, inaccurate, or incomprehensible. Bad because it's non-existent. Bad because it insists on strictly using the vendor's own in-house terms, carefully chosen to be the most twee little metaphors they could imagine, but never explains those terms, thus being both incomprehensible and infuriating. "Enterprise" packages bring their own quirks and foibles, and tend to be some combination of unclear, inaccurate, or incomprehensible. Unless, sometimes, what we attribute to incompetence probably is actual malice.

An augur, sitting on the hilltop, predicting the future

I've brushed up against a lot of ERP systems in may day, ranging from the home-(over)-grown Excel spreadsheet on the network drive all the way to gigundous SAP build-outs.

On such project involved migrating 12 business units from a mixture of home-grown systems, legacy mainframe systems, and home-grown systems running on legacy mainframes into one, single, cohesive ERP. The product chosen was an offering from a company we'll call "Augur". Augur took one look at our insanely ambitious project, knew it was doomed to failure, and muttered to themselves, "Think about the consulting fees we can rack up!"

Of course, my employer didn't want to pay the consulting fees. They already had Augur domain experts hired in from a much cheaper consultancy, and our in-house developers knew how to read documentation. What could go wrong?

Plenty, but one of the smaller, simpler tasks I tackled delivered the biggest WTF. In a factory, there was a flow meter hooked up to a pipe that could tell us how much raw material flowed through that pipe. That flow meter was hooked up to a proprietary database with a very picky and flaky ODBC driver. I needed to get data out of the proprietary database and pass it off, after a little massaging, to Augur's ERP. Based on whatever product the ERP believed was being made at the time, it would then calculate raw material consumption, cost-of-goods-sold (COGS), losses, and all sorts of other wonderful production statistics.

Talking to the proprietary database involved some DLL hell, but once I was getting the data, it was time to feed it into Augur. The documentation for their consumption APIs said that I should call a method called RM_CONS_IN_FRMLU_FPT. It told me how to structure the data. It told me what other parameters needed to be set. I followed the instructions and checked the results: consumption got updated, but not COGS.

I checked my work. I rechecked the documentation. I skimmed through the underlying tables to understand the schema hiding beneath the API. I cried a little when I saw it, and then I went back to the docs. I twiddled a few parameters, and tried again. This time COGS was right, but consumption wasn't. Tried again, and now it refused to recognize the current production formula, and assumed I was just disposing of material, and only incremented my losses.

Eventually, I discover that RM_CONS_IN_FRMLU_FPT is actually a wrapper method for RM_FPT_CONS_BY_UT. I have to bootstrap a few more complex parameters myself, but I try again. Still doesn't works. Back to the docs, and then I notice a tiny little footnote: "To calculate COGS accurately, the parameter rec_cons_config must have its cogs_behavior property set to 57". So I tried that.

It crashed. It didn't just crash, though, it managed to go romping off down a bad code branch, mangled a bunch of records, committed the changes, and then crashed. I reset my dev environment and went back to the docs.

This time, I trace through a few references, discover another footnote which is itself reference to a white paper, which itself contains a footnote. "If cogs_behavior is set,RM_CONS_BY_UT,RM_CONS_IN_FRMLU_FPT,RM_CALC_FRMLUandCOGS_RM_CALC_USAGE may alter data in an unrecoverable fashion."

Now, Augur's database technology separates the header for a code package from the body. This is great for Augur, as they can distribute the compiled versions of their proprietary stored procedures, but not the code. That was less great for me, as I couldn't just read the code to see what it was doing, but I could read the headers.

And there were so many undocumented parameters, each using undocumented record data types- Augur's equivalent of a struct. Tracing through the headers, I eventually found that there was a flag which was, for all intents and purposes, the secret_make_cogs_work_flag. I flipped that to true, and voila, suddenly everything was calculating.

I can't say, beyond a shadow of a doubt, that the documentation lied to me. It could have been wrong, outdated, or I could have just misread things. But given the problem- a major feature doesn't work or even destroys data- and given the simplicity of the fix, I can't see it as anything but an active attempt to mislead.

"Never attribute to malice what could be explained by incompetence- unless it's a major enterprise product vendor, in which case they really just want to sell you consulting."

[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!