Reader Appreciation Day |
In lieu of a traditional WTF, I want to use todays post to talk about the real WTF, or at least the source of all the WTFs we get to write about: our readers.
Weve got great writers here, and every time I hit publish on one of their articles, Im happy with whats about to go out to the world. They do a great job building funny, entertaining narratives that highlight some of the unique challenges of working in IT. We get great support from our sponsors, who fund the site and keep it running.
None of that would matter, though, without the raw materials: the submissions that we get from our readers. This site wouldnt be possible without you. We love reading all of the submissions we get; even if we cant turn them into a story, we read them all.
No matter how creative or inventive our writers are, we could never create a character like Paula Bean, or come up with a solution like the ITAPPMONROBOT. We love our readers, and were happy with the years of support and each of submissions that we get.
And we want more of your submissions. Theres a lovely little Submit Your WTF button on the side of the page. If youve been in this industry for more than five minutes, I know youve got a story that deserves to be told, and we here at TheDailyWTF want to hear about it. Submit early, submit often. You can submit completely anonymously, and were always happy to change details to help keep your anonymity (there are a few stories in our archives that I submitted anonymously, not that youd ever know). Or, slap your name on there and gain whatever degree of Internet fame- or infamy- youre looking for.
So, thank you. Without our readers, without their submissions, we wouldnt have much to do here. And dont worry, we still have a WTF for you today. This comes from Molly, whos inherited some filtering code.
week_ago = datetime.datetime.now() - datetime.timedelta(weeks=2)
Once upon a time, the week_ago variable held, well… one week. Now, it holds two, but changing the name of the variable was too much trouble, so there it sits.
|
Метки: Feature Articles |
CodeSOD: Take a Moment to Reflect |
Modern object-oriented languages tend to support the concept of reflection. Reflection lets you inspect an object and find out its methods and invoke them dynamically. If youre building extensible frameworks where youre handling objects where their type might not be known until runtime, it can be very useful. On the other hand, if youre using a strongly typed language and find yourself in this situation frequently… youre probably doing something wrong.
For that reason, when Adam encounters calls to method.invoke() in Java programs, he gets suspicious. So, when he saw this:
Method method = generator.getClass().getMethod(methodName, null);
customerListList = (ArrayList) method.invoke(generator, null);
Adam knew he had to investigate. First, he looked up how the methodName variable was being populated. A few lines up, he saw:
String methodName = "getCustomerListFor"+ alphaBet.trim().toUpperCase();
And then, he checked the generator class:
public ArrayList getCustomerListForA() {...}
public ArrayList getCustomerListForB() {...}
public ArrayList getCustomerListForC() {...}
public ArrayList getCustomerListForD() {...}
There were twenty six copy-pasted versions of the getCustomerList method, where the only difference was that each had a hard-coded string which defined how to filter the data set.
When Adam asked the developer why they didnt simply use a parameter, the developer replied. I didnt want to have to write a switch statement.
[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 |
Super Lag |
SuperFast Performance Monitoring Systems was an ordinary, average production monitoring company, promising to keep an eye on web traffic and alert customers if they needed to scale up their cloud hardware to match incoming demand. Their core product was simple, straightforward, and solid, doing what it claimed to do without incident ... but it wasn't sexy. Enter Wile E. Coyote, Supergenius Programmer, hereafter called Will for short.
Will didn't seem to be a bad programmer, at first. He was a little slower than he promised, but his task was a complex one: he was to generate multi-variable graphs of the performance of the apps, something your ordinary front-end programmer wasn't necessarily versed in. With a little help, he got the visualizations running. They were sleek, sexy, and downright spectacular, and they wowed the pants off the Marketing folks.
The feature shipped, Will was given a certificate and a hat to reward him for going above and beyond, and sales went through the roof. Everyone was happy.
Except ...
It didn't start out terrible, not really. Of course, they dogfooded their own software, so they kept a close eye on the performance of the graph feature, but it was above and beyond the specs, so people gradually began ignoring that corner of the monitor.
A month or so later, however, it wasn't spectacular anymore. And another month after that, it was looking sub-optimal. Sluggish, even. Nothing too bad, nothing that would piss off users—quite—but something to be concerned about.
"Not to worry, not to worry. It's probably just the disk I/O. I'll just optimize the caching algorithm a bit, we'll be back in tip-top shape." Will's excuse sounded plausble enough, and he dove right into it. And sure enough, the speed bounced back ... a little.
Two weeks later, the performance gains were gone. There was obviously a problem, and it was only getting worse.
Will didn't look quite as confident this time, but he dove into the project with only a little less gusto than before. He drove out to the datacenter to test network connections, he switched to a more highly optimized image generation library, he added more RAM to the database. Each change added just a bit more performance ... which was lost again the next week, or the week after that.
Will wasn't getting any shiny certificates now. He was getting phone calls from department heads and emergency strategy meetings. He took to hiding in the breakroom with his laptop so people couldn't find him to ask for status updates. He lost weight. His hair went frequently unbrushed. All he did now was seek out this performance issue as the meter crept further and further into the "red zone". There was no getting around it: the feature was slow.
Marketing started drafting up new sexy features to sell product, and gave them to someone other than Will. He was a pariah, accursed, unable to escape the burden of his past.
Still, he perservered. It was SQL, he argued. The overhead from relational tables was eating up their performance, they needed to move to Mongo yesterday.
Nobody was having it. Their other report visualization tools were working fine on SQL Server. What made his fancy graphic so different?
Will became a shadow of his former self, always sulking in the corner during status meetings while mumbling about Cassandra. Finally, he cracked, and left the company for greener pastures. Nobody threw him a going-away party.
A couple weeks after his departure, a coworker named Brad decided to take a look into the code himself. He was working on Marketing's newest idea, and wanted to learn from the "supergenius" who'd built the previous toy.
There was a ton of filtering logic in the code. Concerned, Brad took a look at the DAO's query to get the user's information, the very first query in the series of operations that led from historic data to dynamic image:
SELECT * FROM Users
[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 |
Error'd: Quantification of Service |
"So, do I enter a number 0 to 65,535 or -32,768 to 32,767? What if my experience wasn't an integer? This is a really technical question for applying at a restaurant," writes Brennan.
"Typed a short message, and this lovely, informative error message popped up," writes Mike A., "As a bonus, if I click Ok, another one shows. Wait for 15 seconds, Skype crashes."
Aankhen wrote, "Vulture is clearly a very experienced when issues."
"Well, VLC, you should have said something! No need to get snarky after the fact," Kevin S. wrote.
"I purchased some from Ryanair, so I can get flight essentials for lb8 at a savings of -lb8 since it was not defined before. Or something. Footer," Vladimir M. writes.
Brian H. wrote, "Spotted at my local single level supermarket. Did they re-purpose an elevator monitoring station as an ATM?"
"The info kiosk at the Copenhagen City Hall is educating visitors about certificate verification (and allow them to browse the file system through the 'Install Certificate' button)," writes Emil M.
|
Метки: Error'd |
CodeSOD: Exit Thread |
Objects left in the garage or the attic tend to multiply. If you dont clean them regularly, you find mysterious and inexplicable things have bred like rabbits. Why is there a bag of marbles in this box, and when did I ever buy an ugly Christmas sweater?
Without regular refactoring, the same thing can happen to your code-base. Michal is finally taking a look at a bit of code that hasnt been touched since 2001. The original developer has left the company, theres no documentation, and the SVN history has long since been discarded.
This leaves Michal with many questions. For example- why did the original developer pepper the code with dozens of calls to System.exit(0)? While thats one way to end a Java program, its not the sort of thing you tend to scatter through the code-base like rice at a wedding. Even worse, though, the calls looked like this:
if(stopRequested){
Thread terminationThread = new Thread(new Runnable() {
@Override
public void run() {
System.exit(0);
}
});
terminationThread.start();
}
No one knows why this runs in a separate thread. It certainly doesnt need to- a call to System.exit terminates the JVM, along with all the threads in it.
|
Метки: CodeSOD |
The Inner JSON Effect |
Jake eagerly stepped into his new job, grateful for more experience and new challenges, craving to learn new software stacks and see what his new company had to teach him about the world of software.
They told him hed be working on some websites, dealing with JavaScript, Node.js, JSON, and the like. It sounded pretty reasonable for web development, except for the non-technical interviewers comment that it was all built on top of Subversion which he assumed was a simple misunderstanding.
Then he was thrust into a project using the companys custom JSON-based Domain Specific Language, or JDSL. His boss told him to check out a copy of the project hed be assigned to, and spend a week or two getting familiar with it. Just ask anyone for help if you have questions, but you shouldnt have any trouble judging from your experience.
So Jake began an SVN checkout&and long story short it took two days to complete. When he asked about it, his coworker Scott told him, Oh thats normal. Just play Solitaire or something until it finishes.
Two days later he started poking around. He started with a seemingly-innocuous file called customers.json and stared in confusion at its contents:
{
"File" : "Customers.json",
"Class" : "Customers",
"Author" : "redacted@redacted.com",
"Purpose" : "",
"Functions" : [
568,
899,
900,
901,
902,
1877,
2880
]
}
The project was full of such files, along with some apparently-incomplete code files such as this one called customers.js:
Customers.prototype.UpdateBillingInfo = function(info)
{
this.cc = info.cc;
this.type = info.type;
this.name = info.name;
this.expM = info.expM;
this.expY = info.expY;
this.ccv = info.ccv;
/* snip a bunch of similar lines */
this.saveToDatabase();
};
After a couple days of spelunking through the codebase, and not finding even a single code comment, Jake could make no sense of what he was seeing, and finally asked for help. A coworker named Scott was available and sat with him to walk through some things.
Oh, you just dont get it yet, he began. JDSL was written by Tom. Hes a super-genius and wrote JDSL himself. So basically that customers.json is just metadata used to put together the Customers class. He waited for Jake to get it.
He didnt. So&how do I run it? he asked.
Scott laughed. You wouldnt want to just run it. It takes a couple days for a new deployment to finish starting up. JDSL can be a little slow, but its really powerful. Really powerful. Like I said, Tom is a genius.
Jake still wasnt getting it. So walk me through this metadata file. What does it do?
Scott laughed again. This is the genius part. See here where it says Class?
Uh-huh.
Well thats the class name. Now, see down here where it says functions?
Yeah.
Well those are subversions link to all the functions that make up the class!
&I still dont understand& Jake responded. Inwardly he thought he started to understand, but prayed he was wrong.
So you have customers.json and customers.js. The JSON file is the metadata and the JS file has all the code. So the list of functions in the JSON file tells JDSL to look up those revisions of the JS file to find what functions are available. In this case the actual code is in revisions 568, 899, 900, 901, and so on.
Jake blinked slowly, hoping he was just being hazed. Um&
Each revision of customers.js has one function, so to add functions all you have to do is check in your new code and update the JSON metadata file with the new revisions!
Jakes confusion turned into incredulity.
Whenever something makes a function call on a Customer object, JDSL uses the list of function revisions to check out all the actual functions until it finds a match! Understand?
&I think so&
Like I said, Tom is a genius! This lets you track every function that has ever existed. You can add new functions by overwriting the JS file and adding a new revision to the JSON, and you can remove a function just by removing its revision number from the function list. And its still there in history, inactive but never lost! Scott stood. Let me know if you have any more questions, he said as he left Jakes desk.
Armed with Scotts insight into JDSL, Jake slowly began to understand the system, checking out multiple revisions of each file so he could piece them together and see what was going on at runtime. He soon realized it was merely a web portal to allow customers to update their personal information, but thanks to the complexity of JDSL it took days to do coding work that should only take minutes.
As he went through the code, still familiarizing himself with it, he started checking in code comments to help him and his coworkers map together the convoluted mess, and even fixed a few obvious bugs he found just by reading the code. He did this one class at a time, and at the end of the week he updated and checked in all the JSON metadata files to use the new function revisions.
Monday morning, he showed up to a virtual firestorm. Everyone was in a panic. Something broke with JSDL and our customer database got scrambled! Scott quickly explained as he passed Jake in the hallway.
You! a voice boomed.
Jake stopped and turned to face a tall, lanky, pale blond man who was obviously angry. Are you Jake? The new guy?
Yes, he answered carefully.
Im Tom. You broke JDSL!
Uh, what? Jake had only been looking at the customer portal. How could he have caused any problems?
You broke JDSL! he screamed. Im reporting you to the bosses and having you fired! And Tom turned and stormed off, leaving Jake standing confused.
Shortly afterwards, Jake was summoned to a small conference room. Tom, an employee from HR, and a couple Vice Presidents waited for him. Tom looked like he was stewing and could boil over any minute.
Tell us what you did to JDSL, one of the VPs asked.
I dont think I did anything, Jake answered. Ive only been here two weeks, trying to learn JDSL and how the customer portal works. I dont even know how to deploy it!
You made a few commits to Subversion! Tom shouted.
Well, yes. I added a few code comments, trying to
You cant use comments in JDSL! Tom shouted. THATS WHAT BROKE IT!!
Jake stayed silent, trying to process how code comments could wipe out a customer database. Tom continued after a pause. I havent added comment support to JDSL, so the runtime executes comments like normal code! You must have had database updates in some comments?!
Well, yeah, I put a couple short syntax examples in a comment to clarify
Tom burst to his feet. I knew it! You BROKE IT! He turned to face the VPs. I cant deal with coders who dont understand the system! You will either fire Jake&or I quit! And he stormed out of the room.
The VPs turned to the HR representative and talked as if Jake wasnt even in the room. I think our course of action is pretty clear. Toms a programming virtuouso and our best resource, and Jake did delete the database. We have to fire Jake.
And so Jake moved on to greener pastures. Much greener pastures. Ones where production systems didnt do dozens of SVN file checkouts for each function call at runtime. Ones where production systems didnt automatically use the latest trunk. And ones that didnt come to a complete standstill because a newbie checked in a code comment.
|
Метки: Feature Articles |
CodeSOD: It's Log, Log, Log |
Reader Bernie submits for our approval this wonderful C# log base 2 implementation. He says: “We can distinguish two halves in that code. It looks like it was originally written for an unsigned 16-bit int, and later on extended for signed 32-bit integers.”
This code reminds me of the change-sorting machine I have in my closet, which sorts change based on weight. That thing has no error handling if you try to sort, say, a huge boulder through it; it'd just fall apart. At least here, we have the assurance that the universe's biggest numbers all have a log base 2 of 31.
public static int Log2(int x)
{
if (x <= 65536)
{
if (x <= 256)
{
if (x <= 16)
{
if (x <= 4)
{
if (x <= 2)
{
if (x <= 1)
return 0;
return 1;
}
return 2;
}
if (x <= 8)
return 3;
return 4;
}
if (x <= 64)
{
if (x <= 32)
return 5;
return 6;
}
if (x <= 128)
return 7;
return 8;
}
if (x <= 4096)
{
if (x <= 1024)
{
if (x <= 512)
return 9;
return 10;
}
if (x <= 2048)
return 11;
return 12;
}
if (x <= 16384)
{
if (x <= 8192)
return 13;
return 14;
}
if (x <= 32768)
return 15;
return 16;
}
if (x <= 16777216)
{
if (x <= 1048576)
{
if (x <= 262144)
{
if (x <= 131072)
return 17;
return 18;
}
if (x <= 524288)
return 19;
return 20;
}
if (x <= 4194304)
{
if (x <= 2097152)
return 21;
return 22;
}
if (x <= 8388608)
return 23;
return 24;
}
if (x <= 268435456)
{
if (x <= 67108864)
{
if (x <= 33554432)
return 25;
return 26;
}
if (x <= 134217728)
return 27;
return 28;
}
if (x <= 1073741824)
{
if (x <= 536870912)
return 29;
return 30;
}
return 31;
}
[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 |
The Missing Source |
The year was 2006. Nelly Furtado was getting promiscuous, the Winter Olympics were in Italy, and Domino was an application developer for Rocketware, a company that produced multimedia applications. Back then, applications were still commonly distributed on CD-ROMs: small round disks of plastic that contained grooves that could be read by a specialized laser and interpreted as data. This was handy in a period when only 30% of Americans had broadband Internet.
Rocketware had done some software for a government agency, which of course had been bundled with a support contract for updates, paid in advance. Maintenance for this application fell into Domino's lap, and he was soon asked to do a small update.
Unfortunately, the software had been written by an infamous pair of numbskulls. Jessie and James had both been fired over a year previously for sheer incompetence, but they'd worked on this project together, meaning it was a ball of spaghetti held together by twine. Or at least, it probably was. Problem number one on Domino's plate: finding the source code.
The application wasn't in any of the source code repositories; Jessie and James hadn't "believed in" version control. They would've been forced to use it during their tenure, but James had also done network support, and therefore had had access to the bare repositories when he'd been fired. Domino suspected that, in retaliation for being forced to use source control, James had deleted his projects before being escorted from the building.
Thankfully, the pair had lacked access to the backup facility. Domino took the latest backup, added a new database, and implemented the fix: 5 hours of work, after about 3 hours of combing through backups to find the right version. Done and dusted. Right?
Wrong. The agency quickly complained of features missing, of old bugs re-introduced. Clearly that wasn't the version that'd been burned onto the CD and mailed to them, but the source code for that version was nowhere to be found.
Domino's boss, Giovanni, asked him to just go ahead and re-implement the missing features, see if he couldn't get things working to the agency's liking.
Now, this application wasn't any old application. The source code consisted of about 10k lines of Lingo code, entirely undocumented of course, and another 10k lines of ActionScript 1.0. There were 20 files, hundreds of frames and clips, a handful of data conversion tools written in Pascal, an Access database, a V12 database, and even some Excel spreadsheets. It was the Wild West: a little of everything, held together with duct tape and prayers. Still, Giovanni insisted that Domino clean up this mess as best he could:
deXML = deXML & " "
He couldn't do it. Three days into the project, he was back in Giovanni's office, ready to throw in the towel. "Nobody can work with this mess," he insisted. "Only James would know why he did the things he did, or where to even start."
"So get James to come in and explain himself," Giovanni replied.
Domino was incredulous, but somehow, Giovanni got the guy on the phone and convinced him to come in and sit with Domino.
The first question Domino had was easy: "Where's the latest source code?"
"Dunno." James seemed more interested in Domino's bobblehead collection than the code in front of them.
"Was it in source control? Look, I won't tell, but if you deleted it ...?"
"I didn't. Must've been a glitch or something." The George Bush bobblehead jiggled under James' finger.
"Okay, well, what about this?" Domino tapped at his monitor. "What's up with this code? Why is it like this?"
//find next value that can be divided by "value"
value +=1
while(value % steps <>0){
value +=1
}
"If it doesn't work, you just have to debug it," replied James, lifting up the Barry Bonds bobblehead next.
After an hour of pulling metaphorical teeth, Domino gave up, sarcastically thanked James for his time, and had him escorted out again. There was no help to be had from this quarter. He'd have to go it solo.
// check if value is negative
value=value.toString();
if(value.substr(0,1)=="-"){
//Value is negative
...
}
150 hours later, Domino was on the verge of quitting himself. Three builds in, and nothing was working right. If he fixed one issue, ten more things would break. The work was spiraling out of control, bugs being introduced exponentially.
Finally, finally, Giovanni agreed to let Domino just rewrite the entire application ... after he finihed his other projects.
200 man-hours later, they had something they could deliver, this time in source control and infinitely more maintainable.
Of course, that's when the agency really started complaining about all the "features" Domino had "removed" when he fixed obvious bugs. But that's a tale for another website.
[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 |
Error'd: Wait...Press What?! |
"Um, I'm not sure the programmers and the engineers were working together on this one," wrote Rob.
"Apparently, not having any problems is a problem itself," writes Chris F.
Max wrote, "It's ok AT&T, I test in prod sometimes too."
"To get online in Iceland you need to seriously man up...or stop translating sites with Google," Ivan writes.
Daniel wrote, "To avoid any delays to your journey, Red Funnel has redefined the term On Time."
"Feedback goes right into the bit bucket? I guess I shouldn't be too surprised," writes Carl.
Tom writes, "Whilst trying (and failing) to upgrade my phone for the second time in as many days, I decided to give EE's live chat a go. They really want to know what my account type is."
|
Метки: Error'd |
The Keys to Cloud Storage |
When you want to store data in Amazons S3 cloud-based storage, you have to assign that data a key. In practice, this looks and behaves like a filename, but the underlying APIs treat it like a key/value store, where the value can be a large data object.
S3 is flexible and cost-effective enough that Melindas company decided to use it for logging HTTP requests to their application. These requests often contained large data files for upload, and those files might need to be referenced in the future, so a persistent and reliable storage was important.
Each of these incoming HTTP requests had a request_id field, so a naive implementation of logging would be to write the body of the request to an S3 key following a pattern like requests/c418b58b-164d-4e1f-970b-ed00dea855b6. For a number of reasons, however, clients might send multiple requests using the same request_id. Since a logging system that overwrites old logs would be pretty terrible, they decided that each log file also needed an ID, so they could write them out with keys like requests/c418b58b-164d-4e1f-970b-ed00dea855b6/${x}, where ${x} was the ID of the log file.
The developer responsible for implementing this decided that ${x} should be an auto-incremented number. This presented a problem, though: how on earth could they keep that index in sync across all of their API nodes?
function findFreeKey(bucket, key, append, startNum, callback) {
var testPath = key;
if (typeof startNum != 'number' || startNum < 0)
startNum = 0;
else if (startNum > 0)
testPath += (append ? append : '') + startNum;
get(bucket, testPath, function(err) {
if (err) {
if (err == 404)
callback(null, testPath);
else
callback(err);
}
else
findFreeKey(bucket, key, append, startNum + 1, callback);
});
}
function get(bucket, key, callback) {
var client = getClient(bucket);
var req = client.get(key);
req.on('response', function(res) {
if (res.statusCode >= 200 && res.statusCode < 300) {
res.setEncoding(CHARSET);
var str = '';
res.on('data', function(chunk) {
str += chunk;
});
res.on('end', function() {
callback(null, res, str);
});
}
else
callback(res.statusCode, res, null);
});
req.on('error', function(err) {
callback(err);
});
req.end();
}
The core idea of this code is that instead of trying to keep the autoincremented index in sync, instead just start at zero, and fetch requests/c418b58b-164d-4e1f-970b-ed00dea855b6/0. If you get a 404, great! Use that key to write the file. If theres actually data at that key, try fetching requests/c418b58b-164d-4e1f-970b-ed00dea855b6/1. And so on.
This, of course, does nothing to defend against race conditions. There was no requirement that ${x} be sequential, there was never a need to order these log files that way, so the developer could have used a UUID for each log file, and there would have been no problems. Thats not the actual problem with this code, though.
Note the line var req = client.get(key). This uses the Amazon S3 API to get the object located at that key- the entire object, including the data. These requests could contain large data files, and the entire body would be downloaded. It should be noted that there is a perfectly good listObjects function which can simply return a list of used keys with a single request.
So, each time a request_id was reused, the logging of that request took longer and longer, as every single previous request with that request_id needed to be re-downloaded in its entirety before the system could finish logging. It should also be noted that S3 does charge you based on both the content stored there, and how much bandwidth you use.
Melinda noticed this atrocity, and thought her trendy, self-organizing, and democratic team might want to tackle it. Each week, everyone is allowed to nominate a piece of ugly technical debt, and then the team votes for what they want to tackle first. Over the past two years, theyve replaced their terrible test-fixtures with merely bad ones, theyve swapped out the ORM tool that no one liked with an ORM tool that only the technical lead likes, and theyve cycled through every JavaScript build system out there before deciding that theyre better off with an in-house solution.
In those two years, no matter how many times Melinda nominated this particular block of code, its remained their lowest-priority piece of technical debt.
|
Метки: Feature Articles |
Not A Fan |
Larry worked in the IT department of a medium-sized financial company. Bright and early on what should have been a promising day, the phone rang. Larry cursed the caller ID for informing him that Graham was on the line. The resident old man of the office and bane of IT, he frequently disregarded sound advice and policy to satisfy his own whims.
Powering past the foreboding that'd settled over him, Larry picked up the phone and forced out a greeting through teeth that were already set on edge. "Good morning, IT services. How may I help you?"
"Yeah. I need help with my computer." Graham skipped decorum to get to the heart of the matter. "It won't turn on."
The computers the accountants used were old, but still in good shape. Larry hoped he'd be able to deal with this over the phone. "OK. Let's walk through some basic troubleshooting—"
"No!" Graham cut him off. "Someone's gotta come over here! I can't afford to be dead in the water with month-end coming up!"
Larry stifled a groan. "Let me log the ticket in our system, and I'll be right over."
He hung up, sparing himself another useless rant, and filed the ticket. That done, he left his cube to head for the accountants' corner. The heat from their ancient boxes ratcheted the temperature several degrees higher. Half a dozen whirring fans worked overtime, but only pushed hot air around in a futile exercise.
"Where the hell were you?" Graham reclined in his swivel-chair, greeting Larry with a scowl. "It doesn't take that long to walk over here."
Larry tugged at his collar, ignoring the cheerful welcome. "Let's go through some basic troubleshooting, OK? I'm sure you already did a lot of this before you called—" Yeah, right, he thought to himself "—but I just wanna be thorough here. First, let's make sure it's plugged in."
Graham didn't budge an inch in his chair, his expression unimpressed.
Larry verified the computer was plugged in. The monitor powered on obediently, but the box remained dormant. Switching outlets didn't help.
"When did this happen?" Larry asked next. "Did it just shut down while you were in the middle of something, or did you shut it off yesterday and can't start it up now?"
"It was fine yesterday," Graham replied. "It won't start up today."
Larry dug into more specific details, none of which helped with the matter at hand. "My guess is that it's some kind of hardware problem," he concluded with a sigh. "I'll probably have to take your machine to look into it further."
Graham bolted upright in his chair. "Unacceptable! I need this fixed now!"
In his peripherals, Larry noticed that Graham had taken to twirling something through his fingers. He glanced over for a better look, then gaped. Was that ... a screwdriver?
Larry's viscera clenched up. Dreading the answer, he asked, "What'd you need that screwdriver for?"
Graham glanced at the tool in his hand, then shrugged. "The sound the computer was making was bothering me, so I took out the source."
"Oh, for ..." Larry stifled himself, then grabbed the screwdriver. Upon opening the box, he confirmed the fan was missing; a quick search determined its new home to be the trash can in the corner of Graham's cube. In the process of the fanectomy, Graham had also managed to unplug several wires and destroy the motherboard.
Aware that it probably wouldn't stick, Larry nonetheless delivered a remarkably polite, profanity-free explanation about the risks of opening computers, and why one should never remove fans. Before returning to his own desk, he asked all of Graham's cube-neighbors to kindly warn him if they ever noticed a tool in their coworker's hands again.
|
Метки: Feature Articles |
CodeSOD: OhgodnoSQL |
How about those NoSQL databases, huh? Theres nothing more trendy than a NoSQL database, and while they lack many of the features that make a traditional RDBMS desirable (like, um… guaranteeing writes?) , they compensate by being more scalable and easier to integrate into an application.
Chuck Ds company made a big deal out of migrating their data to a more modern, JSON-based solution. Chuck wasnt involved in that project, but after the result went live, he got roped in to diagnose a problem: the migration of data from the old to the new database created duplicate records. Many duplicates. So he took a look at the migration script, and found piles of code that looked like this:
UPDATE DataItemSet SET Content = '{"id":116,"type":"Plan for Today", "title":"Initech Retirement Fund", "learnItemLink":"","content":"Re-balance fund portfolio."}' WHERE Name = 'OPERATION' and Content like '{"id":116,%'
If reading that line doesnt cause you to break out into hives, take a closer look at the schema.
| Id | Content | Unread | Type | Name |
|---|---|---|---|---|
| 79 | {id:9,title:Initech Facilities Revision,type:CR05”,img:images/initechfac,content:{"id:"55, "title":"Billing Code"… } | 0 | Global_Customer | CUSTOMERRESOURCE |
| 102 | {id:94,title:Initech Facilities Construction,type:CR05”,img:images/initechfac,content:{"id:"55, "title":"Billing Code"… } | 0 | Global_Customer | CUSTOMERRESOURCE |
The Content column holds a string of text, and that string of text is expected to be JSON, and they often need to filter by the content of the column, which means they have lots of queries with WHERE clauses like: WHERE Content LIKE '%"title":"Initech"%', which rank as one of the slowest possible queries you can run in SQL. The ID field in the Content column has no relationship to the autonumbered ID field that actually is on the database table. The name column sometimes contains IDs, many of the fields in the JSON content (like the img and learnItemLink fields) are actually foreign key references to other tables in the database. Theres a type column on the record, which seems to control scope, but shouldnt be confused with the type field on the JSON document, which may or may not mean anything.
After many weeks of combing through the migration scripts, it turned out not to be a problem with the scripts at all. One of their customers started a process of simplifying their billing codes, which meant billing codes were constantly changing. Instead of only changing the codes that were… well, actually being changed, the web app which provided that interface created new records for every billing code.
|
Метки: CodeSOD |
Optimizing the Backup |
Leslie, head of IT at BlueBox, knew there was trouble when one of her underlings called her at 3AM. The shared servers down, she said. Disk failure. Accounting cant issue invoices, design cant get to its prototypes, and the CEO just lost his PowerPoint for next weeks conference speech.
BlueBox, like many companies, kept many important documents on a shared server. It also held personal directories for every employee, and many (like the CEO) used it to store personal files. That data, totaling 100 GB, was backed up to a remote server every 24 hours. Okay, swap out the disk and restore it.
I cant find the backup, the underling replied.
Leslie groaned, then rolled out of bed, booted her laptop, and RDPed into the remote server. The blood drained from her face: while there were backups of every other server that BlueBox need to operate, the shared servers was missing.
Bracing for the headache she would face at the office, Leslie made a call to a data recovery specialist. Later that morning, while the shared docs were being salvaged from the failed disk, Leslie prepped for the postmortem.
The remote server held 8 1TB HDDs in RAID 1+0, formatted with ZFS. With that robust configuration, it probably wasnt be a hardware issue that caused the backup to disappear. It clearly had to be something wrong with the file system.
Naturally, a ZFS consultant was hired.
I just dont see how its possible for a 100GB file to disappear. The consultant addressed Leslie and the rest of IT sat in the conference room. He gestured the air quotes. ZFS uses copy-on-write transactions. While a file is getting rewritten, the old file data remains on-disk until the operation is completed. If there were a hardware failure during that time, the file-system would fall back to the old file data. It wouldnt disappear.
Were paying you a lot of money, Leslie said. Why dont you see for yourself.
A laptop was brought with an open connection to the server. The consultant grimaced as he opened the DOS command prompt, muttering something about Bash, then ran several commands to check the integrity of the file-system. As he worked, his mouth went agape, cheeks twitching. No, its not possible& This is a fresh file. Are you sure the file wasnt, well & deleted?
Leslie sighed. Thank you for your time. Security will show you out.
After spending thousands on a dead-end, Leslie decided to start with the basics, interviewing every member of IT about the day in question. After grilling several employees on her team, she called in Heather, who oversaw their backup solution.
Theres a scheduled task to perform the backup on the shared server, Heather began. I have it timed for 3AM.
Thats close to when the backup failed. Does the scheduled task run a batch script?
Yeah. Heather opened the script on her laptop and showed her.
Leslies stomach dropped. Line 12 & you delete the old backup before creating a new one?
I always delete the last backup before I do the next backup, Heather said. It helps save space and keeps the hardware optimized. All the other servers are set up that way.
It was all Leslie could do to keep herself from firing Heather on the spot.
Leslie watched as Heather rewrote every backup batch script line-by-line. 7 previous backups would be kept, with new ones written every 24 hours, and old backups would be deleted only after the most recent backup was written. The consultant was still paid, despite offering little help. His invoice led to upper management reconsidering ZFS for their remote backup solution.
A few days afterwards, Leslie got an unexpected visitor. The CEO of BlueBox, effuse with praise, thanked her for finding his PowerPoint before the conference began. He offered a substantial bonus.
Leslie handed the CEO a business card. It had the contact info for the data recovery specialist who salvaged the PowerPoint file from the failed disk. You ought to give him one, too, Leslie said, since he saved your presentation.
|
Метки: Feature Articles |
Error'd: A Case of Mistaken Identity |
"Wow, even Google doesn't understand the current mess that is British politics," writes Mike R.
"Variables. Gotta catch 'em all!" writes JR
Travis wrote, "I tried to sign in using my username and password, but Facebook wants me to sign in with the body of an error message."
Mark B. writes, "I seem to have found a very popular page on this website."
"I guess if I were to take this job, I'd be praying fervently every month that it was renewed," wrote John O.
James writes, "Gold price apparently spikes 9000% on Brexit worries."
"I was trying to report an issue with an online defensive driving course, but now I have an issue with their bug report form!" wrote Ben B.
Alex D. wrote, "Yes, Microsoft, you're trying your best. You'll make it someday."
[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.
|
Метки: Error'd |
The Not-So-Highly-Paid Consultant |
Consulting. It's as much art as science. You apply for a job to create/change some system, and need to bid an amount that not only covers your time, but leaves a little something extra in your pocket. Of course, we all know that requirements are never absolute, or even well thought out. As such, you need to build some extra cost into your bid to take this into account. Build in too much and you will be overpriced and not get the job. Build in too little and you will be under-priced and get the job at what will inevitably become a loss.
Writing a contract that restricts the work to a specific list of features is nearly impossible because nobody ever thinks through what they want in advance (think about your last outsourced project). Given that, you need to be skilled at letting the client know that you will be nice and implement tiny things that are not in the spec for free, but anything that is outside the contract spec and takes any real time will be at an added cost (the art of saying no: why yes, we can add that feature, but it will take x weeks at a cost of y).
During the start of January 2016, Sean was contracted by a local news organization to modify their news website for them. Their website was built using WordPress. Believing that it was just a simple addition of pages, footers, headers, and theme, he took the job, and agreed upon a deadline of January 31 with a very small fixed fee of $30 (yes, t-h-i-r-t-y dollars for several weeks of work). Sean felt relieved that he was not going to have to build a full-blown news website because he already had another project in his start-up on queue.
My lawn-guy gets more than that for ten minutes of mowing.
Sean was given the credentials to the web host they were using and started to work. Upon opening the website, it took more than 10 seconds for it to fully load. He felt sad but endured the pain because he believed the task was just "easy." In the first two weeks, doing the job felt good. He optimized the WordPress website a bit, added the necessary pages and footers, and added SEO. Everything was fine and Sean was ready to show them the website.
A week later, the client called Sean and completely changed the requirements. They asked him to add a custom look on two of the pages, change the font, and add an interactive news map. That was not in the originally agreed-upon site design! Sean vigorously protested, but the client just said (non-verbatim), "Aww. Sean, you're a very good programmer! You can do it right? It can't be that hard."
When people tell you how easy your job is, the best thing to do is to make them do it for themselves.
Sean was not in a position to increase the cost of the job to cover the extra work, and could not do anything about it at that time. A week passed and he finished the custom look. He even had to pull in the source code from the website to his laptop because the loading was so slow that he could no longer bear it. What was left to be done was the interactive news map.
Now I don't know anything about web design but that sounds like something that's significantly more complicated than you can do for $30, let alone on top of the other work.
The interactive news map they requested was such that when the user clicked on a given province on a map, news for that province would be displayed on the bottom of the map. Sean did not know how he would implement that feature. It was certainly not in the cards given the original fee.
Sean thought that they should receive service that was comparable to the fee they paid. He told to them that the interactive news map couldn't be done because of "technical stuff." They bought the excuse.
What he gave them was a website that looked done but actually had a lot of visual bugs. What they asked him to do was to modify their website by just adding a couple of pages, a theme, and add the necessary information, and that's what he gave them.
Before and during the start of work, Sean learned that he was the second programmer they contracted to develop their website. The first programmer they contracted was a friend of his who was also asked to modify the site and add an interactive news map. He bailed out immediately because of the discrepancy between the pay and the amount of work.
To this day, their news website is still up and running, albeit really slowly. However, it seems that they haven't added their articles yet.
It's like when you see job postings where they want an expert with ten years of experience in each of web design, Java, C++, C# and .NET, system administration and as a DBA in each of Sybase, Oracle, DB2 and SQL-Server, and their pay range goes up to $60/hour. And they wonder why they can't fill the job.
[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!
http://thedailywtf.com/articles/the-not-so-highly-paid-consultant
|
Метки: Feature Articles |
CodeSOD: Lunatic Schema-tic |
One day, Jamess boss asked him to take a look at a ticket regarding the Cash Card Lookup package, which had an issue. James had no idea what that was, so he asked.
I dont know, his boss replied. I just know the call center uses it. Youll need to talk to them.
James picked up the ticket and called the customer.
Oh, yes, the customer replied. We need this to get customer details based on their cash-card number. I think Timmy made it.
Timmy? Whos Timmy?
Hes our tech guy. He sets up our computers, helps us when we have issues, that stuff. Let me transfer you to him…
Timmy had indeed made it, because he did a little programming. There was also the issue of internal billing- like many large companies, each business unit needed to charge other business units for their time. The software development team billed at $95/hr, but Timmy was already on salary to the customer service department.
He had grabbed a spare box, slapped Linux and MySQL on it, then whipped up a simple Perl script that served up a web page for doing the lookup.
Data entry, on the other hand, was a different problem all together. Knowing Remys Law of Requirements Gathering, Timmy gave them an Excel spreadsheet with a VBA macro that could connect to the MySQL database to do bulk uploads of data. "
When James pulled up the code, he saw every horror he expected from Perl and VBA. When he saw the database, it got even worse. The data itself had a number of problems, the first one being that Timmy never set up a test environment, and instead, tested in production. And didnt clean up the test records. Even worse, though, the VBA macro tried to sanitize the inputs, and handle escaping characters like the single quote, but it did it wrong, leading to records like:
| last_name | first_name |
|---|---|
| O | Reilly Kevin |
As you might imagine, the database only had one table, and it was this code that really got Jamess attention.
CREATE TABLE `b2c` (
`masterorder` varchar(16) default NULL,
`ordering_store_number` varchar(10) default NULL,
`order_date` varchar(10) default NULL,
`last_name` varchar(20) default NULL,
`first_name` varchar(10) default NULL,
`middle_initial` varchar(1) default NULL,
`company_name` varchar(32) default NULL,
`address1` varchar(32) default NULL,
`address2` varchar(32) default NULL,
`city` varchar(20) default NULL,
`state_province` varchar(2) default NULL,
`postal_code` varchar(9) default NULL,
`country` varchar(15) default NULL,
`phone` varchar(10) default NULL,
`sequence` varchar(2) default NULL,
`sku` varchar(10) default NULL,
`card_value` varchar(11) default NULL,
`shipping_method` varchar(3) default NULL,
`insert_id` varchar(5) default NULL,
`customer_number` varchar(70) default NULL,
`last_4_cus_number` varchar(70) default NULL,
`card_value2` varchar(70) default NULL,
`prepared_by` varchar(70) default NULL,
`witnessed_by` varchar(70) default NULL,
`card_number` varchar(19) default NULL,
`shipping_date` varchar(10) default NULL,
`invoiced` text,
`ship_method_code` varchar(3) default NULL,
`valuation_date` varchar(10) default NULL,
`comments` text,
`num_of_days_from_ship_to_valuation_date` text,
`ship_date` varchar(20) default NULL,
`activation_date` varchar(20) default NULL,
`id` int(10) unsigned NOT NULL auto_increment,
PRIMARY KEY (`id`)
) ;
Its not just the VARCHARs everywhere. Its things like card_value2 and card_value, which both hold the same data, but have wildly differing lengths. Date fields might be 10 or 20 characters long, the num_of_days_from_ship_to_valuation_date is a text type, but only holds, well… a number, and usually one less than 15. The field invoiced, also text, only holds True or False (or Yes, y, Y, N, ???, NULL).
But the real special absurdity, the real line that made James scratch his head and ask WTF, was this one:
`last_4_cus_number` varchar(70) default NULL
[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 |
A Song of API And Fire |
Emily didn't expect much excitement at her day job. She worked for a health insurance company, so most of her projects were pretty routine enterprise-level things: hooking up the accounting software to the billing software, managing mailing lists, the usual stuff. When she was given a minor role on a large project, she never dreamed it would be any different than the usual fare. She was unprepared for what she received: Project Aegon.
Insurance companies reach out to people a lot: direct mail advertisements, mail to their subscribers, telemarketing phone calls, and the like. Before Project Aegon, each of the contact lists was housed in a different little kingdom. Subscriber information in the North, direct-marketing addresses in the Riverlands, and so on. Project Aegon was meant to unify these all into a single central repository, and that meant conquering several different application datastores and mastering them all in one location, establishing a new primary source of intel in King's Landing.
Emily's part in this large debacle was Dorne, the email provider: think Mailchimp, but more enterprise. Dorne was an important target for the migration, as it controlled most of the company's outgoing email. However, it was a difficult target to attack strategically, as it used guerilla warfare in the form of a terrible API to protect its information. The API used XML, but it wasn't SOAP, preventing Emily from using a simple library to interface with it. It was far from REST as well; there was no rhyme or reason to the endpoint design, as it had grown "organically" over the years.
For a time, Emily thought she was making headway when she discovered the existence of an API for querying the SQL directly. Surely that would be an easier method of obtaining up-to-date subscriber information? Then she saw the example query. She didn't make it any further than the following before bailing:
(
Bound and determined to conquer Dorne, Emily finally found some luck: the batch API. She signed up for a developer key, providing her company email address, and plugged away at the thing until she got it to do what she wanted. The files it generated were massive XML files, but she wrote a shim that received them via SFTP once a day and provided a REST API to query against the data so the rest of the Aegon development team could interface with it. Satisfied, she washed her hands of the seven kingdoms and moved on to Project Braavos.
Years later, while working on Project Ibben, she received a furious email: Dorne's reports were clogging up the system, hogging resources and slowing business functions that shared a server to a halt. Confused as to why she was even being emailed, Emily took a look. Sure enough, the daily process had been run 6,000 times in the past 4 days, with 4,000 more pending in the queue.
A little digging revealed how her name got attached to the project: the current devs were still using her personal API key in the test region. Furthermore, they'd been having a problem, so with the test region still hooked up to the production Dorne server, they had bumped up the poll frequency to every 30 seconds to look for a sporadic issue. Emily was forced to manually cancel and delete all 10,000 batch requests to clear the queue. Once finished, she pulled her API key for good measure. It was time to play a little game with the current devs ...
[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: Hanging By a String |
We all know that truth is a flexible thing, that strict binaries of true and false are not enough.
Danas co-worker knew this, and so that co-worker didnt use any pidling boolean values, no enums. They could do one better.
Now, were missing a lot of the code, but the pieces Dana shared with us are enough to get the picture…
public CustomerRecord fetchNextCustomer()
{
//…
String yesNoString = String.valueOf(BusinessDAO.custFlagIsSet());
if(yesNoString.equalsIgnoreCase("true")) yesNoString="Y";
//… and later in this same method …
if (yesNoString.equalsIgnoreCase("Y")) {
//set a flag on the customer
}
//…
}
True, false, Y, N, its all the same thing, yes? But how does this code actually get used?
public Vector getCustomers()
{
//…
String a = String.valueOf(BusinessDAO.custFlagIsSet());
if (a.equalsIgnoreCase("TRUE"))
{
while(true) {
CustomerRecord aCustomer = fetchNextCustomer();
if (null != aCustomer) {
records.add(aCustomer);
}
else {
break;
}
}
} else {
while(true) {
CustomerRecord aCustomer = fetchNextCustomer();
if (null != aCustomer) {
records.add(aCustomer);
}
else {
break;
}
}
}
return records;
}
Thats an excellent use of if statements. Theyre future proofed- if they ever do need to branch on that flag, theyre already done with that.
But what about that custFlagIsSet code? What on Earth is that doing?
public String custFlagIsSet()
{
BusinessConfig domainObject;
try
{
domainObject = getDomainObject;
}
catch (Exception e)
{
logger.error("",e);
}
boolean isFlag = domainObject.custFlagIsSet();
String isFlagString = String.valueOf(isFlag) ;
return isFlagString;
}
Obviously, what were seeing here is a low-level API- that domainObject- being adapted into a more abstract API. Where that low-level API only uses little booleans, our custFlagIsSet object makes sure it only ever exposes strings- a much more flexible and robust datatype. Now, we can see some of the history in this code- before that custFlagIsSet modernized the underlying API, the other methods still needed to use String.valueOf, just in case a boolean accidentially came back.
If you say it carefully, it almost sounds like it makes sense. Almost.
[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: Not in Kansas Anymore |
Eric G. wrote, "It looks like Dinerware, a point of sale system for restaurants, has a similar problem to the Scarecrow in the Wizard of Oz."
"I noticed an 'Eject Thumb Drive' icon in my system tray and, since I didn't have a thumb drive plugged in, I was curious what it was referring to," Russ J. writes.
"It's one thing to see ~Firstname-YP~}, but my first name is IN the email!" wrote Jack.
"I spotted this at a train station in Atlanta. I guess I'll miss out on what the screensaver was," writes Christopher E.
"Walgreens really wants me to reply to this message but also to understand that they won't process or read it. I'm confused," Aaron D. writes.
"I had to double check, but I don't think that Fitbit knows how to do datetime math," writes Pascal.
Matthew J. writes, "I was trying to install some software and the C++ runtime libraries apparently have a problem with the far east."
[Advertisement]
Incrementally adopt DevOps best practices with BuildMaster, ProGet and Otter, creating a robust, secure, scalable, and reliable DevOps toolchain.
|
Метки: Error'd |
Classic WTF: The Circle of Fail |
During Ulrichs days as an undergraduate, he landed a part-time gig at a nuclear power plant. It was an anxious time to be on board at the nuke plant- the late 1990s. The dreaded Y2K loomed over all of their aging systems. One decimal point in the wrong spot at midnight on January 1st, 2000 and… well, nothing good would come of it.
Ulrichs job for the big conversion was more benign though. He needed to update the simple graphics on the monitoring program the nuclear technicians used to keep tabs on the reactor. The very basic macro language generated Commodore 64-quality graphics; it displayed the position of the control rods, neutron flux, water temperatures & pressure, turbine and generator stats, and how many three-eyed fish were caught in the neighboring lake. All of this was then shown on 10 massive CRT monitors mounted around the main control room.
Ulrich worked diligently to get his screens prepared, and the day came for him to roll out the changes. They didnt have a test control room, so the demo needed to be run live. He invited the engineers to gather round the monitors to see his spectacular new designs. When the program booted and Ulrich went to pull up the control rod screen, all 10 monitors went as black as the cloak on a member of the Nights Watch. As the engineers chuckled, Ulrich turned bright red and ran back to the server room to see what happened. It didnt take him long to realize that whatever he screwed up caused the entire mainframe to go down.
Thus began a two-week battle to troubleshoot the mainframe issue, during which time the computer monitoring was completely unavailable. This caused the nuclear technicians to have to leave their air conditioned control room so they could use primitive analog monitoring tools from the 1970s to check on the reactor. Every time Ulrich walked past one of them, he could sense them glaring and thinking Theres that little pipsqueak that killed the monitors!
The tools Ulrich had to debug the program werent merely useless to him. They went beyond uselessness into outright opposition. The custom macro-language had no debugger or real documentation. The mainframe was purchased from the Czech Republic and one would have to know Czech in order to read the error logs. He was able to locate a sticker on top of the server with the phone number of the vendor. He was able to reach one of their experts named Miklos, who asked him for the serial number of the product. Ulrich provided it but the expert retorted That is not full number! This is too short. What you need help with? Toaster? Coffee maker?
Confused, Ulrich replied, Ummm, a mainframe? Had the nuclear plant bought their server from some sort of Czech Coffee, Toaster, and Mainframe Corp.? Miklos said Oh no, Miklos can not help you. I give you number for Blazej. He does help with mainframe. Blazej was an engineer at another nuclear power plant in the Czech Republic, who also had the same mainframe. Ulrich called there, not expecting much.
Through a series of conversations with Blazej, Ulrich was able to finally narrow down the problem to the presence of circles in the screen outputs. Apparently drawing fancy circles was far too much for the monitoring program to handle. He removed all the circles from his screens, uploaded the changes to the mainframe and finally the engineers could see the reactor statistics on the bright, beautiful monitors; without any circles. The result was ugly, boxy, and barely readable, but it worked. Ulrich breathed a sigh of relief then decided to call Czech Coffee, Toaster, and Mainframe Corp. back to notify them of the horrible bug in their program.
Ulrich once again got connected to his buddy Miklos. Hi Miklos, this is Ulrich. I called a while back concerning our power plant monitoring program crashing the mainframe. Youll be glad to know that Blazej and I were able to determine the problem. It all had to do with circles being drawn on the screen. I know it sounds silly, but that causes the whole mainframe to come down.
Miklos seemed to be offended by such an accusation. You do a circle and server come down? You want Miklos to fix this? You stupid? If you know circle cause trouble, then DO NOT USE CIRCLE! Miklos abruptly hung up. Ulrich shrugged it off since his job was done. He eventually finished his undergrad program before Y2K and moved on from the nuclear power plant. When New Years 2000 rolled around, he made sure he was far, far away at a ski resort just in case anyone else slipped a circle into the graphics and the plant melted down as a result.
[Advertisement]
Otter, ProGet, BuildMaster – robust, powerful, scalable, and reliable additions to your existing DevOps toolchain.
http://thedailywtf.com/articles/classic-wtf-the-circle-of-fail
|
Метки: Feature Articles |