CodeSOD: 1 Moment in Time |
On occasion, we've all faced a situation where we need to check to see if some internal application process has succeeded, or gotten stuck. There are many ways to accomplish this; some better than others. In the old days, folks used loops to count CPU cycles. Of course, as CPUs got faster, this didn't scale all that well. Now you can use myriad combinations of event handlers, semaphores, thread safe flags and threads. Or you can just use the time tested method of hard coding a sleep.
Of course, this requires that you have a decent idea of how long something will take to complete. It also assumes that you know something about the delays that can reasonably be expected in the execution environment.
If it's on your hardware, that may be reasonable. When it's on the customer's hardware in their environment, your ability to accurately guess how long stuff will take decreases exponentially (think solid state disks vs. local physical disks vs. network storage vs. anything in the cloud).
Jerry inherited some installer software written by a former cow-orking cowboy coder named Mike. This software would perform several installation/setup tasks. Each used the same mechanism to see whether or not it had completed.
Specifically, It would spawn a thread that did a sleep for a hard-wired period, and then check to see if the step that was running had completed or not. If not, it reported an error.
Except that it frequently (e.g.: most of the time) reported that the task had hung or failed, when it was simply still (legitimately) running. Mike had made several fixes to this end, but never solved the problem. This annoyed the operations team to no end. Jerry was tasked with figuring out why it would incorrectly flag failures so often.
After some spelunking, Jerry had a headdesk moment when he found Mike's fixes in source control. See if you can spot the problem:
changeset 374223... - _BootloaderController.WaitForInstaller(_Id, timeOut + 10 * 000); + _BootloaderController.WaitForInstaller(_Id, timeOut + 20 * 000);
changeset 374254... - _BootloaderController.WaitForInstaller(_Id, timeOut + 20 * 000); + _BootloaderController.WaitForInstaller(_Id, timeOut + 30 * 000);
changeset 374296... - _BootloaderController.WaitForInstaller(_Id, timeOut + 30 * 000); + _BootloaderController.WaitForInstaller(_Id, timeOut + 60 * 000);
|
Метки: CodeSOD |
Announcements: Submit WTF Code Directly From Visual Studio |
A little more than five years ago, we published a plug-in that allowed you to submit code directly from Visual Studio to The Daily WTF. However, in the years since, that style of extension was deprecated in Visual Studio, and the SubmitToWTF API was lost in the latest site redesign.
The loss was felt by many users. Without the plug-in, submitting bad code requires first printing it out, putting it on a wooden table, taking a picture of it... then printing out the picture, scanning it, then uploading as a PDF to the Submit Your WTF form.
With Christmas right around the corner, we thought it would be the perfect time to restore this much-needed plug-in. Thanks to Ben Lubar, the SubmitToWTF extension has been rewritten and is available directly from the Visual Studio Marketplace.
Because it's in the marketplace, you can simply install the extension from within Visual Studio (tip: search "wtf", not a whole lot comes up), restart Visual Studio... and voil`a! You can once again hilight offensive code and submit it without ever leaving the comfort of Visual Studio.
http://thedailywtf.com/articles/submit-wtf-code-directly-from-visual-studio
|
Метки: Announcements |
The Call of the 90s |
The 90s were a weird decade, and not just because of a strange obsession with flannel. Computers were just becoming a mass-market phenomenon, and nobody really quite grasped what that was going to mean. When I entered college in the late 90s, the campus was still littered with dumb terminals wired up to the VAX. Just a few years before, theyd installed the latest thing in networking- 100Base-TX Ethernet- to all of the dorm rooms and most of the classrooms. They loved their brand new network, and didnt want punk kids messing it up, so you couldnt just connect your computer to the network (you probably didnt have a network card anyway). Instead, they had an outside vendor set up an office in a storage room on campus. You had to lug your tower over there, theyd take your computer for a week or two, and then give it back to you with a new NIC, a bunch of crapware, and a note which said your computer was cleared to use the network. You could then take that note over to the IT offices, and theyd put in a work order to activate the network port in your dorm room, and give you an Ethernet cable. Oh, and this entire process cost $200.
Eventually, they wised up, kicked the outside vendor off campus, and CS majors like myself got to make a couple of bucks installing NICs into freshmens computers. I think many of us might have had that sort of experience. Sabrina did a similar turn in her teens, helping a small ISP get people connected via modem or ADSL, but encountered a few… special edge cases.
One call was a pretty standard example: a family had just gotten a new modem, and wanted to connect their computer to the information superhighway… but couldnt. Yes, they had a dialtone. Yes, the modem dialed. No, it couldnt connect. Remote diagnostic options exhausted, Sabrina went on site. This small ISP primarily served a small city, but that city was surrounded by a large stretch of rural farmland that stretched into mountains. Before long, Sabrina found herself on gravel roads, driving past signs that warned, No Trespassing (and had been peppered with shotgun pellets to drive home the point). Eventually, she found the house- a quiet little place nestled well back into the woods. She greeted the family, waded through a handful of screaming kids, and went straight to the phone first. She picked up the handset.
There were voices talking on the phone.
Do you have another handset? Sabrina asked. Ill need everybody to hang up so I can debug things.
What? the mother said, Oh, no. Weve just got the one. But it is a party line.
A what? Sabrina asked.
A party line. We share a loop with the whole neighborhood.
Sabrina was a little flummoxed, since this hardly seemed like a neighborhood- their nearest neighbor was miles away- but as someone who grew up in the city, shed never even heard of a party-line, as they were mostly extinct everywhere in the country. Instead of giving each subscriber their own phone line, sometime in the past century, the phone company had installed a loop of cable all around the region. Each handset was attached to the entire loop, which meant everyone in the service area shared a single phone line. There was no call privacy, and there was certainly no way to use a modem under those conditions. Sabrina explained the problem to the family.
Well, the phone company has been after us to get a single line, but it just seems so silly when what we have works just fine. But, I guess if we need it to use the Internet…
After leaving that strange intersection of the 19th and 20th centuries, Sabrinas next call took her back into the city. There was a customer complaining that theyd just installed the software that came with their ADSL modem, but couldnt connect to the Internet. This brought her into her towns business district, where she found a the law offices of Duey, Cheatum & Howe. Mr. Duey brought her to his shiny new computer, a Pentium with a Yamaha CDR100- the $5,000 CD-R that Sabrina never thought shed see in person.
Now, he said, let me show you what I did. He put a CD into the regular optical drive. This CD was not one of the ISPs discs, but instead, was a duplicated disk simply labeled with black marker as Internet. Once he brought up the installer, however, it was clear that it was their software. He went through the installer, completely ignoring Sabrina until he had finished demonstrating exactly what he had done to set up the Internet. Once the he failed to connect, he turned to her and said, Well?
Well… Ill need to look at your modem.
My what?
Your modem? The thing you hooked up to the ADSL line? Sabrina asked. Its a little box…
I dont have one of those. I just have the CD.
Right… Sabrina said. But… you need one. A modem, I mean.
What? Thats nonsense. My neighbors bought Internet from your company. I borrowed the disc, made a copy, and now I want Internet at my office. I copy all sorts of programs from my neighbor, the lawyer explained. I paid all that money for a CD burner, and I want to get my moneys worth out of it.
You… youre a lawyer, Sabrina said, scandalized. Thats illegal. And… you copied our software, installed it without a subscription, and then called us for technical support?
Honey, I think I know just a little bit more about whats illegal or not. And you know what is illegal, offering a service that doesnt actually work! I want the Internet on this computer, and I want it now missy.
Sabrina confessed that she couldnt get it to work, and left him with the number to the ISPs sales department. She then beat a hasty retreat and went out on the next service call.
[Advertisement] Release!
is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!
|
Метки: Feature Articles |
CodeSOD: Recycled Code |
Hannes has inherited a legacy project. Like most legacy projects, it has no real documentation, the code is a disorganized mess, and making any change runs a non-zero risk of completely knocking over the house of cards.
What few comments the code has tells us things like this:
//Copied from DateUtil.cs
public static int CW(DateTime Date){
CultureInfo CUI = CultureInfo.CurrentCulture;
return CUI.Calendar.GetWeekOfYear(Date,
CUI.DateTimeFormat.CalendarWeekRule,
CUI.DateTimeFormat.FirstDayOfWeek);
}
I suppose it's nice to know that you copied this code from another file, especially as the copied code is both public and static, and thus copying is completely unnecessary. I guess calling DateUtil.CW would have been too confusing, because I mean, what does CW even mean anyway?
Then, he stumbled across a function called StrLength. At a guess, what might you think StrLength does? You might think it's a reinvention of the built-in String.Length function. Well, what if I told you that it returns a string. In fact, take a look at the signature:
private string StrLength(string s, int len, string repl)
What do you think this function does? If you said, "It's a pad left function," then you win… and we have a lot of questions about how your brain works.
private string StrLength(string s, int len, string repl){
string result = string.Empty;
result=s;
while (result.Length < len){
result = repl + result;
}
return result;
}
So, no, it is not a reinvention of String.Length, but it is a reinvention of String.PadLeft. It also creates loads of unnecessary string instances, and since it does no input checking, could easily receive a multiple character repl value. I guess that's why it's private.
[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!
|
Метки: CodeSOD |
Error'd: Now Playing - Exception, The Movie |
"While browsing the IMDB Android app, I finally found a hacking movie that gets the details right!" writes Jamie.
Josh G. wrote, "They've REALLY toned down Mortal Kombat since the last time I heard about it... and apparently it's dinosaur-themed (and LEGO)!"
"Evidently Microsoft has developed Time Travel but the update was broken," Chris W. writes.
"I'm not sure my mother had the presence of mind to note the time of my birth to the millisecond," wrote Dan.
Jonny writes, "Looks like I've been crapping in the radiator this whole time!"
"I don't know Canada Post, what CAN I do?" wrote Tasos S.
"???AT_LEAST_ITS_SECURE1???" Vladimir B. writes.
[Advertisement]
Incrementally adopt DevOps best practices with BuildMaster, ProGet and Otter, creating a robust, secure, scalable, and reliable DevOps toolchain.
http://thedailywtf.com/articles/now-playing-exception-the-movie
|
Метки: Error'd |
Pulling Teeth |
"Jackie, Brian is leaving the company in two weeks," the boss revealed behind his closed office door. "You'll be taking over maintenance for CONLAB."
Jackie's eyes went wide. Brian was a guru within their IT department; his departure would surely cause a stir. CONLAB was just one of his holdings, a real database-maintenance workhorse that several large internal business units relied upon.
"To get you familiar with it, I'm gonna have you take over some of Brian's open feature requests," the boss continued. "I'll email you the details."
"Sure!" This was good. Jackie could learn the ins and outs of the code while Brian was still around.
"Great! Make sure to arrange some one-on-one time with Brian as soon as possible," the boss said.
Jackie was optimistic about his increased responsibility at first. He already maintained a few smaller apps, and was sure he could make CONLAB "his" fairly quickly.
Unfortunately, getting his feet wet was hard when the pool turned out to be a desert mirage. Brian's calendar in Outlook was unpopulated. His cube was always empty. He never answered emails, never signed into Lync, and let every phone call dump to voicemail. Wall-to-wall meetings? Flaking out? Either was possible.
"Don't worry," the boss told Jackie. "I'll tell Brian to give you some time on his schedule."
Nothing came of this confident offer. As the days slipped by, Jackie had to get creative. He pounced on Brian in the one place everyone wound up at one time or another: the restroom.
Jackie explained how he'd be taking over CONLAB once Brian was gone. "I wanna start working on feature requests right away, but I'll need access to the code first. Can you help me with that?" Granting the proper permissions would be a single mouse-click operation in their project management tool.
"Well, it's complicated," Brian said. "The project lives in two git repos: one with the supporting library, one with the app itself."
Jackie frowned. "Really? Why?"
"It'll make sense when you see it," Brian promised. "Let me finish some refactoring first, then I'll grant you access."
Three days passed with no further progress. Jackie managed to corner Brian in the bathroom and ask again.
"Give me two more days," Brian said.
The extended deadline didn't help. Desperate, Jackie sought help from Alisa, the system administrator, and her incredible sudo-powers.
"Based on file names, I think this is the library he was talking about." Alisa pointed to her laptop screen. "But there are two git repos holding different versions of it."
"Oh, geez." Jackie nursed his temple. "OK, let me try out the one that's been worked on more recently."
Once Alisa granted the proper permissions, Jackie returned to his desk to examine the library. Its codebase lacked comments. It contained an if-statement body that failed to fit vertically on his 23" monitor. But worst of all, there were no test cases to be found.
"There are test cases for the application that also cover the library," Brian revealed in the bathroom some time later. But access to CONLAB's application code remained out of reach.
Alisa and Jackie went through the entire list of projects in the project management system, opening any git repo whose name hinted at having something to do with CONLAB. In the process, they learned their boss kept sales figures and presentations in git, along with more personal items.
"Oh my God, is this a diary?" Alisa asked.
"Close it, close it! I don't wanna know," Jackie said, averting his gaze.
Alisa grepped through the file system. Nothing looked remotely like code for CONLAB. She checked every file server that Brian may have had access to. She checked file servers that Brian shouldn't have had access to. She checked local production servers and even remotely based client production servers. No sign of CONLAB's code.
"Maybe he's bypassing company policy and using some other version control system," Alisa suggested.
She searched for signs of Mercurial, Subversion, CVS, Bazaar, Fossil—all to no avail.
"Seriously, what the hell?" Alisa muttered.
Jackie shook his head, sullen. "Right now, I have two theories. Brian's either storing the code directly on his dev machine, or, CONLAB isn't actually an application at all."
"Not an application?" Alisa repeated.
"CONLAB has no UI. It just processes database entries. So it could just be a batch file running in the background all the time," Jackie explained, then straightened as a third possibility occurred to him. "Heck, that might even be giving Brian too much credit. Maybe he's been handling the database updates manually, every 12 hours, for years now."
Alisa's eyes went wide before she sobered again. "Today's Brian's last day. What'll you do?"
Jackie stood up and scouted past the cubicle walls. He saw the familiar flicker of bad flourescent bulbs, heard the laughter of coworkers talking about anything but work ... and spotted Brian heading toward the men's room for what might be the last time.
"I'm going in," Jackie replied.
[Advertisement] Release!
is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!
|
Метки: Feature Articles |
CodeSOD: Not Getting the Getters |
The number of customers that might purchase your software has a detectable impact on how you develop that software. If youre making a smartphone time-killing game, for example, there are potentially hundreds of millions of customers for that game. This drives software in two directions- you have your mounds of shovelware crap that just hope to make a few bucks fleecing suckers, and then you have the tight competition that optimizes the design of the software.
Contrast that to enterprise software. If youre making an ERP, how many potential customers do you have? Thousands? Tens of thousands? And each one of them is going to want something different from your product, so youll need to either pile on features or build an Internal Platform that lets them customize it. It doesnt matter how much money is in this market, or even how many users there are going to be- its all about the number of customers that might pay for your product. This, I suspect, is a large part of why enterprise software is terrible, and I think it lays out a corrolary to Remys Law of Enterprise Software: the narrower the audience, the worse the software is going to be.
Which brings us to the code sent in by Jason F. Jason recently finished a contract to modernize a PHP web app for agricultural consultants. About twenty or so developers have touched this application at one point or another, and Jason is simply the latest one through the revolving door. A niche market, a series of developers who have never talked to each other, and as the topper, its built in PHP.
One of the preceeding developers left behind this unusual approach to object-oriented programming in PHP…
class AdvisorNewClient extends NewClient
{
...
//Client specific details
public $licensee;
public $advisor;
...
public function __construct($licensee, $advisor)
{
$this->getLicensee($licensee);
$this->getAdvisor($advisor);
parent::__construct();
}
...
public function getLicensee($licensee = null)
{
static $id;
if ($licensee) {
$id = $licensee;
}
return $id;
}
public function getAdvisor($advisor = null)
{
static $advisorId;
if ($advisor) {
$advisorId = $advisor;
}
return $advisorId;
}
...
}
Good idea: having getter methods. Bad idea: having getter methods that force you to pass the value you want to get into them. Worse idea: masking the actual member variables with your parameters. This is the trick, here- you'll note that the parameters to the functions share the name of the member variables, masking them in scope and ensuring that they never get updated. If you actually tried to use these methods like they were sane methods, youd be getting mysterious nulls, but if you just went right for the public members, youd be fine.
[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!
|
Метки: CodeSOD |
Easter Eggs |
Ada worked in QA in the Netherlands, testing a desktop application for a German bank. The app was simple: a C/C++ app that scanned in paper forms, read them with OCR, and processed their contents. It was constructed, as was the fashion at the time, from a number of separate DLLs, each serving one and only one purpose. It was usually fairly boring work, but it was paying for her education, so it was worth putting up with.
One day, however, it stopped being boring. The error message she was looking for was meant to say something along the lines of Name field is not filled out, indicating that—surprisingly enough—the name field was blank. Pretty routine test. The message that appeared, however, was ... different. It read, You stupid woman.
Ada stared at the message for a moment, then looked around, trying to see if anyone was snickering. Was this a prank? Was someone mad at her? Did they deliver her a dud build just to insult her? Or had her computer been hacked? Was she seeing things? Going insane? What the heck was going on here?!
"Nobody's going to believe this," she muttered to herself as she took a screenshot. Then she printed it and carried it to her coworker's cube. "Bernd, I know this is weird, but ..."
No sooner had Bernd seen the screenshot than he pinched the bridge of his nose, looking tired. "Thanks. I'll take care of it."
"You believe me?" she blurted before she'd even realized it.
"Yeah. I know exactly what happened here."
Slowly, she managed to coax the story out of him. You see, in the Netherlands, you're forced to work your notice period, with no option to leave earlier; you're expected to be professional enough to keep doing your job the whole time. At this company, the notice period was two months ... and Edwin, one of their colleagues, hadn't been very pleased with the company when he'd resigned.
"I'm still trying to find all the blasted things," Bernd confessed to Ada.
"It can't be that hard," she protested. "We've been over this thing a dozen times in the last two months."
"He only left last week," said Bernd. "And a lot of them are on random timers. They don't show up every time, only one in three, or after it's been open for ten minutes, or an hour, or a day."
Ada whistled. "Are they all this bad?"
"This one's my favorite," he said, pulling a screenshot off his cube wall. It was a message box just like the one she'd found, only this one read Give me back my bike!—a reference to WWII, when Germany had impounded bicycles in Holland to pay for the war effort.
"If the bank had seen this ..." whispered Ada, horrified.
Bernd nodded. "That one only showed up on Tuesdays."
With Ada's help, Bernd managed to remove another dozen message boxes before they shipped live—and three more after, under the guise of security patches. Starting with the next hire, the company shortened their standard leave back to the typical one month, and started a new policy: developers who were leaving the company would be moved to the testing department for the duration of their notice period, just in case.
[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!
|
Метки: Feature Articles |
CodeSOD: This is the Endian |
Anyone whos ever needed to write cross-platform code in C or C++ knows that TRWTF is endianness. Your options are either to use a lot of platform specific preprocessor macros, or to coerce all of your data into your own specific format, for portability.
Adam Hs company took the latter approach, implementing a ByteWriter class. It was relatively easy to use, with code that looked something like this:
byte* tempData = new byte[128];
ByteWriter* writer = ByteWriter::Instance();
writer->Initialize(tempData);
writer->PutInt32(someIntValue);
writer->PutInt32(someOtherIntValue);
writer->PutByte(someByteArray);
At this point, tempData will hold your integers with the correct endianness, regardless of platform. But gee, that call to ByteWriter::Instance sure looks odd. Is that some kind of factory method? If so, that call to Initialize is weird. Lets go to the implementation of the class…
class ByteWriter
{
private:
int _index;
byte* _data;
static ByteWriter *_instance = 0;
ByteWriter() {}
public:
void Initialize(byte* data)
{
_index = 0;
_data = data;
}
void PutInt32(int32_t w)
{
PutInt16((int32_t)(w & 0x0000FFFF));
PutInt16((int32_t)((w & 0xFFFF0000) >> 16));
}
void PutInt16(int16_t w)
{
PutByte((byte)(w & 0x00FF));
PutByte((byte)((w & 0xFF00) >> 8));
}
void PutByte(byte b)
{
_data[_index] = b;
_index++;
}
static ByteWriter *Instance()
{
if (!_instance)
_instance = new ByteWriter();
return _instance;
}
}
And this is what drew Adam into this code in the first place- it was breaking any time it was touched by multiple threads, and of course it was. This is a classic example of the Unnecessary Singleton design pattern, commonly implemented by people who have skimmed the Gang of Four book, and needed to prove they knew what a design pattern was during an interview.
Unfortunately for Adam, this bit code highlights the problem, but:
This isnt the source verbatim, as TRWTF here is hard to nail down to one snippet, but it should be clear with a few pieces. (It also means that I may have messed up C++ syntax)
Its going to be much more complicated for him to actually fix.
|
Метки: CodeSOD |
Error'd: Null and Vague |
"UPS has sent my parcel to the corporeal equivalent of /dev/null," wrote Steve J.
"If the error message 'recurs', I don't know how much support will be able to help me out," Travis writes.
"When IntelliJ seems to be second guessing it's ability to detect file encoding," writes Felix V.
Eamon B. wrote, "Aww! That UID sure makes me feel loved, Uber. As if my $potential earnings weren't enough!"
"On the one hand, it seems that I'll have to find my departure flight times elsewhere," wrote Fay A., "but on the bright side, I can see that Au Bon Pain is open."
"I didn't want to use an existing certificate, but the advanced options for creating a new one don't leave me much of a choice," writes Ingo B.
"Swarm appears to think that a glass is half full and first place is last as well," Dmitry Z. writes.
[Advertisement] Release!
is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!
|
Метки: Error'd |
CodeSOD: Un-Encoding |
Felix caught a ticket about their OpenId authentication. For some mysterious reason, it had started failing around 30% of the time, specifically because the access token returned by the service was invalid.
Felix had originally written the code, but there was one problem: he wasnt the last one to touch it. Another development team needed their own versions of the code, organized a bit differently, for infrastructure reasons. Eventually, the whole thing was turned into a drop-in library component that was used by all applications which depended on OpenId. The failures started after they made their changes, so obviously their changes caused the failures.
Since the errors were intermittent, their first guess was that the bug was something intermittent- perhaps an infrastructure problem, or a race condition between interacting services? They couldnt reliably reproduce the error, so Felix spent a lot of time eliminating possibilities. Trawling through the code wasnt very helpful. The other team had been operating under unrealistic deadlines and hacked together something that worked and wasnt too worried about how or why it worked. The result included lots of un-patterns (like anti-patterns, but without having a pattern to them), inheritance trees that desperately needed pruning, and old-fashioned SQL injection vulnerabilities copy-pasted everywhere.
Eventually, buried deep in a common service adapter base class, no where near the code that was supposed to be responsible for managing authentication, he found this code for fetching the OpenId token:
public async Task GetAsync(string key)
{
T result = default(T);
using (var httpClient = await CreateHttpClient())
{
HttpResponseMessage response = await httpClient.GetAsync(Route + "/" + key);
if (response.IsSuccessStatusCode)
{
result = _serializer.Deserialize(
WebUtility.UrlDecode(response.Content.ReadAsStringAsync().Result)
);
}
}
return result;
}
Felix cringed a little at seeing a call to CreateHttpClient with each execution- there was a lot of overhead there, and the whole thing would be more efficient if the code only did that once. Still, the problem wasnt performance. Calling response.Content.ReadAsStringAsync().Result could actually cause deadlocks, and should have been await response.Content.ReadAsStringAsync(), but Felix wasnt tracking down a deadlock.
In fact, Felix almost eliminated this code as the source of his problem, until he looked at the call to WebUtility.UrlDecode. The body of the response was a JSON object. There was no logical reason to do that. And the OpenId token was Base64 encoded, using a mapping that included the + character. In URL terms, + might be known as %2B, thus mangling the token any time a "+" sign appeared in it, which coincidentally, happened about 30% of the time.
Felix fixed up this function, removing the nonsensical attempt to decode something which wasnt encoded in the first place, and the bug went away.
|
Метки: CodeSOD |
Frozen Out |
Lex was an employee at GreyBox in the late 90s, a PC-repair shop inside of a large electronics chain. He had spent the entire morning handling phone calls from customer after customer. Each of the calls was supposed to go to his co-worker Gerald, but Gerald hadnt been picking up his phone. Each caller complained that Gerald had taken in their computer for repairs and not actually done the repairs.
I brought my laptop in yesterday, one caller, a wheezy old man, said, and the young man behind the counter just took the laptop and said, come back in an hour. He went into the back room, and when I came back, he looked like he had been drinking. You know, red faced and sweaty. And the laptop smelled funny- like corn chips. And it wasnt fixed!
Lex, along with their boss Kyle, had long suspected Geralds… habits were interfering with his work performance. To wit, every time he was alone in the back room, he came out red-faced and sweaty. The accounting computer, also in the back room, frequently got infected with malware, despite only officially being used for running Excel. Gerald always covered his tracks, clearing history after he went about his business, and liberally spraying Febreeze in the back room afterwards, but they knew what he was getting up to.
Unfortunately, Gerald was the son of the owner. It would take something like the Pentagon Papers to get him fired.
Ill see to your laptop personally, Lex told the old man on the phone. Ill also give it a thorough cleaning for the trouble youve been through.
If Gerald couldnt be fired, then he had to be convinced to quit. He approached Kyle with an idea.
So, Gerald basically comes to work to… play on the computers, right?, Lex said. Well, I could write an application in Visual Basic that could freeze and un-freeze a computer screen. At some point, a copy of Visual Basic had ended up on one of their diagnostic machines, and Lex had spent some time learning to use it. It can disable the mouse and keyboard input, take a screen shot, then place the image over the entire screen. The entire process is reversible, too.
Kyle nodded, liking the general idea. How do you trigger it on his machine without him noticing? Kyle asked.
You can use another machine running the same process. It sends out a CmdPacket with the computer ID of the machine we want to target, along with a flag to either freeze or unfreeze the computer. When I notice Geralds not doing his job, Ill freeze his computer from my own. Oh, and well hide the process from the Task Manager, so he wont be able to kill it.
I dont think Geralds ashamed of what hes doing, Kyle replied. You could freeze… that stuff on his monitor, but hed just turn it off if somebody walked in.
Im not talking about catching him red-handed. We just freeze his screen when hes not doing work, and then unfreeze it when he decides to be useful again.
Kyle shrugged. Well, its worth a shot.
It was all Lex could do to hide his glee that week. Each day, when Gerald came in to work, he and Kyle would keep tabs on him. When Gerald blew off the cashier station for the back room, Lex would press a key combo and enter the computer ID Gerald was at. Gerald would moan and shout expletives, then mumble something about a lunch break before vanishing for an hour.
Gerald never got interested in doing work. Instead, after about a month of this treatment, he just stopped coming in. The owner called Kyle, asking if there was a problem with malware.
Well, Kyle replied, Lex and I havent seen any problems, but maybe Gerald should come in and remove the malware. It is part of his job, after all. Geralds dad never mentioned it again.
The little VB application that Lex installed remained on the computers at GreyBox for years afterwards. While they never had to punish any future employees for viewing NSFW content on company time, it did make for a fun gag during an after-hours LAN-party.
|
Метки: Feature Articles |
Representative Line: Off in the Distance |
Drew W got called in to track down a bug. Specifically, their application needed to take a customers location, and measure the distance to the nearest National Weather Service radar station. It knew the latitude and longitude of each, and needed to find the distance between those points, and it was wrong. It could be off by hundreds or even thousands of miles, especially in more remote locations.
This was the code in question:
from math import sqrt
dist = sqrt((abs(latdiff) * abs(latdiff)) + (abs(londiff) * abs(londiff)))
Now, theres an obvious problem here, and a number of nitpicks. Im going to start with the nitpicks. First, when you multiply a number by itself, itll always be positive, so you dont need the abs, making the line sqrt(latdiff*latdiff + londiff*londiff). Of course, Python also has an exponent operator, allowing you to write the easier-to-read version of, sqrt(latdiff**2 + londiff**2). But now that we bring it up, the math package in Python also includes a hypot function, which just implements the distance formula for you, meaning that whole thing could have been written thus:
from math import hypot
dist = hypot(latdiff, londiff)
Now, if your only criteria is, which solution is more pythonic?, then its clear that the latter solution is superior. Of course, you should still get your fingers whacked with a mechanical keyboard if you tried to check that solution in, because it still has one major problem: its completely and utterly wrong.
If youre not sure why… think of it as a special kind of rounding error.
|
Метки: Representative Line |
The Infrastructure |
George had just escaped from his job, a WTF-laden hellhole where asking for a test database to reproduce an issue resulted in the boss spending hours and hours hand-typing and debugging a fresh SQL script based on an old half-remembered schema.
Initech promised to be a fantastic improvement. We do things right around here, his new boss, Harvey, told him after hiring him. We do clean coding. Our development systems and libraries are fabulous! And each of our programmers get a private office with its own window! Yay, no more cubicle!
George climbed over the required HR training videos, slideshows, and a Himalayan mountains worth of paperwork, then headed to his new desk where a budget small-form factor PC with a single 17 LCD monitor waited for him. Yeah, thats real fabulous," he thought to himself. But perhaps it was just a placeholder system, quickly dug up from elsewhere in the building, to get him started while they ordered a proper developer-grade PC.
It booted up and George realized he didnt know his account credentials, so he wandered on down to the IT office to get set up.
The IT Office, from the outside, appeared to be a large corner office, but inside it was cold and dark and of uncertain size, with the windows covered by blackout curtains and hidden oscillating fans blasting a chilly breeze through the office. All the rooms light coming from a single small table lamp situated at the sole occupants desk. Piles of unsorted equipment and cabling were scattered across the floor, barely visible in the poor lighting, a veritable obstacle course for any visitors with poor eyesight or agility. In contrast to the rest of the room, the desk itself was absolutely spotless, neatly holding the lamp, a keyboard and mouse, and one nice 40" displaynothing else. Not even a telephone. An empty office chair sat in front.
As he entered the blackness, George could hear a rapid-fire chorus of clicking soundsthe kind that usually meant your hard drive had kicked the bucketclustered around one floor-based pile of machinery which was only visible due to the incessant flashing of LEDs it possessedLEDs which blinked in perfect time to the various patterns of clicks emanating from the area.
George coughed to make his presence known, and the IT guy appeared near the desk with such silence that George wondered if he had materialized like a ghost. Due to the placement of their sole source of light, George could not even make out his features.
Hi, Im George, he introduced himself, extending a hand the man did not accept. I just started here and I need an account.
The IT worker grunted slightly. He proceeded straight to one formless pile of equipment and sat down cross-legged next to it, right on the floor, moving so silently that George almost wondered if he had only imagined it. He made some barely-discernible motions in the dark, and a moment later a previously-hidden LCD monitor flickered to life, bringing new light into the room which allowed George to perceive that the monitor was precariously situated upon a pile of about five budget PC towers from at least a decade ago, heaped up like a deranged game of Jenga, the entire fixture surrounded by dark, snakelike cables of various types whiched meandered to and fro throughout the room.
The screen came to, and George watched in fascination as it presented a Windows Server 2000 login screen. He then realized in repugnance that this pile of equipment was the very same one radiating the sickly click of dying hard disks. Surely this was not the companys domain controller!
The IT guy entered his login information, and upon his hitting Enter, the violent ticking of hard disks became frantic. The screen froze for a long momentat the time it seemed like minutesbefore switching to the classic desktop environment of an operating system serving well beyond its prime. The shadowy IT guy fished a mouse from somewhere in the darkness, almost as if by magic, and balanced it upon his scrawney left knee so he could use it. He clicked on the Start button.
Nothing visibly happened at first, but the frenzied jackhammer of Clicks of Death told George everything he needed to know about the companys IT infrastructure. Many long moments later, the Start Menu itself appeared, slowly drawing line-by-line into the desktop space at a painfully-slow rate. It completed rendering and the brutal ticking sound diminished somewhat.
The IT guy attempted to open up the user manager, but as he clicked on its entry, the screen abruptly flashed to the bluest shade of blue, overlaid by a page of cryptic white text. Georges jaw dropped in horror but the other man remained perfectly silent. He reached a hand into the darkness and expertly stabbed the servers reset switch with such ease that George surmised this to be a common occurrence, common enough for him to have developed impeccable muscle memory for the task.
The system reset, flashed through its power-on self test, presented a RAID option ROM full of warnings about disk failure (which the IT guy completely ignored), and sat at the Windows 2000 Server loading screen for an eternity as its hard disks struggled from within to escape by the combined force of a dozen demon-possessed jackhammers.
Um, maybe Ill just come back later? George offered.
NO! The man nearly shouted his first utterance since George met him, his retort sudden and forceful enough for George to flinch.
And so George waited quietly, half-frozen in place by fear, watching the ghostly form of the companys IT guy as he struggled through two more Blue Screens of Death on the companys primary server before successfully opening the user manager and creating a domain account for George. Then he flourished, somehow producing a completed sticky note as if from thin air, and presented it to George. It is done. Now go.
George took the sticky note and left the IT office as quickly and quietly as he could, carefully stepping around nigh-invisible pyramids of computer equipment and treacherous bundles of cable, eager to put the experience behind him and never step foot into the IT office again.
As he entered the light outside the office, he peeked at the note which was scrawled with his username and password. But as he returned to his own desk to try the new login credentials, he could not expunge from himself an intense sense of doom, a growing despair that he had left one hellhole and entered a new dimension of pain and WTF-ery&
[Advertisement]
Atalasoft’s imaging SDKs come with APIs & pre-built controls for web viewing, browser scanning, annotating, & OCR/barcode capture. Try it for 30 days with included support.
|
Метки: Feature Articles |
Error'd: Lenovo Uh-Oh (and more!) |
"I get it that some apps need special permissions, but a GUID is the digital equivalent of 'just trust me - I know what I'm doing'," Kenneth M. writes.

"Sometimes, vendors paint their accessories with golden paint," writes Geoffk C., "On the other hand, if you're Lenovo, you might produce a mouse made of solid gold."
"When it comes to opening .psd files, I only use %1", writes Tony.
David wrote, "I've completely combed through Tanaguru's website and I still can't figure out how I can contact them."
"Mpan caught firefox performing peculiarly performant," writes M.
Pieter V. wrote, "Just when you don't expect an application crash to be sarcastic, VLC delivers."
"Oh, no, thank you, Microsoft for the pretty 'thank you' dialog," writes Tom G.
|
Метки: Error'd |
Just The Fax, Ma'am |
Gus had been working at his new job for a month. Most of his tickets had been for front-end work, making it easier and more efficient to manage the various vendors that the company did business with. These were important flags like "company does not accept UPS deliveries" or "company does not accept paper POs". The flags had been previously set via an aging web-based UI that only worked in Internet Explorer 6, but now they were migrating one at a time into the shiny new HTML5 app. It was tiring work, but rewarding.
Unfortunately, as is so often the case, Gus quickly became pigeonholed as "the flag guy". Whenever it came time in the project to add new flags, there was no question who'd get the ticket. Gus could think of nothing he looked forward to less than touching the Oracle-based backend to the product, but unfortunately, it was his burden to bear.
Adding flags to the database involved going through a special Database Committee. This was separate from the usual change request process. The committee was formed from all 6 of the company's database experts, and they personally reviewed every change. Worse, they were stodgy as all get-out. Any small error would get the change thrown out and the requestor berated for "wasting my time", along with a good helping of grumbling about "kids these days" and "narcissistic millennials" to boot.
Gus submitted his change request asking for a new field 2 weeks ahead of when it was slated to go live, just in case. Submissions were due by Monday and were discussed on Thursday, with the results posted first thing Friday morning on the bulletin board outside the breakroom. Gus filled in every field carefully, checking the whole thing twice—all but the title, which he'd written as "New Database Feild". On Tuesday, he realized his typo. He quietly edited the form, saved it, then crossed his fingers.
Friday rolled around and his change wasn't on the list, neither accepted nor rejected. Chewing his lip, Gus pulled up the change system and skimmed for his change.
It was marked auto-rejected.
"What did you do?" demanded Chuck, the senior developer who'd been mentoring him.
"I don't know!" Gus replied. "Do you think it was the typo? But I fixed it on Tuesday!"
Chuck slapped his forehead with his palm. "You changed the form? Don't ever change the form after it's submitted! That's grounds for automatic rejection!"
"It's okay," Gus said weakly. "We still have another week."
Chuck just looked at him, shaking his head as he walked away.
Gus spent the rest of the day focusing on the tedious form. There were dozens of fields, each with vague instructions, many demanding long explanations. Gus wouldn't be at the meeting to explain his change; he had to convince the committee it was necessary through the form alone. Worse, when he submitted it, it routed through an approval process that required him to chase down no less than 6 individuals to fill out their parts of the form.
"Yes, it's the same one as last week. Just put the same thing you did then. No, sorry, I don't know why it was rejected," he lied. "Can you just sign?"
Monday came and went without another auto-rejection. Gus checked compulsively every day at lunchtime, waiting for the other shoe to drop, but his request made it to Thursday without incident. Finally, Friday came, and he made the trek to the breakroom to check the list.
His change had been rejected.
He didn't know why. He didn't care why. The application needed to be up and running for the first of the month—the following Tuesday. There was no time to try again. Gus walked over to Chuck's cube, his mind whirling. "What do you know about data hiding?"
Chuck's face fell. He rubbed his face with one hand. "Dammit, this is why I try to pull front-end tickets."
"You gotta help me, dude. I'm dying here!"
"Okay, okay, let me think. I've heard about some guys slipping an extra so-called check-digit into integer fields. You have to mask it out before the code gets to it, but ..."
Gus grimaced. "I'd never get all the spots, I barely know the app."
"You're sure you can't push back on the deadline?"
"Yeah. Can't we find a field that's unused or something?" Gus begged.
An hour and dozens of SELECT statements later, they did just that. The Fax field wasn't populated in the old system; not a single vendor had a fax number worth recording. The new system hadn't bothered porting it over at all. Gus and Chuck hooked the flag up to the existing field. No muss, no fuss, and no database review.
[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!
|
Метки: Feature Articles |
CodeSOD: Trimming the Fat |
There are certain developers who dont understand types. Frustrated, they fall back on the one data-type they understand- strings. Dates are hard, so put them in strings. Numbers arent hard, but they often exist in text boxes, so make them strings. Booleans? Well, weve come this far- strings it is.
Tyisha has the displeasure of working with one such developer, but with a twist- they didnt really understand strings, either. Tyisha only supplied a small example:
string RequestDate = dteRequestTB.Text.ToString().Trim();
string valid = string.Empty;
string Format = "yy/MM/dd".Trim();
valid = Dates.IsDateValid(RequestDate.Trim(), Format.Trim()).ToString().Trim();
if (valid == "False".Trim()) {
...
}
Now, IsDateValid does more or less what youd expect- it takes a date (as a string) and a format (as a string), and returns whether or not the input date matches the format (as a boolean).
Tyishas co-worker, of course, converts it into a string before comparing. This is dumb, but nothing we havent seen before. For a bonus, theres absolutely no consistency in variable naming conventions. Theres the mix of pascal case, lower case, and a splash of Hungarian notation.
The real magic here, however, is that this co-worker isnt simply happy calling ToString on everything, but instead needs to also Trim those strings. In fact, they call Trim on every string. Everywhere.
[Advertisement]
Atalasoft’s imaging SDKs come with APIs & pre-built controls for web viewing, browser scanning, annotating, & OCR/barcode capture. Try it for 30 days with included support.
|
Метки: CodeSOD |
Awful On Purpose |
Studying his new work contract, Stewart felt like he'd found a golden ticket. After 2 long and tedious years in the local university's IT department, he was happy for any opportunity to escape that hellhole. TLA Technologies looked like the Garden of Eden by comparison. Instead of being the only person responsible for anything vaguely computer-related—from putting up websites to plugging in power strips—he'd now be working with a "dynamic team of programmers" in a "rapidly growing company tapping into the web development market". Instead of dealing with tools and languages forgotten by history itself, he'd be using "modern, cutting-edge solutions" under "agile and customer-oriented methodologies". And instead of reporting to a pointy-haired supervisor who couldn't tell a computer from a toaster, he'd be working directly under Dave.
Dave was a large part of why Stewart decided to take the job. Like most small company owners, Dave had taken it upon himself to personally interview the new hire—but unlike many of them, he had enough technical skills to make the interview feel less like a trivia game show and more like a friendly talk between fellow programmers. When Stewart's answers had strayed off the beaten path, Dave had been eager to discuss the solutions instead of just dismissing them, and when Stewart had started asking about the inner workings of the company, it'd been difficult for him to stump Dave with even the most precise questions. He seemed to know what his company was doing and what the coders need to deal with. What more was there to ask for from a boss?
Stewart quickly scribbled his signature on the contract and handed it back to Dave.
"Welcome aboard!" Dave stood and extended his hand to Stewart. "You'll start next Monday."
"Thanks for the opportunity," Stewart replied.
Dave smiled. "Hopefully you'll prove yourself out on the battlefield. If you pull that off, maybe you'll stick around for a while!"
In hindsight, the statement should've tripped an alarm in Stewart's mind, but being overjoyed with the prospect of a real job, he dismissed it as yet another cheerful promise. He left firmly convinced that all that glittered in TLA Technologies was gold.
While Dave hadn't exactly lied, there were a few things he'd neglected to bring up during the interview. For example, when talking about "cutting-edge solutions", he hadn't mentioned TLA Technologies was using all of them. No two applications used the same tech stack. Each used whatever was popular at the time, with languages and databases from completely different ecosystems blended together until they worked. Luckily, Stewart got off easy with an only somewhat bizarre combination of a Node.js service running against a SQL Server database.
The reason lay in what Dave had meant by a "dynamic team of programmers". Out of almost 20 developers, only 2 or 3 had any seniority. The rest were interns and juniors who came and went before anyone even learned their names. There was hardly a week that wasn't marked by desks being emptied, only to be filled by new hires within days. Everyone brought their own favorite technology to the potluck—sometimes introducing it through legitimate channels, sometimes sneaking it into parts of the application that'd be deemed untouchable once the original developer left.
There was exactly one person in the company with enough authority to rein the developers in. Unfortunately, Dave spent most of his hours at water cooler discussions, exchanging the latest IT gossip and encouraging the devs to explore new tools. Occasionally, he retired to his office to explain to one of the people he'd just been chatting up that they were "no longer a good fit for the company".
Stewart restrained himself from asking questions for quite a while, until one day he saw an empty desk a little too close to his own.
"Hi, boss," he said, entering Dave's office. "Do you know where Rob is?"
"Who's Rob?" Dave asked in a dry, uncaring voice, barely looking up from his monitor.
"Um ... Rob the front-end developer? He was supposed to finish a feature by today, and—"
"Oh, that Rob. We had to let him go. He wasn't pulling his weight on the new project."
"What do you mean? He's only been on that project for 2 weeks!" Stewart fought the urge to start shouting. "We'd just started introducing him to the codebase. Surely you don't expect—"
"Look, Stewart." Dave interrupted him again. "When we bring a new developer into a project, even an intern like Rob, the customer expects our performance to grow. They want results, and it's our job to deliver them. Unfortunately, with Rob, the entire team slowed down as soon as he started working. I'm sure you understand why it had to be done."
Stewart understood perfectly. With a polite nod, he scooted back to his desk, thinking about an escape plan.
The days kept passing, and Stewart was still gathering the courage to hand in his notice. In the meantime, he struggled to figure out the twisted logic of the service he was working with; one of the previous developers apparently figured that Unix timestamps made great database primary keys. This worked well in development and crashed hard in production. To "patch" it, at every insert, the application would sneak a blank record in between other requests to lock the row for itself. Once it reserved the row, it would then update it column by column—and with some tables having up to 40 columns, that meant 40 UPDATE queries per record.
It was a bizarre, Goldbergian design. Stewart decided to ask Dave to allow him to refactor it into something sane.
"Yeah, that is terrible," Dave agreed. "Why wouldn't they just use an identity field?"
"Exactly!" Stewart felt like he and Dave were finally on the same page. "It shouldn't take too long to fix, and it would certainly be much better for performance and development."
"But the current code works, doesn't it?"
"Um ... for now it does, yes. But it's already a performance killer, and once more people start using the service, it's going to be much worse."
"They aren't using it now," Dave said. "And the client hasn't complained. As a developer, I understand where you're coming from—but as a company owner, I can't agree to spending time on something that delivers no value."
Stewart's eyes widened in shock. It was a catastrophe waiting to happen. At the current rate, the performance would get unbearable in a matter of months. And Dave was just dismissing it like it was nothing? What had happened to the "customer-oriented" company?
"Besides, this is an opportunity to cash in on our support contract," Dave answered, as if reading Stewart's mind. "That's how it works in this business. If it ain't broke, don't fix it—unless the customer's paying."
"I see," Stewart muttered. As he left Dave's office, he decided to take the advice to heart. Not only was he not going to fix the application, but more importantly, he also wasn't going to spend any more time trying to fix TLA Technologies. He walked towards his desk, unlocked one of the drawers, and pulled out a piece of paper that'd been waiting there for far too long.
|
Метки: Feature Articles |
CodeSOD: Indentured |
Speaking with developers, Im always surprised to find a surprising percentage are surprised and baffled by the Fluent API. This object-oriented convention is based on the Builder Pattern, and involves call chaining to construct a configured object. So, for example, if you needed to configure a SystemHandler object to have a series of LinkHandler objects, you might have something like this:
Handlers = SystemHandler.builder()
.AddLinkHandler(…)
.AddLinkHandler(…)
.AddLinkHandler(…)
.SetConfiguration(…)
.ConfigureOtherParam(…)
.build();
Each method of the builder object modifies the builder and then returns the modified instance, giving Object-Oriented programs a sort of composability. Compared to passing a thousand parameters to the constructor, it also offers a nice bit of readability.
I bring this up, because Mireilles co-worker is likely the sort of person that would be confused by a Fluent API.
public HandlerChain()
{
Handlers =
new SystemHandler(
new Link1Handler(
new Link2Handler(
new Link3Handler(
new Link4Handler(
new Link5Handler(
new Link6Handler(
new Link7Handler(
new Link8Handler(
new Link9Handler(
new Link10Handler(
new Link11Handler(
new Link12Handler(
new Link13Handler(
new Link14Handler(
new Link15Handler(
new Link16Handler(
new Link17Handler(
new Link18Handler(
new Link19Handler(
new Link20Handler(
new Link21Handlerx(
new Link22Handler(
new Link23Handler(
new Link24Handler(
new Link25Handler(
new DefaultHandler(
new Link26Handler(
new link27Handler(
new Link28Handler(
new Link29Handler(
new Link30Handler(
new Link31Handler(
new Link32Handler(
new Link33Handler(
new Link34Handler(
new Link35Handler(
new Link36Handler(
new Link37Handler (
new Link38Handler(
new Link39Handler(
new Link40Handler(
new Link41Handler(
new Link42Handler(
new Link43Handler(
new Link44Handler(null))))))))))))))))))))))))))))))))))))))))))))));
}
Much cleaner and simpler than my original solution. I stand corrected.
[Advertisement] Release!
is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!
|
Метки: CodeSOD |
Classic WTF: Illicit Process Improvement |
Christian R. was in trouble. Despite his experience across hardware and software, desktops and server clusters, thumb drives and SANs, he hadn't found any freelance work in weeks. It was clear that he'd have to figure something out to pay the bills.
In August, Christian applied at Drab's PCs, a large retail chain focused on computer hardware and software. He'd shopped there for years and had an impressive level of knowledge about their products, so he accepted a position in Technical Sales.
After a few months of working at Drab's PCs, Christian grew tired of one of his tasks — manually keying in orders from the online store. The online store worked by emailing orders to individual branches across the country, which were then printed, given to the branch manager, and then distributed to employees. The employees would then key in each order, line by line, item by item.
Entering orders was more time consuming than it had to be. Since each system had a barcode scanner, it didn't make sense to totally retype UPC codes and serial numbers. Having worked with PHP's image manipulation functions, Christian decided to take on a hobby project — a quicker interface to enter online orders.
He bought himself a barcode scanner and got to work. After a few evenings of coding, he had a working prototype. It would take in an order email, convert UPCs, serial numbers, quantities, and prices to barcodes. The barcodes were aligned on the page such that the barcode scanner could simply be dragged from the top of the page to the bottom, generating a complete, accurate order.
For a few weeks, Christian would use his application rather than typing orders in manually. Even after verifying that the order was complete and correct, he would still finish well before his coworkers. Gradually, word spread about his application, so he shared it with a few friends at his store.
His circle of users were happy, but when word of Christian's application bubbled up to management, Christian was called into his boss's office. "Let's have a competition," his boss, Warren, began. "I'll have Bill enter an order against your program," he said. "He's the fastest at this, and I want to be sure that we're doing this the most efficient way we can."
Christian and Bill started, and before Bill had fully keyed in the first item, Christian had processed an entire order. Happy with the results, Warren thanked Christian for his work and told him he'd talk to the branch manager about it.
A few days later, Christian's branch manager, Larry, called him into his office. "I saw the order entry program you made," he began. "You're lucky I haven't fired you."
"I... I'm sorry?" Christian was dumbstruck. "Did it mess up an order or something?"
"No. I just don't appreciate your interfering with the deployment of the new system." The "new system" had been coming soon since the day Christian was hired. Christian had never intended to interfere with plans made by corporate, he just wanted to make his life a little easier. He tried to defend himself, but Larry was unconvinced. His application had put him at odds with corporate.
A year passed, the following winter came, and Christian was due for a performance review. After his boss, Warren, and the branch manager, Larry, had finished Christian's performance review sheet, he was called into Larry's office to review. Christian took a deep breath before walking in.
Before Christian could even sit down, his review began. "You're not smiling enough," Larry began.
"You have the best feedback out of all of our staff, though." Warren was happy. "Customers love yo-"
"But they think you're cold and unfriendly. Why don't you smile more?" Larry interrupted.
"Really, though, your technical knowledge is great," Warren said. "And I've had more customers thank me for your hel-"
"I see here that you were almost ten minutes late on June 8th. You missed a team-building exercise!" Larry scowled and leaned forward. "Why don't you tell me about that day."
"Well, there was a car accident which caused a delay," Christian began, "and I don't really have a good direct route in anyway. Still, I was still at my desk, ready to serve customers when the doors opened, so I don't think it was that big a deal..."
"Yes, yes. Well, let's cut to the chase. We've decided you can keep your job," said Larry with an insulting smile. "Sound good?"
Christian was speechless. He looked to Warren for help, but Warren was timidly staring at the ground. He stumbled while mentioning a few improvements he'd made to the store, some thankful customers he'd served, but those comments were barely acknowledged.
"I'm not being considered for a raise then?" Christian finally asked.
"No, but you can keep your job," Larry reiterated.
"Will I be eligible for a raise next year?"
"No."
"The year after that?"
"Y... maybe."
"So, to get this straight, I have to work three years on my best behavior, be essentially the most incredible employee the store has ever had, and then, maybe I'll get a raise?"
"Well, if you put it like that..."
"Understood." Christian sighed and went back out to his desk. Two months later, he found a new position and has been there for several years now. He found out that corners were being cut across the board not only because the store didn't have a great year, but a new, expensive corporate office had been built that year.
And that new system is still coming soon, but it's seriously right around the corner.
http://thedailywtf.com/articles/classic-wtf-illicit-process-improvement0
|
Метки: Feature Articles |