MJ to JC, God’s DRY Humor

Michael Jackson was remembered this week, having died last week at the age of 50. John Calvin was born 500 years ago this week. He died when he was 55. Both of these men were odd ducks. (Trust me, I knew them both very well.) It is a stretch to fit them into this blog entry, but I’m not so much crafting these entries as shedding them from my brain when they arise.

I’m not sure how much MJ and JC have in common. I started a comparison list that made me laugh, but I’ll save you the effort of trying to figure out my humor and save myself the shame of not being able to pull of what David Letterman does. While the exercise gave me some of that We are the World sense of unity, thinking about these two men also brought to mind how God must use the Don’t Repeat Yourself (http://en.wikipedia.org/wiki/Don’t_repeat_yourself) approach to the construction of humans. At the very least, thinking about MJ and JC together made me appreciate the sense of humor of the Divine.

My next door neighbor is writing her dissertation on Calvin’s view of the body. You might wonder what the odds are that I would live next door to another Calvinist, but around here the odds are very high (I was going to write “good” but…). I live in a city with a population around 6,000 and at least 10 churches of Dutch Calvinist descent, right here in the heartland of America.

As an aside (as if the rest of this were not), while the popular press often highlights Irish-American, African-American, Italian-American and other ghettos, rarely does the national press pick up on stories related to Dutch Americans. Except in a few odd places around the country, we are a people who fade into the backdrop, or equally likely, step up to the plate looking like the average American. In some ways, we are a good example of the melting pot at work.

In the popular press, Calvinism has typically taken abuse in those cases where I have noticed it was referenced during my adult life. I would have no problems taking a few jabs at this “-ism” myself, since I consider it descriptive but not prescriptive for myself (this is where another blog entry might go off on a data schema tirade, I’ll stop myself here), but most of what I have heard has simply been inaccurate.

Calvinism is now getting some revived popularity. Bill Clinton mentioned recently that he was “too much of a Calvinist…” regarding his work ethic (http://video.aol.com/video-detail/clinton-not-a-house-husband/1604078481) and someone just pointed me to this more recent post too http://news.bbc.co.uk/2/hi/europe/8140821.stm. There is a New Calvinism discussed in religious circles, even if among a group more conservative, it seems, than I (those apposed to women in church offices, for example). I wonder if it will ever be cool to be a Calvinist?

I have gone off on quite a tangent here, but let me talk about one tiny place where I would like to see a revival. I have several cases where the use of a DRY approach to coding would suggest factoring out some similar code. In particular, I have a tab 6 in one web page that should be almost identical to tab1 in another, with a few differences. Right now I am going to specify these pages in XML by cloning one to seed the other. Cloning and changing is part of the lifeblood of developers, but unless the changes are significant, it should also prompt one to try to figure out how to not have to write and maintain the same or similar code in multiple places, how to write DRY code.

In our framework there are several ways to reuse code. In this particular case I do not think any of the approaches of which I am aware would be quite right. This is not a good case for subclassing a superpage. Taking the contents of an entire form and other components from a page and rolling them into a single component would also make for unnecessary complexity. Additionally, the use of iframes has pros and cons and we have avoided them to date for such purposes. This isn’t a good case for making new aggregate objects, more shared methods than already planned, nor even for a good old-fashioned shared subroutine.

You know what would work in this case? A simple insert or copy code with a code fragment, in this case a piece of xml that might not even be well-formed (the start of the xml differs in each case), that is simply inserted into each of these classes at the right spot. That isn’t a hip way to employ DRY programming tactics, but it has served the discipline well for years in many places, from COBOL copy books to server-side includes for html. I’m missing that feature right now and I would like to have it.

I would ask, just to make sure that I am correct in thinking I do not have this option with my toolset, but I have other dumb questions to ask so I won’t waste a chit on this. Plus it’s Saturday, so maybe I’ll bake this gluten-free Bob’s Red Mill chocolate cake and decorate it with R.I.P. M.J. and Happy 500th J.C. Maybe I’ll just google to see if anyone has made a John Calvin moonwalking video instead.

Crap Code

I wrote a lot of crap code the summer of 1977. It was COBOL and not of the structured variety. Oh, it had a structure and I developed and adhered loosely to many standards I dreamed up, but I knew nothing of structured programming at the time. My boss and mentor hired me based on a referral from my undergraduate college when he was looking for a student for the summer. He saved me from starting either of the two jobs for which I had been hired that summer: nurse’s aid in a nursing home, which is what I had done from ages 17 – 19, and waitressing, a job for which no one who knew me thought me to be a good candidate. Those half-credit courses in COBOL, BASIC, and Fortran during my junior year of college paid off.

That summer I wrote Accounts Payable, Accounts Receivable, General Ledger, Payroll, and Depreciation systems for a storage company, from scratch. I had never taken an accounting course nor worked in that area, so I learned a lot. I learned about debits and credits and what a 10-key was. I was fast. I could write and maintain spaghetti code and manage volumes of important and sensitive data as if I had no clue to the relevance of any of it. There is something to be said for hiring students.

After I learned about structured programming, I was embarrassed by the code I had written. Some years later when I taught COBOL and suggested a student for my old employer to hire for the summer, I let that student know it was important to make sure all of my code was gone or rewritten. She should do as I said and not as I did in my past.

So now that I am back at it again, after a couple of decades away from heads-down coding, my code is more structured, more OO, more easily maintained than my 70’s code…in theory. I’m adding in after posting this that I should be clear that in the 80’s my code was pristine, lovely, elegant, and in the 90’s my OO code employed various elegant design patterns, so spaghetti code is not the only thing I have written.

We started this project as one of the first teams to attempt to use the Model-View-Controller approach with the Zen platform on Cache’ and a MultiValue database implementation. We were new to almost everything about it. Both the MV and AJAX implementations were relatively recent for InterSystems too and the combination of these was not yet out in general release, so there were glitches here and there.

Others on our team had programmed a lot of MV BASIC over the years, while I had not. Most of the production code I have written was COBOL with a good percentage of that being CICS, so I had to learn JavaScript and MV BASIC better, having previously had a bigger-than-a-breadbox taste of each.

With the Zen framework, we are writing XML specifications, OO declarations, SQL against MV structures, MVBASIC and JavaScript methods, html, and CSS. In some cases, every one of these languages is in a single Zen page class. While learning all of these pieces and how they interact, something we are still doing, we often employed a strategy of stopping once something worked. So, if we took four roundtrips when one ought to work, but we can figure out how to make it work with this platform with the four roundtrips to the server, then we get to the point where it works and we move on to the next thing.

I have a bunch of little to mid-sized changes to make to what we have done to date to enhance the user experience, so I’m tempted to do some refactoring of old code based on what I know now. That has risks, will take time, etc, but will also pay off. Once there are customers it is much harder to be proactive about such. On the other hand, one could tweak working code indefinitely too.

I recall playing scrabble with my father-in-law when I knew there was a good move to make, but I wasn’t coming up with it. So I flipped my letters over and asked the others at the table to help me make the optimal word. Bad move. That wasn’t how my husband’s family played the game. I got the results I wanted and even told them they didn’t have to add it to my score. That wasn’t how they played either. Live and learn. I’ve considered asking if either InterSystems experts or peer volunteers could take a look at our code and make suggestions, but I figure that given that we have tons of suggestions when we look at our own code, that approach would not gain enough right now. Once we have something we think is good, then that might be a better time to ask, but I suspect that would be hard to do for a number of reasons, pride being one of them.

I’ll try to make good business decisions on when to refactor, when to do minor changes to improve such things as variable names since our standards have evolved somewhat. Is it ever a good decision to leave crap code in the software? I hate to say it, but probably. I can certainly imagine a good business decision in some cases will mean that there will still be crap code left after going through and making these changes, but I would prefer that everything be top notch, of course.  Hmmm…decisions, decisions.

The Lewis and Clark UX

We had a lovely day on Lewis and Clark lake, behind an Army Core of Engineers dam on the Mighty Mo (the Missouri River) last Friday. We had been to Lake Okoboji on Memorial Day, a fun, busy lake that reminds me of lakes back in Michigan. Lewis and Clark lake is surrounded by state park areas, however. It is quiet. We stayed at the vacation home of friends of ours, a beautiful house on a bluff overlooking this beautiful, peaceful lake.

After boating on the lake for a bit, we stopped to take in nature and settled in to read. I pulled out Don’t Make Me Think: A Common Sense Approach to Web Usability, 2nd Edition I don’t often read such books a second time, but this was a good time in the project to re-read this one, and it was the right-sized book to bring along. It is simple, to the point, and almost like vacation reading, but with less of a plot.

One point Klug makes is that where there are standards in user interface design, it is good to use them or to know why you have opted not to do so. I can certainly agree with that. What might be a reason not to use the same user interface as others do when implementing similar features?

For some design choices, I choose a 1980’s style design over a Web 2.0-like design (and no, I won’t discuss the meaning of that overused marketing term). I want a bit of that simple, rock-solid, ATM-like interface that even my mom would use without thinking it has disrupted life. I don’t want to surprise people with something they don’t want to see.
Or do I? Imagine my surprise when right there on Lewis and Clark lake, where the shore was almost undisturbed by civilization, I spotted a farm (you might call them confinement lots, we call them farms). If you have read previous blogs, you might recognize that one reason for me to get out of town and head to a lake is that I am allergic to cows and pigs and we live ever so close to ever so many of them. Really surprising to me is that I spotted it before I smelled it. Even when we got closer to see that this was a very meticulous farm, it still did not smell much at all.
We later learned that this was a Hudderite farm. The story we were told is that each year each of the men in this Hudderite community draws their job for the coming year out of a hat (metaphorically, at least). I enjoyed the story, enjoyed seeing a farm on this otherwise very secluded lake in spite of typically avoiding such, and enjoyed my entire time on the lake. This farm added to my enjoyment, it did not detract from it.

My Lewis and Clark lake experience recap: I left our farm town to find fresh air on a lake a couple of hours away, only to find that cows and pigs followed me there, showing up on a confinement lot on the shores of the Mighty Mo. What a terrible user experience (UX) this should have been, but it wasn’t. I enjoyed every bit of it. I like confinement lots even less than the average PETA person. It was a surprise, but an oddly good one, to encounter this farm.

Who would have thought that seeing a confinement lot on this lake would have been a good user experience for me? It seems so unlikely. Perhaps the fictitious, but likely, farmer on the boat a mile down from us was disturbed by seeing the farm. But how can anyone know in advance? Maybe on another day under different conditions each of us would have had the opposite reaction.

It really is very hard to know what your users will experience when they use your software. You can do UX testing until the cows come home, and you will learn a lot, but there will still be many mysteries. If you make everything calm and peaceful, like floating on a lake with beautiful weather and undisturbed (ok, that dam was quite the disruption at one time, no doubt) nature all around for miles, maybe that would not be as good a user experience as having users see or do something unexpected, even if not pretty.

From now on when I am surprised in some potentially negative way when doing a pre-UX test of our software, I might just consider the feature to be part of a Lewis and Clark UX.

No Customers Means No Customer Service

Someone once told me that librarians would be happiest if everything were checked in and no one was visiting the library.

We are at the point of needing to have at least a plan for collecting requests, suggestions, issues, and bugs from users. I purposely excluded a help desk application from the design for our software, intending to keep my eyes open for trends and free alternatives.

Twitter. Google for the words customer support twitter and you get close to 50 million hits. Wow!  Most of these are not about getting support for using twitter, they are not about Twitter’s customer service. Just the thought of using twitter for our own customer service is __________ (you choose)! I don’t know at what point simple e-mails and phone calls will be too much for us to handle, but even just one tweet might put me over the edge, and I am not even having them flow to my phone. Am I am too easily overwhelmed? 

If you check out the possibilities for software to help you collect and manage work orders issued by or ideas from users, they are numerous. Lots of software, but not an obvious solution so far, from what I have seen. Anyone with half a mind to write help desk software does, it seems (with a nod to Mark Twain as I think I am paraphrasing him, but googling is not yielding a quotation right off).

Google Groups. I’m not a fan of forums that are not e-mail based, but maybe google groups with their wiki is a good option for some aspects of customer service. That works for me as an InterSystems user for informal chatter as well as solid assistance. My frustration with yahoogroups is quite high right now.

Trac and Bug-trackers. E-mail lists and e-mail software on their own are not good for tracking. Each incident deserves at least a unique number. We are using trac internally for our tickets, but that doesn’t seem quite like the right type of software for public use. I might be wrong about that, because as a user I do like to be able to search for open issues, see what questions and postings others have had, and generally get the lay of the land from a ticket system that is open to the public.

Delay? Certainly with the number of customers we will have the first year of operation, we should be able to manage without putting a big whiz-bang customer service software infrastructure in place. On the other hand, “in place” seems better than “out of sorts.” 

So, if anyone knows any great free. as in beer. tools where we don’t have to do any work other than making a link from our site, and perhaps turning in a circle and reciting a chant, to get customer service software in place, please clue me in. We will be heading into more user experience testing in the coming months. I would like to get something in place for documenting issues or suggesting changes during such testing that can move with us into production. That needs to be tested too, and it can be useful at the same time.

Alas, the design for such, whether homegrown or selected, is not even started, nor can it fit on the plate very well just yet. Oh, yes, I do know that a high percentage of help desk software only had design in the mind of the developer while they were churning out code, and we might very well follow suit on that old tradition, but I hope to avoid that.

We do not have to write this software. While customer service is the new marketing (surely someone else has said this, but I’m not checking) and it must be done well, it is a supporting service to the software we are writing. I would rather not write it. I would rather not think about it at all right now.

While there is something difficult about being in that time where we are developing software with no income, with this posting I will also take a minute to count the roses.  Call me a librarian, but there is something really nice about having software with no users.

One Step and then the Next

Cady took her first steps this week. I can’t wait to see her again and wish my grandbaby did not live so far away.

I’ve been taking a few steps lately too. Perhaps my writing muse was having a hard time keeping up and left me for a few too many days in a row. I’m not sure I have it back yet, so, I’ll catch you up on just a few details, nothing technical.

No sooner did I mention in a blog entry that I might be open for a gig than I got back to back calls. It has been about three years since I have taken on any new clients, so the calls had dried up. Perhaps the notice on my website that I was not doing any consulting helped with that too. After I wrote here that maybe I should take a call or two, I got them. I wasn’t even practicing The Secret on this one, so go figure. 

I took a gig about a month ago, which will help pay for a few hours this summer from two students, both of whom have other jobs. I was hoping to get a full-time student developer, but it didn’t pan out that way. I probably didn’t pick the right picture for my Dream Board (maybe I should start one of those).

An idea! Since I’m not one with twitter (ohm), what if I put a bunch of tweets together into a single article so that people are not interrupted by bits of information they could care less about, such as:

We are down to four. It wasn’t fitting well into Bobby’s life so he decided to bench himself before getting comfortable with the toolset.

Josh, a student, and Tony, a recent grad, will each work a few hours a week this summer.

[What’s with full sentences consistently, she asks herself. Get with the program.]

Still working to catch a stride, but making progress, putting one foot in front of the other, need to run without noticing the steps

Youngsters can be fearless, so I’m assigning them some things I don’t yet know how to do so they can teach me

Speaking of teaching, while being 100% dedicated to SnupNow, after a tough decision, I agreed to teach 2 courses next school year

I am trying not to worry about all the work right now and to figure out how not to worry about it at all, just do it

Teaching half-time is perhaps the hardest way to get a tiny amount of funding, but they came to me and said they needed me, I caved

I justified it to myself as something good for this project. I’m optimistic that it will work out well for SnupNow, but concerned too.

Only Tuesday and Thursday classes and I plan to keep all prep and grading to those days too

If you have ever taught, you likely know how hard that will be to pull off.

Lots to do on SnupNow this summer, and that is my focus right now.

Everyone likes this time in the school year best — when school’s out for the summer.

Hubby will be teaching in Zambia, gone for 7 weeks this summer. I will miss him. Hopefully I’ll get a lot done.

So, what do you think? Will this approach of putting all your tweets together rather than changing your facebook status or tweeting all the time catch on? I wonder what twitter’s retention rate is. I will avoid the temptation to google for that or write the question in an evernote. This is the concluding sentence where I tie it all together and go on to the next item on my list, getting things done one step at a time.


Identifying the Identifier

This article describes the various names for the primary key for a MultiValue developer working within the Cache’ software development environment. I would think this would only be of interest to those writing MultiValue applications using extended features of Cache’ and possibly to InterSystems employees who I am hoping will agree with me that this could be a bit overwhelming for a Cache’ beginner. 

If you are converting a MultiValue application from another MV implementation, then primary keys and their names convert as you would expect, so this only applies once you want to expand into the wealth of add-on features that Cache’ brings to the table for a MultiValue developer. If you were to use a variety of tools for the variety of work we can do using Cache’ alone, then you might have a similar, if not more complex, scenario.

1. @ID.

If using the Cache’ MultiValue Query Language, CMQL, from the colon prompt or in an MV select statement executed from MVBASIC, you can always refer to the primary key for a file as the @ID in our application. It is not a Property in a persistent Cache’ Class, however, which means it is not a Property we can reference anywhere outside of CMQL.

In the case of auto-incremented files, our Cache’ class for that file does not generate the @ID in the DICT automatically (rats), so we force that field into the DICT by coding it in an XData MVAdditionalDictItems section of the persistent class.

2. PartyId or similarly named key

We have coded our metadata source in Cache’ classes, so that each key has a synonym that is typically, but not always, the file name, sans package name, followed by Id. We have PartyId, ProfileId, OrgId, and AddressId, for example. An example of where it is otherwise is in the file that is keyed by Email, which is an e-mail address, one of the non-numeric primary keys.

There is a big caveat with this name for the primary key. In an auto-increment class it is also specified along with the @ID in the XData MVAdditionalDictItems section of the class. That means it is not an actual Property of the class. It is a Property when the @ID is not an auto-increment key, but otherwise it cannot be referenced within Zen pages or other Cache’ classes. It is then secret metadata that only CMQL knows about, just like the @ID. You can likely guess that I’m not delighted with that approach, but I can roll with it.

3. ID

Think of ID in SQL as a synonym for @ID in CMQL. 

4. %ID

For our software, we use ID instead of %ID in any SQL code, although these will function the same for us. There are a couple of cases where these would give different results, but we have no such cases in our application, so, for us, %ID returns the same results as ID in an SQL statement. Don’t use %ID in SnupNow–think of it as something we translate to ID when we see it in any examples or documentation.

5. %id

Use %id only with Zen M-V-C and only with a Model, whether a persistent class or otherwise, where the primary key is an auto-increment key. In those cases, we could not give the primary key a name except for the DICT projection, so Zen gives it the name of %id.

I wish I could say that where it is @ID in CMQL and ID in SQL, it is %id in Zen M-V-C, but that is not the case. That is only true with an auto-increment key, otherwise you must use the synonym for @ID that is specified as the primary key property in the persistent class.

This is one case where I would have liked to see a different implementation so that %id would be the name for the modelId no matter how the values of a primary key are determined.

6. modelId

modelId is an attribute of a dataController object, corresponding to a hidden dataController component placed on a page and used by a form on the page, for example. This modelId does correspond to the @ID in all cases. 

7. %Id()

This is a method of %Persistent classes. If you call this method on an instance of a persistent class (a record), you get the value of the @ID for that record. The only place I am currently using this is in Model classes when I need the @ID from a record where the file has an auto-increment primary key. In those cases, we do not have another name for the primary key, so we can retrieve it this way. If we have a P.Party record (object) that we have named r.party, then in our OO-enhanced MVBASIC we might write

partyid = r.party->%Id()


This is related to SQL. We are not using this and it might be specific to COS (Cache’ ObjectScript), I dunno. Maybe someday we will need it. The documentation says “%ROWID is set to the RowID of the last row modified by the most recent INSERTUPDATE, or DELETE operation” which might prompt us to ask for the definition of RowId, but I’m thinking by now you might be exhausted.

I am exhausted and have perhaps exhausted this topic, although we haven’t even gotten to %XML.Id. That is fine, however, because, PTL, it is NOT another name for our @ID.

May I see your @ID?

My sister got carded around the time she turned 40, and they were not carding everyone. She might not want you to know she is over 40, but heigh ho, it’s pretty cool that someone might think she was underage at this point. With two adorable little boys, she still looks young and hip (too hip to use that term, I’m guessing). She definitely looks younger than I, and, well, she is. She says that she used to think that she was the cute one and I was the smart one, but now with her living in sunny Pasadena and me living in Iowa, she realizes that she is also the smarter of the two of us. Of course, she would have said “smartest.” 

Dawn, Mom, Beth

Dawn, Mom, Beth

I have almost never been carded. I guess I drank even less when I was younger than I do now, when I have a drink perhaps 6 times a year, give or take 4. With different allergies to at least beer, wine, gin, and tequila, count me in for the vodka or rum drinks, with an occasional white wine. You might think I have no good point here, other than to chitchat before talking about primary keys, but there really is a good reason to bring this up. Because the audience for this blog is small, I have met or will meet many of those reading this, and I mentioned a martini earlier, but now there might be a better chance you will buy me a vodka martini with 3 olives. In my role as a preacher’s wife, this is a very rare occurrence.

The ID I show when flying or were I ever to have been carded is my driver’s license. The unique identifier on it has 3 digits, then two alpha characters, then 4 more digits, although that pattern varies across the planet, even from state to state within the U.S. Let’s store information about a bunch of these driver’s licenses. We can do that by creating a database table, or, in our case, a (logical) MultiValue file. 

In the relational model there are candidate keys, those combinations of attributes that constitute a unique identifier for a relation. These are implemented as one or more columns in a table. In many DBMS implementations, one of these candidate keys, composed of one or more columns, is selected as the primary key for a table. 

In a MultiValue database, each File has a primary key that is a single field. This is typically referred to as the @ID. Not only can an MV file be modeled as a mathematical relation, just as tables are in a relational database, it can be modeled as a function. Functions, in mathematics, are relations with special characteristics, but I won’t bore you with too many details. A File named Drivers.Licenses is a function in that Drivers.Licenses(@ID) = @RECORD where @RECORD is the rest of the fields, other than the primary key. With Drivers.License as our function, Drivers.Licenses(“123AB4567”) = (“Mary Smith”, “F”, “01/01/1960”,…), a tuple of information related to the drivers license with license id 123AB4567.

The @ID is a single field, but it might be composed of multiple parts. So, where one might have a composite key in a relational database table, this would turn into a multi-part key in a MultiValue file, typically with parts of the key separated by a delimiter, such as an asterisk. We don’t need that for this example. We have a single field, LicenseId, that can be our primary key, aka our @ID. 

In this example, I have used what is called a natural key in that the driver’s license identifier, LicenseId, is created outside of our system. We could, alternatively, have selected a surrogate key, one we generate within our system. What might prompt us to model our data with a surrogate key for our Drivers.License file? 

1. Ease of implementation I

Cache’ gives an easy means of creating an auto-increment key, one where the first one written is 1, the next one is 2, and the 537th one is 537. In other words, using a surrogate key in Cache’ is a piece of cake.

 To get this feature packaged in, we need to write records using object syntax of newkey = myrecord->%Save(). Since we are using the class definition as the source for our metadata, if we specify no primary key index on any property in the class, then it is assumed that the primary key is an auto-increment key.

As best I can tell, use of an auto-increment key in Cache’ is almost assumed, so that if you use a natural key for an MV file in Cache’ someone might tell you that you are overriding the id. Don’t punch them out if they say that, even if that is your inclination.

2. Ease of implementation II

In the Zen AJAX framework, using Model-View-Controller, when you refer to the %id in a page with a dataController, it refers to the primary key if and only if the key is an auto-increment key. In your XML specification for a form field, for example, you can specify dataBinding=”%id”. Otherwise you are on your own for figuring out the name of the primary key. There is no general name for the unique identifier for a model class.  

If I am struggling with some of the basic Create-Read-Update-Delete (CRUD) features in a Zen web page, it is likely that the Model I am using is keyed with a natural key. Few examples in the Cache’ documentation or sample namespace are done with anything other than an auto-increment primary key.

3. Bitmap indices

We can create way-cool bitmap indices for Cache’. While I have not yet defined any of these (who optimizes for performance before a system is live, eh?), I anticipate these could be very helpful in due time. As the Cache’ documentation indicates, “bitmap operations are optimized for transaction processing: you can use bitmap indices within tables with no performance penalty as compared with using regular indices”.

One requirement for these is stated as “you can only define bitmap indices in tables (classes) that either use system-assigned numeric ID values, or use an IDKEY to define custom ID values when the IDKEY is based on a single property with type %Integer and MINVAL is greater than 0”. There you have it, we have this added feature available for files that have numeric keys. 

4. The Usual Reasons for Choosing a Surrogate Key

Of course there are the usual reasons for using an auto-increment or system-generated key that is not the same as the number on a physical object, such as a driver’s license. The argument between selecting a natural or surrogate key is well-worn. I am more likely to argue for a natural key when the decision seems to be a toss-up. 

What do we do if we find that everything about the driver’s license was entered properly except for the LicenseId? Unless we write tools to do otherwise, that would be a delete and re-enter scenario if the key is the LicenseId, but would be a piece of cake if the LicenseId were just another field like the Gender.

Of course, if this is not really a Drivers.License file for tracking driver’s license information, but one where we want to track a person so that they can change their driver’s license number and we want to reflect that change here, then we would also not want the LicenseId to be the primary key.

Some of those are better reasons than others for choosing a surrogate key. Although I look first for natural keys, with our SnupNow software we have more files that are keyed with an auto-increment key than we might have were I not to have adjusted the MultiValue modeling skills acquired over my prior years of experience. Of those files we have started using in our builds, 9 out of 16 [16 files translates to ~50 relational tables] have an auto-increment key, with some of the others being co-files of these, in that the value of their key is the same as the auto-increment key in a sister file. I can only think of two files I specified with alpha characters in the key. Obviously the Email primary key includes alpha characters.

I am not typically a fan of creating unique identifiers for unique identifiers, surrogate keys when there are obvious natural keys, but there were not many natural keys for this application anyway, with Email being an exception. I would have had more multi-part keys if implemented in another MV environment, however. I steered away from some of those simply because multi-part keys are typically not numeric, having an alpha delimiter between the parts. I created two multi-part keys with no delimiter, but with the second part of the key being a fixed length so we can find the parts without a delimiter.

Since this is the first Cache’ implementation for which I have done any data modeling, time will tell if I made good primary key choices. A more accurate way to state that might be to say that time will tell which were the poorest choices I made regarding primary keys. I don’t recall discussions among developers where we talk about how delighted we are with a particular choice for a primary key, but I certainly can recall times when what previously seemed a good choice has turned out to be a lousy one, typically due to new requirements.

If I were a purist, or maybe even an excellent software engineer, I would state right now that when we see that an @ID should be redefined, we will refactor for the change right then and there so we do not perpetuate poor design choices as we add to the software. Truth be told, however, I would be ID’d as a pragmatist and a business woman, so any such decisions will be made given the cost and benefit information we have at the time.

I will be continuing this topic, with the next article documenting the various names for the @ID within our development environment. If you thought this one was getting a little too detailed or technical, you should definitely avoid the next one. They can’t all be winners to all types of people. In fact, before I let you read that one, may I see your @ID?