The Daily WTF

Syndicate content
Curious Perversions in Information Technology
Updated: 21 hours 13 min ago

CodeSOD: The Toggle that Wouldn't

Fri, 14/11/2008 - 12:00am

"I work for a software development house that creates business software, maintaining legacy MFC applications," Graf writes. "We recently received an issue where a filter-toggle wouldn't switch back and forth, never changing from its default value. It's was a small utility function, rarely used, so we were a bit surprised to see it come up. Taking a quick glance at the code revealed the following:

#define ENABLE_FILTER void CReport::ToggleFilter() { #if defined(ENABLE_FILTER) #undef ENABLE_FILTER #else #define ENABLE_FILTER #endif } bool CReport::IsFilterEnabled() { #if defined(ENABLE_FILTER) return true; #else return false; #endif }

Brought to you by the Non-WTF Job Board:


MUMPS Madness

Thu, 13/11/2008 - 1:00am

This year’s Corporate Technology Expo was no different than the ones for years previous. Various departments gathered in the company’s large, wood-paneled group meeting hall and highlighted their top projects and initiatives that were completed during the past year. There was everything from the ASP-to-ASP.NET upgrade of the customer portal to the enterprise-wide implementation of COGNOS 7. The scene was a three-hour, seemingly unending procession of PowerPoint slides with enough laser pointers to take down an incoming ICBM.

Nobody would probably show, let alone stay awake, if it weren’t for the free coffee and bagels.

However, you knew that the light at the end of the tunnel was approaching when the AppDev’s “big guns” arrived: a cabal of four MUMPS developers headed up by a hairy yet balding man named Tyson. They were the brilliant minds behind the company’s core application, codenamed CASTLE. This year, they brought t-shirts for the audience.

Tyson went into the usual spiel about the impressive accomplishments of their application, the 99.9% uptime, and the tens-of-gigabytes doled out by the CASTLE system which fed data to the previous presenters’ systems. To wrap things up, Tyson revealed his “one more thing” – a brand new, home brewed combination web and mail server written entirely in MUMPS without any use of any common API. Basically, even with the grandstanding, the presentation was a friendly reminder that everybody’s livelihood depended on Tyson’s group.

Quick MUMPS Review

For those who aren’t familiar with exactly what MUMPS is, you’d be missing out if you didn’t check out A Case of the MUMPS. To summarize, if you’re associating MUMPS with the awful disease of the same name, you’re very close.

Quite possibly created as an exercise in sadomasochism, the “Massachusetts General Hospital Utility Multiprocessing System” was developed back in the mid-1960’s by Dr. Octo Barnett and with the help of federal grant money. Originally limited to medical information systems, MUMPS has found its way into other fields. Most notably, the financial sector.

To give a little more “real world” example of the horror that is MUMPS, start by taking one part [[International Obfuscated C Code Contest]], a dash of Perl, two heaping measures of FORTRAN and SNOBOL, and the independent and uncoordinated contributions of dozens of medical researchers, and there you go.

The Project

Everyone in Steve X’s department lived in fear of the CASTLE. While Steve’s background and job title may not shout “MUMPS Developer”, part of his job is to work with the quartet of diehard MUMPS developers who designed the system.

Thanks to the ignorance of management (and perhaps a “wink and a nod” here and there), Tyson and his “boys” had built CASTLE as a 350,000-line strong fortress of MUMPS over a period of more than twenty years. Tyson and his group had pigeonholing down to a science; everyone had relied on their system so much that they were untouchable and their group was impenetrable. Except for now.

“It’s taken a while,” the auditor said to Steve “but we’ve finally convinced Tyson to let someone go in and clean up some of the ‘junk’ tables that have built up over the years.”

“How’d you do that,” Steve smirked, “a note from God?”

“No, no, no. I pulled the Sarbanes-Oxley card on him. You’ll see a meeting invitation with his group for Monday morning. Good luck!” the auditor said as he dashed into the nearest hallway.

The following meeting with the quartet of MUMPS-men went relatively smoothly – probably from Tyson’s desire to get the auditor and Steve out of his hair and out of his system as soon as possible.

Steve got to work. His investigation could be compared to peeling back layers of wallpaper and seeing the horror it was really covering up. After a month of work had passed, he showed that, out of the 393 known tables, 225 were no longer in use. To make things even more interesting, many had been out of use since 1985 or earlier.

Included in the interesting finds were:

• A table called “GIVE THIS A GO” with zero records.

• A table called “Clinician Orders”, which was apparently used to record what drugs/medical procedures the clinician ordered for the patient at a given time. It had 133 columns:

Date Visit Clncn Student Trtmnt Obsrvtns CrtdUser CrtDtTm LstEdtUs LsEdDtTm [ un-named column ] DscUsrSg DscDtTm DscSgnUs - Discontinued Signed-In User AthCntUs - Authorize Controlled User AthCntDh N1amOrdr - 1am Order N2amOrder - 2am Order ... N11pOrder - 11pm Order N12mOrder – 12 Midnight Order N1amSgnt - 1am Signature ... N12mSgnt - 12m Signature N1mDtTm - 1am Date/Time ... N9mDtTm - 9am Date/Time [ un-named column ] [ un-named column ] [ un-named column ] N1pDtTm - 1pm Date/Time ... N12DtTm – 12 Midnight Date/Time N1amUser - 1am User ... N12mUser – 12 Midnight User N1amCmmn - 1am Comment ... N12mCmmn – 12 Midnight Comment

That’s right: At least 5 fields for every hour of the day. God only knows what would be done to this poor table if clinicians decided they wanted half-hour (or worse yet, 15-minute) granularity.

• The calculation to determine drug pricing was extremely complex and un-commented. There were three different price fields:

PrcUntCs - Purchase Unit Cost SpcRxPrc - Special Rx Price SpclCost - Special Cost

Depending on a complex calculation (including such WTFs as “Is there an ‘@’ symbol in the field specifying the type of drug?”),any of the three price fields could be used and a variable markup added. For bonus-bonus fun, here is the actual code for the calculation:

set cost=$s(spc:spc,1:puc)*1.3 ;cost + 30% set amt=qty/each*cost ... if drug falls into another category ... set amt=amt-(amt*.3)

Tyson claimed they intended to “take away that 30% markup,” not realizing that (X * 1.3 * 0.7) != X. He never quite explained the reasoning behind "amt=amt-(amt*.3)" instead of "amt=amt*.7".

• Compounding information on the drug table.

Since drugs can be compounded (i.e. made up of several other drugs), the programmer thoughtfully added these columns to the drug table:

Item1 Itm1Qty Itm1Lbl Itm1Prc Item2 ... Item10 ItmTenQt ItmTenLb ItmTenPr ItmLotNo - Item1 Lot# Itm2Lot - Item2 Lot ... Itm9Lot - Item9 Lot Itm1Lot - Item10 Lot Itm1Expd - Item1 Expdate ... Itm9Expd - Item9 Expdate ItmTenExpdate - Item Ten Expdate

Fortunately, someone explained how related tables worked to this programmer before CASTLE needed to handle drugs made up of 11 items. Thankfully, the above compounding system was only used for 15 years or so.

The VISA Problem

After Steve’s database debridement project was completed, he was given one more task by the auditing group: search for and remove any credit card numbers that may have been stored in the system.

As it turned out, CASTLE had been storing customers’ full sixteen-digit credit card number for years, just in case someone needed to look up a transaction and the last four digits weren’t good enough. Eventually, Visa came out with their PCI requirements, making this kind of thing a no-no. So, to avoid a potential disaster and a hefty $500k fine, Steve built a scrubber tool to seek out and destroy the credit card numbers in the database, including the ones entered into the “notes” section of the client records.

