Feed View | The Daily WTF

The Daily WTF

Curious Perversions in Information Technology

Subscribe | Retrun to feeds | Users subscribed: 3 | Last Updated: Apr 24 2009, 14:18:49

Sponsor Appreciation, Cabling Confusion, Dividend Bling, & More

24 Apr 2009 13:00:00 | Alex Papadimoulis | Feature Articles | Comments

Please show your support for The Daily WTF by checking out the companies that have been kind enough to sponsor us. And, in doing so, I’m sure you’ll find some pretty cool products and services built by like-minded developers and IT professionals.

 

Microsoft/web   Microsoft/web - We teamed up with Microsoft/web to answer a burning question: with the dizzying array of languages, frameworks, tools, and technologies, what do you think about web development? Take the survey and let us know... there's a free TDWTF sticker in it for you!
Cushy CMS   Cushy CMS - a hosted CMS built from the ground up with ease of use in mind. It's incredibly simple to use: no PHP or ASP required. If you can add CSS classes to HTML tags then you can implement CushyCMS. And best of all, it's free. Spend a few minutes and try it out!
New Relic   New Relic - makers of RPM, a pretty impressive Ruby on Rails application monitoring product that helps you keep your app humming. You get deep, real-time visibility into your app, so you always know what's up. Use it on as many applications and hosts as you like. For as long as you like. And they even offer a free version.
Data Springs   Data Springs - offers a whole bunch of DotNetNuke modules and SharePoint WebParts. In addition to their ever-growing list of complementary products, they can also help with just about any of your other DotNetNuke needs or integrations.
Splunk   Splunk - Search, navigate, alert and report on all your IT data in real time. Logs, configurations, messages, traps and alerts, script, code, metrics and more. If a machine can generate it -- Splunk can eat it.
Discount ASP.NET   Discount ASP.NET - award-winning, developer-ready, and enterprise-class ASP.NET web hosting. They support all versions of ASP.NET (including MVC) and have a whole bunch of cool components you can use. Plans start for just $10/month.
Rails Kit   Rails Kit - developers of the Software as a Service Rails Kit, which includes well-tested modules, controllers, and utilities to handle all the billing/account/merchant legwork for your RoR application.
Tall Components   Tall Components - makers of PDFKit.NET, a 100% managed .NET component for, reading, creating and manipulating PDF documents and PDF forms on the fly. You can also split, append, stamp, and encrypt PDF documents and forms. If you have to do anything with PDF, you should definitely download the free trial.
Peer 1   Peer 1 - provides award-winning Managed Hosting, Dedicated Hosting, Co-location, and Network services offered through 15 data center across North America. With over 10,000 businesses hosted on their legendary SuperNetwork™backbone, PEER 1 delivers one of the highest server performance and network outputs in the industry.
Mindfusion   MindFusion - a great source for flow-charting and diagramming components for a variety of platforms including .NET, WPF, ActiveX and Swing
A Sane Approach to Database Design   A Sane Approach to Database Design - the book that tells you how to build a smart database, with lots of examples of people who did it wrong. And although the irish girl has nothing to do with database design, I certainly appreciate keeping up the tradition.
Software Verification   Software Verification - software engineering tools for memory leak detection, code coverage, performance profiling, thread lock contention analysis and thread deadlock detection, flow tracing and application replay on the Windows Vista, 2003, XP, 2000 and NT platforms.
SlickEdit   SlickEdit - makers of that very-impressive code editor and some pretty neat Eclipse and VisualStudio.NET tools and add-ins, some of which (Gadgets) are free. Check out this short video highlighting just one of SlickEdit's Visual Studio integration features.
SoftLayer   SoftLayer - serious hosting provider with datacenters in three cities (Dallas, Seattle, DC) that has plans designed to scale from a single, dedicated server to your own virtual data center (complete with racks and all)

And now, back to our regularly scheduled program.

 

"This was in a document for creating cables for a Ethernet media converter," wrote Chris. "Would a table have been all that difficult?"

 

Such network able illustrations are best left to professionals. Like this diagram (sent in by Jon) from a NetGear switch manual. Err, wait...

 

"Woo hoo," D.A. writes, "my IBM stock paid dividends! Cha-ching!"

 

"Err," David Hunter wondered, "where is the change machine located?"

 

"I saw this at a Tucson McDonald's," David Daniel wrote, "I'm not sure what Drive Thru Parking is all about. Is it some form of dynamic parking?"

 

"These signs were right outside of the restrooms at Middle Tennessee State University," Chris noted, "I'm not sure if it's an act of Political Correctness, Accessibility, or Stupidity."

 

"Our repair shop got this computer in recently," writes Renato Ciuffo, "as for it's claim of being 'never obsolete', I'd beg to differ."

 

"I know I've seen a similar computer-generated sign in an Error'd or two," Paul Taylor said, "but hand-writing this out? That takes it to a whole new level."

 

"The sign does make a valid point," Patrick wrote, "you really should never stop warning children."

 

"This is from a Kroger in Troy, MI," wrote Mike. "Perhaps it's proof that Kroger is not lying when they say they are an equal opportunity employer?"

 

"I noticed this interesting image on the cover page of a shareholder's notice," Seb wrote. "Somehow, I can't see this going over very well for a company in the US."

 




Brought to you by the Non-WTF Job Board:




The Mod Out System

23 Apr 2009 15:00:00 | Mark Bowytz | Feature Articles | Comments

When Gary was first hired at an aircraft component repair company, one of his first duties was to add functionality to their Oracle 11i based application that would "automatically add mods" to the system.

As Gary soon learned, a "mod" referred to the work that needed to be performed on particular piece of equipment for maintenance or repair. Because the company specialized in a fairly specific type of components (multimedia), the steps to perform the work were fairly consistent: 1) Remove any certifications or other affixed notices; 2) Remove field-serviceable access panels 3) Remove factory-serviceable panels; ...; 18) Replace joints with new silicone glue; etc. This worked out well as, due to federal regulations, all modification steps taken needed to be recorded in the equipment's recertification file.

To represent this in their application, a user would enter a comma-separated list of numbers in the "Related Modification Steps" field. However, since a piece of equipment could have anywhere from a handful to several dozen mods done to it, the field accepted "shorthand" input to represent a range of numbers. For example, entering "1-6,8" would represent the same steps as "1,2,3,4,5,6,8". Upon saving the repair order, the "mods" string would then be used to add data to a linking table associating the repair order with the pre-defined repair steps.

What a great first assignment! Gary thought as he went searching for the value set responsible for validating the user's input. He figured that the developer must have written a spiffy little PL/SQL function that would parse the string of numbers, detecting one or more ranges of numbers and take into account the occasional "one off" digit that would not be included in any range.

However, one question lingered for Gary. Why was he assigned to write functionality to "auto-add" mod sequences when they would be auto-converted from what the user inputted in the first place?

"Well," Gary's supervisor explained, "every now and then you come across a mod level that hasn't been entered. This of course means emailing one of three designated employees to add it, which means the process of logging equipment out has to be put on hold. This can be a problem if one these employees are out of the office, or they just simply skip over the email."

"Okaaaay," Gary said, quizzically raised an eyebrow. He still wasn't sure exactly what his boss was referring to.

"You'll win friends for this one!" cheered his supervisor.

When Gary had a chance to dig in to the code, he found a clue that answered exactly he was supposed to do. It was the monster-sized table named ALL_MODS:

Oracle Apps 11i is teh funzorz.

Instead of parsing the "mods" string, the original developers created a table that would validate and then convert the user's input in to the appropriate string of values. If the user's input wasn't in the table, he'd have to ask one of the "specialists" to add the row.

The good news was that Gary would have an opportunity to write a spiffy little PL/SQL function that would parse the string of numbers. And of course, the bad news was that this was just the tip of the iceberg.




Brought to you by the Non-WTF Job Board:




Error'd: Circular Logic

23 Apr 2009 12:00:00 | Alex Papadimoulis | Error d | Comments

"Well that's an easy fix," Clemens noted, "all I have to do is open the— hey, waitaminute!"

 

"Things kinda went downhill from here," commented Derrick.

 

"Screw that," Josh Forman said to himself, "I'm not waiting 2 days to check out."

 

"Glad to see Lowe's is doing their part in these times," writes Michael Ansel.

 

Murray Macchio wrote, "thanks for asking me a question, and not giving me a choice, Netbeans."

 




Brought to you by the Non-WTF Job Board:




CodeSOD: zzGeneralFunctions

22 Apr 2009 13:00:00 | Alex Papadimoulis | CodeSOD | Comments

A codefile whose name is prefixed with “zz” can be one of two things. It's either a file that someone wanted to get rid of but was afraid to delete, or it's an intentional naming scheme to keep the file at the bottom as part of some crude code-organization technique. There used to be a third option - the file's a part of an application commissioned by a certain American rock trio known for their beards and cheap sunglasses - but the band dropped that requirement a long time ago.

However, when Mark Arnott stumbled across "zzGeneralFunctions.asp" as part of a maintenance project he was assigned, it was pretty clear why the file existed. Its first line contained the following comment:

 ' If you do something more than once, put it in a function here.

After a quick skim through the tens of thousands of lines of code, it was fairly obvious that, while the developers followed that "more than once" comment to the letter, they didn't follow the implied advice: before you put a function here, check if that function already exists. Take, for example, calculating a given month's name.

 function MonthName(mNum)  dim m  on error resume next  m=0  MonthName="??"  'if IsDate(mNum) then m=month(mNum)  m=int(mNum)   if m=1 then MonthName="January"  if m=2 then MonthName="February"  if m=3 then MonthName="March"  if m=4 then MonthName="April"  if m=5 then MonthName="May"  if m=6 then MonthName="June"  if m=7 then MonthName="July"  if m=8 then MonthName="August"  if m=9 then MonthName="September"  if m=10 then MonthName="October"  if m=11 then MonthName="November"  if m=12 then MonthName="December" end function

Ignoring the fact that there's already a built-in VBScript function that does just that, and that the built-in function is also named MonthName, this code seems perfectly logical. In fact, so logical that it was repeated a few lines down.

 function GetMonthName(thisNum)  dim m  on error resume next  m=0  GetMonthName="??"  'if IsDate(thisNum) then m=month(thisNum)  m=int(thisNum)   if m=1 then GetMonthName="January"  if m=2 then GetMonthName="February"  if m=3 then GetMonthName="March"  if m=4 then GetMonthName="April"  if m=5 then GetMonthName="May"  if m=6 then GetMonthName="June"  if m=7 then GetMonthName="July"  if m=8 then GetMonthName="August"  if m=9 then GetMonthName="September"  if m=10 then GetMonthName="October"  if m=11 then GetMonthName="November"  if m=12 then GetMonthName="December" end function

And then there was this function which did mostly the same thing, and also replaced the built-in functionality of VBScript's MonthName.

 function MonthAbbr(m)  on error resume next  MonthAbbr="??"  if IsDate(m) then m=month(m)  if m=1 then MonthAbbr="Jan."  if m=2 then MonthAbbr="Feb."  if m=3 then MonthAbbr="Mar."  if m=4 then MonthAbbr="Apr."  if m=5 then MonthAbbr="May"  if m=6 then MonthAbbr="Jun."  if m=7 then MonthAbbr="Jul."  if m=8 then MonthAbbr="Aug."  if m=9 then MonthAbbr="Sep."  if m=10 then MonthAbbr="Oct."  if m=11 then MonthAbbr="Nov."  if m=12 then MonthAbbr="Dec." end function

The combinations and permutations of almost identically named and functioning date/time methods were astonishing. At some point, functions names started to end with a number. And then came the prefixes.

 function zzFormatDate4(thisdate)  dim tmp, m  on error resume next  tmp = ""  if (IsDate(thisdate)) then   m = month(thisdate)   tmp = ""   if m=1 then tmp="January"   if m=2 then tmp="February"   if m=3 then tmp="March"   if m=4 then tmp="April"   if m=5 then tmp="May"   if m=6 then tmp="June"   if m=7 then tmp="July"   if m=8 then tmp="August"   if m=9 then tmp="September"   if m=10 then tmp="October"   if m=11 then tmp="November"   if m=12 then tmp="December"   tmp = tmp & " "   tmp = tmp & right("00" & day(thisdate),2)   tmp = tmp & ", "   tmp = tmp & year(thisdate)  end if  zzFormatDate4 = tmp end function

By the time Mark got to zzFormatDate4, he just gave up looking. It was going to be a very long maintenance project.




Brought to you by the Non-WTF Job Board:




An Unlikely Network Outage

21 Apr 2009 15:00:00 | Jake Vinson | Feature Articles | Comments

Dario sighed, placing the call on hold to answer another. "Network support, Dario speaking."

"Hi, this is Seth," the caller began, as though Dario knew who this "Seth" was. "My computer isn't working today. All morning, nothing." Specificity clearly wasn't one of the caller's strengths.

Before Dario could ask for more information, another call came in. "Hold please," he said, answering yet another support call.

The new caller introduced herself and complained of an inability to pull a file from the network. In the background, Dario could hear Seth complaining "no, he put me on hold, I'll find out in a minute!" All of the calls were coming from the same department.

The Network Layout

In theory, the undisclosed department of the government where Dario worked (let's call it the "Department of Government") had a pretty decent network setup. In practice, the situation wasn't so rosy. The year was 1996, and Dario was babysitting said network – and it was a very fussy baby. Seldom did a day go by without a user losing connectivity to one of the servers.

The network was laid out like so:

  • A thick 10Base5 "backbone" cable, with intrusive taps that provided them with AUI drops. The tap would pierce the 10Base5 cable and had an AUI connector on the other side. From there, an AUI cable could connect to the NIC on the back of a server.
  • Several 10Base2 hubs. There were a dozen or so, each of which had roughly 20 computers on it.
  • The occasional fiber link to other buildings.

And with no false ceiling or floor to run the cables through, cables were draped from the ceilings with taps dangling like party streamers for the worst party you've ever been to. For each new system, Dario would have to run a cable down from the ceiling, cut it, add a T connector, hook the connector up to the 10Base2/BNC connector on the computer, go back up with the cable, run it to the next machine, and so on, ultimately ending the line in a terminator. And throughout all of it, Dario had to keep in mind the minimum distance between computers, the maximum cable lengths, etc., as required by the 802.3 standard.

90% of the issues could be fixed by the obvious; going to the user's desk, looking around, and identifying what's missing from the picture. Had someone unplugged the T connector from the NIC? Maybe; the cleaning crew would do this fairly often for whatever reason. Had the terminator been removed or pulled off? Maybe. They had a tendency to fall off or disappear altogether, and Dario never found out why.

This issue was different, though. Dario had a dozen users lose their access! He packed up his toolbox, hooked one thumb in his belt, and marched into the accounting department's area.

The Troubleshooting Process

"I'm Dario and I'm here to fix the network," he announced, embarrassed that he'd accidentally said it in a low voice like a superhero. "*ahem* I mean, I'll be checking all of your computers, but I'll try to stay out of everyone's way."

OK, time for computer #1. Had the cleaning crew unplugged it? No. The connection from the computer to the T connector was fine, no signs of damage to the cable. Second, third, fourth, and so on – same deal. Just to be sure, he verified the terminator was there. No signs of distress.

Meanwhile, Dario was overhearing the grief that his users were experiencing. With no network access, they couldn't process payments. Without being able to process payments, they were even later than usual on some already wildly overdue payments. "No, we have IT here right now, but I don't think they'll be able to fix it," one of the users said into her phone loudly. "I know," she continued, "yes, I know," she said, pausing. "Look, I can't help you until our network issues are resolved." Every time Dario looked up, he'd catch a stink eye from one of the accountants.

Without any user confidence, and vendors being driven up a wall since they wouldn't get paid while the network issues persisted, Dario worked as quickly as he could. He switched the segment to another port on the same hub, still nothing. He replaced the hub entirely, still no change. Well, except that the users had begun fashioning shivs from whatever they had on their desks.

Desperate Times

There was no other option – they had to call Carl, the cabling guy. Carl answered his voice with a kind of sinister cheerfulness; the kind that an overacting movie villain would have after successfully luring the hero into a trap. "I'm on another call," he said. "And I'll have to charge extra for the rush job. And for bringing some of my guys over to help. And for some extra hardware and cables. But don't worry, we'll have you up and running again in no time."

Fine by me, Dario thought, since we won't be able to pay the invoice until our network works anyway.

While he waited for Carl to arrive, Dario figured he could check the computers again; specifically the one that belonged to Helga. Helga was a very large woman, and messy. Her desk had stacks of papers, books, office supplies, wrappers, and folders, most of which were covered under a thick layer of dust. Worse, the mess had extended onto the floor under her desk, which is why it was the only desk that Dario hadn't given a thorough check previously. The blight cloud that surrounded her desk was why Dario had given it the least thorough check before. Down on all fours, coughing and rubbing his eyes as his lungs filled with dust, he started excavating Helga's computer.

Helga's system had its network cable securely attached. All that for nothing, he thought as he stood up and dusted himself off. Following the cable to the T connector, he found that that was securely connected as well. About two inches from the connector, though, the cable was damaged. Odd, Dario thought, this looks... intentional. Going in for a closer look, he found a bundle of 15 or so copper strands tightly twisted to make a thicker cable. Following that cable led him back to her desk. The cable was connected to an ancient-looking AM/FM radio.

From Miles Away

"Helga, do you know what this is about," Dario asked, pointing to the cable.

"Oh, well, you see, I brought in this radio so I could listen to music while I work."

"And...?" Dario pressed.

"And somehow the antenna came loose, and I lost it."

"And...?"

"And the reception wasn't very good then."

Dario didn't speak, he just waited for her to continue.

"Actually, no reception at all! So Johnny fixed it and now I can listen to radio stations from miles away! It's incredible!" Dario's expression revealed that he wasn't as impressed as she'd expected.

So Helga and her, uh, let's say "resourceful" friend, were using the network infrastructure as a giant radio antenna. And sure, it took down the network, but you haven't heard "Forever Young" until you've heard it via a building-sized antenna!

By simply disconnecting Helga's cable, everyone else was able to work again. Dario called off the visit from Carl the cabling guy, and went back to his desk to decompress. The first course of action? Typing up and distributing a memo explicitly forbidding use of network cabling for purposes other than... network cabling. No extended-range antenna, no jumping rope, no hanging clothes to dry, nothing.




Brought to you by the Non-WTF Job Board:




Error'd: Headline Across Here

21 Apr 2009 12:45:00 | Alex Papadimoulis | Error d | Comments

"I didn't realise 'The Chronicle' (Canberra) had become a 'do it yourself' newspaper," Kevin Rudd commented.

 

Michael caught this in the Guardian.

 

"1?" Liza D. wrote, "No wait, 5."

 

"I had this pop up in my Lenovo Message Center," Jason B. writes. "With potential battery hours like those described in the message, I better upgrade today!"

 

Scott Stocker didn't find this information very helpful...

 




Brought to you by the Non-WTF Job Board:




CodeSOD: Self-Documenting

20 Apr 2009 13:00:00 | Alex Papadimoulis | CodeSOD | Comments

Robert W and the rest of the peons in the COGS application group didn't have their own Architecture Team. Their break room wasn't stocked with an endless supply of snacks. In fact, they didn't even have the budget for quarterly "developer retreats". All they had was a CVS repository, a few servers, and a dedication to their client, the COGS group.

For years, everything ran smoothly: they delivered in full, on time, and had a very satisfied client. That is, until the elite developers from Central IT got wind of their rinky dink operation. After a week-long assessment, they determined that Robert’s team had a number of “serious trouble points”, the worst of which was JavaDoc compliance. Apparently, only 53.8% of their code was fully and properly documented.

"But not to worry," the consultant from Central IT assured them, "we've developed a number of tools and technology that will address the trouble points and ensure your development runs smoothly. Most importantly, we'll get you set up with The Documentor."

The Documentor, as it turned out, was a custom CVS commit hook that would automatically add JavaDoc to any method definitions lacking them. So, checking in this...

 public int calculateExpiryScale(String keyCode)    throws KeyCodeInvalidException {      ... snip ...  }

... would turn into this...

   /**    * DOCUMENT ME!    *     * @param foo DOCUMENT ME!    * @return DOCUMENT ME!     * @throws KeyCodeInvalidException DOCUMENT ME!    */ public int calculateExpiryScale(String keyCode)    throws KeyCodeInvalidException {      ... snip ...  }

This was the only documentation required by Central IT.




Brought to you by the Non-WTF Job Board:




What the Ad? - Blatent Theft

17 Apr 2009 13:00:00 | Mark Bowytz | Feature Articles | Comments

Tsk tsk 80's software companies! When you're not out there making grandiose, larger than life promises to sell your product, you're playing right into your readers' knowledge of popular culture.

First, for shame Atron.  You give us this wall o' text where you quote the President of Borland singing your praises, but what's this?  "Bugbusters keep you from getting slimed"?  Oooh, if I were Dan Ackroyd or Harold Ramis, I'd circle "Cease and Desist" on my Customer Inquiry Card!

Like I have room to talk, but they misspelled scary

You know how Chinese knock-offs are close to the real thing...but not quite? The logo or the brand name are just askew enough to enter that gray area of copyright laws, but you just know was ripped off from somewhere.  Well, consider this ad for the 1981 and 1982 season of National Computer Shows. I think I've seen that robot ...somewhere...

Finally, the people at TranSec Systems Inc. may not be citing "popular" culture, but defeating copy protection of software published by big name companies "Only to Improve the Usability of Legally Acquired and Operated Software"...riiiight.




Brought to you by the Non-WTF Job Board:




Announcement: Announcement: Alex on StackOverflow Podcast

16 Apr 2009 21:00:00 | Alex Papadimoulis | Announcement | Comments

Every since I picked up a new phone (the venerable yet non-hipster Nokia E71), I've found myself getting more and more into podcasts. NPR's podcast, software podcasts, you name it — heck, I've even thought of doing our own, Daily WTF podcast (anyone interested?).

That said, I was pretty excited to catch up with Joel Spolsky & Jeff Attwood on the StackOverflow Podcast. We chatted a bit about The Daily WTF, the ever-so-popular Worse Than Failure name change, and a whole bunch of other things.

If you'd like to check it out, download the MP3 or hope that someone else edited the transcription wiki.




Brought to you by the Non-WTF Job Board:




eTeller Horror

16 Apr 2009 15:00:00 | Mark Bowytz | Feature Articles | Comments

Most large applications are designed with multiple, autonomous interacting components. In very high level terms, they look like this:

The two circles above are two mutually dependent components. The arrow is an avenue of communication between the two, and two classes can only communicate where they are connected to one another. In general, you want there to be as little 'surface area' between two classes as possible, and the avenue of communication should be as narrow as possible. Neat, simple, orderly, supportable.

Now consider the following:

This is how the eTeller application supported by Steve looked under the hood.

Prices So Low, They're INSANE!!!

Infotech is a company that produces budget enterprise software for various financial institutions. Sure, in this context, "budget" may be defined as being in the neighborhood of a generously equipped new car. But in the eyes of a bank, even a small one, spending this kind of money is a bargain when compared to writing and supporting something written in-house. So, to remain competitive and keep their prices appealing, Infotech, like many companies with similar goals, bottled up their requirements and offshored their development.

The same process was applied to Infotech's latest initiative, eTeller, which was a suite of applications used by bank tellers at their stations to keep track of day-to-day things like deposits, withdrawals, receipt printing, and the like. After a year of development, eTeller 1.0 was released and, thanks to a base of existing satisfied customers, the money rolled in. However, their growing customer base was quickly turning from a blessing into a curse.

The "Fit" hits the "Shan"

Working on the front lines, Steve's group of support analysts were well aware that the product they supported was, by definition, crapware. Six months after the initial release, eTeller was up to v1.5 and had gained a following of thoroughly disgruntled customers. Every day, more and more users were calling in about the frequent application crashes mid-transaction, inaccurate reporting that lead some banks to think their tellers were robbing them blind, and several other nasty things were not just keeping them from going about their daily business, but also making them seriously ticked off!

After apologizing in a soothing tone, analysts in the US would send a list of new bugs to the offshore developers, who would then address the problem and release a patch which, when installed by the client, would open up three new bugs in its place.

With customer satisfaction at an all-time low and bank presidents calling Infotech's CEO, at home, threatening to sue, something had to be done. The contract with the offshore developers was terminated and the source code was recalled with the plan being to fix the bugs and make enhancements locally at the only-slightly-higher-than-offshore "greenhorn" rate.

The developers complied, but nothing could have prepared Steve, the CEO, or anyone else for what they were about to inherit.

The Beast Revealed

Source analysis revealed that eTeller was over 100k lines of tangled, messy, and completely unmodularized C# code...and not a single line of it held any redeeming value whatsoever. It was so bad that refactoring it would have probably made it worse; the whole thing just needed to be rewritten.

A few of the "highlights" included:

  • Excluding classes generated by Visual Studio, there were all of five classes used in the entire application. Each was a static class containing exclusively static methods. The main class, "Globals", contained 1000s of variables to maintain the state of application. The only types used in the Globals class were bool, string, decimal, and DataSet.
  • As a result of the lack of classes, no business-specific classes existed in the application. Instead, ArrayLists, HashTables, and DataSets were used to move around data.
  • 20,000 lines of code were embedded in a single file called frmMain.cs. It printed receipts, performed account inquiries, controlled the cash dispenser, you name it!
  • No primary keys, indexes, or foreign key constraints existed on tables, nearly all fields were of type varchar(50), and 100% of fields were nullable.
  • Who needs stinkin' parameters when you could store everything in the Globals class? In the rare instance that parameters were passed to a method, they were passed as strings for convenience.
  • Some forms had invisible labels. The programmers used the .Text and .Tag properties to hold miscellaneous data. Invisible labels must have been easier to create than inserting yet another variable into Globals.

Of course, because they had to support customers who were reaching for their last straw, a full rewrite of eTeller had to be put on hold. Banks were demanding to have bugs fixed on the same day they were reported...or else. Each new bug the development team into crisis-mode: bugs were being fixed as fast as possible and a new release was being sent to QA almost immediately.

Against the recommendations of QA and developers, new versions of eTeller were being released to customers every two to three days. Fortunately, this was only a "temporary" operating mode and, once things cooled down, they'd scale back a bit and focus on the big, rewrite project. At least, in theory.

Many, many months later, when they finally delivered the arbitrarily-numbered eTeller v1.89b.6a, the system was at a state where it performed its most basic tasks with minimal errors. There was still a steady stream of bugs coming in, but one thing was certain: a rewrite was never, ever going to happen.

Taming The Beast

Steve's team was faced with a foe they could never defeat. Every time they worked to slay a bug, the codebase would grow and become an even larger monstrosity. Instead of going head-to-head with the beast, they decided to take a less ambitious approach: surgically remove dead features and rewrite functionality whenever a change request came through.

The approach seemed to work, though it did have it drawbacks. Not only did changes take longer to implement, but the codebase didn't seem less ugly; it was only a bit smaller. Sure, the once 20,000-line frmMain.cs had shrunk by 60%, but was still an 8,000-line mess.

Eventually, their careful, calculated approach caught up with them. When it came time for a major new set of features, there was no way Steve and his team could maintain their pace of bug fixing and deliver the changes in a timely manner without hiring more developers.

Fortunately, managers, in all their wisdom, knew exactly what to do. And all Steve’s team would have to do is bottle-up a few technical requirements...




Brought to you by the Non-WTF Job Board:




Error'd: To Pay or Not To Pay

16 Apr 2009 12:00:00 | Alex Papadimoulis | Error d | Comments

Tian van Heerden wrote, "this message came up on the automated parking pay-station at Cavendish Square here in Cape Town."

 

"I was searching for lyrics on Google, when I came across this search result,"writes Aaron M.. "How would Google know the SQL behind this page? I checked the page source: <span style='display: none;'>SELECT * FROM tblLyr WHERE album = 'Illinois' AND auteur = 'Sufjan Stevens'</span>. I guess you can 'none', but you can't hide from Google!"

 

"Luckily, I was porting my old number," James Seward writes, "I don't think anyone could dial my new one."

 

"I was playing Red Alert 3 when suddenly it crashed," Jasmin wrote, "the dialog went on and on and on... here's the top 10% fof the screen snag."

 

Paul decided to pass on watching this.

 




Brought to you by the Non-WTF Job Board:




The Developers' Book Club

15 Apr 2009 15:00:00 | Alex Papadimoulis | Feature Articles | Comments

Pretty bad, Tal M thought to himself on his first day on the new job. Pretty, pretty, pretty bad.

In all reality, the code and development practices at Tal’s company weren’t that bad. At least, not when compared with some of the monstrosities we’ve all see published here. Sure, they had the base class to end all base classes (basically an IObject), plenty of does-it-all-and-then-some classes (a good old ISwissArmyKnife), and a seemingly endless supply of wrappers and wrapper wrappers, but there was nothing that went completely over the top.

Disappointed that he’d be working at yet another company with a dysfunctional codebase, Tal decided to take a stroll and explore the five floors that the programming department utilized. The first stop on his self-guided tour was a place called the “Developer Resource Center”. Situated between conference rooms 402 and 408, it was mostly an alcove of bookshelves filled tomes such as DOS 4.0 Fundamentals and Mosaic for Dummies. But there was one shelf that caught his eye.

Technically, it wasn’t so much the shelf that drew his attention, but the passive-aggressive sign written in red, 58-point Chiller. Do Not Take Any of THESE BOOKS, Tal read the words in his head. Code Complete 2… Pragmatic Programmer… what the—

His internal monologue was cut off by another stream of thought. Is this why the code is so terrible? Is someone trying to hoard all of the best practices knowledge? Or is this some harebrained scheme to monopolize all local copies of good programming books?

Don’t Touch, Explained

After some investigation, Tal learned why the Developer Resource Center was stocked with so many look-but-don’t-touch volumes. Some time ago, a developer who had long since left the company organized the “Developers’ Book Club.” Though the exact details were lost to time, the idea was that like-minded developers would get together at lunch and discuss things like Code Complete 2: Chapter 16: Controlling Loops. It was supposed to be a great way to learn and reinforce good coding practices.

Unfortunately, the book club never made it past buying that initial stock of books. It was hard to say why, but Tal speculated that the initial organizer got so frustrated with the lack of interest that he gave up and never looked back. Or maybe he got hit by a bus.  But either way, the books had been carefully guarded by the ominous chiller sign, effectively preventing anyone from accessing the invaluable knowledge contained within.

Developers’ Book Club 2.0

Not only did Tal hate to see such great books go to waste, but he knew that his fellow developers could really learn a thing or two from the material. At his previous job, he had seen great things happen with similar “light training” programs, and he knew the perfect way to get things going again. Through the Lunch & Learn.

Organizing a Lunch & Learn group at the new job seemed like an all-around great idea. It offered a fairly high ROR (Return-On-Résumé) and would show management that he was very serious about improving not only his skills, but those of his colleagues. After finagling a bit to get the lunch portion paid for, Tal sent an email invitation to the 600 on-site developers for the very first Lunch & Learn and patiently waited two weeks for the event.

No one shows up to the first anything, Tal reassured himself before convening the discussion. Nine attendees aren’t too bad, and these things take time to grow.

As Tal went into his spiel about Lunch & Learns and learning in general, he noticed that the attendees were helping themselves to one, then two, and then three, and even four slices of pizza. Not that it mattered, developers get hungry and there was plenty of pizza to go around.

However, as the 15-minute mark neared and they were finishing their meal, two of the attendees got up and excused themselves. Apparently, they both had to be on an “important 12:30 call” and couldn’t miss it. Then another attendee excused himself. And then another. Before the hour discussion was over, all of four people – Tal included – remained.

2.0 SP1

Given the low attendance and early leavers, Tal figured that his presentation was below par. For the second Lunch & Learn, he knew he’d have to prepare a bit more and build in as much interactivity/discussion as possible.

Pretty good, Tal was pleasantly surprised that twenty-two developers stopped by for the second Lunch & Learn. Pretty, pretty, pretty good.

But before he even started talking, he noticed that a small clique of developers was leaving with a plate-full of pizza in hand. Apparently, they were just stepping out for a minute, but would be right back. During his brief, thirty-second introduction, Tal saw another handful of other developers leave.

When it came time for discussion, no one had even read the cover, let alone a few pages or a chapter. Fortunately, Tal came armed with Power Point slides and was able something that resembled a conversation going. It was a good start but came to an end prematurely as everyone seemed to have a “mandatory 12:30” they couldn’t miss.

The Final Nail

Hoping to nip the freeloading problem in the bud, Tal’s invitation for the third meeting implored attendees not to dine and ditch, and reminded everyone that the value came in discussion and attending for the full hour. He figured that should shame just about everyone from freeloading.

And he was right: none of the known freeloaders were in attendance and there was only one suspected freeloader. Period. Just a single, suspected freeloader. No one else attended the Lunch & Learn. As for why Tal suspected she was freeloading, she wasn’t actually a developer and instead worked as a systems administrator for the DB2 group.

That was the last Lunch & Learn that Tal organized. Since then, he’s come to learn how deep-seeded the noninterest in improvement had become. Not that it matters, though. These days, Tal finds himself grumbling at the bad — but not quite The Daily WTF bad — code. Pretty bad; pretty, pretty, pretty bad.

 




Brought to you by the Non-WTF Job Board:




CodeSOD: Well, at least it compiles...

15 Apr 2009 13:00:00 | Mark Bowytz | CodeSOD | Comments

Working on a team that is uplifting a legacy application into a newer technology, Neil K. is responsible for ensuring that the new application is working the same as the one being replaced.

While looking into the new functionality, he found the following tucked away in a stored procedure (of which this is only an exerpt).  For his sake, I hope for two things. First, I hope he's only responsible for testing it and doesn't have to maintain this hornet's nest of code. Second, in the name of all that is good in this world, I hope that the whomever is responsible for this mess contained their version of insanity to only one stored procedure.

SELECT @tv_100 = (@b_M - 1) + 4*(2 - @b_sd)
SELECT @tv_101 = (@b_M - 1) + 4*(2 - @b_sd)
SELECT @tv_102 = (@b_M - 1) + 4*(2 - @b_sd)
SELECT @tv_104 = (@b_M - 1) + 4*(2 - @b_sd)
SELECT @tv_109 = ((10 - @f_M) + 4*(2 - @f_sd) + (@g_M - 1) + 4*(2 - @g_sd)  +  (@q3_M - 1) + 4*(2 - @q3_sd))/3
SELECT @tv_111 = ((10 - @g_M) + 4*(2 - @g_sd) + (@m_M - 1) + 4*(2 - @m_sd)  +  (10 - @o_M) + 4*(2 - @o_sd)  + (@q1_M - 1) + 4*(2 - @q1_sd))/4
SELECT @tv_115 = ((10 - @f_M) + 4*(2 - @f_sd) + (@g_M - 1) + 4*(2 - @g_sd)  +  (@q3_M - 1) + 4*(2 - @q3_sd))/3
SELECT @tv_116 = ((@b_M - 1) + 4*(2 - @b_sd) + (@f_M - 1) + 4*(2 - @f_sd)  +  (10 - @g_M) + 4*(2 - @g_sd)  + (10 - @o_M) + 4*(2 - @o_sd))/4
SELECT @tv_118 = ((@b_M - 1) + 4*(2 - @b_sd) + (10 - @f_M) + 4*(2 - @f_sd)  +  (@q3_M - 1) + 4*(2 - @q3_sd))/3
SELECT @tv_122 = ((@b_M - 1) + 4*(2 - @b_sd) + (@m_M - 1) + 4*(2 - @m_sd)  +  (@q1_M - 1) + 4*(2 - @q1_sd))/3
SELECT @tv_123 = ((10 - @e_M) + 4*(2 - @e_sd) + (10 - @h_M) + 4*(2 - @h_sd)  +  (10 - @m_M) + 4*(2 - @m_sd)  + (@q1_M - 1) + 4*(2 - @q1_sd))/4
SELECT @tv_125 = ((@a_M - 1) + 4*(2 - @a_sd) - 0.5*ABS(5.5 - @i_M)  +  (@L_M - 1) + 4*(2 - @L_sd))/2
SELECT @tv_126 = ((@b_M - 1) + 4*(2 - @b_sd) + (10 - @f_M) + 4*(2 - @f_sd)  +  (@g_M - 1) + 4*(2 - @g_sd)  + (@q3_M - 1) + 4*(2 - @q3_sd))/4
SELECT @tv_127 = ((10 - @f_M) + 4*(2 - @f_sd) + (@g_M - 1) + 4*(2 - @g_sd)  +  (10 - @q1_M) + 4*(2 - @q1_sd)  + (@q3_M - 1) + 4*(2 - @q3_sd))/4
SELECT @tv_129 = ((10 - @m_M) + 4*(2 - @m_sd) + (10 - @o_M) + 4*(2 - @o_sd)  +  (10 - @q1_M) + 4*(2 - @q1_sd)  + (10 - @q3_M) + 4*(2 - @q3_sd))/4
SELECT @tv_131 = ((@e_M - 1) + 4*(2 - @e_sd) + (10 - @g_M) + 4*(2 - @g_sd)  +  (10 - @q2_M) + 4*(2 - @q2_sd))/3
SELECT @tv_132 = ((10 - @a_M) + 4*(2 - @a_sd) + (@e_M - 1) + 4*(2 - @e_sd)  +  (@g_M - 1) + 4*(2 - @g_sd)  + (10 - @q1_M) + 4*(2 - @q1_sd) + (@q2_M - 1) + 4*(2 - @q2_sd))/5
SELECT @tv_134 = ((@a_M - 1) + 4*(2 - @a_sd) + (10 - @c_M) + 4*(2 - @c_sd)  +  (10 - @g_M) + 4*(2 - @g_sd)  + (@i_M - 1) + 4*(2 - @i_sd) + (10 - @L_M) + 4*(2 - @L_sd))/5
SELECT @tv_135 = ((@a_M - 1) + 4*(2 - @a_sd) + (10 - @b_M) + 4*(2 - @b_sd)  +  (@i_M - 1) + 4*(2 - @i_sd)  + (10 - @L_M) + 4*(2 - @L_sd) + (10 - @q3_M) + 4*(2 - @q3_sd))/5
SELECT @tv_138 = ((10 - @b_M) + 4*(2 - @b_sd) + (@g_M - 1) + 4*(2 - @g_sd)  +  (@q3_M - 1) + 4*(2 - @q3_sd)  + (@q4_M - 1) + 4*(2 - @q4_sd))/4
SELECT @tv_139 = ((10 - @b_M) + 4*(2 - @b_sd) + (@g_M - 1) + 4*(2 - @g_sd)  +  (@q3_M - 1) + 4*(2 - @q3_sd)  + (@q4_M - 1) + 4*(2 - @q4_sd))/4
SELECT @tv_140 = (10 - @q3_M) + 4*(2 - @q3_sd)
SELECT @tv_141 = ((@b_M - 1) + 4*(2 - @b_sd) + (@q3_M - 1) + 4*(2 - @q3_sd))/2
SELECT @tv_143 = ((10 - @a_M) + 4*(2 - @a_sd) + (10 - @i_M) + 4*(2 - @i_sd)  +  (@L_M - 1) + 4*(2 - @L_sd))/3
SELECT @tv_145 = ((10 - @b_M) + 4*(2 - @b_sd) + (10 - @m_M) + 4*(2 - @m_sd)  +  (@o_M - 1) + 4*(2 - @o_sd)  + (10 - @q1_M) + 4*(2 - @q1_sd) + (@q3_M - 1) + 4*(2 - @q3_sd))/5
SELECT @tv_146 = ((10 - @f_M) + 4*(2 - @f_sd) + (@g_M - 1) + 4*(2 - @g_sd)  +  (@q3_M - 1) + 4*(2 - @q3_sd))/3
SELECT @tv_147 = ((10 - @b_M) + 4*(2 - @b_sd) + (@g_M - 1) + 4*(2 - @g_sd)  +  (@q3_M - 1) + 4*(2 - @q3_sd))/3
SELECT @tv_148 = ((10 - @b_M) + 4*(2 - @b_sd) + (@g_M - 1) + 4*(2 - @g_sd)  +  (@q3_M - 1) + 4*(2 - @q3_sd))/3
SELECT @tv_149 = ((@c_M - 1) + 4*(2 - @c_sd) + (10 - @q4_M) + 4*(2 - @q4_sd))/2
SELECT @tv_150 = ((@c_M - 1) + 4*(2 - @c_sd) + (10 - @q4_M) + 4*(2 - @q4_sd))/2
SELECT @tv_151 = ((@c_M - 1) + 4*(2 - @c_sd) + (@g_M - 1) + 4*(2 - @g_sd)  +  (10 - @L_M) + 4*(2 - @L_sd))/3
SELECT @tv_152 = ((@c_M - 1) + 4*(2 - @c_sd) + (@g_M - 1) + 4*(2 - @g_sd)  +  (10 - @L_M) + 4*(2 - @L_sd))/3
SELECT @tv_153 = (10 - @q4_M) + 4*(2 - @q4_sd)



Brought to you by the Non-WTF Job Board:




How to Tempt Fate

14 Apr 2009 15:00:00 | Jake Vinson | Feature Articles | Comments

"No, it's not write 'click', it's right click, like click the button on the right-hand side." John R. realized his mistake as he said it.

"I already am holding the mouse with my right han-"

"I mean the button under your ring finger."

Keep it Together

John wasn't the stereotypical surly Nick Burns-esque support guy, and he didn't think the users were stupid. Certainly, they were a source of frustration, but as he kept reminding himself, just another year and a half and I'll be done with my computer science degree. Keep it together, John.

He'd come to hope that Hexasys wouldn't be representative of his future in the field. Adequate employees, acceptable coffee, reasonable pay, off-white walls decorated with typical abstract art that wasn't too abstract as to inspire creative thinking. Nothing to hate, nothing to love. Just adequate.

One of Hexasys's largest clients was Decabyte, a large company that provided data storage for backups. It was cheaper for them to outsource their support to Hexasys than to bring it in-house, and their need was great enough to require both an on-site team during the day, and on-site 24x7 support at Hexasys HQ. John was at HQ, but he often worked with the on-site team.

Typically, all that was required was answering support calls. Occasionally, John would have to push updates via Microsoft Systems Management Server (Microsoft SMS, not the other kind of SMS), which provided the ability to push patches, remotely control machines, and remotely install software. SMS packages could be deployed to a user, a group, or the entire network, and for better or worse, would run without any interaction from the user.

The packages themselves were distributed from Hexasys to a computer set up by the on-site team. Transmission was done via 56K modem; these were the days when the environment was mixed Windows 95 and NT. The packages could fail if they went to the wrong system, so everyone tried to keep vigilant.

At the end of a shift one day, John received a call asking for a particular SMS package. John noted the user, the operating system, and the package, and started the transmission.

THE SMS Package

The following day, John heard rumblings about "The SMS Package" and fears about Decabyte, and no one would make eye contact with him. He was a ghost in the office that day; no acknowledgment of his presence, yet other people suddenly felt cold when he was near.

Damn, damn, damn, damn! I screwed up big time, he thought. John had been working on some projects and studying for finals that were looming on the horizon, so he must have sent the wrong package. I *did* send the wrong package because I'm a stupid idiot! Unable to silence his thoughts, the realization slipped in that he was a dead man walking. Any minute he'd get the call to clear out his desk and that security would escort him out. His days now numbered, his perspective shifted dramatically. He didn't want the job to be over, he wanted to stay! Suddenly he gained an appreciation for the posters of abstract art in the conference rooms; they were no longer bland and generic, they leapt off the slightly yellowed glossy poster print, oozing with emotion. He became drunk on the intoxicating bouquet of the burnt coffee. His co-workers weren't "adequate," they were shining beacons of knowledge; John, the freaking idiot who'd sent the wrong package didn't deserve the honor of basking in their brilliance. His brain continued its battle against itself. You probably sent the right package to the wrong system, it teased. Or, he thought as he swallowed hard, you distributed the wrong package to the entire network. A wave of panic engulfed him, and his entire body felt hot.

By the time he got to his computer, he was sweating. He checked the remote file list and saw that the package he'd sent the previous day wasn't there. Strange, because the patcher shouldn't delete something after it's done installing...

He went one-by-one, feeling like a ghost as he checked with each technician to see if they'd done any patching; no one knew anything. Meanwhile, the official word came down: "We have a few systems at Decabyte that are on the fritz."

Ah, good, John thought, embarrassed at his previous overreaction. We at least have it contained. He exhaled a deep sigh of relief.

Moments later, his boss poked his head in again. "Scratch that, most of the systems are down."

For the second time, John's skin flushed red and his body felt hot. He longed to be in a dark corner of a conference room, rocking back and forth in fetal position, abstract art poster in view.

Fortunately, John heard that the on-site team had sprang into action. They quickly figured out how to fix the problem and began drafting a formal procedure to fix the other systems. And after several hours, they'd fixed... one system. Meanwhile a dozen more had been added to the heap that had gone inaccessible.

They continued as fast as they could and got better with the speed, but it was too late. Decabyte wanted Hexasys out. That is, once this SMS snafu was resolved. The contract was kept alive for a short while, during which all of the systems were brought back online.

Psychology in Reverse

Reverse psychology is a funny thing. A "do not touch" sign makes exposed high-voltage wiring seem like an adorably cuddly kitten begging to be petted. The allure of defecating in onesself's pants is irresistable when the goal is precisely the contrary. And naturally, the next words to come out of a someone's mouth after "don't tase me, bro" are probably going to be "Aaowwwgh!"

The SMS package that the technician had sent out to the entire network not only wasn't for the right operating system; but it wasn't intended to be used ever. Perhaps that's why the package had been named "DO NOT SEND THIS SMS PACKAGE!!" John cannot fathom why someone hadn't deleted that package rather than leaving it there; said technician must have just wanted to tempt fate.




Brought to you by the Non-WTF Job Board:




Error'd: It's Started

14 Apr 2009 12:00:00 | Alex Papadimoulis | Error d | Comments

"Hyperinflation. It's started," writes Luke Heidelberger. "$1800 for a family-sized bottle of cheap white wine."

 

"That is quite the challenge," Jay notes.

 

Misha saw this on a bus in Circular Quay, Sydney, Australia.

 

"I encountered this using DVDFlick to create a disc image," Tom D. writes. "It turned out to be not quite as serious as the message suggested."

 

"While I was cleaning up I found my copy of the Caesar III game manual," Niels wrote. "Before throwing it away, I noticed this gem in it."

 




Brought to you by the Non-WTF Job Board:




CodeSOD: That Kind of Security

13 Apr 2009 13:00:00 | Alex Papadimoulis | CodeSOD | Comments

Alexandre Hetu was thrilled to not only be out of college, but to land a job at a small development company. He was even happier when he was given his first assignment: develop a shiny, brand-new application.

"I'm surprised they don't have any software to do this now," Alexandre told his boss after learning the business requirements, "or, were they using some vendor product?"

"Actually," his boss said sheepishly, "this is technically replacing an earlier system we built. Once you get in, you'll see why."

His boss wasn't joking. The thousands of lines of code where a wonderful mess, a redundant, unreadable and lengthy mess. It was filled with function names like "doit", "printit" and "makeit". And naturally, there were no comments... the code was self-documenting.

One thing Alexandre noticed was that the original developer was very concerned with database security. Not security as in, using prepared SQL statements. Or security as in escaping parameters sent through the web interface. It was security, as in this:

 procedure TDataModule1.DataModuleCreate(Sender: TObject); begin    conn.connectionstring:=decodeit('F?@Z[SfLSX/}~xÉpÉÇzÅ~fJEH?CLtâxb/'    + 'Étzrp_JtÑÅcLtÉp{Ç}pÅc/~ÉÑPJ@LtÅptÅ_/Å~u/tÅÑstr~Å_/tÇdJ|{ÄÇz~~{'    + 'LtrÅÑ~b/pÉpSJg^aTgn]^XcPadcRPULv~{pÉpR/{pxÉx}XJbca^_TaQTfLSX/ÅtÇ'    + 'dJtÑÅcL~u}X/àÉxÅÑrtb/ÉÇxÇÅt_JEDCQTfLsÅ~ÜÇÇp_J@=QST[^[`bLÅtsxÖ~Å_'); end;

And, fifteen lines of code later, there was this:

 function decodeit(thistext:string):string; var tempstr:string;     counter:word; begin    tempstr:='';    if length(thistext)>0 then    for counter:=length(thistext) downto 1 do       tempstr:=tempstr+chr(ord(thistext[counter])-15);     result:=tempstr; end;

Alexandre wasn't so thrilled any more.




Brought to you by the Non-WTF Job Board:




CodeSOD: Spaced Out

10 Apr 2009 13:00:00 | Alex Papadimoulis | CodeSOD | Comments

"While going through some old code," John Preston writes, "I found this interesting set of global variables."

 Private space1, space2, space3, space4, space5, _         space6, space7, space8, space9, space10, _         space100 As String

"Now, what might said variables be used for?" John continued, "Why clearly, they are space counts."

 Private Sub fillSpaces()     space1 = " "     space2 = "  "     space3 = "   "     space4 = "    "     space5 = "     "     space6 = "      "     space7 = "       "     space8 = "        "     space9 = "         "     space10 = "          "     space100 = "                                                  " + _                "                                                  " End Sub

"Considering we already have 11 variables full of spaces, and don't want to add any more, obviously the way to go was a new function to generate spaces for us as we need them! No need for silly pad functions of Spaces(#) or other such internal functions, who trusts those things after all?

 Private Sub GenerateSpaces(ByVal SpaceCount As Integer)     Dim i, count10, remCount As Integer          NumSpaces = ""          If (SpaceCount = 100) Then         NumSpaces = space100     Else         count10 = (SpaceCount \ 10)         remCount = (SpaceCount Mod 10)         For i = 1 To count10             NumSpaces = NumSpaces & space10         Next                  Select Case (remCount)             Case 1                 NumSpaces = NumSpaces & space1             Case 2                 NumSpaces = NumSpaces & space2             Case 3                 NumSpaces = NumSpaces & space3             Case 4                 NumSpaces = NumSpaces & space4             Case 5                 NumSpaces = NumSpaces & space5             Case 6                 NumSpaces = NumSpaces & space6             Case 7                 NumSpaces = NumSpaces & space7             Case 8                 NumSpaces = NumSpaces & space8             Case 9                 NumSpaces = NumSpaces & space9             Case Else         End Select     End If End Sub

"And finally," John added, "the code that actually used these functions looked like this, because, you know, you have to keep them guessing..."

 Call GenerateSpaces(19) Line = Line & "                  " Line = space4 Line = Line & "                  "



Brought to you by the Non-WTF Job Board:




Throw Some Hardware at it!

09 Apr 2009 15:00:00 | Mark Bowytz | Feature Articles | Comments

Thank you and please come again.The Sohcnum Family Convenience store chain knew two things about their fax-based price distribution process: it was extremely time consuming and completely un-cool. Managers at their twenty-eight locations absolutely hated having to write out, by hand and with a big marker, the hundreds of new price signs that came through every morning. It all seemed so unnecessary, especially considering that it was 1997 and "hi tech" was officially in. Plus, with their aspirations to grow the chain by impressing and attracting big investors, a whiz-bang price distribution system was a must-have.

Enter the Automated Sign System. With a shiny new UI on the frontend and a hulking Oracle server running on the backend, it would send data across the Internet to the individual stores for automated, overnight printing. In the morning, the managers would take the large stack of signs and hang them up around the store. All told, the corporate developers had created a system that generated consistently-formatted signage for all stores and saved a ton on labor costs. The managers also appreciated not having to arrive at 4:30am to write out a day's worth of signs.

So what was one thing that could improve upon this modern marvel? Application performance would have been an added plus.

Since the system had been thrown together in somewhat of a rush so that they could say to investors, "hey investors, we print our signs over the Internet and save a bundle doing it", performance was a bit slow. So much so that it would take a good two hours to consolidate the information for a day's worth of signs for a single store. They could eventually work on this, but in the meantime, when the dough from investors would start rolling in, they planned to just throw some additional hardware at the problem and run the print jobs in parallel.

"We'll get around to rewriting the thing," the IT manager would say, "One of these days."

Twelve Years Later...

Skip ahead twelve years, andthe once venerable Sohcnum Family Convenience Stores grew to over 2,000 stores and gained the more hip moniker of Flying S Convenience Stores. And recently, Scott, who worked in the corporate headquarters, had been given a task of truly great magnitude: improve the performance of the Automated Sign System.

By this point, the application's performance wasn't just hurting, it was bleeding. As the number of stores grew, so did the data set. In fact, it had grown so large that, even with processing split across twenty-four physical servers, it took nearly fifteen hours to create a day's worth of signs.

It turned out that, all the while, the corporation found it simpler (read:cheaper) to just keep adding hardware whenever they needed to scale up their printing needs. Sure, there was some maintenance here and there for Y2K and the occasional bug or upgrade, but for the most part, the now-legacy VB application was still puttering away on 21st century hardware. Hardware that was due to go off-lease in three months.

Migrating the software to a new server, surprisingly, wasn't that big of a deal. But what WAS a deal was that the Flying S big wigs were planning on acquiring and integrating a smaller, 400-store competitor in the next year. Hoping that they could continue to use the application with the additional stores, management turned to Scott for help.

Peeling Back the Wallpaper

During his investigation of how the system worked, Scott was surprised to find that the process of creating the actual sign was pretty simple stuff: roll through a list of signs generated from a SQL query, render a TIFF of each sign, then make a Batch for the printer and print them.

Scott also found that the vast majority of the signs in stores were the same across different markets. For example, something like a box of tissues for $1.50 or a bottle of anti-freeze for $7.00 is the same price everywhere. Unless, of course, the store is in Canada where a third-party module would do the US-to-Canadian dollar conversion.

However, even though there were so many common items, the software would still scroll through every sign record for every store within the company. Immediately spotting a point to improve, Scott got to thinking "Why hadn't the original developers used a unique identifier for each generated sign? That way, the system wouldn't have to regenerate the same TIFF over and over, and things would have been more efficient from the start."

Funny thing was that the original developers did include a unique identifier...mostly.

Chicken or the Egg?

Scott noticed that, after a TIFF was created, it passed through a fairly complex hashing function to generate a 64-byte long "ImageHash", which was then used as the TIFF's unique identifier. Oddly enough, the hashing function seemed to be tied to server's MAC address: given the exact same data, one server would consistently produce the same ImageHash while another would consistently produce a different ImageHash.

After realizing this, Scott knew what he had to do. Surely he could improve performance by tweaking the hashing function to produce consistent results, which would allow the servers to share what TIFFs were created, so that they wouldn't have to keep creating the same TIFF over and over again.

"Waitaminute," he thought, "You don't know what the ImageHash of a sign is until AFTER the TIFF has been created." Realizing that the Hash Generator paradoxically created the very condition that it was helping to solve did nothing but give Scott an even greater headache than he had already received after pouring through enterprise-level VB5 code.

In the end, Scott weighed the level effort it would take for a complete rewrite against just throwing more hardware against the application. Since management had said time and time again that the application DID work, Scott ended up suggesting top-of-the-line systems to replace the off-lease ones. His only hope was that, one day, a server would be released that would not be capable of running the old VB 5 code, and could therefore end the viscous cycle.




Brought to you by the Non-WTF Job Board:




Error'd: #NO DATA

09 Apr 2009 12:00:00 | Alex Papadimoulis | Error d | Comments

"While walking around Baltimore," Neal notes, "I came across a ticker that had one news story that didn't seem complete."

 

"When precision is lost," Thomas Bounds writes, "accuracy is sometimes next to follow."

 

"I received this while browsing some website," writes Ian R, "I can only assume that my web browser has a funny accent, or that it needed a different kind of 100-continue."

 

"I tried to delete a module on our Cincom Socrates platform," Christian Riis wrote. "I don't know why I couldn't do it and the server wasn't much help."

 

"Hmmm," Jerry A wonders, "I'm not sure my disc will get back to them with this."

 




Brought to you by the Non-WTF Job Board:




The SQL Guru

08 Apr 2009 13:00:00 | Alex Papadimoulis | Feature Articles | Comments

“Really!?” Warren was stunned. “They went with us? What’s wrong with them? Why on earth would they have done that!?”

Warren had a good reason to be skeptical. While his employer, Aderrific, was one of the region’s top advertising agencies, they weren’t exactly known for building Customer Relationship Management systems. Yet, their largest client – a major soft drink company famous for a certain challenge – had retained Aderrific to do just that.

“I guess our price was right,” Warren’s fellow developer said. “Either way, I’m sure we’ll be able to build them something decent. Or, at the very least, something decent on the ‘first-ever-attempt-at-anything-that-resembles-CRM’ scale.”

Though Warren and his colleague had raised concerns about the project long ago, they were largely ignored by management. After all, Aderrific wasn’t in the business of turning down business, especially when that business paid very well. Their programming team of two would just have to deal… and build a working CRM system, of course.

Building it Out

Fortunately, Warren did have a fair amount of experience building database-backed applications and had worked with enough clients to feel comfortable gathering software requirements. He also knew that their existing tools – Microsoft Access for simple internal applications and Perl/MySQL for client websites – probably weren’t the best fit. Java, having just celebrated its fifth anniversary, seemed to be the right choice for application development, while Oracle (which their customer already had) was the logical choice for the database.

After feverously trying to climb as many learning curves as possible, Warren and his coworker spent the next few months designing, developing, and implementing the CRM application. One decision they made early on was that, above all else, data integrity was critical. No matter how many bugs or oversights made it into the application, so long as the database was chock-full of constraints, their data would be valid.

One of the key tables in the CRM database was the users table (named “usr”). As the name implies, it contained all the relevant information for a user of the CRM system. The most important column in the table was the user’s email address, as that was used as a login and served as the only method for contacted users of the system. As such, the column had a UNIQUE constraint defined and a rather sophisticated CHECK constraint to make sure the value at least resembled an email address.

The Launch

When their CRM system eventually went live, it had its share of issues. It was a little slow, a little confusing, and a little shy on features, but it worked well enough. One exceptionally annoying bug, however, was the fact that users just couldn’t seem to understand how to write out their email address. A quick peek in the users table revealed many failed attempts: jdoe@www.anyco.com, jdoe.www@, anyco@anyco.jdoe, anyco@www.com/jdoe.

Fortunately, Warren’s boss had the perfect solution for their launch woes: Aderrific would bring on a SQL Guru to review the design, suggest improvements, and recover the countless invalid email addresses from the data. Sure, it was a little late, but it was definitely better than never.

The SQL Guru Delivers

The good news was that, after the consultant spent a few days analyzing and tweaking the database, no further changes were needed. Amazingly, Warren and his fellow developer had done such a bang-up job developing the CRM system.

The bad news, however, was the application had even more bugs than before. Upon further investigation, Warren found that there were two rows in the user table with the same email address. Worse still, neither of those email addresses were formatted even remotely correct.

Warren figured that the database must have somehow been damaged while the SQL Guru optimized things, as there were two different constraints that would prevent this situation from occurring.

“That’s simply not possible,” the SQL Guru procalaimed when Warren explained some of the bugs the application was having, “I hardly touched the database. It must be your application code.”

Not quite convinced, Warren decided to dig a little further. Since all SQL*Plus sessions were logged, he decided to look there. Following is what he came dug up.

<... snip ...>
SQL> select email from crmadmin.usr
 2 change column email www.j.doe@anyco.com / j.doe@anyco.com;
change column email www.j.doe@anyco.com / j.doe@anyco.com;
       *
ERROR at line 2:
ORA-00933: SQL command not properly ended
SQL> select email from crmadmin.usr
 2 change crmadmin.usr.emailwww.j.doe@anyco.com / j.doe@anyco.com
 3 ;
change crmadmin.usr.emailwww.j.doe@anyco.com / j.doe@anyco.com
       *
ERROR at line 2:
ORA-00933: SQL command not properly ended
SQL> select email from crmadmin.usr
 2 change email www.j.doe@anyco.com/j.doe@anyco.com
 3 ;
change email www.j.doe@anyco.com/j.doe@anyco.com
       *
ERROR at line 2:
ORA-00933: SQL command not properly ended
SQL> update crmadmin.usr.email
 2 change www.j.doe@anyco.com/j.doe@anyco.com;
update crmadmin.usr.email
                   *
ERROR at line 1:
ORA-00971: missing SET keyword
SQL> update crmadmin.usr.email
 2 set www.j.doe@anyco.com/j.doe@anyco.com;
update crmadmin.usr.email
                   *
ERROR at line 1:
ORA-00971: missing SET keyword
SQL> update crmadmin.usr.email
 2 change www.j.doe@anyco.com set j.doe@anyco.com;
update crmadmin.usr.email
                   *
ERROR at line 1:
ORA-00971: missing SET keyword
SQL> update crmadmin.usr.email
 2 set www.j.doe@anyco.com set j.doe@anyco.com;
update crmadmin.usr.email
                   *
ERROR at line 1:
ORA-00971: missing SET keyword
SQL> update crmadmin.usr set email
 2 www.j.doe@anyco.com set j.doe@anyco.com;
www.j.doe@anyco.com set j.doe@anyco.com;
*
ERROR at line 2:
ORA-00927: missing equal sign
SQL> update crmadmin.usr set email
 2 www.j.doe@anyco.com = j.doe@anyco.com;
www.j.doe@anyco.com = j.doe@anyco.com;
*
ERROR at line 2:
ORA-00927: missing equal sign
SQL> update crmadmin.usr set email = www.j.doe@anyco.com = j.doe@anyco.com;
update crmadmin.usr set email = www.j.doe@anyco.com = j.doe@anyco.com;
                                                    *
ERROR at line 1:
ORA-00927: SQL command not properly ended
SQL> update crmadmin.usr set email = www.j.doe@anyco.com/j.doe@anyco.com;
update crmadmin.usr set email = www.j.doe@anyco.com/j.doe@anyco.com;
                                                          *
ERROR at line 1:
ORA-02019: connection description for remote database not found
SQL> update crmadmin.usr set email = 'www.j.doe@anyco.com'/'j.doe@anyco.com';
update crmadmin.usr set email = 'www.j.doe@anyco.com'/'j.doe@anyco.com';
                                *
ERROR at line 1:
ORA-01722: invalid number
SQL> pdate crmadmin.usr set email = 'www.j.doe@anyco.com' to 'j.doe@anyco.com';
SP2-0734: unknown command beginning "pdate crma..." - rest of line ignored.
SQL> update crmadmin.usr set email = 'www.j.doe@anyco.com'to 'j.doe@anyco.com';
update crmadmin.usr set email = 'www.j.doe@anyco.com'to 'j.doe@anyco.com';
                                                     *
ERROR at line 1:
ORA-00933: SQL command not properly ended
SQL> update crmadmin.usr set email 'www.j.doe@anyco.com = 'j.doe@anyco.com';
ERROR:
ORA-01756: quoted string not properly terminated
SQL> update crmadmin.usr set email =
 2 where email = 'www.j.doe@anyco.com;
ERROR:
ORA-01756: quoted string not properly terminated
SQL> update crmadmin.usr set email = j.doe@anyco.com
 2 where email = 'www.j.doe@anyco.com;
ERROR:
ORA-01756: quoted string not properly terminated
SQL> update crmadmin.usr set email = 'j.doe@anyco.com'
 2 where email = 'www.j.doe@anyco.com;
ERROR:
ORA-01756: quoted string not properly terminated
SQL> update crmadmin.usr set email = 'j.doe@anyco.com';
update crmadmin.usr set email = 'j.doe@anyco.com';
*
ERROR at line 1:
ORA-00001: unique constraint (CRMADMIN.UN_USR_EMAIL) violated
SQL> l
 1* update crmadmin.usr set email = 'j.doe@anyco.com'
SQL> /
update crmadmin.usr set email = 'j.doe@anyco.com';
*
ERROR at line 1:
ORA-00001: unique constraint (CRMADMIN.UN_USR_EMAIL) violated
SQL> l
 1* update crmadmin.usr set email = 'j.doe@anyco.com'
SQL> update crmadmin.usr set email = 'j.doe@anyco.com'
 2 where email = 'www.j.doe@anyco.com;
ERROR:
ORA-01756: quoted string not properly terminated
SQL> update crmadmin.usr set email = 'j.doe@anyco.com'
 2 where email = "www.j.doe@anyco.com";
where email = "www.j.doe@anyco.com";
              *
ERROR at line 2:
ORA-00904: invalid column name
SQL> l
 1 update crmadmin.usr set email = 'j.doe@anyco.com'
 2* where email = "www.j.doe@anyco.com"
SQL> update crmadmin.usr set email = 'j.doe@anyco.com'
 2 where usr.email = "www.j.doe@anyco.com";
where usr.email = "www.j.doe@anyco.com";
                  *
ERROR at line 2:
ORA-00904: invalid column name
SQL> update crmadmin.usr set email = 'j.doe@anyco.com'
 2 where usr.email = 'www.j.doe@anyco.com';
1 row updated.
<... snip ...>
SQL> update usr set email =
 2 'www.%com' where email like 'www.%com';
update usr set email =
*
ERROR at line 1:
ORA-00001: unique constraint (CRMADMIN.UN_USR_EMAIL) violated
SQL> alter table usr
 2 disable constraint CRMADMIN.UN_USR_EMAIL;
disable constraint CRMADMIN.UN_USR_EMAIL
                           *
ERROR at line 2:
ORA-00933: SQL command not properly ended
SQL> alter table CRMADMIN.USR
 2 disable constraint CRMADMIN.UN_USR_EMAIL;
disable constraint CRMADMIN.UN_USR_EMAIL
                           *
ERROR at line 2:
ORA-00933: SQL command not properly ended
SQL> ALTER TABLE USR
 2 disable constraint UN_USR_EMAIL;
Table altered.
SQL> update usr set email =
 2 'www.%com' where email like 'www.%com';
update usr set email =
*
ERROR at line 1:
ORA-02290: check constraint (CRMADMIN.CK_USR_EMAIL) violated
SQL> ALTER TABLE USR
 2 disable constraint CK_USR_EMAIL;
Table altered.
SQL> update usr set email =
 2 'www.%com' where email like 'www.%com';
240 rows updated.

It was only the tip of the iceberg. Somehow, the SQL Guru had taken their CRM system – which did, at one point, rate very high on the first-ever-attempt-at-anything-that-resembles-CRM scale – and brought it near the bottom of that bell curve. Tried as they did, Warren and his fellow develop were never quite able to bring it back.

After that project, Aderrific decided to stick to advertising. And fortunately, they haven’t looked back in the nine years since.




Brought to you by the Non-WTF Job Board:






Subscribe | Retrun to feeds | Users subscribed: 3 | Last Updated: Apr 24 2009, 14:18:49To top



 



Sign in to NewsAlloy
E-mail 
Password 
  Remember me 



News Alloy © Copyright 2005 - 2008 Mobispine AB. All Rights Reserved.

buy clomid buy zithromax buy cheap celexa buy cheap cymbalta buy naltrexone purchase finasteride purchase sildenafil citrate cheap tadalafil