Having been a software consultant for the past two decades or so, John wasn’t too worried when his client asked for some help developing against a “fairly niche” vendor SDK (Software Development Kit) for reading genealogy data from various file formats. When his client mentioned the SDK author had gotten the nickname Dinosaur Bob, John just shrugged his shoulders. He had conquered many a SDK in his day, so how bad could Dinosaur Bob’s SDK be?

The first alarms started going off when John tried to use the SDK’s test program to open a sample project. One of the file formats the SDK supported was called TMG, and that format happened to be developed by the very same Dinosaur Bob. It seemed like the logical place to start, so he loaded up the Dinosaur Bob’s TMG software and created a small sample project called simplest.

On disk, the simplest project was nothing more than a zip file named simplest.zip, and it had a whole lot of files inside, none of which had a .tmg extension. The SDK included a test program (naturally called TEST.EXE) that could be used to open any supported file format, so John simply typed in TEST.EXE simplest.zip and hit enter. The testing program responded with two simple (and mostly correctly-spelled) words: invaild input.

With documentation as terse as the error message, John had little choice but to reach out to Dinosaur Bob himself. From what he could make of Dinosaur Bob's reply, the correct way to open simplest.zip was to create an input file called input.txt containing the following magic instructions:

GbInit 3 50000
GbOpen simplest.zip
GbIndiv 1
GbName 1

Then, you could run TEST.EXE input.txt output.txt, which would presumably open the file, read the first individual, read what one would assumed to be his first name, and write to output.txt. Of course, when John ran TEST.EXE input.txt output.txt, he got a slightly different error message: Database could not be opened at simplest.ZIP.

“You don’t pass in the zip,” the first half of Dinosaur Bob's response read, “have to unpack it first.”

Hoping for an “aha moment”, John unzipped the file and found the following.

SIMPLEST_$.CDX                                  simplest_b.dbf
SIMPLEST_.LST                                   simplest_c.FPT
SIMPLEST_A.CDX                                  simplest_d.FPT
SIMPLEST_B.CDX                                  simplest_d.dbf
SIMPLEST_C.CDX                                  simplest_dna.FPT
SIMPLEST_C.DBF                                  simplest_dna.dbf
SIMPLEST_D.CDX                                  simplest_e.FPT
SIMPLEST_DNA.CDX                                simplest_e.dbf
SIMPLEST_E.CDX                                  simplest_f.FPT
SIMPLEST_F.CDX                                  simplest_f.dbf
SIMPLEST_G.CDX                                  simplest_g.FPT
SIMPLEST_I.CDX                                  simplest_g.dbf
SIMPLEST_K.CDX                                  simplest_i.FPT
SIMPLEST_L.CDX                                  simplest_i.dbf
SIMPLEST_M.CDX                                  simplest_k.dbf
SIMPLEST_N.CDX                                  simplest_l.FPT
SIMPLEST_ND.CDX                                 simplest_l.dbf
SIMPLEST_NPT.CDX                                simplest_m.FPT
SIMPLEST_NPV.CDX                                simplest_m.dbf
SIMPLEST_O.CDX                                  simplest_n.FPT
SIMPLEST_P.CDX                                  simplest_n.dbf
SIMPLEST_PD.CDX                                 simplest_nd.FPT
SIMPLEST_PPT.CDX                                simplest_nd.dbf
SIMPLEST_PPV.CDX                                simplest_npt.dbf
SIMPLEST_R.CDX                                  simplest_npv.dbf
SIMPLEST_S.CDX                                  simplest_o.dbf
SIMPLEST_ST.CDX                                 simplest_p.FPT
SIMPLEST_T.CDX                                  simplest_p.dbf
SIMPLEST_U.CDX                                  simplest_pd.FPT
SIMPLEST_W.CDX                                  simplest_pd.dbf
SIMPLEST_XD.CDX                                 simplest_ppt.dbf
born in virginia or tennessee.acc               simplest_ppv.dbf
end of line ancestors.acc                       simplest_r.FPT
females who are not living.flp                  simplest_r.dbf
living status.acc                               simplest_s.FPT
males and females.acc                           simplest_s.dbf
people who are adopted.flp                      simplest_st.FPT
people whose given name begins with john.flp    simplest_st.dbf
people with more than six children.flp          simplest_t.FPT
simplest_$.dbf                                  simplest_t.dbf
simplest__.PJC                                  simplest_u.dbf
simplest__.log                                  simplest_w.dbf
simplest_a.FPT                                  simplest_xd.dbf
simplest_a.dbf                                  women whose given name contains liz.flp

Now what? John asked himself, which of these files should I open? He was pretty sure it wasn’t people with more than six children.flp or women whose given name contains liz.flp

After trying a half dozen different file names, John asked Dinosaur Bob exactly what file name he was supposed to pass in. “simplest_” was Dinosaur Bob’s single-word reply. And like that, it worked. It was finally time to try the coding against the API.

In the input.txt file, the magic numbers 3 and 50000 were absolutely critical components of the API. You see, before you can open a file, you have to call a function called GbInit and pass the file format and a buffer size. So GbInit(3,50000) means, you are planning to open a TMG file (file format 3) and will be passing a buffer that’s 50000 to receive the data after opening the file. With this API, you have to plan everything in advance!

In the example we saw GbName 1 to read the first name. You might think GbName 2 and GbName 3 would read the next two name entries, but you’d be wrong. The correct way is:

GbName(1)  // Read the first name
GbName(0)  // Read the next name
GbName(0)  // Read the next name

Some of the commands worked like that (1 indicated reading the first record from the file, 0 meant read the next), while others were 0-indexed and others were 1-indexed. But a lot depended on the file format you were working with. In TMG, if you wanted to, say, find the total number of individuals, you’d call GbIndiv(0).

Of course, that alone wouldn’t return the total number of individuals, you’d have to loop through each record and check for “empty entries” and “deleted entries”. However, since each file format handled those concepts differently, it seemed the best course of action was to keep calling GbIndiv(#) until you get the error 1 (End of list). Or 2 (Record not found), 3 (Empty Record), or 4 (Deleted Record)

The most surprising thing about the SDK was that John’s first day of working with it was by far the best and most productive. Since there was no ticketing system for filing bugs with Dinosaur Bob, John had to file bugs via email. When he offered to use his own ticketing system, Bob refused saying that, “learning a new system would take away the productivity from actually fixing bugs.”

As he continued using the SDK, John could tell that Dinosaur Bob was really starting to dislike him. Some of his favorite responses included

  • “Your application lacks proper philosophy.”
  • “You lack sympathy for hard-working SDK developers”
  • “You do not know how to use other people’s programs”
  • “You are filing too many tickets to keep up”

Eventually, John was banned from emailing Dinosaur Bob directly. A ticket system would have accomplished a similar objective, but Dinosaur Bob instead chose his company’s receptionist.