Later, just before the scrubber was to be run in Production, Steve was shocked to find the following enhancement made to his code:

set ^tnc("scramble","notes",d0,d1)=data

In human-speak, this code is a loop where d0 is the clientId and d1 is the number of the note attached to the client’s record. data was the note containing a credit card number. tnc was someone’s initials. More specifically, they were Tyson’s initials.

What Tyson had accomplished was that he had inserted a line into the scrubber that effectively saved all credit card numbers to his personal database right before they were scrubbed.

The untouchable Tyson explained his reasoning as to cover the situation. It was just in case they needed to recover that data in the future. Normally, hearing that a developer is storing off live credit card numbers might raise an eyebrow or two, but with Tyson being a nice guy and all, everybody in the department believed him and let it go.

Knowing the path to hell is often paved with the very best of intentions, Steve went about and deleted Tyson’s “special file”.

Conclusion

While it may sound like there’s enough work to keep an entire department of MUMPS programmers working to fix the application sludge created by Tyson and his cohorts, nothing is going to be done about it anytime soon. To clean up the tables and remove the credit card numbers robbed Steve of two month of his life that he’ll never get back.

As a final line of defense against outsiders, the keepers of the CASTLE created enough red tape to ensure that even the simplest change would take long enough to thwart any major changes to their system. In a best case, if one was very productive, he’d find himself with weeks and weeks to kill while people try to make meetings to review his code or get back to him on requirements. Of course, the good news in all this is that Steve’s efforts just might make a bullet point on the MUMPS team’s presentation at next year’s Corporate Technology Expo.



Brought to you by the Non-WTF Job Board:


Status, Please

Wed, 12/11/2008 - 3:00am

“Just give me a damn status!” growled Murray, the aging IT project manager who everyone thought would have been retired by now. In fairness, the fifty-nine year old’s job performance hadn’t waned one bit through his decades-long tenure at Bell Labs. In fact, some would even say that in his later years, he traded some of his trademarked ferocity for geniality. “Dammit,” Murry barked two seconds later at Tom Limoncelli, one of the developers sitting around the conference table, “I don’t have all day! Give me a status!”

“Okay, okay,” Tom nervously responded, flipping through some papers, “we’re… uh, 30% through AMQ, 60% percent towards AMA-2, and… err… 100% for DBD.” Murray frowned and gruffly murmured something unintelligible. That was his way of saying “thank you.”

If a project was progressing on time and on budget, Murray’s mood would be best described as a grumpy indifference. But if things went awry, his demeanor became more threatening than rabid pack of wolves. With firearms. And laserguns. Murray wouldn’t hesitate to publically lambast a colleague simply for knowing someone that knew someone who was holding up the project. And unfortunately for everyone at the weekly meeting, someone was holding up the project.

Although Tom’s rapidly-delivered, precise status report spared him from Murray’s wrath, someone else sat squarely on his warpath. “And you,” he seethed, pointing at the junior developers, “you didn’t give me a status! I asked for status yesterday, where is it? I need a status from you, now!”

The junior grimaced. “We’re… not yet at,” he uncomfortably swallowed, “at… 30% of AMA-3.”

Murray’s face turned a bright red. He closed his eyes and tightly clenched his fists, forcibly and calmly saying “that status is unacceptable. This will put us behind.”

“I know,” he nervously responded, “we’ll stay late, come in on the–”

Murray cut him off, responding with a crescendo of anger. “You should have come in LAST WEEKEND! I NEEDED A BETTER STATUS FROM YOU!” By the time he got to his last words, his fist was pounding on the table.

As Murray continued to berate the developer who had fallen behind, Tom noticed that Chris, one of the other developers attending the meeting, was uncomfortably biting his lip. He couldn’t quite tell if he was holding out for the restroom or holding back a lionesque roar of laughter.

“This status is meaningless to me now,” Murray shouted, apparently trying to make the junior cry, “I needed this status three days ago! What can I do with this status now? Go back in time and assign more resources to get me a better status for today?”

This time, someone let out a rather loud snort. Murray was far too engaged too notice, but Tom’s eyes shifted towards Chris. He was definitely holding back laughter, as evidenced by the uncontrollable shakes and the rather ineffective attempts at covering it up with a series of “cough-ha’s”.

Thirty minutes later, after Murray had thoroughly chewed out the junior and picked each and every bone clean, the meeting ended with a somber reminder to all, “the sooner you get me a status, the better it is for everyone.”

Later that day, Tom’s curiosity got the better of him and he walked towards Chris’s cube to see what he was laughing at during the meeting. After a bit of cajoling, he finally agreed to let Tom in on the joke.

“Okay,” he explained, “so, you know how Murray is always demanding the status? Well, whenever he says the word ‘status’, just replace it with…”

Chris looked over his shoulders and then leaned into Tom, whispering something in his ear.

 “Glow job?” Tom questioned, envisioning the brightly-colored neon lights that some people put on the underside of their car.

His response was met with a blank stare.

“Ooooh,” Tom realized, slapping his palm against his forehead. “You mean bl—” he quickly moved his hand to his lips, stopping mid-syllable as not to utter the not-safe-for-work word.

Chris subtly nodded and smiled.

“Uuuuhhh,” cringed Tom as he tried to repress any thoughts of that particular activity, especially as it related to Murray.

Tom didn’t think much of the joke until the following week, at their weekly meeting. Generally speaking, the meetings with Murray were painfully difficult to sit through. Even when Murray wasn’t furious, listening to everyone say, “I’m blah-blah percent complete on some-blah-task” was almost unbearable.

That week, however, the meeting was difficult to survive for an entirely different matter. As Murray went around the room with his usual criticisms – “why can’t you give me a better status than that?” and “again, this problem is caused by a lack of status!” – it became painful to hold back the laughter.

When it came time to once again lash-out at the junior developer, Tom was afraid he wouldn’t make it. “If you don’t give me a good status right now,” Murray fumed at the junior, “I swear… I’m going to explode!”

Try as he might, Tom couldn’t bite his lip hard enough to hold back a few snort-filled laughs. Almost instantly, Murray shot his head towards Tom and stared daggers through him. “What’s so funny?” he shouted, “you’re still at 30% AMQ! Your status was terrible!”

This time, Chris couldn’t help himself. His laughter made Murray even more upset, and he just kept harking on about how everyone’s status was behind.

It didn’t take too long after that for the word to spread across the team and then across the floor. Eventually, it made its way to other projects and teams throughout Bell Labs.

Although Murray has long since retired, to this day, Tom still avoids the word “status” in his meetings.



Brought to you by the Non-WTF Job Board:


Error'd: $50 Cash Fast

Wed, 12/11/2008 - 12:00am

I don't know, Dexter, I don't see anything weird about getting $50 fast cash...

...oh, now I get it:

 

This is the error message John R. gets whenever he has a typo in his password. I'm pretty sure his password isn't actually "injustice."

 

Brendan Nee observed some children at a Hong Kong airport enjoying one of my favorite passtimes – dancing on a projected DOS prompt!

 

Vivek Thomas got this error when he clicked the "Forgot Password" link. It's nice that they consider it such a serious issue, but still, I think this is probably bad advice.

 

I don'tunderstandwhy youstruggledwith thisPaolo Tresso.



Brought to you by the Non-WTF Job Board:


CodeSOD: Now I Have Two Hundred Problems

Tue, 11/11/2008 - 1:00am

-rw-r--r--. If that looks familiar to you, skip this and the next paragraph.

