Serendipity |
Given the title, most of you are expecting a story that goes as follows: Boy meets girl. Girl writes phone number inside a book in a used book store. Ten years pass and boy searches for book. Boy finds book and gets girl. But not this time. Instead, Andrew is the source of a story that ranks much higher on the believability scale.
Andrew's father worked for SmallishNicheCo where, like many small companies in the early 1990s, the sum total of IT knowledge was non-existent. Every problem and request was passed to an outsourced help desk, which in the tradition of solid customer service for which IT help desks have become renown, could take up to 3 days to acknowledge receipt much less dispatch a person to solve the problem. If you needed to have the brightness on your monitor adjusted, you were looking at 5-7 days. And that was after passing the gauntlet of questions to ensure the problem was 'real' (Is your computer plugged in? How about your monitor?)
With next year's budget being worked out, Andrew's father offered up his son's services to help out with the corporate spreadsheets. Andrew was looking for work and was particularly keen to work with computers. Really keen. So keen, in fact, that his resume contained the line "I *love* working with computers". Keep in mind that this was before the advent of bold fonts. And at the time Andrew was 19. He knew a lot about DOS, a little bit about Excel, and absolutely nothing about crafting a compelling resume.
Andrew's initial 'try-out' was a two-week gig helping out the elderly financial controller with the aforementioned spreadsheets. An old-school curmudgeon, even for the 1990s, the controller was someone who thought that printer paper was better used as a scratch pad then as the surface for reports. Early in the gig, Andrew was asked to not use the computer to set up a table of columns for him, but to hand-rule and write it instead. Said request was dutifully ignored.
Prior to Andrew's arrival, there were no spare computers available. So a new one was purchased and one of the help desk analysts came out to lay the appropriate cabling and set up a network account. On the then gold standard of networking environments, Novell Netware 3.11. In spite of the fact that Netware had a dedicated server, the attached console provided no opportunity to administer the network. Probably to avoid the potential security hole of having employees brute-force hacking the password. Instead, the support person sat at Andrew's computer to set up the new account. And given his teenaged, computer-geek interest, it's not surprising that Andrew was standing back and watching with rapt attention.
Eyes staring down at the keyboard and hunched over as if to shield the keystrokes from Andrew's prying eyes, the support person quickly typed.
LOGIM SUPERVISOR CBK
Looking up to the screen, he was surprised to see the commands. A quick 'CLS' cleared the screen and he logged in again. Successfully this time. But Andrew had already seen the instructions and stored that knowledge away for future use.
After a few days of gnawing curiosity, Andrew decided to see if the password still worked. It did. Andrew quickly logged back out, in case someone caught sight of his screen or a red "Intruder Alert" started flashing. Another few days passed with nothing untoward and Andrew tried again. The password still worked. This time, he started to poke around the system. There were lots of commands in the system directory, and so he tried out some of the ones that seemed less likely to cause permanent damage. Turns out that Andrew had access to everything in the network, including the user data. By changing a few security settings, he set his own login to have the same access rights as the supervisor account.
As you might expect, the need for stealth was completely unnecessary. No one had a clue about the IT systems and there was no remote access to the network. So the two week gig became a massive learning opportunity. Near the end of his two weeks, a staff member at SmallishNicheCo moved from one office to another and needed her default printer changed. This is the type of taxing request which would usually take 5 days through the help desk. Andrew overheard when the employee requested a support visit. Not one to miss a chance, Andrew offered to make the change himself. He did so successfully and three months later was offered a full-time position that included IT in his list of responsibilities. Over time, Andrew continued to construct more of a position for himself, creating interactive reporting programs for senior managers. As time passed, the CEO came to rely on Andrew's programs for all of the sales/budget information. Eight years later, IT became his only responsibility and after 14 years, the company had grown to include an IT staff of three, all working under Andrew.
That's right. A full-fledged and successful career all launched on the back of a misplaced 'M'
Photo credit: SuperFantastic / Foter / CC BY
Метки: Feature Articles |
CodeSOD: The UntouchaDBles |
Casa de Quixote is a small, state-run retirement community in La Mancha, in central Spain. Sergio continues his job as the sole developer of software managing hundreds of residents.
It's always a bonus when the same brave soul delivers multiple WTFs for our exasperation. Our very own man from La Mancha has been doing a lot of refactoring lately, retaining the GUI of his employer's Assistance-Management System while replacing the zany consultantware underneath with vastly improved code.
Now, I wouldn't blame you for viewing Sergio's hack-and-burn mentality with a skeptical eye, wondering if the legacy code was truly awful or just a victim of Not Invented Here. As justification for his crusade, Sergio sent us this representative snippet of his predecessors' work. Let's play Count The WTFs:
// "concertado" = "partner", and the method returns a boolean indicating whether
// the patient's nursing home belongs to Casa de Quixote or one of its partners
public ActionForward concertado(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
GestionSolicitudFormBean gestionSolicitudFormBean = (GestionSolicitudFormBean)form; //"Gestion Solicitud" = "Patient Episode"
try {
Calendar calendar = new GregorianCalendar();
Espacio centro = gestionSolicitudFormBean.getEntidad().getCentro(); // get patient's nursing home
calendar.setTime(centro.getFechaC()); // get nursing home's creation date
boolean esReinaSofia = centro.getNombre().equals("Centre de Dia Reina Sofia");
String resultado = "false";
if ((calendar.get(Calendar.DAY_OF_MONTH) == 16
&& calendar.get(Calendar.MONTH) == Calendar.MAY
&& calendar.get(Calendar.YEAR) == 2013) || esReinaSofia) {
resultado="true";
}
response.setContentType("text/xml;charset=UTF-8");
response.getWriter().write(resultado);
} catch (Exception e) {
log.error("Error en AdmAbstractSolicitudAccion, error al enviar el "
+ "tipo de centro (concertado o no): " + e.getMessage(), e);
}
return mapping.findForward("");
}
Did you catch them all? I got four:
true
when the nursing home isn't a partner and false
when it is.When asked what made this delicious morsel of ridiculous business logic necessary, Sergio explained that the previous developers didn't want to add database fields to those defined in the spec, so they took advantage of the fact that all the owned homes were added on the day the system was rolled out and bestowed responsibility for identifying partner homes on the lowly Creation Date field. When Centre de Dia Reina Sofia was added a year later, they likewise didn't want to back-date its creation. You've got to hand it to those Highly-Paid Consultants: though willing to commit WTFs like this in Java, at least they went to great lengths to keep their hands off the database.
Метки: CodeSOD |
Marketing Software |
We've all dealt with marketing people who, in the very depths of their souls, believe that if they promise something to a customer, it will magically happen. Regardless of actual manpower, time or cost. It will work perfectly the first time, and every time, because they promised that it would. It will be cheaper than they expected because, let's face it, how hard could it be to build something, even if it's merely software...?
Aargle interviewed with all of the developers and technical folks in his new department. They all seemed sane, grounded in reality and realistic about what was - and wasn't - doable.
Given that, he dove in head first, and in a few short days, pile-drove himself waist deep and upside down into the steaming pile that was the marketing department. He encountered the company Vice President and a Marketing Drone sitting in a conference room doing design work. Since neither was associated in any way with the development team, he asked one of the other programmers who informed him that the VP and MD had decided that the programmers were just too slow because we were taking around a year to develop new products. He continued: they are going to design a product and have an outside company complete the project.
Aargle thought to himself Uh oh, what did I just get myself into? Fortunately, it turned out that the department he was in consisted of perfectly competent developers and support people, and there was real development to do. The other developer also told him that the MD had previously been part of the programming team, got fired for incompetence and was immediately re-hired as the MD.
Fast forward two years and the marketing-development project was declared done, even though it was missing features and simply didn't work right. It ran very slowly. While some of that could be blamed on the simple 1MhZ 8051 processor it used, the device's purpose was simple enough that an 8051 should have tackled the targeted tasks just fine.
Hardware guys usually get it right (because chips can't sort-of or mostly-work; they need to work), but seeing this device in action initially made Aargle wonder. Operations that took an instant on a PC took upwards of 10 seconds to compute on this gizmo. There were also interface issues. Depending on what you needed to do, you might have to press up to 6 keys on the keyboard simultaneously. The keyboard was a standard PC set-up, but with custom key-caps. Have you ever seen a color-blindness test? That's what the key-caps were.
Text would be green on red, red on blue, blue on green, and so on. Consulting with a graphic artist for 5 minutes at the start of the project might have saved that part of the project, but it didn't happen.
Of course, when beasts like this are released, the production nightmares are usually quick to follow. Every time one of these devices shipped to a customer, the production staff had to specify unique settings for the customer, then build the binary code which was then put to an EPROM and that in turn inserted into a socket in the device. Failures became a common problem.
The outside contractors told the production staff that it was probably static (electricity) and outlined steps for them to take. Soon the production people were hooking themselves into grounding straps before handling the EPROM and then making sure the new device was inches from the burner so there was minimized activity involved in getting it from the burner to the device. The software would still fail.
In addition to the problems with the chips, getting updates to the customers was it's own little Circle of Hell. It's simply not reasonable to ask non-technical people to pop and replace chips on circuit boards, but that was the update procedure. Update kits were sent to customers, but that failed far too often.
After months of all this, Aargle was tasked to look into the project to see if there was anything at all that could be done. At the very least, even if the software was awful, could it at least get loaded reliably?
The software and customization went out to a file in hexadecimal. That in turn was sent via com port to the burner. How hard could the process be to screw up? Remember, this was created by a Marketing Drone! In the middle of the "C" program used to perform this task was this:
void main(int argc, char **argv) { char response[10]; //... printf( "Do you concur? (y/n)" ); scanf( "%s", response ); if ( strcmp( response, "y" ) != 0 ) { main( argc, argv ); } // ... }
The use of the word "concur" was merely awkward, but calling 'main' recursively? Huh?
Finally, he found where they opened the hex file, read block after block from it and just wrote it to the COM port they had open. The C standard library doesn't know from flow control. Is the burner picky about it? Yup. The manual was pretty clear about that.
Using a proper terminal program with hardware flow control, he made the company's first properly produced chip - ever. A few scripts for the comm program later and the whole create/burn/install process was finally working.
Aargle told his boss that this was just the tip of the iceberg, and did he want him to look into fixing it up? The boss told him to take a few days and figure out what he could.
After getting the cross-platform development environment going, he got his first successful build of the existing C code. So far so good, and not even a warning. Wait: warnings were disabled. Let's enable them and see what could be fixed. After a good many minutes of watching warnings scroll off the screen at an unreadable pace, that approach was abandoned.
Among the many warnings were hundreds of functions that returned 'int' but there were no return statements. Maybe the compiler didn't support 'void', but that wasn't it. Maybe they were just lucky and nothing was being done with the return value. Nope. Not that lucky. There were lots of loops and conditions that checked for true/false from these functions that had no explicit return value. The return codes were essentially random numbers. Sadly, this was small potatoes.
In digging through the code, he found that there was a single #include file. But this was still in the '80s and the 64K page-limit needed to be heeded on DOS boxes. Eventually, the compiler couldn't handle their all-encompassing header file. At this point a programmer of even below-average skills would realize that maybe it's time to categorize the constants in the header file and then selectively include the various files with the constants. But this was not done.
Instead, they created two matching include files and essentially divided their source files into two groups and included one header file for one half, and the other header file for the other half. Then deleted constants for one group and different constants for the other group until the compilation would once again fit in memory. This stunt was done yet another time when the number of entries once again got too large. This meant there were 3 header files with overlaps. If you changed a constant in one header, you had to go through the others and make sure you changed the matching entries.
One of the reasons that it was so slow was because all of the financial calculations were being done in double-precision math. Even though all the numeric values were whole numbers and simple integers would have sufficed.
Even simple things were done in the least efficient way. While the function to put a single character to the device's display worked efficiently, the software guys created this to output strings to it:
int print( char *text ) { int i; for ( i=0; i < strlen(text); i++ ) { putChar( text[i] ); } }
On a 1MhZ computer, there's a visible price to pay for re-calculating the length of your output string on each pass of the loop. When the screen clear function was called, you could watch the spaces crawl over the display.
At this point Aargle told his boss that the code was irreparable, but that he wouldn't mind re-writing it from scratch. Amazingly, he agreed. It was his first chance to be chief cook and bottle-washer on something like this. The complete re-write, including re-design of the keyboard and manuals, documentation and marketing paraphernalia was done in under 6 months... and the production people got to dispense with the silly wrist-straps. And the customers got ZIF sockets for the update chips.
Marketing: 0 Programmers: 1
Метки: Feature Articles |
CodeSOD: Brick by Brick |
Jannik worked for a company known for a line of building products
. They were an international company, which meant they had to make sure their website supported multiple languages. They embedded this information into the URL, eg http://company.com/eng/orders
.
They tracked the list of valid languages in an array:
///
/// A list of supported folder names
///
public static string[] VALID_FOLDERS = new string[]
{
"eng", // English
"deu", // German
"fra", // French
"jpn", // Japanese
"kor", // Korean
"dan", // Danish
"fin", // Finnish
"swe", // Swedish
"nor", // Norwegian
"dut", // Dutch
"spa" // Spanish
};
One of Janniks co-workers was given a simple task- given a URL, make sure the URL contains a valid language string. His solution was to compare… brick by brick.
public static string GetLanguageFromUrl (string Url)
{
foreach (string s in VALID_FOLDERS)
{
if (s[0] == Url[1])
{
if (s[1] == Url[2])
{
if (s[2] == Url[3])
{
return s;
}
}
}
}
return string.Empty;
}
Метки: CodeSOD |
The Shadow Over ShipPoint |
In the winter of 2012-13, I was fired from the ill-rumored e-commerce company known as ShipPoint. Though I remained stalwart to the end, the wretched darkness embodied in ShipPoint's CTO and his twisted worshipers dogs me still, a malignant growth choking the very life out of my career aspirations. And although I fight every day to forget, to leave my time at ShipPoint behind, I still awaken in the uttermost black of night, shuddering, my mind wrenching itself free from nightmare's grip. I record this grim history only because I fear I may soon slip irredeemably into madness.
It was 2011 when, freshly downsized, I found myself wandering the LinkedIn Jobs Directory, seemingly in vain. I had almost made up my mind to hang out my shingle as a consultant when I received an email from a recruiter. I don't remember his name, nor the firm that he claimed to represent, only that he demanded that we meet in person; apparently he was privy to a lucrative opportunity whose details could only be revealed face to face. While suspicious, I must admit I was gripped by curiosity — tinged, I must now believe, with a touch of the wild. I met the recruiter, a grim, swarthy fellow of furtive glance and questionable heritage, in a refuse-choked alley far from the central business district. It was there, amidst the dumpsters and commercial-grade recycling bins, that I first heard in a grating croak the name whose syllables I would one day shudder to write.
"ShipPoint," he said in response to my question about their development environment, "is dedicated to becoming cutting-edge with their development tools and processes. They use Subversion, and I hear they have a focus on quality and testing." I proceeded through a phone interview, and then on to meet James Akeley, ShipPoint's development manager. Imploring that I call him "Jimmy", he proclaimed his easy-going attitude to be matched only by his and ShipPoint's commitment to quality. Though the pay was a bit on the low side, I accepted his offer. I was to start the following Monday, taking the train and then a bus to the ugly one-story building of nondescript gray that contained ShipPoint's offices, a geriatric hulk muttering tonelessly to itself as it wallowed in its crumbling and almost-abandoned office park by the seashore.
My first day at ShipPoint began as prosaically as one could expect with a simple task that would lead me through their codebase. As an e-commerce provider, ShipPoint's stock in trade was web applications written using ASP.NET, and I made careful note of several places where classic code smells made themselves apparent. The team went out to lunch, as was their custom. Jimmy drove, with Jack Mason, the second-most senior developer, in the passenger seat. Sharing the back with me was Rob Carter, the company's web designer — one who would prove himself my most stalwart companion in the unguessed-at trials that lay ahead. While our lunchtime discussion was generally mundane, with only Rob expressing any interest in developing familiarity with his new associate, I found an appropriate pause in the conversation to present Jimmy and Jack with the potential problems I had detected during my brief venture into the code. Given his repeated assertions regarding dedication to quality, I expected Jimmy, at least, to be keenly interested in my discoveries. My surprise was considerate when he and Jack rebuffed me, declaring that Dan Marsh — the CTO — didn't want us to spend time refactoring code. "He and the other executives think it's a waste of time," Jimmy explained, some small measure of remorse evident in his voice, while next to him Jack nodded his head approvingly. "They want us to focus on new deploying new features."
I was disappointed by this, and by the subsequent revelation that, though ShipPoint did indeed mandate Subversion for source control, Jimmy and Jack only ever copied all the files to a separate, timestamped folder before committing. While the two senior developers were hesitant to discuss their mysterious and unseen leader, I was eventually able to coax from Rob what little he knew of the enigmatic Mr. Marsh. It seemed Marsh wasn't a developer, but, after joining the company a decade prior, his possession of certain esoteric scraps of scripting knowledge qualified him as ShipPoint's sole IT person. His authority spread as the years went by, unquestioned by his superiors and the developers he eventually allowed to join his staff, until he now led all technological decision-making at ShipPoint from within the only private office on their floor, an office whose door opened by invitation only.
After several months of my attempted improvements being either stutteringly denied by Jimmy or gruffly rebuked by Jack, new allies arrived at ShipPoint. Arthur Gilman was a brave and clever youth who joined the company alongside his mentor. Walter Peaslee was a hoary old veteran who had been using .NET since the framework was in beta. If anyone could help me champion sane coding and source-management practices at ShipPoint, it was these dynamic individuals. And changes were surely needed, as the months had shown me deep-rooted stability issues that would cause pages to crash or take minutes to load. It had likewise become clear that the senior developers were unwilling or uninterested in tackling these issues, holding up Mr. Marsh's desire for them to complete his endless list of superficial improvements as reason to hack as quickly as possible, leaving Rob and me to fix up the messes they left behind them.
At Christmastime, a chink in the armor appeared. Jimmy announced that he was leaving the company, taking his passive deference to Mr. Marsh with him. I decided to take action, and, with the idealistic Arthur at my heels, endeavored to implement a few changes. First, set up a bug-tracking system and then begin using Subversion properly, setting my prot'eg'e to create branches that would let the team collaborate without creating multiple copies of the application's source. Jack agreed to the changes in principle, and victory seemed close at hand. Only no sooner had Arthur went live with the Subversion changes than a blood-curdling cry was heard from Jack's cubicle! His files, Jack insisted, were gone, and he accused us of the most sordid and calculated mayhem, insisting that we sought to discredit him before Mr. Marsh. Not waiting for Arthur to explain that the files had simply been moved to a branch folder, Jack stormed into the CTO's office. By the time we had returned perplexed to our workstations, a directive to return the source control repository to its previous state awaited us, bearing the CTO's imprimatur. This was merely a prelude of things to come as repeated future attempts to sanitize our source-control procedures (and reclaim the gigabytes of storage consumed by the many redundant copies of our source code) were met with similar fear, uncertainty, and doubt from Jack, rapidly followed by executive sanction.
In the venerable person of Walter Peaslee, I was sure a sane counterpart had been found to our volatile senior developer. But the hand of Marsh proved subtle. When attempting to bring Walter's vast experience to bear on our DevOps dilemma, great was my surprise when I found him languishing on a project to produce a report for ShipPoint's CEO. Harbored as the chief executive was on far alien shores, all features of the report required Mr. Marsh's approval. With a sigh that seemed to carry a weight beyond even his advanced years, Walter explained that the CTO would lead him on for weeks regarding the simplest decision, often ignoring multiple emails. With his calendar eternally full to ward off meetings, Mr. Marsh would eventually return terse feedback along the lines of "this is the wrong color", disregarding the actual functionality.
I was saddened, but not surprised, when Walter graciously notified me that he would be submitting his resignation at the end of the week. After being regaled with the sanity-challenging truth of his experience working with Mr. Marsh, I had not the heart to try to convince him to stay. Indeed, I wondered if he might have awakened to a reality that I, too, should embrace. Arthur, on the other hand, being young and impressionable perhaps to a fault, was distracted by a new assignment: the task of utterly redesigning the central UI of our flagship application. It was here, in this project, that the forces of order and of chaos manifest at the heart of ShipPoint would collide in a last, terrible sortie. My support had meanwhile been secured by a timely email from Mr. Marsh, promising to install me as the lead of a new team of developers, since, he astutely pointed out amidst aggravating hints that the two shared some dark and malignant tradition, Jack was content to be a lone wolf. I must admit that the appeal to my leadership aspirations led me to lapse into a period of content productivity, and as the months went by I mostly avoided Jack and his hasty, problematical contributions to the codebase wherever I could, bringing as much improvement to the features I implemented as possible without incurring the wrath of Jack or the dreaded and still unseen Mr. Marsh.
Arthur, alas, had no choice but to collaborate with Jack, who effectively owned the backend of the application he was redesigning. While I thought I had coached the young man to weather this abominable partnership, the elder developer proved maddeningly cunning. While Arthur attempted to coordinate front-end and back-end features in the hurried sprints that Mr. Marsh had demanded, each release was plagued by wave after wave of new bugs, lapping like a foetid, corrosive black tide at a bleak, doomed shore. It was only Rob's fortuitous glimpse of an email seen over Jack's shoulder that we determined Mr. Marsh had been secretly communicating a list of shadow features he had apparently sold to management, and Jack was hacking code at a maddening pace to deliver said features in each release. It was with grim resignation that I entered the repository and inspected the terrible results. I perceived that Arthur's excellent front-end work had been reduced to little more than window-dressing, twisted into whatever shapes Marsh and Jack required to realize their fiendish goals. When I opened the solution containing Jack's jealously-guarded back-end code, obfuscated though it was behind incomprehensible names like "Solution1" and "MvcProject4", only then did I begin to grasp the horror that had taken root beneath the facade of a UI redesign. I saw them in a limitless stream—flopping, hopping, croaking, bleating—surging inhumanly through the spectral moonlight in a grotesque, malignant saraband of fantastic nightmare! That interminable list of poorly-implemented features, its shapeless mass extending blasphemous profusions in all directions throughout the code. It seemed to surge and breathe even as I watched...
It was with a mind gone almost entirely over to the feverish that I found myself composing email after email to Mr. Marsh, laying bare the deleterious effect that this noxious circumvention of procedure was having on our product. Rob was good enough to support this dangerous endeavor, and together we believed we may have been turning the tide of the CTO's sentiment against Jack, whose bland reassurances had apparently blinded Mr. Marsh to the depth of the horror. This last flicker of naivet'e on our part was efficiently snuffed when Arthur's employment was terminated without notice. Though no word from Mr. Marsh was forthcoming, Jack's smug explanation was that the youth was slowing down the delivery of critical new features, and, worse, his incompetent code changes were found to be at the root of the catastrophic server instabilities. Perceiving the tolling of a grim bell to have begun, Rob informed me he was thinking of getting out of the technology game altogether, returning to the simple pastoral life he had known while running an organic fruit stand outside a nearby beachfront town. I tried to reassure him that we would find a way to prevail, but in truth my own hope was waning. ShipPoint and its uncouth stewards had ground my desire to write excellent code and promote best practices down to their merest remainder. Deep within me a malaise had taken root, and I knew when I looked hard into the glass that the end was drawing near.
The harbinger came, as it so often does, with a revocation: came a day that Rob needed me to reconfigure something for him on the Production server that had long been my charge, when, upon attempting to connect, I was rebuffed by the server's protestations of an incorrect password. Under my questioning, Jack hesitantly and stutteringly informed me that the password had changed and he'd forgotten to update me. No sooner had he left to fetch the promised credential than my phone rang. Shouldering the receiver, I heard the voice of the spectral Mr. Marsh for the first time. Never have the words "Could you pop by my office for a sec?" been uttered in such a sardonic and inhuman tone as to induce in the listener a shocking wave of panic fear. I felt numb as leaden limbs carried me to the unopened door. Pulled into the dark recesses the portal revealed, I came face to face with unbounded horrors that defy description. Let me only say that the stated reason for my termination was "a change of corporate direction towards a smaller, more agile development team".
Though I survived my meeting with the terrible Mr. Marsh, I was rendered practically an invalid by my abruptly-curtailed employment at ShipPoint, and made my way to a relative's country home to engage in a lengthy convalescence. I received an email from Rob soon after my firing, informing me that he had left the company and was exiting the industry altogether, going so far as to delete his LinkedIn profile. The horrifying dreams in which I blindly shoveled hastily-implemented code into a branchless Subversion repository while pursued down lightless corridors by a shapeless unseen terror had begun to pass when the first job posting appeared. ShipPoint was calling, its unspeakable tendrils reaching out across the vast cosmic gulfs of the internet to ensnare unwary developers. And while I have sworn never to take a job without assurance of sane development practices again, I do not know that my programmer's soul will ever be entirely free of its taint...
So far I have not yet deleted my LinkedIn profile as Rob did. The tense extremes of horror are lessening, and I feel queerly drawn toward the job postings instead of fearing them. I see and do strange things in Subversion, and commit my changes with a kind of exaltation instead of terror. Stupendous and unheard-of splendors await me in Marsh's cube farm, and I shall seek them soon. I"a-R'lyeh! Codethulhu fhtagn! I"a! I"a! No, I shall not delete my LinkedIn profile—I cannot be made to delete my LinkedIn profile!
I shall coax Rob back into software development, and together we shall go to marvel-shadowed ShipPoint. We shall take the bus out to that brooding industrial park by the sea and dive down through black abysses of code to the Cyclopean and many-columned database, and in that lair of the Expert Beginners we shall dwell amidst wonder and glory for ever.
Photo credit: gagilas / Foter / CC BY-SA
Метки: Feature Articles |
Error'd: CMD: Completely Malicious Data |
What? Friday already!? Not quite, but close! We have something really good coming up tomorrow for Halloween, so here's your weekly dose of Error'd a day early. Enjoy!
"Yep - nailed it AVG. Well done," writes Jordan R.
"I tried to configure a VNC client using an SSH tunnel and I guess this is how I succeeded to connect... or not," wrote Yanick.
Chris S. wrote, "Well, I'd love to participate in your survey, Microsoft, but..."
"I wanted to download Oracle SQL Developer, but unfortunately, they won't let you do that without registering. When it was time to choose a job title, Oracle was kind enough to give me some suggestions, unfortunately, I was scolded by the form validator for using an invalid character. How silly of me!," writes Patryk.
"At a car dealership for service, this appeared in the waiting area," wrote Ari S., "By the way, a license costs about US$60."
"This is the website where every highway contractor in my state has to log in to get plans and specifications in order to bid on projects," strong>Ben F. writes, "The site itself is chock full of WTFs everywhere you go, but this little notice on the front page aptly summarizes the sorts of things you can expect once inside."
"The 'pine-fresh' flavor was a poor approximation of an actual pine forest. Disappointed; would not recommend," Pi wrote.
"Certain people at my workplace decided to enact some very creative marketing strategies in order to correct a mis-priced item," Tony writes.
http://thedailywtf.com/articles/cmd-completely-malicious-data
Метки: Error'd |
The Alpha-Team |
In 2010, a crack development team was formed inside of a Fortune 500 company. These developers promptly escaped the maximum security Project Management Office and instituted an Agile Scrum. Today, they survive as green-field developers. If you have a problem, if traditional corporate IT cant help, and if you can find them, maybe you can hire… Alpha Team.
When Thom interviewed at said Fortune 500 company, he didnt know he was interviewing for Alpha Team. He assumed that it would be like any other huge enterprise development shop- tedious line-of-business applications that helped ship widgets but didnt do much more. The product and the team was sold to him as being very exciting, and he liked the idea of the stability a large company offered, so Thom joined the Alpha Team.
The team room was slightly larger than the inside of a large van. John, the team lead, greeted Thom with a sly grin. Great to have you on the team. Youll be sitting between Albert and Murdock. I hope you dont have any plans for lunch- todays our weekly team lunch. Good chance for you to get to know everyone.
The teams architect, Murdock, grabbed Thom for a few minutes to brief him on the applications architecture. It wasnt surprising: a SQL server backend, a web-service based middle-tier, and a hybrid ASP.NET and WebForms presentation tier. This application is extremely flexible, Murdock said. Thats the main goal, really. Weve got it set up so our business analysts have a lot of control over the display, so that we arent wasting time just changing field names around. The exact details were simply described as magic, which Murdock didnt have time to explain right then; Its documented, and I need to crank on a few tasks, our burndown is terrible this sprint.
Albert showed Thom where to find the key documents. You should start with the environment setup. I pity the fool that tries to set up their dev environment without reading that. Thom spent the rest of the morning following Alberts advice. The environment setup document covered how to install and configure Visual Studio. There was nothing unusual or surprising in the document, except perhaps its enthusiastic level of detail- it was over 100 pages of screenshots covering every possible screen and message you might encounter while configuring your environment.
Thom didnt meet the product owner until lunch. Im sorry I wasnt there in the morning, but you know how it is with meetings, Templeton said. User engagement, same old, same old, right? The good news is that I specced out a feature which we can sneak into this sprint. It should be easy for you to implement.
Oh, that sounds good, Thom said. Are you sure we should change the deliverables mid-sprint?
Templeton shrugged it off. Dont think of it as changing the deliverables. Thisll just give you a head start on the next sprint. Youll probably need the extra time while youre learning the ropes.
The new feature was a simple memo field on a transaction entry screen. It was a string field, with a 500 character max-length, and was informational only. Templeton had estimated it out as a 50 hour task, which seemed amazingly generous, but when Thom checked the backlog, add a single field was routinely estimated between 40 and 100 hours. Thom wondered: had he joined a team that padded out its estimates and spent only three days doing real work out of any given month? Or was there something much more wrong?
Thom dug into the docs and the code to try and find out. The first time he saw Alberts documentation reference the Data Dictionary, he assumed it was a reference to the SQL Server data dictionary. The Data Dictionary kept appearing, again and again, which seemed odd. Then Thom saw this line:
The Data Dictionary should be stored at \CorpFileSrv01\d$\TransApp\DataDictionary.accdb. Contact the service desk to be granted write permissions. Use Access to edit the file.
Thom had found the magic in Murdocks design, but it was dark, twisted and evil magic. For example, lets say you wanted to add a memo field to the transaction screen in the accounting module. First, you needed to find out the ModuleID
for the accounting module by looking in the Modules
table. Then, you could go to the Screens
table and find the record for the transaction entry screen. With that ScreenID
, you could now add a record to the Elements
table, which described the field. The elements table required you to specify the DisplayName
of the field, the DataType
, ServiceName
, ApplicationName
, and DatabaseName
. You also had to create a set of records in the Validations
table, which described the validation rules which should be applied tot he field.
Once Thom had entered a set of records to describe his TransactionMemo field, he could then add widgets to the ASP.NET page. The label needed to have the ID lbl_TransApp_Accounting_strMemo
. Memo was the value in ApplicationName
. The actual text box needed to be IDed txt_TransApp_Accounting_strMemo
, while the read-only display of the memo field needed to be IDed txt_show_TransApp_Accounting_strMemo
.
The idea was that business analysts could control the DisplayName without involving the developers. Since Access databases couldnt be versioned by source control, and since the BAs were constantly changing things in production based on user feedback, there was only one version of the Access database, shared by production, test, development, QA, etc. Since Access isnt exactly built around multi-user deployments, or trivial things like security, the BAs constantly changed columns they shouldnt, breaking one or more environments in the process.
Thom decided to keep his head down, and just do his best. After a few months, all of the team lunches in the world couldnt help his morale, and he was ready to quit. Ready, that is, until he heard about the Beta Team. You see, in 2014, a crack development team was formed inside of that Fortune 500 company. These developers escaped from legacy code. Today, they survive as rearchitects , identifying and redesigning broken applications. If you have massive technical debt, if you have an unsupportable product, and if you can find them… maybe you can apply to work on the Beta Team.
Метки: Feature Articles |
Representative Line: Advanced Time Management |
Whenever a computer wants to sync its internal clock, usually right around reboot, it'll check in with a time server. This is built-in functionality that spans across every modern OS.
Now, in some cases you might have a reason to disable the time check - and that's fine.
However, if you were Paul M., you might find that your admin had implemented a third option in the form of the below script that he uncovered while hunting down a shell script bug.
DATE=`wget -T 3 -t 5 -S --no-check-certificate https://www.example.com/default.css -O /dev/null 2>&1 | grep Date | awk '{ print $3 " " $4 " " $5 " " $6 " " $7 " " $8 }' 2>/dev/null` date -s "$DATE" >/dev/null hwclock -uw >/dev/null
To break it down, here's the result of the wget:
mbowytz@mbowytz-PC ~ $ wget -T 3 -t 5 -S --no-check-certificate https://www.example.com/default.css -O /dev/null --2014-10-22 08:00:07-- https://www.example.com/default.css Resolving www.example.com (www.example.com)... 93.184.216.119, 2606:2800:220:6d:26bf:1447:1097:aa7 Connecting to www.example.com (www.example.com)|93.184.216.119|:443... connected. The certificate's owner does not match hostname ‘www.example.com’ HTTP request sent, awaiting response... HTTP/1.1 404 Not Found Accept-Ranges: bytes Cache-Control: max-age=604800 Content-Type: text/html Date: Wed, 22 Oct 2014 12:00:12 GMT Etag: "359670651" Expires: Wed, 29 Oct 2014 12:00:12 GMT Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT Server: ECS (iad/19BF) X-Cache: 404-HIT x-ec-custom-error: 1 Content-Length: 0 2014-10-22 08:00:07 ERROR 404: Not Found.
That result is then grepped for the text "Date" to get the current GMT date and then use awk to extract the 3rd through the 8th data fields so that the result is in DD Mon YYYY HH:MM:SS GMT. Oh, and there's no 8th field, but on the bright side - it works.
Метки: Representative Line |
It's Easier This Way |
After more than two years at WTF Inc., I thought I'd seen everything that could be done wrong actually done wrong in the worst possible way. Whether it was DBAs who wcouldn't administer a database if their lives depended upon it, managers who wcouldn't manage anything, or business people who simply could not understand the concept of save a dollar today, spend ten tomorrow to fix it.
After that dalliance, I'm back in my chosen field. While crazy things sometimes get done in insane ways, it's usually in the name of beating the competition to market, and (almost) always with the understanding that it will be fixed later - at a price.
However, this one struck me as sooo wtf that I'm not even going to try to anonymize it.
Every project from hello world on up has a source tree. It might be as simple as a single directory with one or more source files, or it could be an entire hierarchy of packages, common and external libraries, and so forth. The one thing they all have in common is that the one or more main programs in a project are all applications that pertain to that project. You never see two unrelated projects sharing the same source tree. They might share a common shared library, but not the same source tree. It just isn't done.
Or so I thought.
At my present firm, the culture specifies that for major architectural/code reviews, there must be one very senior member from an unrelated team/department present, and that individual has veto authority on anything that's said or presented. This is to allow an unbiased opinion to be offered without threat of reprisal by the manager.
As one of the more senior folks, I was volunteered for this task at a department that could only be linked back to me from five levels up. I didn't know any of these people, and so had no axe to grind. I went in with an open mind.
When they described their project, for the most part, their approach, level of scalability and parallelism, use of database, messaging and services, etc. made sense. Then they showed me their repository tree. It did not make sense. There were thirteen different (unrelated) projects in there. Together:
MasterRepository | |-- classes |-- srcproject1 | |-- com | | | |-- company | |-- business | |-- comm | |-- gui | |-- services | |-- util |-- srcproject2 | |-- com | | | |-- company | |-- business | |-- comm | |-- gui | |-- services | |-- util | ... |-- srcproject13 | |-- com | | | |-- company | |-- business | |-- comm | |-- gui | |-- services | |-- util
Naturally I queried why all the other projects were in there together, and why all of their source directories were configured as source directories in this project, I was told that they were told that it's easier this way.
Though I began to shudder, I just had to know, so I looked into the source trees. There were numerous classes with the same names and implementing the same interface at the same package path but in multiple source trees. Thus, auto-complete could pick any one of them because they all had the same signature, albeit subtly different implementations. As you might imagine, this led to all sorts of debugging fun at run time.If they were lucky, something would be null and it would dump the stack. If they were less than angelic, it wouldn't perform the calculation in quite the right way. If they had been particularly bad, if wouldn't perform the calculation in quite the right way only some of the time.
As if this wasn't far enough off the beaten path, I noticed that they were all using the same build/package/deploy mechanism, but at seemingly random intervals. It turns out that to prevent each of the teams from blocking any of the other teams from doing a deployment-at-will, all of the units of work were designed to be less than one day. That is, you had one day to design, code and test your work before committing. Thus, if the other team needed to deploy, they could grab the entire tree - including all of the tiny units of work done by the other teams - that compiled but didn't necessarily accomplish anything useful - package it up and deploy it.
Of course, if someone happened to be changing some piece of functionality that was shared, but hadn't yet made all of the one-day-of-work units that comprised the larger logical change, it was possible to get a melange of code that could best be described as: it might work.
Needless to say, the entire department was experiencing very high levels of instability, blocking deployment collisions when some piece of code absolutely could not be deployed without the rest of the related changes - without breaking the other projects.
When I pointed out the folly of all of this, they told me that the boss four levels up had experienced massive problems with multiple projects under his control, and decided that a single source tree would only need to be fixed once and would thus improve throughput. I told them that all of the projects had to be liberated separated into individual project source trees. Anything that was common would need to be its own project and released on its own schedule. When they were informed that this had to be done, they said they were under a mandate from four levels up. I went to the common manager five levels up, explained the situation, and that this was the reason for all the red on the dashboard.
The order to break it all apart was given.
Метки: Feature Articles |
Error'd: Undefined Favorites |
"It's great I can ship my favorites to Europe, I just wish I knew what they were," writes Nick.
"Nope. I don't think I'll be buying my Froot Loops there," wrote Bernard.
"I'm kind of afraid and yet curious to see what would happen if I attempted to convert 1 AUD into USD," writes John.
"Whoa! I wonder where I could get one of them driver's licenses that don't expire for 60 years," wrote Russ.
"Ah yes...The dreaded 'infinite spam notification loop'," writes Jeff J.
"While tracking a package via Israel Post's website it became so confused that it ATE the error!" Dor writes.
"As the year winds down I thought a good idea to review mutual fund options," Dan wrote, "However, I found myself wondering why they only rate against 0x8000 other funds and not 0xFFFF."
"Okay...I give up. Microsoft, you win. YES," Alan wrote.
Метки: Error'd |
CodeSOD: The Beginning of the Zend |
Karol found a program that needs to look at a timestamp, and determine if that timestamp is before or after an expiration date. The code that was handling this looked like this:
public function _isSmsCodeExpired($id)
{
$genDateStr = $this->db()->query('SELECT date FROM table')->fetchColumn();
if (empty($genDateStr))
{
return true;
}
$expireDateArr = array();
$intervalSec = 120;
$genDataTmp = explode(' ', $genDateStr);
$genDataArr = explode('-', $genDataTmp[0]);
$expireDateArr['year'] = $genDataArr[0];
$expireDateArr['month'] = $genDataArr[1];
$expireDateArr['day'] = $genDataArr[2];
$genDataArr = explode(':', $genDataTmp[1]);
$expireDateArr['hour'] = $genDataArr[0];
$expireDateArr['minute'] = $genDataArr[1];
$expireDateArr['second'] = substr($genDataArr[2], 0, 2);
$intervalMin = (int) $intervalSec / 60;
$intervalSec = (int) $intervalSec - ( $intervalMin * 60 );
$expireDateArr['second'] += $intervalSec;
$expireDateArr['minute'] += $intervalMin;
$expireDateArr['second'] += $intervalSec;
if ($expireDateArr['second'] > 60)
{
$expireDateArr['minute'] += 1;
$expireDateArr['second'] = $expireDateArr['second'] - 60;
}
if ($expireDateArr['minute'] > 60)
{
$expireDateArr['hour'] += 1;
$expireDateArr['minute'] = $expireDateArr['minute'] - 60;
}
if ($expireDateArr['hour'] > 24)
{
$expireDateArr['day'] += 1;
$expireDateArr['hour'] = $expireDateArr['hour'] - 24;
}
$daysInMonth = date("t", strtotime($expireDateArr['year'] . "-" . $expireDateArr['month'] . "-01"));
if ($expireDateArr['day'] > $daysInMonth)
{
$expireDateArr['month'] += 1;
$expireDateArr['day'] = $expireDateArr['day'] - $daysInMonth;
}
if ($expireDateArr['month'] > 12)
{
$expireDateArr['year'] += 1;
}
$expireDate = new Zend_Date($expireDateArr);
$now = new Zend_Date();
if ($now->isEarlier($expireDate))
return false;
else
return true;
}
The real fun part of this was the choice to use Zend_Date
, which not only parses date strings, but also has built in methods to add seconds to a date. Of course, even thats overkill
for solving this problem. Karol replaced most of the function with this:
return ((strtotime($genDateStr) + $intervalSec) > time()) ;
Метки: CodeSOD |
Security through Idiocy |
The ticket Bruce found in his help desk queue seemed innocuous enough on the surface. A user in the Finance department complained about not being able to create a file named Wire Transfer in their network folder. Being in finance, they did this many times in the past, but suddenly it no longer worked. Bruce assumed the user was doing something wrong, and that it would be resolved in five minutes.
Bruce navigated to the Finance network share, and attempted to create a new file named WireTransfer.txt
. A big, ugly ACCESS DENIED: Security Policy Violation! message box stared back at him. Thats odd… Bruce muttered, knowing he had write access to the directory. Ill bet Duane had something to do with this…
Duane was the resident security expert, which always made him Public Enemy #1. He was a kooky old-timer, with a short temper and a low tolerance for human interaction. Duane spent most of his time researching everything but the threats their systems were likely to face. Bruce slinked up to Duanes office, took a deep breath, and said, Hey, Duane, I got a ticket for…
Duane held up a hand to silence him, and continued staring at his screen. Im reading the FBI cyber-security threat assessments for the week. This is more important than your helpdesk crap.
Well, this is a critical issue, Duane. Finance needs to make this multi-million dollar wire transfer…
Hey! Duane interjected. Ive been thinking that one of our janitors looks suspiciously like D.B. Cooper. He pointed at the Americas Most Wanted printout on the wall. If you see him, or anyone else on this poster, let me know immediately! These criminal types can be anywhere. Even you could be one!
Uh huh… sure. Listen, is there any strange reason why no one can create a file named Wire Transfer? They need to do that to process wire transfers.
Duane rolled his eyes and threw his bald head back. Ohhh, no. No. That is strictly forbidden. Im not cleaning up after another wire transfer virus again! Duane explained that a month ago, a dozen employees received an email with a zip file named WireTransfer.zip
. It claimed to be from YOUR BANK HERE, and said to open the attachment to claim the spoils of a bank error in youre[sic] favour! Despite Duanes constant warnings about suspicious attachments, several users opened the file and infected their computers.
You see, Bruce, I deal with these attacks every day! This is my life. I flexed my security muscles and I took care of the problem. The network wont allow anything with the words wire and transfer in the name. That virus will never get through here again! Now, toddle back to your little help-desk station, and explain to our users, in small words, that they need to figure out another way to do transfers. Duane waited a beat, and when Bruce didnt vanish as quickly as he wanted. You need to leave my office. I have to go traverse the building perimeter to look for physical vulnerabilities! Duane leapt out of the chair, pushing Bruce ahead of him, while leaving his workstation unlocked.
Back in his own cube, Bruce contacted the user to see if they could name the file something different. Unfortunately, the inflexible, in-house application they used to process transfers only accepted files with names styled WireTransfer20141023
. Bruce resigned himself to a bleak future, where he escalated this to his manager, who then escalated to the finance manager, who would then go above Duanes head to the IT director, who would then force Duane to remove this fix. Duane would then catch wind of Bruces betrayal and vengefully pull some strings in the security community to get Bruces mug added to that Americas Most Wanted poster, right next to D. B. Cooper.
Метки: Feature Articles |
Announcements: Tokyo Meet-up & Site Fixes |
Tokyo readers -- I am once again visiting your fine city this week, and thought it'd be fun to try for another Tokyo/TDWTF meetup. Earlier this year, we got together at an izakaya for nomihoudai:
If you're unaware, nomihoudai is an easy way for a group of folks to get as much food and drink from the menu as they'd like for a set price over a set duration, without fussing over details like who ordered what and how many. While Japanese people often see this as a convenient offer, as an American I recognize it for the challenge it is -- and conquer it I shall!
So, if you're up for getting together this Friday (possibly Saturday?) in Shinjuku or Shibuya area, please drop me a note via the contact form or direct, apapadimoulis/inedo.com.
As for everyone else, thanks for submitting the bugs/issues/suggestions for the new site. We just fixed a bunch of them earlier today, and will continue to fix stuff as it comes in. Your help is greatly appreciated -- not just for submitting issues but for helping with fixed teh codez as well. If you're brave enough to explore the TDWTF codebase, I'll gladly send you some brand new TDWTF stickers with the updated logo.
Метки: Announcements |
CodeSOD: Is It Safer to Use Numbers? |
Mac didn't know anything about how the JavaScript on the search page worked, and he wasn't that great at CSS styling, but that didn't matter. He had his orders. As part of the latest round of enhancements, the front-end developer had added another search parameter which would be passed via the regular search URL, and the back end needed to be adjusted to accomodate. (You know... instead of 'http://initrode.com/search?a=xxx&b=yyy' it now was 'http://initrode.com/search?a=xxx&b=yyy&c=zzz'.)
No problem. Mac made his tweak in the code and ran a quick test...which failed instantly in a spectacular way. "WTF? It's a parameter. Must be already used..." he thought, but nope.
Digging deeper, Mac came upon the following:
public enum eQueryParametersCount { New = 2, Filtering = 3, Navigation = 6, SwitchView = 7 }
Odd. And then peppered throughout...
int iCount = Request.QueryString.Count; if (iCount != (int)eQueryParametersCount.New && iCount != (int)eQueryParametersCount.Navigation && iCount != (int)eQueryParametersCount.Filtering && iCount != (int)eQueryParametersCount.SwitchView ) { logger.Log("QueryString error: invalid querystring"); Response.Redirect(PageManager.ErrorPage); }
...and...
else if ((Request.QueryString.Count == (int)eQueryParametersCount.Filtering) && (!SetConfirmationMessage())) { if (!GetOverallQuality()) { logger.Log("QueryString error: r not found or invalid value"); Response.Redirect(PageManager.ErrorPage); } }
In short, the previous coders figured that it was much better to 'count' the number of parameters to determine what the user wanted instead of actually reading them. It also means you can never have 3 params because that is taken by a different enum.
As Mac set about tearing things apart he found himself considering how tough it would really be to pick up some web design skills.
 
Photo credit: Laineys Repertoire / Foter / CC BY
Метки: CodeSOD |
CodeSOD: Parallel SQL Queries |
Daniele worked at a pharmaceutical firm that had an old web application that allowed commercial customers to look up information. Since the data was quite complicated, there were numerous fields that needed to be queried in order to populate the form.
Unfortunately, as the amount of data in the system grew, the time to load the form grew as well. And grew. And grew.
Fortunately, the DBA in charge of setting up the underlying tables was actually quite capable at setting up tables with the proper relationships. For example, an address consists of street, city, zip, province and country. A country can contain multiple provinces which can contain multiple cities which can contain multiple zip codes, and so forth. As it was well organized, the database was not the problem; the source of the slowness was likely in the code.
And what code it was. The programmer that engineered this had to have revered this piece of brillance as well. They decided that they would support substantial data growth by querying the data in parallel. Yes, there would be a separate query for each field - run in a separate thread - in parallel. In other words, all of the queries had essentially the same where-clause (except for the joins); only the fields that were selected were different. For cases where one field depended upon another, the dependency was handled like this in the corresponding query classes, which all followed the same pattern:
class StreetQuery implements Thread { // Street names can be duplicated. We need to know in which // city this street resides in order to query for it. private CityQuery city; private boolean finished = false; public StreetQuery(CityQuery city) { this.city = city; } public boolean isRunning() { return !finished; } public void run() { // Wait until query on which we depend finishes while (city.isRunning()); // do query here, using any results from dependent queries as needed finished = true; } }
Daniele replaced all of that with a single stored procedure and the delays were gone.
One can't help but wonder if the author of the original code might have been helping themselves to a few too many sample products...
Метки: CodeSOD |
Announcements: The New Look is Here |
As you may have noticed, the site looks quite a bit different! As I mentioned back in March, it's been almost seven years since the look and feel of The Daily WTF has been updated, and I was getting pretty tired of the "2003ish" vibe the site had.
You guys gave some fantastic feedback to help guide the new design, and in July I shared a preview look. After some more feedback - both on the GitHub issue tracker and the forums - we put on the finishing touches and launched the site this evening.
Of course, it's not perfect - there are a few issues I found when writing this article, and I'm sure we'll find a lot more. But it's a big improvement and, because all of teh codez are on GitHub, it'll be a lot easier to fix things. So if you notice any glitches or have ideas for improvements, please post an issue, submit a pull request, post something in this article's discussion, or contact me directly.
Метки: Announcements |
Error'd: Sorry, but You Can't Do the Math |
"I guess that Intuit might have reasons for not allowing me to say Math was my least favorite subject in school," writes Alan R.
"I really wanted to buy an audiobook or three, but I doubt it would be prudent considering the price," wrote L. H.
Based on Petrea M's error, I have to wonder if there's also a TRUE and FALSE were also beginning in Hearthstone.
"Even if nobody is in line at McDonalds, turns out it can still get pretty busy," writes Bob W.
"At first, I was a little concerned that iFixit didn't carry the tool I needed to fix my Wii U," Tyler writes, "Thank goodness iFixit had it in stock!"
Jan wrote, "I'm not sure that these are the enterprise experts that I want to work with!"
"Sadly, I don't think that I'm smart enough to sign up," Sam P. writes.
"While browsing Careers 2.0, I noticed this Amazon job," wrote Caleb, "I don't think that applying would be good for my self-esteem."
http://thedailywtf.com/articles/Sorry,-but-You-Cant-Do-the-Math
Метки: Error'd |
A Stupid Comment |
Paul worked for a branch of the Defence Department in Australia, writing reams of C++ using the standard template libraries on a Linux box. On a typical afternoon, Paul checked some code into CVS with a comment:
Fixed bug 7551, see issue report 2119. Tinky Winky is my favourite Teletubby.
The addendum continued a long-running inside joke. At this point, the weird check-in comments were only funny because they were applied so consistently.
“Hey Paul, come over here a second!”
Paul’s friend and fellow developer Stan had initiated an impromptu gathering around his desk. Once Paul joined the huddle, Stan turned back to his computer screen. “I’m getting sick of these warning messages. You know, the ones our compiler throws because our namespace names are longer than 256 characters? I have trouble finding the real errors around these things. Do any of you know how to shut them off?”
“I do,” Paul said. “Here, let me show you what I’ve done.”
Paul supplied the name of a header file he’d been working on recently, then pointed to a line near the top. “See that pragma statement? It’ll suppress those warnings during compile time.”
// We don't need these stupid warning messages PMJ
#pragma warning( disable : 4507 34 )
“Oh, cool. I’ll try that,” Stan said. “Thanks, Paul!”
Life went on.
The trouble started a few weeks later, during a code review. Paul was asked to attend as an impartial reviewer for a project he had no involvement with. When he sat down in the meeting room, Burt the project manager was already there, giving him narrowed eyes.
“Paul,” Burt began, “are your initials PMJ?”
Paul frowned. “Yes… why?”
“The research scientists on my team are complaining that the word ‘stupid’ appears at the start of almost every header file.”
“What does this have to do with me?” Paul asked.
“Well, you’ve been touching all this code.” Burt brought up a Word document on his laptop, which was projected onto a screen in the meeting room. “I compiled some samples the scientists showed me. This right here, for instance…”
Paul blinked at the offending screenshot, which displayed the following two lines:
// We don't need these stupid warning messages PMJ
#pragma warning( disable : 4507 34 )
“Oh! That’s just code for suppressing warning messages during compile time,” Paul said. “I wasn’t the one who put it in here. One of the other developers must’ve copied and pasted it in wholesale.”
“‘Stupid?’” Burt demanded and accused all at once.
“That’s just a comment. It doesn’t actually do anything.”
“It makes the scientists angry,” Burt snapped. “It’s inappropriate- and it’s everywhere! They’re questioning the entire code base and the quality of our in-house software! I think we should take this offline for further discussion.” His glowering lifted as more project members filtered into the room for the code review.
A few days later, Paul was roped into a meeting with Burt, his own boss, and a very offended research scientist.
“Stupid! Do you think national defense is stupid?” the scientist fumed. “Do you think I’m too stupid not to notice? What good is the code in that stupid file, anyway?”
“I didn’t touch all those files,” Paul tried to explain.
“You initialed every line!” the scientist cried.
“Check CVS. I wasn’t the one checking in those changes!” Paul returned. “And who cares anyway, it’s just a stupid comment! It doesn’t do anything!”
“Again with the stupid! It reflects an attitude that is rude and demoralizing. How would you like it if I called your work stupid? Oh wait, I see you already did!”
“Let’s calm down here,” Paul’s boss intervened. “Paul, you said it’s a comment, right? Taking it out won’t change the behavior?”
“No, course not.”
“Well, then that means it’d be no problem for you to remove the word ‘stupid’ wherever it appears in the code base- right?” His boss smiled with the glow of a self-assured master diplomat.
It turned out Paul’s fellow developers had copied the warning suppression code to hundreds of files. Paul wrote a shell script that nuked all occurrences of the offending word and his initials, which he ran during a couple of code base merges when he had everything checked out.
Disaster averted- or so Paul thought. Paul’s boss reared his head again a few days later, frowning. “Is Tinky Winky really your favorite Teletubby? If you think you had too many meetings about stupid, think about how many I had. You’d better edit the log.”
Метки: Feature Articles |
A Stupid Comment |
Paul worked for a branch of the Defence Department in Australia, writing reams of C++ using the standard template libraries on a Linux box. On a typical afternoon, Paul checked some code into CVS with a comment:
Fixed bug 7551, see issue report 2119. Tinky Winky is my favourite Teletubby.
The addendum continued a long-running inside joke. At this point, the weird check-in comments were only funny because they were applied so consistently.
“Hey Paul, come over here a second!”
Paul’s friend and fellow developer Stan had initiated an impromptu gathering around his desk. Once Paul joined the huddle, Stan turned back to his computer screen. “I’m getting sick of these warning messages. You know, the ones our compiler throws because our namespace names are longer than 256 characters? I have trouble finding the real errors around these things. Do any of you know how to shut them off?”
“I do,” Paul said. “Here, let me show you what I’ve done.”
Paul supplied the name of a header file he’d been working on recently, then pointed to a line near the top. “See that pragma statement? It’ll suppress those warnings during compile time.”
// We don't need these stupid warning messages PMJ
#pragma warning( disable : 4507 34 )
“Oh, cool. I’ll try that,” Stan said. “Thanks, Paul!”
Life went on.
The trouble started a few weeks later, during a code review. Paul was asked to attend as an impartial reviewer for a project he had no involvement with. When he sat down in the meeting room, Burt the project manager was already there, giving him narrowed eyes.
“Paul,” Burt began, “are your initials PMJ?”
Paul frowned. “Yes… why?”
“The research scientists on my team are complaining that the word ‘stupid’ appears at the start of almost every header file.”
“What does this have to do with me?” Paul asked.
“Well, you’ve been touching all this code.” Burt brought up a Word document on his laptop, which was projected onto a screen in the meeting room. “I compiled some samples the scientists showed me. This right here, for instance…”
Paul blinked at the offending screenshot, which displayed the following two lines:
// We don't need these stupid warning messages PMJ
#pragma warning( disable : 4507 34 )
“Oh! That’s just code for suppressing warning messages during compile time,” Paul said. “I wasn’t the one who put it in here. One of the other developers must’ve copied and pasted it in wholesale.”
“‘Stupid?’” Burt demanded and accused all at once.
“That’s just a comment. It doesn’t actually do anything.”
“It makes the scientists angry,” Burt snapped. “It’s inappropriate- and it’s everywhere! They’re questioning the entire code base and the quality of our in-house software! I think we should take this offline for further discussion.” His glowering lifted as more project members filtered into the room for the code review.
A few days later, Paul was roped into a meeting with Burt, his own boss, and a very offended research scientist.
“Stupid! Do you think national defense is stupid?” the scientist fumed. “Do you think I’m too stupid not to notice? What good is the code in that stupid file, anyway?”
“I didn’t touch all those files,” Paul tried to explain.
“You initialed every line!” the scientist cried.
“Check CVS. I wasn’t the one checking in those changes!” Paul returned. “And who cares anyway, it’s just a stupid comment! It doesn’t do anything!”
“Again with the stupid! It reflects an attitude that is rude and demoralizing. How would you like it if I called your work stupid? Oh wait, I see you already did!”
“Let’s calm down here,” Paul’s boss intervened. “Paul, you said it’s a comment, right? Taking it out won’t change the behavior?”
“No, course not.”
“Well, then that means it’d be no problem for you to remove the word ‘stupid’ wherever it appears in the code base- right?” His boss smiled with the glow of a self-assured master diplomat.
It turned out Paul’s fellow developers had copied the warning suppression code to hundreds of files. Paul wrote a shell script that nuked all occurrences of the offending word and his initials, which he ran during a couple of code base merges when he had everything checked out.
Disaster averted- or so Paul thought. Paul’s boss reared his head again a few days later, frowning. “Is Tinky Winky really your favorite Teletubby? If you think you had too many meetings about stupid, think about how many I had. You’d better edit the log.”
Метки: Feature Articles |
CodeSOD: Line by Line |
In the bowels of a business unit, a director got a great deal on a third party software package. He bought it, without talking to corporate IT, and then was upset when it couldnt gracefully integrate with any of the corporate IT assets. Eager to throw good money after bad, the director hired his nephews consultancy to build an integration tool to make his new toy work.
A few months later, the users complained about performance, and somehow, fixing this thing became Jeffs problem. The process was simple enough: slurp enterprise data out of a text file, and pass the data on to the third-party tool. It didnt take Jeff long to figure out why it performed poorly:
Private Sub ProcessFile()
' prepare to do stuff
Do Until blnLastTime = True
Set fileReader = fso.OpenTextFile(strFileName)
If fileReader.AtEndOfStream = True Then
blnLastTime = True
Else
strTextLine = fileReader.ReadLine
End If
' actually do stuff
fileReader.Close
Delete_Line (strFileName)
Loop
fileReader.Close
End Sub
Private Sub Delete_Line(strFile)
Set fileReader = fso.OpenTextFile(strFile)
If fso.FileExists(strFile & "2") Then
fso.DeleteFile (strFile & "2")
End If
Set fileWriter = fso.CreateTextFile(strFile & 2)
If fileReader.AtEndOfStream = False Then
fileReader.ReadLine
End If
If fileReader.AtEndOfStream = False Then
strLine = fileReader.ReadAll
fileWriter.Write (strLine)
End If
fileReader.Close
fileWriter.Close
fso.DeleteFile strFile, True
fso.CopyFile strFile & "2", strFile, True
fso.DeleteFile strFile & 2, True
End Sub
Start by opening a file foo.txt. Read a single line from the file. Send it to the third party app. Close the file. Open foo.txt again. Open another file, called foo.txt2. Read the first line from foo.txt, again. Throw that away. Read the remainder of foo.txt, and write it to foo.txt2. Copy foo.txt2 back over foo.txt. Now, go back to the top of the loop and read a single line from foo.txt again.
So, for a 10,000 line file, this would perform 30,000 file open operations, write nearly 50 million lines, delete 20,000 files, and perform 10,000 copy operations. It didnt take Jeff very long to rewrite this to simply read the file, one line at a time. The runtime dropped from a few hours to less than a minute.
Метки: CodeSOD |