- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
Well, duh. You're handling a new type of record, so you need new code to handle it.
What this type of problem indicates is that the database structure is incorrect, in the sense that the content should indicate the record type. Or maybe there's a single table with two (for large values of two) types of record in it, which is also a major no-no.
But when we add a new type of information to the database, we will inevitably have to add new code to handle it.
(In the context of the article, I'd say that the biggest immediate problem is that once you're down this rat-hole, you need to modify these switch()es (whatever the language calls them) everywhere. It's almost guaranteed that some day, someone making such a change will overlook one of the switch()es, and manage to find a hole in the automated tests, and ship stuff that breaks at runtime.)
Admin
Pascal, 2002, starting development. 'Nuff said.
Admin
Oh, and I'd guess that the original is not in Pascal, since Pascal
case
statements don't requirebreak;
to separate different cases. There is no implicit fall-through in Pascal. Handling multiple values of the selector with a single block of code requires a comma-separated list of values:Admin
Would that mean the
break;
s are breaking out of the inner loop instead then? Seems reasonable since the matching record has already been found.Of course, I don't actually know Pascal, so for all I know they could be jumping out of the
case
completely pointlessly. (In which case it is also possible that the dev. responsible for this doesn't know Pascal as well as they thought either...)Admin
Take all the hard drives on which a copy of that codebase has ever been stored.
Throw the hard drives inside of a volcano.
With the molten metal, forge rings of power and give them the pointy-haired bosses.
Then grab popcorn and watch the world burn!
Admin
I joined a project that used this kind of anti-pattern. We had a database table with half a dozen “record types”, and a bunch of code that linked behaviours to the record types.
Adding a new record type required first adding the entry in the database, and then writing new code to handle that record type. I was bemused… why bother with the DB table at all, since we’re going to have to make code changes every time… why not just use an Enumeration or similar?
The answer came a few weeks into the newest client project… when client X said “Oh, we only want to support record types 1 & 2, forget the rest”. Voila, no code changes, we just deleted the extra entries from the DB table, and those record types were no longer available for use. They’re still supported by the code though, so if that client ever changes their minds, we just need to add those extra types back in, and again, no code changes needed.
After some thought, I’ve decided I quite like this pattern, and it has more value than I originally assumed.
Admin
I think the
break
statements are to break out of thefor
loop once a matching record type is found, notcase
Admin
Ah yes, the for-if anti-pattern.
https://devblogs.microsoft.com/oldnewthing/20111227-00/?p=8793
Admin
Ash nazg durbatulûk
Ash nazg gimbatul
Ash nazg thrakatulûk
Ag burzum-ishi krimpatul
Admin
Now, Sauron, we've talked about this in our previous sessions. You really need to learn new tools and new methodologies. Remember the mantra we practiced? "Not everything needs to be hit with a hammer, even if it looks like a nail."
Admin
Last time I touched Pascal for anything significant was ... (thinks) ... (thinks some more) ... well, it was a long time ago, and the Turbo Pascal versions I used then didn't have
break;
at all, but a little digging shows that it's a C-likebreak;
that breaks loops even used insidecase ... of
statements.Admin
well, this is because c is nuts using 'break' to mean 'end of case'. you either have no fallthrough or you use an 'endcase' statement like bcpl.
Admin
well, this is because c is nuts using 'break' to mean 'end of case'. you either have no fallthrough or you use an 'endcase' statement like bcpl.
Admin
i did not post the previous comment twice >.<
Admin
Unfortunately I have seen this "DIY join" anti-pattern many times. Also in the other form: the super big "IN" clause, with a very (VERY) long list of keys to be found - which is not just inefficient, it trashes the cache and kills the performance of ... well, everything else that uses the database. Among those cases, the worst one: this anti-pattern was combined with a totally unnecessary (ab)use of the C# "yield" feature, so the queries were executed multiple times (facepalm!)
Admin
@Steve:
Or a type and a sub-type. Seen a million times. Often... er... did it myself :( What would the "correct" solution be in this case? A table for each of the two types and/or sub-types? This could be done when the value of two is two, but may not be viable for large values of two. e.g. an Invoice that has Items, and there are many types of items ... if there are 10 types of Item, shall I create 10 tables, all with FKs to the Invoice table? And that would not change the problem: when adding the 11th type of Item, I should modify the application code anyway, if only to CRUD the new Item type. Or am I missing something?
Admin
Fair point, although I was thinking of a more WTFish case where the "types" require more different handling than what you're suggesting, such as the distinction between "hammers versus screwdrivers" (at least they are both hand tools) and "apples and screwdrivers" (there's not much useful in common but at least they are both physical objects) or "justice and hammers" (they don't even have "physical object" as a shared attribute). If a table's contents are like justice and hammers, there's a real problem, but if it's "screwdrivers and hammers", they do at least share the commonality of both being hand tools.
Admin
Is this one of those cases where you want to look at NoSql?
Admin
I like it! "Justice & Hammers" sounds like a spinoff from "Law & Order", and maybe there is a crossover episode with Doctor Who: "Justice & Screwdrivers". Jokes aside, now that you've said that, I'm afraid I'll start seeing "justice and hammers" anti-pattern everywhere (starting from my code, of course...)
Admin
One thing that comes to mind is OOP inheritance. As in figure out which fields are the same for all types and make that a base table. Than have specializing tables with just the data you need for the individual types and link those together.
So your child item table might look like this: Child ID (PK), Parent ID (shared fields), unique field 1, unique field 2...
And of course, if several children have their own wider subsets of shared fields you can just add another table for those: Root ID (PK), field 1, field 2... Middle Child ID (PK), Parent ID (shared fields), unique field 1, unique field 2...
Leaf type 1 ID (PK), Parent ID (middle child), unique field 1, unique field 2... Leaf type 2 ID (PK), Parent ID (middle child), unique field 1, unique field 2...
Assuming your system isn't completely apples and oranges this should get you something that is easy to implement and extent both in the DB and code. The only downside is that you have to suffer through the performance penalty of joins. But that's a choice you have to make based off the amount of data in your system and the number or lack there of of shared fields.
Admin
You're right. And I especially like the bottom line: almost everything in our job is a trade-off. Most of the time I leave ER design to more expert people, hoping that that'll get it right, but nobody is perfect. The problem is that we often have to make choices quickly, with incomplete knowledge. And this is more problematic in databases: if you pick the wrong choice, you may be stuck with it for years, databases are hard to refactor because of the DATA. One day I'll make a submission about a very bad case of crazy ER design, but it's still too soon...
Admin
The first thing that hit my eye was the break statements. Pascal 'case' statements, unlike C 'switch' statements, don't need 'break'. And that's doubly good, because Pascal doesn't have 'break'. This is in some weird Pascal dialect and written by someone who was trained on C or something. Nobody thinking in Pascal would write those 'break' statements.