OK, now that it's just you and me, Bill Gates, it is an example of Unix file permissions. The example given means that the user (owner) can read/write to the file, and others can only read it. Checking these permissions in Perl is simple; just use the stat method to check its mode (the file type and permissions). For example, if you wanted to check read permissions, you'd check bits 4 (owner read), 32 (group read), and 256 (other read). This is 292 in decimal, 0444 in octal. Compare that to the mode, and you'll know whether you can read the file. In code, stat($path)->mode & 0444. Easy peasy!

Ed's colleague hated built-in functions. Why trust mode when you can roll your own permission checking algorithm?

my $perms = stat($path); my $permsbin = unpack("B32", pack("N",$perms->mode & 0777)); $permsbin =~ s/.*(.)..(.)..(.)../$1$2$3/; if ($permsbin != 111) { # file is not readable # ... }

So first, the value is packed into a 32 bit unsigned long (that's what the pack("N") means), then he converts it into a string of bits. That is, literally, a string of ones and zeros. Then he uses a regex to parse out the specific bits in the read positions for owner, group, and other, and turns it into its own string of bits, hoping the resulting string is "111". Finally, he has Perl compare "111" to 111, forcing his new string to be magically converted into an integer. Clearly, this guy is a fan of Rube Goldberg machines.

You know the famous quote about regular expressions?

Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems. — Jamie Zawinski

I think it's safe to say that Ed's colleague has more than two problems in his oft-copied-and-pasted permissions checking routine.



Brought to you by the Non-WTF Job Board:


CodeSOD: A Touch of Genius

Sat, 08/11/2008 - 12:00am

“I recently started on a new contract,” Vedran R writes, “and the experience has been rather… interesting. The project I’ve been assigned to is a VB .NET 1.1 web application, and the code is rather… bad. Now, I know that developers make all kinds of compromises because of lack of time or experience but this is just… well, here’s some of the code.”

“Why fix the problem where it originates, it’s much simpler to handle it this way!”

sSql = GetSql(sTypeCurrency, sWHERE, sOrder) If bGroup = True Then sSql = Replace(sSql, "WHERE and", " WHERE ") sSql = Replace(sSql, "WHERE and", " WHERE ") sSql = Replace(sSql, "WHERE AND", " WHERE ") sSql = Replace(sSql, "WHERE AND", " WHERE ") ...snip... End If

"So how do you to determine if an object is null in JavaScript? Simple...

if (top.arrLisAdjCodEmp[f] != 0 && top.arrLisAdjCodEmp[f] + "" != "undefined")

... first we check if the object equals 0 and then we check if it not null by casting it to a string and comparing it to 'undefined'. Nice one!"

 

"Classes? We don't need no stinking classes!"

Private Function fWhere(ByVal bGroup As Boolean, ByVal lCodCompany As Integer, ByVal sCodAutonomy As String, ByVal sCodProvince As String, ByVal sCodArea As String, ByVal sCodDelegation As String, ByVal sDateFrom As String, ByVal sDateTo As String, ByVal iDate As Integer, ByVal sCodClients As String, ByVal sCodClientFrom As String, ByVal sCodClientTo As String, ByVal sDesClientFrom As String, ByVal sDesClientTo As String, ByVal sCodclientRange As String, ByVal iUte As Integer, ByVal iOrderEst As Integer, ByVal dOffer1 As Double, ByVal dOffer2 As Double, ByVal sCodGroup As String, ByVal sCodSubGroup As String, ByVal aDivision As Array, ByVal aCodTypoLicita As Array, ByVal aCodGroups As Array, ByVal aCodCompanies As Array) As String

 

"How to execute a „complicated“ SQL in a stored procedure? Piece of cake!"

DECLARE @QUERY AS VARCHAR(1000) SET @QUERY = 'SELECT NUMTASK, YEARTASK, DATEOPEN ' SET @QUERY = @QUERY + 'from TaskStudio ' SET @QUERY = @QUERY + 'WHERE ( ' SET @QUERY = @QUERY + 'CODCOMPANY = ' + CONVERT(VARCHAR,@CODCOMPANY) + ' AND ' SET @QUERY = @QUERY + 'DATEOPENINGS = ''' + CONVERT(VARCHAR,(CONVERT(DATETIME,@ DATEOPENINGS,103))) + ''' AND ' SET @QUERY = @QUERY + 'CODCLIENT = ' + CONVERT(VARCHAR,@CODCLIENT) + ' AND ' SET @QUERY = @QUERY + 'OFFEREURO = ' + CONVERT(VARCHAR,@OFFEREUROVAR) SET @QUERY = @QUERY + ' ) ' PRINT (@QUERY) EXEC (@QUERY)

 

"If the variable contains an empty string, then assign an empty string to the field; else assign the value of the variable to the field."

If sCompanyGroup = "" Then Field46 = "" Else Field46 = sCompanyGroup End If

 

"If the variable contains an empty string, don’t do anything; else don’t do anything."

If bResult = "" Then Else End If

 

"Here's a first class if."

If bGroup1 = 0 Then bGroup = False ElseIf bGroup1 = 1 Then bGroup = True ElseIf bGroup1 = 2 Then bGroup = True EndIf

 

"More JavaScript. Is it a string or an integer?"

if (obj.value>="9000" && obj.value<=9999)

 

"Ugh, I love my job."



Brought to you by the Non-WTF Job Board:


Go Phish

Fri, 07/11/2008 - 3:00am

A few years ago, researchers at Harvard University and UC Berkeley published a rather interesting study about phishing. After running a usability study to see how well people can detect phishing attempts, they found that:

  • 23% of the study's participants did not look at the address bar, status bar, or the security indicators
  • 68% proceeded without hesitation when presented with popup warnings about fraudulent certificates
  • 90% were fooled by good phishing websites.
  • Neither education, age, sex, previous experience, nor hours of computer use showed a statistically significant correlation with vulnerability to phishing.

To make matters worse, the study's participants were actually trying not to get tricked. "Our study primed participants to look for spoofs," the researches explain, "thus, these participants are likely better than 'real-world' (un-primed) users at detecting fraudulent web sites."

Clearly, phishing is a very serious problem and anyone, anywhere could be vulnerable. Jeff Anderson, the CIO of Auburn University at Montgomery, knew this, and sent out an email warning all students and faculty to be on the lookout for phishing activity.

From: Jeff W. Anderson, Ph.D.
To: Everyone
Priority: High
Subject: Email Phishing Warning
 

We have noticed an increase in phishing attempts, similar to the message below. AUM will never request that you provide you user name and password in an e-mail. You should not provide any private information, including passwords, through e-mail.

Here is an example of a recent phishing attempt:

------------------------------------------- Subject: ATTENTION: EDU WEBMAIL SUBSCRIBER: ATTENTION: EDU WEBMAIL SUBSCRIBER: This mail is to inform all our {EDU WEBMAIL} users that we will be upgrading our site in a couple of days from now. So you as a Subscriber of our site you are required to send us your Email account details so as to enable us know if you are still making use of your mail box. Further informed that we will be deleting all mail account that is not functioning so as to create more space for new user. so you are to send us your mail account details which are as follows: *User name: *Password: Failure to do this will immediately render your email address deactivated from our database. Your response should be send to the following e-mail address. (end of phishing example) -------------------------------------------

Other phishing attempts include messages that appear to have been sent from financial institutions or companies such as Microsoft. Your financial institution will never ask you to provide your account information through e-mail, and Microsoft does not send out updates through e-mail.

When you receive these types of messages, you should delete them and not respond. It is also a good practice to avoid clicking on any links in suspicious e-mail messages.

If you feel you have been a victim of a phishing scheme regarding your AUM account, please contact the ITS Help Desk at 244-3500 or helpdesk@aum.edu

Thank you,

Jeff W. Anderson, Ph.D.
Chief Information Officer
Auburn University - Montgomery
 

 

Obviously, a single email won't prevent all phishing scams -- especially the advanced variety that links convincing websites -- but it should at least remind people to never, ever email their password. Right?

Not so much. A few days later, Jeff was forced to send an update to his previous email.

From: Jeff W. Anderson, Ph.D.
To: Everyone
Priority: High
Subject: Phishing Update
 

I would like to stress, again, that you should NEVER send your user name and password to ANYONE through email. If you receive a request for this information, it is most likely an attempt to use your account for fraudulent purposes.

In my previous alert, I included the text of a phishing email as an example. Some students misunderstood that I was asking for user name and password, and replied with that information. Please be aware that you shouldn’t provide this information to anyone.

If you do receive an email requesting your credentials, please call the help desk at 244-3500, or forward the email to helpdesk@aum.edu. Do not reply to the message, even if it states that you account will be disabled.

I apologize for the confusion.

Thank you,

Jeff W. Anderson, Ph.D.
Chief Information Officer
Auburn University - Montgomery
 

 

 

Thanks to AUM student Justin for passing this along



Brought to you by the Non-WTF Job Board:


Error'd: Moving Technology Forward

Fri, 07/11/2008 - 12:00am

"I saw this sign in the window of an empty storefront," Jason Sullivan wrote, "and I can't decide if the biggest WTF is using poster board, stencils and multiple colors of what appears to be chalk in their quest of 'moving technology forward', or the fact that they apparently made a mistake while putting the 'N' in consulting and just decided to use a bit of masking tape to correct it, rather than flip the board over and start again."

 

Apparently Dice wasn't kidding in their ad for SQL Injectors..."


(from Craig Maloney)

 

"Ha," Nathan L Smith writes, "I always knew that Dreamweaver was a slacker!"

 

"I caught this random whoops the other day," writes Anthony, "I'd like to think the guy on the left was somehow involved."

 

Chris notes, "Our company's internet security is a bit excessive."

 



Brought to you by the Non-WTF Job Board:


Slow-Motion Automation

Thu, 06/11/2008 - 3:00am

Despite being considered a small player in the insurance field, Mike I.'s company writes $1.1 billion in premiums annually and has carved itself a nice niche in the area of non-standard automobile insurance. Non-standard is for drivers who are rejected due to things like too many speeding tickets, fender benders or DUIs. Like all other insurance companies, Mike's relies on complex custom software to quote and write its policies.

Complex is a bit of an understatement. Because the company does business in more than 40 states, it has to comply with each and every state's specific insurance regulations. Certain types of coverage aren't allowed in some states, deductibles vary everywhere and the limits seem to randomly change. One of the biggest challenges with such complex software is that testing becomes very difficult.

For years, the testing strategy was entirely manual. Testers would enter thousands of test cases -- each taking a good five minutes or so. After a while, management multiplied that by a bimonthly release and realized that there were a lot of hours tied up in testing that could be automated with data-entry scripts. In an effort to save more money, management outsourced the automation project to an offshore team.

After spending nearly a year in development, the offshore team delivered the Policy Testing Suite (PTS). It was a stand-alone Windows app that tied into the policy systems by binding to fields using the Windows API and provided testers with a state-specific library of macros that would fill out the various forms and submit them. Behind the scenes, the macros were simply a collection of VBScript files that were to be created and maintained by Mike's team.

It didn't take too long for Mike to notice a fundamental flaw in the PTS design -- there was no way to share scripts between states. Although each state had its unique set of requirements, there was a lot of common functionality such as the insured's name, address, phone number, etc. To work around this, they had to simply copy/paste scripts between states and change them as needed. Any changes to the common areas needed to be applied to all 40-plus versions of the script. Though testing time was reduced, programming time quickly skyrocketed.

A Better Solution

Well aware of the maintenance problems with the thousands of various VBScript files, management had the offshore team completely rewrite PTS. The new version, the offshore developers promised, would not only ease maintenance, but would be data-driven in an extensible manner so that business analysts could develop the macros instead of programmers.

At the core of PTS version 2 (PTSv2) was the concept of policy actions, which were merely a collection of VBScript subroutines that were defined like this:

Sub SetPrimaryInsuredFirstName( target, value )

This allowed business analysts to define test cases as a series of named actions (SetPrimaryInsuredFirstName) each with a target (Policy) and a value (John). To make test case development even easier, PTSv2 used Microsoft Excel spreadsheets as its data store. To add new test cases, all one had to do was edit a spreadsheet on a share folder and voila! it would appear on testers' consoles.

It didn't take long for Mike to notice a fundamental flaw in the design: there was still no way to share between states. However, because automated test-case maintenance had fallen on the shoulders of business analysts, he simply let them worry about the redundancies. Besides, his team had their own issues. Because of the data-driven nature of PTSv2, debugging problematic test cases became nearly impossible.

The Slowdown

As the months passed and more and more test cases were migrated to PTSv2, testers noticed that data entry was slowing down. In the old system, clicking a testing macro resulted in the forms being filled out instantaneously. In the new system, however, they could actually see each field being filled out.

After several more months of effort, all of the test cases were moved to PTSv2. But by that time, testing had ground to a halt. Clicking a macro resulted in a flurry of disk activity and a several-second wait between each field. On a big testing day, it would take nearly 20 minutes for PTSv2 to enter a single test case.

Realizing that testers could actually type in the data faster than their computer could, management declared automated testing to be a failed experiment and required that all testing be manual once again. But Mike wasn't convinced, and investigated why the scripts ran so slowly.

What he found in the code made him want to cry. The test machines had a dual-core processor and 2GB of RAM, and each of the Excel spreadsheets was about 1MB. Whenever PTSv2 needed to find a cell value, it would open the file over the network, parse every single line and then extract the single value from the row. Because this happened thousands of times per test case, it was no wonder why it was so slow.

Fortunately, after a bit of convincing, management agreed to redevelop the PTS and, after a couple of months with a new team, PTS is once again entering data faster than the testers can.

Slow-Motion Automation was originally published in Alex's DevDisasters column in the Sep 1, 2008 issue of Redmond Developer News. RDN is a free magazine for influential readers and provides insight into Microsoft's plans, and news on the latest happenings and products in the Windows development marketplace.



Brought to you by the Non-WTF Job Board:


CodeSOD: If I've Said It Once, I've Said It Fifty Times

Thu, 06/11/2008 - 12:00am

I can think of several ways to improve the code below from Jeff S., or at least to reduce its line count by two or three.

function submitTrap3() { var n = 0; var f =0; var elementItem = ""; if (window.event.keyCode == 13) { for (n=0;n<document.forms[0].elements.length;n++) { elementItem = document.forms[0].elements[n].name; if ((document.forms[0].elements[n].value != "") && (elementItem == trim(document.forms[0].txtControlName.value))) { switch (elementItem) { case "header1:SearchBox" : { __doPostBack('header1:goSearch',''); break; } case "Text1": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text2": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text3": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text4": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text5": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text6": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text7": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text8": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text9": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text10": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text11": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text12": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text13": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text14": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text15": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text16": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text17": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text18": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text19": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text20": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text21": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text22": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text23": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text24": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text25": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text26": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text27": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text28": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text29": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text30": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text31": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text32": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text33": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text34": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text35": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text36": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text37": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text38": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text39": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text40": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text41": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text42": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text43": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text44": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text45": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text46": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text47": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text48": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text49": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } case "Text50": { window.event.returnValue=false; window.event.cancel = true; document.forms[0].elements[n+1].focus(); break; } } } } } }

There's a pattern there. See if you can find it!



Brought to you by the Non-WTF Job Board:


Circling the Solution

Wed, 05/11/2008 - 3:00am

Tore S. had it made. He landed an enviable position that many of his fellow students had been gunning for – an evening/night shift as a Unix admin and general support for a large company that let him work from home. And you know what that means: equal time given to work and dancing around in your PJ's Risky Business-style. He could sleep and get paid for it, so long as he kept his cell phone on and would wake up and answer if/when it rang. Then he'd have to VPN into the network, do his thing, and then carefully weigh the decision to have another one-man dance party or go back to sleep. (Sleep usually won.)

One fine Saturday morning around 11:00, Tore was sound asleep, visions of sugarplums dancing in his head – only to have his wonderful dream violently interrupted by the screech of his cell phone. Tore squinted, rubbed his eyes, and read the caller ID. Damn, it was work. He quickly practiced saying "hello" without sounding tired, and then answered.

"Hel-"

"THE LOTUS NOTES SERVER IS UNREACHABLE." Ivan, Tore's boss's boss's boss, was furious. Tore was used to his attitude and had learned not to take it personally.

"So you want me-"

"FOLLOW THE SUPPORT PROCEDURE." *click*

Tore sighed, dragged himself to his computer, and looked up the standard operating procedure. The Lotus Notes server was outside of Tore's authority, so this was going to be easy. "Call internal support," the document read. Tore dialed the number, reported the problem, they assured him that they would contact the responsible admin, and Tore moved on to his next task: procuring a bowl of cereal and watching some TV.

Tore was impressed by how quickly he escaped Constable Cornpuff's maze, decrypted Mr. Marshmallow's word scrambles, and figured out all of the words in Baron von Blueberry's crossword puzzle. Mysteries on the back of the cereal box solved, Tore paid more attention to whatever forgettable show was on the TV. After a half hour or so, another call.

"Hey, Tore, this is Martin," he began. Martin was one of the system managers. "The Lotus Notes server is down; I need you to take care of it."

"Oh, yeah, I know. It's already been reported, and currently being worked on." Since Tore had no access to their internal ticket system, he was officially out of the loop. "I'll let you know as soon as I get an update."

Martin sighed. "OK, fine." *click*

Tore was a diligent guy, though, and figured he'd better call internal IT just to check up. "We've escalated it to the responsible admin," they reported. Uh oh, Tore thought, usually this is just a server reboot. This must be a serious issue if it's taking this long...

Right after getting off that call, another came in. "TORE." Ivan was clearly still upset, and was inadvertently giving Tore's cell phone speaker a stress test with his yelling. "THE LOTUS SERVER IS STILL OFFLINE."

"Right. I've reported it to internal IT, talked to Martin, and just got off the phone with internal IT again. They've escalated it to the appropriate person. I've done everything in my power."

Ivan demanded that he call internal IT. Though it had been less than two minutes since he'd talked to them, he wasn't going to agitate Ivan any further. Internal IT put Tore on hold while they called the tech for an estimate. As Tore listened to the Michael Bolton hold music, he noticed that Martin was calling on the other line. He quickly switched over.

"Hey Tore, do you have a status update on the Lotus Notes situation? What's the ETA?"

Tore responded, "No news just yet, but I'll let you know as soon as learn more." Satisfied, Martin hung up. Tore switched back over to internal IT. A minute later, the IT support guy said that someone was working on it, but that couldn't give a solid estimate. Tore called Ivan with the update, and got back to his TV show.

Again the phone rang. Again, it was Ivan. After another call to internal IT and a status report, and close to an hour of the server being down, Ivan was about ready to explode. "GIVE ME THE NUMBER FOR INTERNAL IT. I'LL SETTLE THIS MYSELF," he barked. Tore couldn't help but feel bad about the verbal beat-down that internal IT was about to receive.

Another five minutes passed, before Tore's next phone call. "Tore." It was Ivan, but he wasn't speaking in all caps, his rage having melted away. "The problem's fixed. What was the name of the system manager you talked to?"

"Martin."

"YEAH. THAT'S WHAT I THOUGHT." Uh oh. His rage is back.

"Uh... is there a problem?"

Ivan went on to explain, with varying rage levels, that Martin had been the responsible admin for the Lotus Notes server all along. Martin had just decided to be lazy that morning, and that he was going to pass the buck to Tore.

The circle went thusly: Tore called internal IT, internal IT called Martin, Martin called Tore. And occasionally Ivan would jump in just to keep things interesting. Martin didn't realize that Tore didn't have any control of the server, despite the fact that Martin was the one who'd set up the security. All Martin had to do was a server reboot, but apparently that was too much to ask.

For over an hour, the four circled the solution and grew more and more frustrated with one another. And as a result of this mess, Ivan fired Martin for this and other similar incidents.

Tore's job was eventually replaced by an Indian service desk, where no doubt their poor staff are getting yelled at by Ivan, calling internal IT...



Brought to you by the Non-WTF Job Board:


Error'd: Not Quite $30

Wed, 05/11/2008 - 12:00am

"I took this with my cell phone at the gas station," T. Bare writes, "I think there's something wrong with their rounding... unless there invented a new increment of the dollar that I'm unaware of."

 

"I encountered the following while installing Mobile Master," Marjin wrote, "I actually do not have a Nokia Phone."

 

Aryel Tupinambá writes, "they also sold 'criminal records' and 'head trauma', but they had special pricing on 'wrongful deaths'."

 

Jason Makstein snapped this Windows Media error in Washington, DC next to the Gallery Place in Chinatown.

 

"For a change, I thought I'd take the time and fill in a site satisfaction survey," Chisel Wright wrote, "it's a shame they didn't ask me how satisfied I was with the survey itself."

 

Aparently unafraid of a stationary rationing, Mark Miller's coworker has devised a unique "away" system...

 



Brought to you by the Non-WTF Job Board:


CodeSOD: Raiding the RAID

Tue, 04/11/2008 - 1:00am

"I'm currently in the process of customizing the firmware for a RAID controller used in some of my company's products," jspenguin wrote, "The LCD Controller Module (LCM) is written in PHP and, as it turns out, an LCM is not quite what PHP was designed for. In addition to abusing exec() all over the place, they poorly re-implement functions that are built-in to PHP."

function strcenter($string, $len = LCM_ROW_LEN) { //printf("%s\n", __FUNCTION__); $size = strlen($string); if ($size > $len) return $string; $divisor = ($len - $size) / 2; unset($new_str); for ($i = 0; $i < $divisor; $i++) { $new_str .= " "; } $new_str .= sprintf("%s", $string); for ($i = strlen($new_str); $i < $len; $i++) { $new_str .= " "; } //$test = strlen($new_str); //echo "len = $test\n"; return $new_str; } function strleft($string, $len = LCM_ROW_LEN) { //printf("%s\n", __FUNCTION__); $size = strlen($string); if ($size > $len) return $string; $remainder = $len - $size; unset($new_str); $new_str .= sprintf("%s", $string); for ($i = 0; $i < $remainder; $i++) { $new_str .= " "; } //$test = strlen($new_str); //echo "len = $test\n"; return $new_str; } function LCM_get_base_position($length, $tag=TAG_NONE) { for ($i = 0; $i < $length; $i++) { $string .= "X"; } switch ($tag) { case TAG_ENT: case TAG_SCROLL: $max = LCM_ROW_LEN - 1; break; case TAG_SCROLL_ENT: case TAG_UP_ENT: case TAG_DN_ENT: $max = LCM_ROW_LEN - 2; break; case TAG_NONE: default: break; } $string = strcenter($string, $max); //printf("%s: str = %s, max = %d, length = %d\n", __FUNCTION__, $string, $max, $length); $pos = strpos($string, 'X'); if ($pos == false) { printf("%s: Failed to get postion\n", __FUNCTION__); } else { return $pos; } }

jspenguin continued, "I especially like the sprintf("%s", $string). As for their exec() abuse..."

function alarm_mute() { //exec("echo 0 > /proc/ems/alarm/tone; echo 0 > /proc/ems/system/error_led"); exec("echo 0 > /proc/ems/alarm/tone"); } function GetIfaceInfo(&$config, &$address, &$submask, &$gateway, &$dns) { $dhcp_cmd = "grep \"iface eth0 inet dhcp\" /etc/network/interfaces"; exec($dhcp_cmd, $a1); if ( count($a1) == 1 ) { $config = "dhcp"; } else { $config = "static"; } $get_addr_cmd = "ifconfig eth0 | awk '$1 ~ /inet/{print $2}' | awk -F: '{print $2}'"; exec($get_addr_cmd, $temp); $address_string = $temp[0]; GetIfaceforIP($gateway_string, $submask_string,$dns_string); TransIfaceInfo($address_string, $address); TransIfaceInfo($submask_string, $submask); TransIfaceInfo($gateway_string, $gateway); TransIfaceInfo($dsn_string, $dns); }

"And as a bonus, due in no small part to the kernel module, exec() is slow. Really slow. It takes nearly a whole second to fork and execute a process. This means it takes two or three seconds to write a single event to the log. So, if there was a problem that affected all eight hard drives -- say, a power issue -- this is what will happen:

1. LCM reports the first drive failure and starts alarming. 2. User presses the Mute button and, three second later, the beeping stops. 3. Seconds later, LCM repors the second drive failure and start alarming. 4. User presses the Mute button and, three second later, the beeping stops. -- snip -- 16. User presses the Mute button and, three second later, the beeping stops. For good.

"I doubt anyone actually makes it until the last step, though. It's much easier to just yank the power plug in frustration."



Brought to you by the Non-WTF Job Board:


What the Ad?

Sat, 01/11/2008 - 1:00am

A few weeks ago, TDWTF contributor Mark Bowytz shared some fun classic computer ads. Apparently, Mark has an entire attic filled with Byte magazine and other '80s computer magazines, and has dug through them to pull out some more. Stay tuned for more What the Ad?...

Here, Mr. Shatner says, in his smoothest voice, "Buy a Commodore, you know you want to. Look at the features - appreciate the value. I know technology. I know computers, I'm. the. Captain. Of. The. Enterprise!!"

 

Meanwhile, Mr. Cosby is saying "Are you dense, son? You need this calculator. It's a good deal! Do you see how I'm dressed? This is exactly how smart people dress! Be smart like me."

 

Sure the PET's technical specs dwarf the TI's, I can take the TI anywhere. Also, while the TI uses magnetic cards for storage, the PET uses good ol' floppy diskettes and you can even network them! So many features…

I give up. I'll just take whatever the Joe Howard, the Mathnet guy, is selling.

 



Brought to you by the Non-WTF Job Board:


CodeSOD: One In 3.4*10^38

Fri, 31/10/2008 - 11:00pm

Jonathan did a double-take when he glanced over this function:

Public Sub KillTheChildren() Dim objIntegrationAccount As IntegrationAccount For Each objIntegrationAccount In mcolItems Set objIntegrationAccount = Nothing Next Set objIntegrationAccount = Nothing End Sub

I probably would've gone with another name for this function. Perhaps ClearIntegrationAccounts, RemoveChildObjects, or really anything else that wouldn't imply that I have a chemical imbalance that makes me want to murder children.

Comparatively, though, another bit of code that he sent over is worse. (Condensed for your sanity.)

If blnContinue Then If CreateConnection Then If DeleteData Then If CreateLocations Then If SaveServiceProviders Then If LoadServiceProviders Then If LoadCategoryNames Then If LoadFiveServiceProviders Then If CalculateAllActivations Then If UpgradesCalcNoExchange Then If UpgradesCalcExchangeReturns ' (25 more levels here) End If End If End If End If End If End If End If End If End If End If End If

Probably the most interesting thing about the application is this assortment of GUIDs.

With 2128 possible GUIDs, how many must they've used to get several so close together? (Probably less than the odds of a custom function that chooses the next unused GUID or entering them by hand.)



Brought to you by the Non-WTF Job Board:


Tales from the Interview: Persistence is Key and The Nightmare Dream Job

Fri, 31/10/2008 - 2:00am
Persistence is Key

After two years, Thomas B. had become somewhat bored with his job. He was the first developer the small TV station had ever hired, and while he enjoyed building a PHP-based CMS that they'd use internally, over time his job had essentially been reduced to babysitting the web site. He accepted another offer and told his boss about his plans to leave.

Since the CMS had been built from the ground up and Thomas was the only one who knew everything about the system, he was an integral part of the interviewing and hiring process. His boss delivered him six résumés and told him that all six of those candidates would be in that day. Thomas hadn't been given much time to review the résumés, so he just had an opportunity to skim them before the first candidate arrived.

Five of the résumés sounded like they'd all make at least decent candidates, but the sixth almost seemed like it had been submitted as a joke. It looked completely unprofessional, and when Thomas scanned the page for "PHP," "MySQL," or even "JavaScript," he couldn't find any of them. Her most recent work experience was essentially "stay at home mom."

Thomas asked his boss if it was too late to cancel her interview, but his boss stubbornly insisted that the interviews would go as scheduled. So one-by-one, he interviewed the candidates until the last interview of the day – Joyce.

Joyce arrived dressed like a sorority girl – white, fur-lined boots matching her white, fur-lined coat, which she wore over a leopard-print blouse – though the getup probably would've been more appropriate on a woman less than half her age. Joyce had a very cheerful disposition and was clearly excited about the opportunity to work at a TV station. After introductions, Thomas's boss asked an easy question. "So, tell us, why did you apply for this position?"

Joyce's smile grew larger. "Well, I want a challenging job, and making web pages really interests me!"

"So, how many web sites have you worked on?" Thomas asked.

"None yet."

There was a brief moment of silence in the room.

"OK, so..." Thomas was eager to get things back on track. "Ours are built in PHP, XHTML, and CSS. Have you worked with those?"

"Yes, I know HTML and the CCS."

Really, did she just say "the CCS" instead of "CSS?" "And what about PHP?"

"No, I don't know that yet." Her smile faded a bit, as she must have understood how the interview was going. "But I'm very motivated and I'm a fast learner!"

She had spirit and a great attitude, but almost no qualifications. Thomas all but checked out at that point, letting his boss take the reins. Thomas was hardly paying attention, but did hear one last amazing answer. His boss asked "Joyce, what do you think qualifies you for this position?"

"Well," she began, seeing this as a chance to turn things around, "I use a computer every day, for seven, eight hours! And I have lots of programs installed on it!"

A few minutes later, they said their goodbyes and thanked her for her time. Joyce was polite and cheerful until the end, even though it was clear she wouldn't be getting a call back.

By now it was after 5:00, so Thomas was about to get ready to go home. Still, something was bothering him.

"So Mike," he asked to his boss, "I don't understand why we brought her in for an interview. Her résumé was terrible, and her interview wasn't much better."

"Well, for one," he began, "I admired her persistence. She's called about the position several times and showed the most genuine interest out of all the candidates."

"I see," Thomas responded, still thinking that it had been a waste.

"Also, we don't want a sexual discrimination lawsuit."

  The Nightmare Dream Job

It couldn't have been a more ideal position. It was an ad for a company just over 100 miles from his small town, but they'd allow Kirk S to telecommute. Since his wife's job wasn't very portable, this was very important to him. Still, if he ever had to go to the office for any reason, it was within reach – less than a two hour drive. Plus the skillset they were looking for synched almost completely with what he'd been doing for the last few years. Excitedly, he took the drive to their office for his interview.

The technical interview was going well, so one of the interviewers started to give some detail about their operations. "So what we're doing is going to revolutionize subscription monitoring." He went on to explain that they worked with hundreds of magazines and newspapers with millions of subscribers. They were working on an application that would push information about subscribers' accounts and subscriptions to the subscribers' computers, assuming they had the desktop software installed. Kirk was dubious, as he'd never cared that much about a magazine subscription to require a monitoring service for it, but whatever. The pay was good and they seemed to know what they were talking about.

"So," Kirk asked, "how often are you feeding this information to subscribers?"

"Once per minute."

Kirk's jaw dropped. "Seriously? How often does this information change?"

He dodged the quesiton. "We feel that the customer deserves to know current information about their transactions. Don't you agree?"

"Well, what if their information hasn't changed in the last minute?"

At this point, the two interviewers exchanged a glance that Kirk could only interpret as meaning "he's an ignorant outsider, and he totally doesn't 'get it.'" Defiantly, one of the interviewers contended "Look, we already have the service written. It sends updates once per minute. That's how it works, and that's how we want it to work, and that's how we'll want you to keep it working. Our millions of subscribers deserve the best!"

They'd said "millions" earlier, but it hadn't really registered with Kirk before. "What kind of bandwidth do you guys have?"

"A T-1. Why?"

Some quick mental math revealed to Kirk that there was no way a single T-1 could handle a minimum of a million packets (roughly 17Mb/s) dispatched every sixty seconds. He told this to the interviewers, who clearly hadn't thought of it before, and sent him on his way to someone in HR.

She assured Kirk that he'd done well in the interview and that they'd probably make an offer. "So when can you start? Do you have a place in Omaha yet?"

"Um, no. The ad said this was a telecommuting position."

"Oh, right, it is! After the first year, you'll get to work from home for a day or two a week!"

Between the misleading job posting, the utter futility of the project, and the fact that they were betting the company on a service that would be mathematically impossible to provide, he wished them luck and started the long drive home.



Brought to you by the Non-WTF Job Board:


Error'd: Floor -1

Thu, 30/10/2008 - 11:22pm

“A popular job interview question goes something like, ‘program me an elevator control system,’” Stephen writes, "apparently, the elevator company never thought to ask their programmers that question."

 

"I was looking for a synonym for the word 'completed'," Mark noted, "but according to thesaurus.reference.com, there are no synonyms for 'completed'. Maybe I should try 'completed' instead?"

 

"The cheapest and most useless network cable tester available on teh internets came complete with this comedy insert," Vic Edge writes, "Remember, do not change it on your mind."

 

Peter Sloboda writes, "after right-clicking for the 100th time inside the SourceGear's Vault Diff tool, choosing 'copy', and then having the subsequent paste fail, I have finally discovered the Vault programmer’s inside joke."

 

"This recently came to our house in the mail," Cassandra writes, "odd thing is, neither I nor my husband attended SDSU."

 

"Hmmm, I don't remember requesting two arrays," Fox wrote, "I must be going senile or something."

 



Brought to you by the Non-WTF Job Board:


Effective Immediately

Thu, 30/10/2008 - 2:00am

Every job has its quirks. That’s what Kirk reassuringly told himself on his first day of work after meeting the company’s most egregious quirk, The Colonel. Kirk wasn’t quite sure if the impeccably-dressed man’s gruff introduction – which solely consisted of looking Kirk up, then down, then up again, and scoffing “that’s a pretty sad excuse for a Double Windsor” – was in jest or contempt, so he stuck with a the more palatable label of quirky. Fortunately, by the time Kirk realized that deranged was much more appropriate than quirky, he knew that he’d never have to personally work with The Colonel: the chain-of-command simply wouldn’t allow for it.

Having spent the larger part of his life in the military, The Colonel faithfully chose the same rigid structure for his civilian venture, a technology start-up that developed real-time logistics tracking systems. The “high-discipline” company worked well for the first year or so, as The Colonel had only hired ex-military employees and had only solicited to the military. However, when it came time to expand into the private industry, a few concessions were needed to attract the less-disciplined civilian talent: health benefits, sixty-minute lunch breaks, casual Fridays, etc. Of course, the company’s core values – chain-of-command, strict rules, top-of-the-line accommodations for executives, and so on – would never change.

A Good Problem to Have

When Kirk joined, the company was in the middle of “a good problem to have.” Months earlier, the development team had created a prototype to demonstrate the company’s capabilities to prospective clients. Their prototype was pretty impressive for the time: using inexpensive GPS units, standard cell phones, and off-the-shelf server hardware, their system would track “field assets” such as delivery trucks in real-time and display the asset on an interactive map.

As for their problem: The Colonel and his sales team told prospects that the prototype was their core product, and managed to sell a handful of licenses for it. Since putting more soldiers on the ground apparently solves all military problems, The Colonel employed the same tactic and nearly doubled the staff. With a company of fifty (half of which were developers), they were bound to successfully deliver the product they had sold.

But Still a Problem

As it turns out, developing a complex, customizable geographic information system that interfaces with an amalgam of less-than-ideal equipment is kinda hard. There are things like specs to consider, user interfaces to develop, equipment drivers to create, and so on. Add in to the mix aggressive deadlines, angry customers, and large refund checks to cut, and it creates something far worse than a “good” problem. The immediate result of all this is one seriously angry colonel.

The Colonel knew very little about software development, software, and computers in general. In fact, he didn’t even have a computer in his office; his secretary was responsible for printing out his email and typing up his dictated replies. What he did know, however, was that computer programs are made up of computer code, computer code is typed up by programmers, and when programmers aren’t typing code, they’re not making computer programs.

To ensure that programmers were focused on programming, The Colonel cut out a lot of the unnecessary parts of the software development process like system design and testing. While the quit-wasting-time-and-type-in-your-computer-code approach certainly helped get more code written, there were a few side effects. Namely, their software didn’t quite meet the requirements and it was pretty buggy. The Colonels’ new stop-writing-all-this-buggy-computer-code approach didn’t seem to help, either.

A Bad Problem To Have

After six long months of non-stop coding, development finally hacked together a system that could pass as the product sold to their clients. It kinda, sorta, somewhat tracked a variety of asset classes across a map, and usually displayed the results correctly. That is, assuming one was using the exact configuration of cell phones and GPS units that the development team had.

Unfortunately, the first client took the “compatible with any receiver” feature literally, and bought completely different GPS units. While their system read the GPS data in, the coordinate system used was completely different, which meant that incoming GPS data piled up in the system’s processing queue. Changing the input filter on the cell phone fixed the incoming data, but there was still a mountain of bad data to deal with; and the customer really wanted the data fixed.

The Colonel was furious when he learned about this major glitch, and insisted that the problem be addressed immediately. There was just one caveat: since computer code caused the problem in the first place, adding more computer code would likely exacerbate the problem. They needed a solution that didn’t call for any programming to deal with the bad data.

Since the developers had absolutely no idea how to solve the problem without coding, The Colonel offered his solution: covert the data by hand, row by row. And he wasn’t joking; in fact, The Colonel never joked. The two developers assigned to documentation duty were relieved of that job and given an Excel spreadsheet and a desk calculator.

For nearly a week, the pair worked sixteen hours a piece, each day, typing in data from a print-off and calculating the results by hand. This effort did result in a fixed data file for the client, but also left two casualties: one of the developers quit, the other had simply lost all will to live. Things went a bit downhill from there.

Despite having two somewhat successful field installs, the company was not having any luck selling to other prospects. As the weeks passed, The Colonel was becoming more and more agitated that business was not picking up. So, he did the only logical thing and clamped down on all the slacking employees.

Cracking Down

The harbinger of many further disciplinary emails came after three employees had an impromptu meeting for a few minutes in an unoccupied conference room.

ATTN EMPLOYEES: Effective immediately, no conference room may be used without first reserving the room on-line. We have a system for a reason and want to make sure the rooms are utilized appropriately. There are no exceptions to this policy. DICTATED BUT NOT READ, The Colonel

The next reminder came a day later after The Colonel spotted someone walking around with a cup of coffee and having a few words with someone past the time where everyone should be dutifully at their desks, slaving away:

ATTN EMPLOYEES: Effective immediately, we will now be enforcing tardiness and desk policies. In addition, we will also be tightening up some of the attendance rules at the office: 1. WORKING HOURS. There shall be no more "thirty minute flex time". You are expected to be at your desk no later than at 8:00AM and leave no earlier than 5:00PM. 2. BREAKS. You have two fifteen-minute breaks and a half-hour lunch break. While you can combine your breaks, you may no longer "split" them and take five minutes, five minutes, etc. 3. DESK - When you are at your desk, you are expected to be working. DICTATED BUT NOT READ, The Colonel

The Colonel clarified these rules the next day.

ATTN EMPLOYEES: There appears to be a misunderstanding of the attendance rules. You are to be at your desk, working, by 8:00AM and are expected to work up at least 5:00PM. This means your computer must be turned on before 8:00AM, and you need to pack your items up after 5:00PM. DICTATED BUT NOT READ, The Colonel

To no one’s surprise, the crackdown didn’t quite help morale or increase business in the least. It did lower expenses quite a bit; by the time this next email was sent out, twelve of the staff had resigned:

ATTN EMPLOYEES: Effective immediately, we will no longer have "casual Friday." We don't stop working on Friday and should therefore dress for work. DICTATED BUT NOT READ, The Colonel

Over the next two weeks, another eight employees quit. By this point, The Colonel implemented some brilliant countermeasures.

ATTN EMPLOYEES: Effective immediately, breaks may no longer be "combined". There have been far too many employees abusing the break/lunch policy and taking a full hour for lunch, each and every day. Morning Break may be taken between 9:00AM and 10:30AM. Lunch Break may be taken between 11:30AM and 1:00PM. Afternoon Break may be taken between 2:00PM and 4:00PM. DICTATED BUT NOT READ, The Colonel

Obviously, through all these crackdowns, Kirk had turned looking for a new job into a full-time endeavor. Unlike so many other employees, he wasn’t quite comfortable just up and quitting without another job in the bag.

Of course, everyone has their limits. As it turned out, Kirk’s limit was this personalized email from The Colonel himself.

ATTN KIRK: Earlier this week, you had brought in several large personal items and placed them in your workspace. You told your manager that the purpose of this was so that your items "did not get too hot during the day" in your car. Please note that we are not a storage facility. Your workspace needs to be clean and orderly; large personal items are not acceptable. There are no exceptions, even if you need to store items just for just one day. DICTATED BUT NOT READ, The Colonel

Kirk resigned shortly after that. While he tried his best to forget about The Colonel and the GIS system he had worked on, he verified that, four years later, they have yet to release their product.



Brought to you by the Non-WTF Job Board:


CodeSOD: Where'd param3 Go?

Wed, 29/10/2008 - 11:00pm

When I'm creating a function, I try to make sure it passes two simple tests:

  1. Using the function should require less code than just duplicating what the function does, and
  2. whatever the function does shouldn't be the same as a built-in operator

That said, this code that Paul G. sent in doesn't meet my criteria.

public string StringConcat(string param0, string param1, string param2) { return param0 + param1 + param2; } public string StringConcat(string param0, string param1, string param2, string param3, string param4, string param5) { return param0 + param1 + param2 + param4 + param5; }

Actually, come to think of it, that second function is OK, because presumably a rule in their organization is to ignore every fourth string. Also, it is cute that the author of this code was so close to discovering the params keyword...



Brought to you by the Non-WTF Job Board:


The Ralph Code

Wed, 29/10/2008 - 2:30am

Ralph's rage was the stuff of legend – and it was equaled only by his anal-retentiveness.

Ben had heard horror stories about Ralph and shrugged them off as exaggerations fostered by years of oral tradition. If the rumors were to be believed, Ralph could breathe fire and was the height of three men. Probably the stereotypical Nick Burns-esque IT guy, he reasoned.

That is, until Ben was at a colleague's downed PC. During the process, he moved some icons around on the desktop. "OH MY GOD DON'T DO THAT RALPH WILL BE SO ANGRY," she shouted with genuine fear. She begged Ben to move the icons back and not tell Ralph. Ben arched his eyebrow with confusion, but agreed.

After moving the icons back to their original positions, a wave of calm passed over his colleague. "Thank you. I can't tell you how upset and embarrassed I was last time." She went on to explain the tirade she'd received for setting her desktop wallpaper to the default, rather than the one that had received Ralph's blessing. She told of another colleague that had been reduced to tears after being chewed out for her copy of Outlook crashing. He'd refused to help users that used unauthorized mouse pads. Seriously. He wasn't Nick Burns – he was worse.

Not even their hardware vendors were free from Ralph's scorn, though at least they didn't have to deal with it directly. He arrived to work furious one day when he learned that HP was changing its numbering schemes for ink cartridges. Previously, each was identified by six or so characters (for example, "C8727A"), but now they're two numbers and (sometimes) a letter (in this case, "27"). It was a good move on HP's part, as they'd made everyones' lives easier.

Everyone except Ralph that is.

Ralph did the same thing that any poorly-adjusted, chemically-imbalanced, borderline-psychopathic IT guy would in this situation – fix their numbering scheme. His invention took him a morning to set up and put into practice. First, he drew up what was basically his numbering scheme's decoder ring. Each printer model was assigned a letter. The one nearest to his desk became "A." The second-closest on his floor was "B." And so on, until he'd hit all the printers in the office and used up a good portion of the alphabet. Similarly, he'd apply one of these labels to the corresponding ink cartridges.

After some unruly staff members rejected his numbering scheme, favoring the inferior labels from the vendor, Ralph had to take action. He reprinted all of the labels, this time using huge 5"x7" ones, which were large enough to obscure the whole box.

Still, the labels weren't completely opaque, so the users adopted a habit of holding it under a light to read the packaging beneath the labels. Of course, this made Ralph even more furious, so he took a Magnum 44 black marker which he used to angrily scribble over the entire label, any other exposed information not covered by the label, basically everything except for its Ralph Code. Users could no longer see the manufacturer's cartridge number or compatible printers; mission accomplished.

Unfortunately, Ralph had overlooked one crucial detail in his original plans – the 27 cartridge works in over a dozen different printer models. And since Ralph's brillant labeling system was printer-specific, he had to come up with something that would work without him having to admit that his original idea had been poorly conceived. When the next order of cartridges arrived and he had 27s that would work in printer A and printer N, he simply applied the label A to half of them, and N to the other half. Problem created by a solution to a non-existent problem created by Ralph solved!

Finally, he set out to make the master key document that would be used to match printers' locations to their Ralph Codes, and their associated ink cartridge numbers. The first draft of this document, however, was wildly inaccurate, effectively obliterating any real or imagined value from this crackpot labeling system.

Ralph has since been let go. And sadly, despite his best efforts, his ink labeling system didn't last beyond his termination date.



Brought to you by the Non-WTF Job Board: