Error'd: amp, #039 and a0B30000004la04EAA& ...
"I saw this on my way home from work," Daniel Moore writes, "thank goodness CVS is doing something about Maryland's crippling shortage of whooping cough!"
"While trying to learn Open Bravo," writes Otmane Malih, "I learned that there are countries I've never heard of."
"My university has a site license of Mathematica for all Mathematics and Physics students," Simon Hollingshead wrote, "when trying to view some information about the license key, I got this message. Not to worry, it can go in my binder named 'Error messages from various websites'."
"Woah, bad password," wrote Micah, "that's cool man."
"Now that's a lot of readme," writes Frank de Weger.
"I was filling out a satisfaction survey after buying a new car," writes Jeremy Hutchinson, "even the optional questions required an answer."
"This is from a well-known vendor of libraries," writes Adrian Edmonds, "what to do next is a bit of a puzzle."
"This Mongolian ATM had a rather unique way to notify that it could not print a receipt," writes Matthew Asquith.
CodeSOD: The Percent Conversion ...
"Lucky me," writes Joe from the Submit-To-WTF Visual Studio Add-In, "I just inherited a home-grown system information application."
"Judging from the code the previous programmer wrote, this is sadly one of the better pieces."
Public ReadOnly Property BatteryPercent()
' This code will retrieve the BatteryLifePercent property and convert it to a percent.
Get
If SystemInformation.PowerStatus.BatteryLifePercent.ToString = "1" Then
Return "100%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.99" Then
Return "99%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.98" Then
Return "98%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.97" Then
Return "97%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.96" Then
Return "96%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.95" Then
Return "95%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.94" Then
Return "94%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.93" Then
Return "93%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.92" Then
Return "92%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.91" Then
Return "91%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.9" Then
Return "90%"
'...
'snip
'...
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.2" Then
Return "20%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.19" Then
Return "19%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.18" Then
Return "18%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.17" Then
Return "17%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.16" Then
Return "16%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.15" Then
Return "15%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.14" Then
Return "14%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.13" Then
Return "13%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.12" Then
Return "12%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.11" Then
Return "11%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.1" Then
Return "10%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.09" Then
Return "9%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.08" Then
Return "8%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.07" Then
Return "7%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.06" Then
Return "6%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.05" Then
Return "5%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.04" Then
Return "4%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.03" Then
Return "3%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.02" Then
Return "2%"
ElseIf SystemInformation.PowerStatus.BatteryLifePercent.ToString = "0.01" Then
Return "1%"
Else
Return "NA"
End If
End Get
End Property
Announcements: Code PaLOUsa 2012 ...
Last year's Code PaLOUsa (held in downtown Louisville) was a blast, and it was great to meet up with some of you guys who were able make it out. I'm definitely excited about Code PaLOUsa 2012; there's a lot of great speakers, and it's right in the heart of bourbon country.
My Talk — Ugly Code: Beauty is in The Eye of the Beholder
It's said that without evil there can be no good and that without darkness, there can be no light. Is the same true of ugly and beautiful code? Maybe... but that's certainly not a question I'll be answering in this talk. Instead, we'll talk about ugly code, where it comes from, how to avoid it, and how to rid your codebase of it. And of course, I'll share some of my favorite anti-examples from The Daily WTF.
The TDWTF Discount + Bonus!
How about a $50 discount? If you register before Febuary 21st, it will only cost you $200 (instead of $250) using discount code TDWTF at checkout. Not only that, but you'll also get one of the elusive The Daily WTF mugs.
About Code PaLOUsa
Code PaLOUsa is a three-day software development conference that covers all aspects of software development regardless of technology stack. The first day consists of hands-on workshops, followed by two-days of ten different development tracks:
- Cloud - All things about the cloud, including the who, what, where, when, why, and how about cloud computing
- Mobile - All things mobile - platforms, devices, content distribution, social networking, community building, and anything else used in conjunction with those devices which have small screens
- Web Development - Web services, Ajax frameworks, and all things related to the browser
- Methodologies - Anything pertinent to how modern development methodologies help build software faster, cheaper , and better
- Languages - Discussions on what's new and cool in software development languages such as C#, Java, PHP, Python, Ruby, Visual Basic, etc.
- Entrepreneur - Envision MDM Strategy as Part of Broader Information Strategy to Treat Information as Corporate Asset
- Desktop Development - Standard applications, fat/smart client, client/server, and all things running local on Windows, Mac, or Linux
- Architecture - SOA, W3C standards, WS* implementations, interoperability, and all things 30,000 feet or higher
There will be 62 technical presentations and panel discussions from well-known professionals in the software development community and two keynote talks from Billy Hollis and Jim Benson.
Save the Project for Failure ...
If it takes two contract developers six months to drive a project to failure, then four developers should be able to fail in half the time! Josh assumed that was why he and Sam were carted out to the client site and tossed into the oubliette of the PowerPac project. They were armed with nothing but a rusty spoon and a requirements document so old it needed to be stored in an oxygen-free environment.
The original development pair was Sally "I can code but I'm more of a designer" Jorgensen (the CEO's daughter) and Billy "I taught myself HTML in a week and am now a programmer" Jorgensen (the CEO's brother). They ran the project exactly like you'd expect such a dynamic duo to run it- directly into the ground. By the time Josh and Sam joined, it was already well past deadline and over budget.
To make a good impression on the client, Billy and Sally didn't work out of the consulting firm's office, but instead moved to the client site. The pair had improvised a server room to work out of. It could be easily distingushed from a broom closet by the piece of duct tape with "SEVER ROOM" sharpied onto it. Inside, an overheating rackmount server balanced on a crate of toilet paper. On a sagging plastic card table sat the developer workstation running VS2005, which doubled as their source control box, since it ran Visual Source Safe.
Josh thought their physical environment was bad, and then he looked at their application. Billy, it seemed, had read one website on database design and walked away with the idea, "if normalizing data across tables is good, normalizing it across databases bust be even better!" Their wheezing Sql Server instance hosted a dozen databases, one for each entity and an extra DB to hold tblIncrementingIDs(strCurrentID VARCHAR(50)), so that unique IDs could be consistent across all of these databases.
The first and last thing Josh noticed about the web code was the fact that each page had a multi-megabyte ViewState. Coupled with terrible coding practices, Josh and Sam junked the VSS repo and then started laying out a plan to rescue the application. They moved the dev team back to the consulting firm's main office, where they had a true development environment, complete with modern dev tools and a well administered TFS2010 instance, along with labs for automated testing. They rounded up people from the client and pinned them down on requierments. They beat Billy and Sally about the head and shoulders with three-tiered architecture until the two of them got it, and proceeded to wrench the project back onto course.
Four months later, Josh and Sam had accomplished the impossible- twice. They had gotten Billy and Sally to turn out code that wouldn't flunk a 100-level college course. The slighly less impossible achievement was that they had turned the project around. It went from "this is never going to be finished" to "it's late, overbudget, but we're within striking distance of an actual deliverable product." They were on track to deliver in two more months.
This kind of success on a project draws accolades and back-pats and lunches paid for by the consulting company for a job well done. It also draws something far more sinister: project managers who want to steal that glory for themselves. Doug, from the client-site, was exactly that kind of project manager. In the closing months of the project, he swooped in with the promise to manage the hell out of this project and keep it on track.
Doug did everyone the favor of standardizing the process. The QA Officer (Doug) had to approve any code before it could be checked into source control. The Compliance Officer (Doug) needed a report of every file modified before any build could be run, down to the specific line numbers changed. He couldn't just extract this information from TFS because, "It's part of the developer's job!"
Only the Build Officer (Doug) could kick off a new build, and not using TFS (a developer tool). Doug would run builds from his own computer, and if he forgot to perform a Get Latest to ensure he had all of the changes, well, that was the developer's problem. They should have followed the communication plan.
Josh protested and escalated and did all of the things you're supposed to do when someone's tanking your project, but to no avail. He couldn't understand how Doug was getting away with this until he sat in on Doug's status meeting. Doug had compiled a PowerPoint full of pretty graphs and dashboards showing nothing but green boxes. He used words like synergy, Agile, "code coverage", "core principles" and "industry standard best practices". It was entirely fabricated nonesense, but management swallowed every drop.
When they didn't hit Josh's original target dates, the money officially ran out. The project was cancelled, and the client informed the consulting company that Josh and his team should never be assigned to one of their projects again. Doug got transferred to another "at risk" project for the client, so that he could "save" it.
CodeSOD: The .NET Whistleblower ...
Terry had spent the better part of the past decade digging through the trenches of QuidCorp's flagship application QuidFlow -- a program used to flowchart business processes. Though QuidFlow performed well and, overall, customers were happy with the product, whenever it came time to address a bug or investigate just how the filename validation worked; the source code was beginning to show its age.
Terry raised his concerns to management. Much to his surprise, management approved a plan to transition their C++ developers into the world of .NET through a little on-the-job experience.
Homemade with Love
Paired up with a senior programmer who had been working on QuidDoc, an ASP.NET document control app written in VB.NET, Terry was handed some completed quality assurance (QA) test plans.
"Don't stress yourself out trying to figure out how to solve every problem just yet," the senior programmer advised, "really just get yourself versed in how to check the code out, compile it and poke around a bit."
The application refused to start and when Terry eventually managed to get it going, exceptions were thrown all over the place by the runtime environment when he tried to run the application on his local machine.
Throughout the codebase, there was one section of code common to all the pages. Sharing common code is a great thing -- Terry had employed a similar method in C++. However, in this one module, above all others, there was something funny about how it all worked.
Not in Kansas Anymore
First of all, in his old role functions returned a meaningful value. However, littered through QuidFlow were functions, which always returned the same value of False, whether they were completed successfully or not:
Function UnLockRecord(strTableName) As boolean
if strTableName = "" then
strSQLText = "DELETE FROM LOCKINFO
WHERE PERSNO=" & SQLQuote(session("LOGGEDUSER"))
Else
strSQLText = "DELETE FROM LOCKINFO
WHERE TABLENAME = " & SQLQuote(strTableName) & " AND PERSNO=" & SQLQuote(session("LOGGEDUSER"))
End If
ExecSQL(strSQLText)
Unlockrecord = false
End Function
Function SystemInfoClear() As boolean
ExecSQL("DELETE FROM SYSTEMINFO")
SystemInfoClear = False
End Function
It was widely known that QuidFlow would kick back strange and frightening messages when things went horribly wrong. As such, Terry could appreciate why a developer would want to shield a division by zero error or a similar condition from a user. However, this feeling of appreciation was reversed somewhat after seeing two similarly named functions immediately thereafter.
Though he wasn't even remotely close to being able to call himself a Web developer, Terry felt that there had to be an easier way of rendering the HTML at the top of each page:
if cSYS_NONAVFRAME<>"1" Then
response.write("<script language=Javascript>" & Chr(13) & Chr(10))
response.write("if (top.location == self.location) {" & Chr(13) & Chr(10))
if Session("NAV_TOP") Then
response.write("document.write('<html><head><title>"
& session("WINDOWTITLE") & "</title></head>')"
& Chr(13) & Chr(10))
response.write("document.write('<frameset ID=QUIDPROFRAME
rows=" & Chr(34) & "0,25,*" & Chr(34) & " cols=" & Chr(34)
& "*" & Chr(34) & ">');" & Chr(13) & Chr(10))
response.write("document.write('<frame id=USERDEFINEDFRAME
framespacing=0 frameborder=0 border=0 name=USERDEFINEDFRAME>');"
& Chr(13) & Chr(10))
response.write("document.write('<frame id=NAVFRAME
framespacing=0 frameborder=O border=0 name=NAVFRAME >');"
& Chr(13) & Chr(10))
response.write("document.write('<frame id=MAINFRAME
framespacing=0 frameborder=O border=0 name=MAINFRAME>');"
& Chr(13) & Chr(10))
response.write("document.write('</frameset>');"
& Chr(13) & Chr(10))
response.write("document.write('</html>');"
& Chr(13) & Chr(10))
response.write("parent.USERDEFINEDFRAME.location='"
& application("SYS.QUIDPROROOT") & "basetable/general/userframe.aspx';"
& Chr(13) & Chr(10))
response.write("parent.NAVFRAME.location='" & application("SYS.QUIDPROROOT")
& "navigator/top/topnavigation.aspx';" & Chr(13) & Chr(10))
response.write("parent.MAINFRAME.location='" & strRealPage
& "';" & Chr(13) & Chr(10))
Else
response.write("document.write('<html><head><title>"
& session("WINDOWTITLE") & "</title></head>');" & Chr(13)
& Chr(10))
response.write("document.write('<frameset ID=QUIDPROFRAME rows="
& Chr(34) & "0,*,25" & Chr(34) & " cols=" & Chr(34) & "*" & Chr(34)
& ">');" & Chr(13) & Chr(10))
response.write("document.write('<frame id=USERDEFINEDFRAME
framespacing=0 frameborder=0 border=0 name=USERDEFINEDFRAME >');"
& Chr(13) & Chr(10))
response.write("document.write('<frame id=MAINFRAME
framespacing=0 frameborder=O border=0 name=MAINFRAME >');"
& Chr(13) & Chr(10))
response.write("document.write('<frame id=NAVFRAME
framespacing=0 frameborder=O border=0 name=NAVFRAME >');"
& Chr(13) & Chr(10))
response.write("document.write('</frameset>');"
& Chr(13) & Chr(10))
response.write("document.write('</html>');"
& Chr(13) & Chr(10))
response.write("parent.USERDEFINEDFRAME.location='"
& application("SYS.QUIDPROROOT") & "basetable/general/userframe.aspx';"
& Chr(13) & Chr(10))
response.write("parent.NAVFRAME.location='" & application("SYS.QUIDPROROOT")
& "navigator/bottom/bottomnavigation.aspx';" & Chr(13) & Chr(10))
response.write("parent.MAINFRAME.location='" & strRealPage & "';" & Chr(13) & Chr(10))
End If
response.write("}" & Chr(13) & Chr(10))
response.write("</script>" & Chr(13) & Chr(10))
End If
Whistleblow
Concerned that QuidCorp might actually ship something so fetid and maligned, Terry decided he had to pay a visit to QuidFlow's project manager.
"You're right, Terry, this is in no way a solid application, but unfortunately, it is what it is," the project manager explained. "However, that's why we're assigning all you C++ guys with your awesome track record to look into these bugs so we'll be able to ship QuidFlow!"
Somehow, the compliment didn't feel right. At the end of the week, Terry and his fellow QuidFlow developers were pulled from their on-the-job .NET training. QuidCorp had just sold a motherload of QuidFlow licenses to a corporate client and they were asking for some big-time enhancements, which would of course mean they needed all C++ developers on hand immediately.
While the move of QuidFlow to .NET was on hold until some time freed up, their hands-on .NET training wasn't all for nothing. When the time came, at least they would know how not to develop a .NET app.
The .NET Whistleblower was originally published in the December 2010 edition of Visual Studio Magazine. VSM is the leading site for enterprise .NET developers, and offers a free magazine subscription for influential readers.
Error'd: 19999 Below ...
"Mac OS X has an odd definition of gigabyte," writes Kevin Kelly.
"I saw this when on holiday to Barcelona," writes Greig Hamilton, "it was a huge screen on La Rambla, the busiest street in Barcelona"
Drake wonders, "just what would I be saying 'Yes' or 'No' to?"
"Well, apparently it actually is possible to get colder than 0 Kelvin," Dorian H, "and of course I'm right there."
"In the end," Mark wrote, "I just ended up spelling out 'thirteen'."
Bryan Scott writes "at least it doesn't charge me when they give me thanks for choosing Dell."
"I tried to resolve a simple bug submitted to our tracker," writes Michael, "and it clearly didn't appreciate the ease with which this bug was quashed."
Sketchy Skechers.com ...
Imagine yourself as an eager, young developer. After many long months of self-study, you’ve carefully honed your craft and have skillfully mastered virtually all development technologies from enterprisey to hipster. Your twelve-page résumé could land you a job anywhere, and as it would happen, the job you decided to take was at a highfalutin consultancy filled with like-minded developers who were almost as skilled as you.
You and you cohorts could build anything. Literally, anything: a software cure for cancer; a software cure engine that could dynamically load cure plug-ins at runtime to cure anything; or even a software engine factory that could dynamically create engines that could dynamically load plug-ins that could do anything.
And as it so happened, your virtually unbounded skillset was desperately needed to solve an otherwise unsolvable problem: build skechers.com. The requirements for the shoe company’s website were mind-bogglingly complex: retrieve product information from some enterprisey ERP system, format it prettily on the web, and let people place orders online.
Although no one in the history of software development had ever undertaken a project of such scale, you were prepared for anything. In fact, even before hearing what the website would be for, you had already spec’d-out the architecture: use XML-based XSL to transform server-generated XML into XHTML and JavaScript.
Hopefully now you can appreciate the mindset that the developer(s) of Skechers’ website must have had. Their masterpiece can be seen by a simple view-source of skechers.com:
That’s the XML data sent by the server when visiting http://skechers.com/. Your browser then spends a bit of time transforming into HTML and JavaScript using the following XSL:
While the idea of building a website like this in XML and then transforming it using XSL is absurd in and of itself, digging through the code is a treasure trove of WTF. I’m sure there are at least three levels of Hell that are more pleasant than having to maintain this JavaScript-generating XSL code:
<script type="text/javascript">
var skxProduct = {}; var skxStyle = '<xsl:value-of select="$style/@code"/>';
<xsl:for-each select="$style/product">
skxProduct['<xsl:value-of select="@color"/>'] = {
color: '<xsl:value-of select="@primary-color"/><xsl:if test="@secondary-color">
/ <xsl:value-of select="@secondary-color"/>
</xsl:if>',
images: [
<xsl:for-each select="media">
<xsl:sort data-type="number" select="@view"/>
<xsl:if test="position() < 7">
'<xsl:value-of select="@image"/>'
<xsl:if test="position() != 7">,</xsl:if>
</xsl:if>
</xsl:for-each>
],
inventory: [
<xsl:for-each select="sku">
<xsl:sort data-type="number" select="@pos"/>
{
size: '<xsl:value-of select="@size"/>',
<xsl:if test="@type">
type: '<xsl:value-of select="@type"/>',
</xsl:if>
stock: '<xsl:value-of select="@in-stock"/>',
<xsl:if test="@disc">
disc: '<xsl:value-of select="@disc"/>',
</xsl:if>
price: '<xsl:value-of select="@price"/>',
upc: '<xsl:value-of select="@upc"/>'
}
<xsl:if test="position() != last()">,</xsl:if>
</xsl:for-each>
]
};
</xsl:for-each>
</script>
I shudder at the thought of how labyrinthine the server-side code generating this must be.
I’ve preserved (well, after some indentation/formatting) some of the files for posterity. Just right-click download, then view in your favorite text editor for best experience.
I’m sure there’s plenty more fun examples to be found at all levels of skechers.com; feel free to share them in the comments or send them to me if you think they’d deserve an article of their own.
Tales from the Interview: The Storage Warehouse, The Most Ethical, and The Customizer ...
The Storage Warehouse (from Grig)
The first recession I remember was in the early 1990’s, and I remember it so well because I was looking for a job. The want ads listed an opening for a UNIX admin – something which was right up my alley – so I gave the company a ring.
“Ye-LLO!” was the greeting after a couple of rings. In the background, it sounded like John Philip Sousa March music was playing on a 1960s AM transistor radio.
“Um… I am calling about the want ad in the paper for a UNIX admin?”
“Yeah yeah, sure sure,” he responded enthusiastically.
After a long pause, I asked “is the position still available?”
“Uh nuh.”
Another long pause led me to ask “So it is?”
“Yah.”
“Would you like me to come in for an interview?”
“Nah, I can do it over the phone,” the sound of a chair squeaking came through the line and the music stopped playing, “Okay… I am looking for someone who can program UNIX. Also, has to know PASCAL pretty well. Processor design. Vast familiarity with X.25 protocol. Some BASIC, ALGOL, Lisp, Borland, relational databases, Lotus spreadsheets, VAX administration, PC repair, all those sorts of things. Oh, and also, have a degree in engineering and computer programming.”
“Um, really? Processor design? What kind of job is this?”
“Well, it’s an assistant manager of a storage warehouse.”
“You mean, like a data center?”
“No, no,” he chuckled, “self-storage. You know, like U-Haul and EZ-Storage.”
“So why would an assistant manager of a storage place need all those skills?”
“They don’t. I am just sick of getting dumbass applicants. I thought I’d raise the bar a little and only get smart college guys and the like.”
I didn't know what to say. I wished him well, and hung up. That ad was up for nearly a year in the want ads.
The Customizer (from D Lewis)
When I walked in for my interview, I saw that the receptionist was on the phone so I smiled at her to make my presence known and waited quietly near the back of the room. Looking around, I admired the outdated wallpaper falling off the walls and the non-framed artwork Scotch-taped to the wallpaper. I also couldn’t help but overhear the receptionist’s conversation; it definitely wasn’t business related.
“They better give me my raise,” she said with an attitude, “it’s been three years and I am well overdue.” A few moments later, “mmmkay, well I’ll talk to you later then, I gotta go anyway.”
The experience didn’t inspire a lot of confidence. Eventually, the receptionist let them know I had arrived and the development manager lead me to the board room. She boasted that the company made three million last year, and they were really on a growth path. As she described their application portfolio, she kept mentioning that they’re doing all of their work in Microsoft Access.
“But this is something you’re looking to move away from,” I said inquisitively, “as part of the expansion?”
“Oh no no,” she replied, “Microsoft Access is by far the best model for our company. Here, let me show you why.”
She then pulled out her laptop and navigated to a folder on her drive that had a hundred or so different Access databases. Each was for a different customer and was slightly customized to have proper label names, field names, form fields, etc. A large part of my job would be rolling out “product wide” features to each and every database.
“You know, a .NET-based solution using SQL Server would scale much better,” I explained, “you could use plug-ins, templates, or all sorts of things to keep each customer’s database unique but share a common code base.”
“Well,” she responded, “they already do, we just make sure to copy and paste the same module code across each database. Everyone’s familiar with it, so we’re sticking with Access.”
Shortly after that, the HR Manager walked to discuss other aspects of the job. When he opened up his briefcase, a Knife, Fork and Spoon fell out onto the table, making a loud clanking noise. “The cleaner has a habit of stealing silverware,” he quipped, “so, I tend to bring my own.”
By this point, I had decided there was no way I’d ever work at such a place. Of course, I was too shy to walk out, so I let the HR manager give his spiel.
“We have had a problem with people leaving prematurely,” he said, “so you would need to sign an agreement that you’ll work here for two years.”
I said nothing.
“But after that, we give great raises.”
The URL Rewriter (from Jon)
Despite overseas developers getting some bad press now and then, one has to feel sorry for the working conditions they must have to put up with. According to this guy's CV not only did he have to code on paper, but they also made him stand in for the web server some of the time.
Responsibilities: * Coding in C#.net (asp.net). * Written Java Script functions, bug fixing. * Url rewriting.
The Most Ethical (from Fred Rosenberger)
“We’re different than all the rest,” the smiling account manager at a recruiting agency told me, “we pride ourselves on being the most honest and the most ethical of all placement firms.” That same line was repeated by nearly everyone I met at the organization: the technical interviewer, the senior headhunter, and even the president himself.
They all seemed nice enough, but in a nice used car salesman sort of way. As we reviewed different job openings they were trying to fill, one in particular was seeking a candidate with an Electrical Engineering degree who had moved over into software.
“You mentioned that your father was an Electrical Engineering professor for thirty-five years, right?”
I nodded, not sure where that was going.
“Well, I’m sure in all those years you learned a thing or two about Electrical Engineering? I mean, how could you not with your father talking about it so much.”
I furrowed my brow a little bit.
“Let’s figure out a way to get your father’s experience in Electrical Engineering on your resume – that’ll certainly get you past HR and score an actual interview.”
I almost laughed out loud. Not wanting to get in an argument with them, I made some excuses that I didn’t want to drive that far. In retrospect, they still may have been the most honest and the most ethical of all placement firms.
CodeSOD: Globally Coupled ...
"I work on a team maintaining a large and enterprisey PHP system," writes Amber, "and as such, my job mostly involves doing enhancements and fixing bugs."
"It sounds normal enough, if not for the fact that almost all variables are globals and each of them might or might not be initialized in the same way, or the same place, as seen in this screenshot."
"That's tolerable, but the real problem arises when I need to reuse a function in a different location. I've added line breaks and formatting to make some sense of things..."
global $dbCon;
$dbCon->InitOpen($cf_db, 'db1');
.... snip a few hundred lines ....
function getRanking () {
global $dbCon, $dbCon_test, $dbCon2, $cf_db;
include '../rtuser/rtutil.php';
$dbCon_test->
InitOpen($cf_db, 'db2');
..... snip ....
/* rt_rank() requires $dbCon as db connection to testdb
* in this context, $dbCon currently points to Db1 thus
* temporarily pointing $dbCon to testdb is necessary (fred)
*/
$tempdbConDb1 = $dbCon;
//assign $dbCon_test to $dbCon to have testdb connection
$dbCon = $dbCon_test;
$memcacheKey = 'hof_ranking_' . $cntr . ':' . $offset;
//call rtutil.php's getrtRank()
// cache db r in memcache for 5 minutes
$r = unserialize(getMemCache($dbCon2, $memcacheKey, '5 minute', 'getrtRank', $args));
//swap back $dbCon so that the code relying on $dbCon pointing to Db1 won't be affected
$dbCon = $tempdbConDb1;
include '../rateuser/rateutil.php';
... snip ...
/* rate_rank() requires $sql as db connection to testdb
* in this context, $sql currently points to gm thus
* temporarily pointing $sql to testdb is necessary (fred)
*/
$tempSqlGm = $sql;
//assign $sql_test to $sql to have testdb connection
$sql = $sql_test;
$memcacheKey = 'hof_ranking_' . $cntr . ':' . $offset;
//call rateutil.php's getRateRank()
$result = unserialize(getCacheInfo($sql2, $memcacheKey, '5 minute', 'getRateRank', $args));
list($uidlist, $nicks, $votes, $imageIds, $genders) = $result;
//swap back $sql so that the code relying on $sql pointing to gm won't be affected
$sql = $tempSqlGm;
//....
}
Amber continues, "what happened here was that, in file A, a global database link identifier pointed to database 1 but in the include file B, the same variable was supposed to point to database 2. What I did was to swap out the link identifier whenever a function in file B was involved, then swap back whenever a function in file A was involved. Injection was not an option as the Globals were so deeply and variably coupled that decoupling them needs to be done on a case-by-case basis. And that was just one place...
Error'd: Sponsor Appreciation, SQL Scourge, and More Error'd ...
We've got some great companies that sponsor The Daily WTF. And all they ask in return... just take a moment or two to check out what they do. It's some pretty cool stuff.
TDWTF Sponsors
SingleHop Cloud Instances 98% off - Design, deploy and manage your cloud instance on the public cloud for only $1 for your 1st month (normally $50/month!) Use your Cloud Instnace to test new code, experiment with new software or gain extra development time...it's your choice! Try it today with coupon code "CLOUD1". New Relic is basically a magical, real-time performance and user monitoring tool that works on virtually any web platform: Java, Ruby, PHP, .net, Python, Ruby on Rails. I'm not sure how it works (magic?), but it's incredibly easy to use and is pretty inexpensive. Remember: performance is a must-have feature! Monetate - their testing, targeting and personalization platform for online retailers is used on leading websites like Best Buy, Sports Authority and Urban Outfitters. If you’re a problem-solver who is passionate about rich web applications, scaling Internet applications to billions of page views, and working with big data, then you’re a perfect fit for our close-knit and agile team.! Inedo - the makers of BuildMaster, the free, and easy-to-use, web-based deployment and release management tool. Going far beyond Continuous Integration, BuildMaster delivers a series of robust features unparalleled by other build-promote-deploy-distribute tools. Oh, did I mention it's free? Amazon DynamoDB - is a fully managed NoSQL database service that provides fast and predictable performance with seamless scalability. With a few clicks in the AWS Management Console, you can launch a new Amazon DynamoDB database table, scale up or down request capacity for the table without downtime or performance degradation, and gain visibility into resource utilization and performance metrics.
And now for our regularly scheduled program...
"When filling out a web health assessment, I'm pretty sure I didn't mention the scourge of %_SQL_TEXT that runs in my family," writes Josh Ward, "it's an embarrassing condition, to be sure!"
"I knew Ikea carried a lot of stuff, but a Petabyte is bigger than I expected," Nero Imhard, "still, I waited until I was within WiFi reach before proceeding."
"I got this while trying to start DBArtisan," writes Willy, "is it telling me or asking me?"
"I read that the HTC Thunderbolt has great download speeds but poor battery life," Andrew writes, "but I noticed that the clocks are a little out of sync. Maybe I can find an app that syncs both clocks to the correct time."
Erkki Laite found this in his local paper, the Finnish Turun Sanomat on 02.11.2011.
Jim Moyle spotted this on the front page of booking.com.
"I guess if someone at the mall searched to find where multi(0)disk(0)rdisk(0)partition(1) was, the directory would have been correct," writes Darin Rousseau.
CodeSOD: Pluralized! ...
"When digging through some code that was on the refactor list, I came accross some validation logic that checks if the user selected enough options on the form," writes Chris Osgood, "if enough options weren't selected, you'd get an error message along that said something like 'at least 3 options are required'."
"It took a little bit of coding to get that validate message. The '3' was obviously dynamic, and if there was only one missing selection, then 'are' was replaced with 'is'. As for the word 'option'...it was is PLURALIZED!"
/// <summary>
/// Changes a singular string to plural e.g. "Monkey" => "Monkeys".
/// </summary>
/// <param name="text">The text to PLURALIZE!</param>
/// <returns>A plural string.</returns>
public static string Pluralize(string text)
{
if (text.Length == 0)
{
return text;
}
string result = text;
if (result.Equals("sheep", StringComparison.OrdinalIgnoreCase))
{
return "sheep";
}
else if (result.Equals("leaf", StringComparison.OrdinalIgnoreCase))
{
return "leaves";
}
else if (result.Equals("thief", StringComparison.OrdinalIgnoreCase))
{
return "thieves";
}
else if (result.Equals("potato", StringComparison.InvariantCultureIgnoreCase))
{
return "potatoes";
}
else if (result.EndsWith("y", StringComparison.InvariantCultureIgnoreCase) &&
!result.EndsWith("ey", StringComparison.InvariantCultureIgnoreCase))
{
// Don't pluralize "by"
if (result.Length > 2 && !result.EndsWith(" by", StringComparison.InvariantCultureIgnoreCase))
{
result = result.Truncate(result.Length - 1) + "ies";
}
}
else if (result.EndsWith("us", StringComparison.InvariantCultureIgnoreCase))
{
// http://en.wikipedia.org/wiki/Plural_form_of_words_ending_in_-us
result += "es";
}
else if (result.EndsWith("x", StringComparison.InvariantCultureIgnoreCase))
{
result += "es";
}
else if (!result.EndsWith("s", StringComparison.InvariantCultureIgnoreCase))
{
result += "s";
}
return result;
}
Chris continued, "naturally, this was the only usage of this otherwise highly useful function. We could have easily utilized this function to pluralize things like foots, tomatos, boies, wifes, and etc.!"
Support The Daily WTF in Supporting the Support SOPA Movement ...
It’s January 18, 2012 and, while most of the internet has decided to blackout their sites in opposition to the Stop Online Piracy Act (SOPA), we’re taking an opposite stance and are whiting-out The Daily WTF in support of SOPA supporters.
If there’s one thing that SOPA proponents like myself and SOPA opponents can agree on, it’s that PROTECT-IP and the Stop Online Piracy Act have little to do with protecting intellectual property and stopping online piracy.
After all, those who choose to steal creative works like the “I Have a Dream” speech from artists like Martin Luther King Jr. can already be sued and prosecuted under existing United States copyright laws. IP thieves living overseas can already be extradited to face justice in our federal courts. And the Department of Homeland Security can already arbitrarily seize domain names that fit its arbitrary standard of violating national something-or-other.
While these laws will make such acts more illegal (and therefore reduce infringement), they’re doing something much, much more important: helping dismantle DNS and the internet as we know it. And that’s something that we firmly support and can stand by.
You see, back in the day, if you wanted to get online and access electronically-stored information like digitized photographs, electronic bulletin boards, and informational databanks, there was only one thing you needed: a telephone number. You’d simply fire up your favorite telecommunications program (mine was Telix), have it dial that phone number, and after a refreshing symphony of beeps and hisses, you were online.
Each phone number transported you to a quaint, peaceful community that was almost entirely self-sufficient. There was no “hyperlinking” between systems: you simply wrote down the phone number, signed-off of the current system, and then dialed into the new system. And let me tell you, there are few experiences in life that can parallel the utter bliss of discovering a new phone number and a new electronic resource.
And then the Information Superhighway – and its tightly integrated Domain Name System – came along, decimating these peaceful, independent communities. The bulletin boards of old were ground up and churned in the giant “dot com” machine, leaving an interconnected web of domain names. There’s no more “going online” – you’re already online – and if you want to access an electronic resource, you can use a “domain name” like TheDailyWTF.com.
Domain names are highly confusing in that they not only describe what the electronic resource is, but where it is as well. Nothing else in the world works like this for obvious reasons. Could you imagine the complete confusion in day-to-day things like getting a phone number? Is that “jenny eighty-six dot com” or “jenny eighty-six dot net”? We would be in complete chaos.
SOPA and PROTECT-IP offer hope in returning to the golden age of telecommunications, and to the days before the Information Superhighway polluted the online culture with this domain name nonsense. Let the Domain Name System a natural death and prepare yourself for the Internet Protocol Number (IPN) renaissance. All you need to do is start a notebook that lists electronic resource names and their corresponding IPN. And let the first entry in your notebook be
The Daily WTF 74.50.110.120
We can only hope that our legislators introduce common sense guidelines to ban HTTP (and HTML/JavaScript) as well so we can all return to the more sensible GOPHER standard.
Update 2012-01-19 00:01 - thank you all for supporting the Support The Daily WTF in Supporting the Support SOPA Movement article! In case you missed it, any request simply to content on thedailywtf.com served up this:

Things should be restored to normal (in theory), and note that the server IP did actually change from 74.50.106.245 to 74.50.110.120. If you are still hitting the old server, your DNS is a little behind in catching up to the change.
Terrorists! ...
“She’s convinced that terrorists have compromised her computer,” Tom Davidson’s colleague – a front-line helpdesk technician – reported, “best I can tell, it’s some sort of virus problem, or something. It’s is a bit out of my league, but I’m hoping you can help.”
As a junior sysadmin for a mid-sized university, Tom found himself playing second-tier helpdesk support more often than not. He didn’t mind – it was certainly better than first-tier, after all – and he appreciated solving the unique problems that were escalated to him. The terrorist virus was definitely one such problem, and it was nothing he had heard of before.
He opened up the ticket the ticket report to see what sort of troubleshooting the technician was able to do.
****************************************************** * TICKET #APX-914321 *OPEN* 2001-05-13 * ****************************************************** * * * ASSIGNED : Tom Davidson * * DEPT CODE : T2-SUP * * CUSTOMER : Wendy G------ * * HARDWARE : Standard Desktop D8-AM6 * * RESOLUTION: * * * * * * __ ISSUE __ * * * * The user reports that her computer may have been * * compromised by hackers or terrorists. * * * * __ TROUBLESHOOTING __ * * * * #2001-05-13 9:33 AM # * * For the last few days, whenever she is using any * * Microsoft product -- Word, Outlook, even Excel - * * her screen will suddenly start filling up with * * text. Most of it will be gibberish, but there * * are frequent references to guns and bombs and * * terrorists. She believes it's a person and not a * * virus, as there are sometimes were weird ref- * * erences to local news. * * * * Her computer is currently turned off. Perhaps * * sensibly, she will not turn anything on until a * * technician physically disconnects it from the * * network. I will visit ASAP. * * * * * * #2001-05-13 11:18 AM # * * When I arrived, the computer was still turned on * * but the monitor was turned off. She left open * * Microsoft Word, and there was indeed lots of * * gibberish on the screen. I shut down and ran a * * full scan off boot. No problems reported. I * * could not find any evidence of any problems, and * * the problem would not appear when I was there. * * * * * * #2001-05-16 10:03 AM # * * The user called again, and said that the problem * * started happening again in Microsoft Excel. I * * advised her to not touch a thing, and I headed * * over immediately. I was able to observe the * * problem first-hand. After disconnecting network, * * problem still occurred. I opened up Notepad, and * * noticed text continued to be entered. Most is * * gibberish, but the intelligible text and words * * implies that it's not bad keyboard, etc. * * * ******************************************************
Tom was intrigued. He called up the end user to say that he’d be over in just a bit. He wandered down to her office, one of those cozy professorial spaces packed tight with decades of accumulated unlabeled folders and empty tea tins, and tried repeatedly and unsuccessfully to reproduce the problem. The soft instrumental music on the radio soothed him a bit, but he definitely was getting a little frustrated. She felt it, too, and practically shouted: “I’m not crazy! I don’t understand! Usually whenever I open anything, they start right up!”
And at that moment, the words appeared. “Stand, you silly. We never eye a penny thing they start. Dry up.”
The classical piece on the radio came to a conclusion, and the announcer let listeners know that they had been listening to Bach. So did Notepad, although it spelled it “Bock” and said something about the “fast circling wagons” instead of “last symphony”. and it otherwise did a pretty good job.
It took another couple of minutes to figure out how to turn off Speech Recognition, since it wasn’t a feature that Tom – or quite obviously the user – had knowingly used before.
Coded Smorgasbord: Schizophrenic Haiku Comments and More ...
"I found a schizophrenic comment that either intentionally or unintentionally happens to be a haiku," wrote Ben Vanik, "svn blame says this single line is the work of 3 different people across 3 years of coding."
// should delete the temp files here, no cannot because, we havent read it in yet!
"I'm modifying some firmware for a product that has a serial connection," Fahrzin Hemmati writes, "this was found in the method that translates the incoming data into useful bytes."
//Clear it, or it, smack it, flip it, rub it down //(Oh nooooo...) mem[iAddress] &= ucClearBit; mem[iAddress] |= ucAssignBit;
"How do you feel when you see this code on the first day of your job?" wonders Ritesh
#define EIGHTY 256
"I found this piece of java code in our corporate directory," writes Peter S, "two of our JUnit test classes end in this method. I do not know if these were intended phuns/easter eggs."
@Test
public void testNothing() {
assertTrue("Assert just to keep JUnit happy!", true); }
"When debuging some client code I came across this," wrote Blair, "tmpnum8 was wrong. Now I just have to figure out what all the other tmpnums are..."
tmpnum6 = tmpnum2 + tmpnum * (tmpnum4 - tmpnum2); tmpnum7 = tmpnum3 + tmpnum * (tmpnum5 - tmpnum3); tmpnum8 = tmpnum6 + tmpnum1 * (tmpnum7 - tmpnum6);
"The previous developer on our OBIEE environment had some interesting ways of developing queries," wrote Bart, "not only did he not know about Oracle functions like NVL(), requiring him to write everything using lengthy CASE statements, also using joins seemed out of the question. This code is een excerpt from a _large_ view unioning large blocks of codes like this to eachother. I also like how he did code reuse, he copied large pieces of code to different views."
SELECT decode(authorization_kd, 3,3, 4,3, 6,3, 7,3, 34,3, 55,3, 57,3, 58,3, 24,4, 10,4, 11,4, 21,4, 71,4, 36,4, 37,4, 38,4, 13,4, 14,4, 84,4, 53,4, 15,4, 33,4, 31,4, 32,4, 09,5, 12,6, 52,6, 54,7, 19,8, 20,8, 79,8, 99,8, 9) process_kd FROM dossier WHERE authorization_kd NOT IN (1, 30, 35, 85, 86, 87, 16, 17, 18)
"Starting a work in a project is always a kind of challenge," notes Wiadran, "if the project is developed for years and written mostly in ASP classic... it might become a nightmare. Nevertheless, projects developed for years have some bright side as well: parts of not-understandable code and commentaries."
For intI = 7450 To 7450 'Now lets go and create the f*&ker ... snip... Next
Jimmi found yet another wrapper for the illusive '!' operator.
private static bool InvertBool(bool org)
{
bool returnValue = false;
if (org)
{
returnValue = false;
}
if (!org)
{
returnValue = true;
}
return returnValue;
}
"How many naming conventions can you find in the following line of code?" writes Malcom
StandardResponse UnSubscribeNewsletterUserAccount( string opTinGUID,string email, string sellingRegion, string source, DateTime opt_out_date, string strevent, string reason);
"While diving through some old code I'm maintaining, I found this jewel," Frank writes from the Submit-To-WTF Visual Studio Add-In, "Not only is this snippet a part of a rather intricate XML merge system, but it also merges the XML by string operations. To add insult to injury, the XML is not possible to define in a schema (as elements have to occur in certain patterns, while the name of the only valid elements in the XML 'schema' is either FLD or REC. The types of REC depends on the NAME attribute, and it is the NAME attribute that ultimately decides the order of the REC elements in the document. In other words, a truly fubar mess."
// Dear future developer(s):
// I have no idea who actually came up with such a glorious violation of the
// XML definition, but legacy systems being legacy systems means that we can't
// switch this.
// I feel for you, young padawan; I'd rahter kiss a wookie than mess with this.
if (line.IndexOf("REC NAME=\"Hovednivå\"") <= -1) continue;
Classic WTF: Rutherford, Price, Atkinson, Strickland, and Associates Dentistry, Inc ...
I'm at CodeMash today (stop by the Inedo booth if you're there!), so I thought it'd be a great time for this classic. Rutherford, Price, Atkinson, Strickland, and Associates Dentistry, Inc was originally published on January 30th, 2008.
July 19th, 2004 marked a new chapter in New Portlandopolis’s rich dentistry history. It was on that day that the bitter rivalry between Dr. Rutherford, DDS; Dr. Price, DMD, DDS; Dr. Atkinson, DMD; and Dr. Strickland, DDS/DDS-PhD, had finally come to an end. Though there’s much debate on what exactly started the feud, everyone knows what brought the dentists together: the nationwide “denta-corps” that can out-price, out-service, and out-anything their small, family dental practices.
Although the partnership talks had begun years before, July 19th was their agreed-upon D-Day, wherein the four separate practices would officially combine to be Rutherford, Price, Atkinson, Strickland, and Associates Dentistry, Inc. In the months leading up to D-Day, and after much bickering and debate, the four dentists got everything ready from new signage to new logoed toothbrushes. The only thing that remained was combining their computer systems. That task was left to Aaron B, an IT consultant who had the pleasure of working with each office through many of the “ugly years.”
Fortunately for Aaron, each of the dentists used the same practice management system: Beaglesoft’s Practice EnterprisePlus. It certainly wasn’t the best software, but it was among the most expensive. Perhaps more-importantly, Beaglesoft offered all sorts of outrageously-priced add-ons that the dentists could buy to one-up one another. For example, a wand-shaped oral camera required a $7,000-per-site “camera driver,” in addition to the ungodly amount the camera cost in the first place. When Aaron plugged the camera into his laptop (which didn’t have any Beaglesoft software running), it was recognized as a plug-and-play camera and immediately started streaming video. Not that it mattered though; as soon as Dr. Price had his installed, the other three dentists had to get one as well.
“While our prices might seem high,” a Beaglesoft rep once told Aaron, “keep in mind that you’re paying for quality. Our products are rigorously tested to work in today’s and tomorrow’s high-tech dental office.”
And for that reason, Aaron wasn’t too worried about Beaglesoft’s portion of the D-Day migration. They assured him on several occasions that their latest and greatest – Beaglesoft Practice EnterprisePlus Elite with Networking – could network a “virtually unlimited” number of practices. The four Aaron was linking together was “chump change” compared to what the system could do.
When Friday, July 16th – the weekend before D-Day – had finally come, the dentists were ready. They closed their offices at noon and, per Beaglesoft’s instructions, initiated the migration process. Over the next twelve hours, so the plan went, each practice’s system would upload its data to the Central Server at Dr. Strickland’s office. Naturally, none of the other dentists were too thrilled about having a “Central Server”, especially one at Dr. Strickland’s.
Aaron arrived at Dr. Strickland’s office early Saturday morning to find a surprising message on the server: “Migration Completed Successfully.” He ran through some initial smoke tests and it appeared that the migration did, in fact, complete successfully. After a trip to the other three dentist offices, Aaron verified that he could access any patient’s file from any office. He called up the four dentists to share the good news: come Monday, they should be in business.
Monday came and, shortly thereafter, the four offices were out of business. The system had completely grinded to a halt. Every click of the mouse was met with a several-minute delay, and every delayed response was met with more clicking. Aaron, who happened to be on-site “just in case,” immediately suspected the newly-installed T1 lines.
Aaron called up the phone company. They ran a few diagnostics on their end, only to find that each office’s T1 line was completely pegged. Most certainly, the technician claimed, the problem was on their end. Perhaps a router gone haywire?
Aaron checked and rechecked the switches, the hardware, the ports, and the routers. He rebooted once, twice, and thrice. Everything seemed functional, aside from the fact that the Central Server was firing packets off non-stop.
Not sure what else to do, Aaron bridged his laptop between the Central Server and its switch. Within seconds, he logged hundreds of megabytes of data, far too much for anyone to go through in the middle of such a crisis. He had no choice but to take the “satellite” dentists offline to investigate the problem. They grew suspicious of this and, of course, Dr. Strickland, and demanded that there was foul-play involved.
With only a couple users accessing the Beaglesoft system, Aaron was able to get a handle on the traffic. As he assuaged the other dentists over the phone, Aaron noticed that a lot of the data seemed to be coming from SQL Server. Specifically, it was from queries like this:
SELECT * FROM Patients
Digging further, Aaron figured out that, whenever a user wanted to look up a patient, the program would run “SELECT * FROM Patients” query, returning the entire Patients table to the client computer.
What’s worse, the query would run any time a character was typed in the patient search box. Searching for just his first name – A-A-R-O-N – resulted in five SELECT * queries.
What’s still worse, the same method of client-side filtering was used for appointments. It wouldn’t just get, say, today’s appointments. Or this week’s. Or, say, any that haven’t happened yet. It would query for every appointment that they ever had or would have in the future. That’s about 100,000 rows.
And since each appointment involved a patient, it’d have to fire off queries for each appointment to download and filter information about the patient.
It was apparent that Beaglesoft’s “rigorous testing” of “Practice EnterprisePlus Elite with Networking” involved, perhaps, a single computer and two, maybe three patient records. He immediately called Beaglesoft to report their issues and a demand a resolution.
(an actual screenshot from Beaglesoft’s install directory)
Within a few hours, three of Beaglesoft’s finest were on a plane to New Portlandopolis. When they arrived, two of them split off to work on “de-migrating” the system into the original four databases. The other Beaglesoftie, a product manager, worked on “damage control” – and boy did she have a lot of damage to control.
By that time – ten hours into Rutherford, Price, Atkinson, Strickland, and Associates Dentistry, Inc’s first day – the dentists were at each other’s throats. Dr. Price blamed the mess on Dr. Strickland who was “online the entire time, ” while Dr. Strickland was convinced that Dr. Atkinson had somehow “spiked the T1s,” while Dr. Rutherford believed that Dr. Price “wanted to retire, and was bringing everyone else down.” Eventually, Dr. Atkinson stormed out and tore down the new "Rutherford, Price, Atkinson, Strickland, and Associates Dentistry, Inc" sign. As he stomped the sign into pieces, he vowed never to work together again. Things pretty much went downhill from there.
After things cooled down a bit with the dentists, the product manager met with Aaron. Angered that his future prospects looked like a repeat of the “ugly years”, he lambasted Beaglesoft’s latest and greatest, and asked why, oh why, they couldn’t have done some client-side caching. Or, at the very least, use the magical WHERE clause.
She was astonished by Aaron’s technical knowledge and eagerly asked more questions on “WHERE clauses and other optimization techniques.” Near the end of their conversation, she actually offered Aaron a job as a Lead Developer at Beaglesoft.
Aaron ended up declining the position. He figured that they’d never be willing to tar and feather the existing development staff. That, and after the Beaglesoft Fiasco of 2004 (as it’s called today), he’d have a lot of cleaning up and intra-dentist diplomacy to do. Besides, how could he miss taking part in the latest exciting chapter in the dentistry history of New Portlandopolis?







































