The Daily WTF
Christmas in the Server Room 2: A New Batch
Last year, we spent our Christmas looking at some Christmas movies and specials, and rated them based on the accuracy of their portrayal of the IT industry. We're going to continue with that this year. Just like last year, we'll rate things based on a number of floppy disks- 💾💾💾💾💾 means it's as accurate as Office Space, whereas 💾 puts it someplace down around Superman III.
GremlinsTechnology has conquered the world, but none of it actually works. As Mr. Futterman (played by the classic character actor Dick Miller) points out: they've all got gremlins in them. Except, thanks to a goofy dad's last minute Christmas gift and some careless 80s teens, the gremlins aren't just taking over technology, but the entire town with their goofy violence.
This was the most mentioned film left out last year. As far as tech industry representation, we've got a lot to discuss here. First, the father who purchases Gizmo- the Mogwai that becomes the source of all the gremlins- is an inventor. This is the 80s, and thus we're all recovering from the fads of Rubik's Cubes and Pet Rocks, so Randy Petlzer is trying to crash whatever the next fad is. He's got a collection of goofy gadgets, including the orange juicer above, which is itself a premonition of the Juicero startup, itself a goofy disaster of venture capital.
An independent inventor with no real business model but a bunch of goofy ideas also thinks he's a genius. Where have I heard that before? At least, he did "read the manual" (listened to the instructions given to him by the very 80s orientalist stereotype) and even communicated them, so credit to that. But nobody actually followed those instructions anyway, which leads to all the chaos. Do you think I used the word "goofy" enough to describe this movie? It's very goofy, and I think it's gotten goofier with age, honestly. Without nostalgia, I wouldn't call it good, but it is goofy.
The highlight of the film is Phoebe Cates's monologue about why she hates Christmas: a grisly tale about her father's death.
Rating: 💾
The ApartmentBud Baxter has an apartment conveniently close to work- so convenient that all the executives at his company bring their mistresses there. It's great for Bud's career, but less good for his reputation and his own personal love life.
So, this may be a stretch as Christmas movies go. It takes place around Christmas, but doesn't have a lot of Christmas themes. You know what it does have? A load of entitled management types who not only control Bud's life around the office, but his life at home, and definitely don't care about how that affects him. If this were in 2024, they'd be using bossware to track him and smart door locks to keep him out of his own house.
Rating: 💾💾💾
The Knight Before ChristmasA modern gal in Ohio has given up on love. A 14th century knight is magically transported to Ohio. Together, they discover the true meaning of Christmas- and love.
This is Netflix's stab at a Hallmark level Christmas movie. The whole thing revolves around the Ohio town having a Christmas tradition of erecting a "Christmas Castle" and doing a pseudo-Ren Faire thing every Christmas which is not, as far as I know, a thing anywhere, except perhaps a few small towns in Europe, where they have naturally occurring castles. Our gallant knight gets to be flummoxed by modern technology, like the Alexa, but basically figures all this stuff out over the course of a few days.
For IT accuracy, this is definitely:
Rating: 💾
However, it's also worth noting that the plot kicks off with our modern gal hitting the befuddled knight with her car at the Christmas Castle. They go to the hospital, where everyone assumes he's an actor from the Castle, and now has amnesia after being hit by a car. Since he has no ID, instead of providing medical care for what they believe to be severe brain damage, they just… let her take him home with her. So, if we were rating this for accurately representing the health care system in the US:
Rating: 💉💉💉💉💉
The Bear: Feast of the Seven Fishes"The Bear" focuses on Carmy, who is trying to turn his deceased brother's sandwich shop into a Michelin rated fine-dining restaurant. This episode flashes back to a Christmas before his brother died, and shows us what his family life was like, as his mother prepares the traditional "Feast of the Seven Fishes" for Christmas.
So, unlike Christmas Castles, Feasts of Seven Fishes are real. I grew up with the loud Italian family. My grandmother was so Italian she came through Ellis Island and also had one of these to point at her Christmas Tree. We did not do the complete Feast of the Seven Fishes, because nobody wanted to work that hard, but deep fried kippers were always featured. These were whole fish, which you'd eat. Bones, faces and all. That was fine, but I was honestly really there for the ginettes (everyone else calls them anise cookies, but we called them ginettes).
Our Christmas wasn't as stressful as Carmy's, and while folks got drunk, it was strictly "the old guys drink too much and fall asleep in their chairs" levels of drunk.
Rating: 🍝🍝🍝🍝🍝
Dominic the DonkeyWhen Santa wants to visit his "paisans" in Italy, his reindeer can't handle the hills- so he relies on his friend, Dominic, the Italian Christmas Donkey.
Look, I had to suffer through this song growing up, so now you do to. Hit play. Put it on loop. You're trapped in here with us. Jingety jing! HEE HAW HEE HAW! IT'S DOMINIC THE DONKEY.
Rating: 🫏🫏🫏🫏🫏🫏🫏🫏🫏🫏🫏🫏🫏🫏🫏🫏🫏🫏🫏🫏🫏🫏🫏🫏🫏
The Iron GiantAn alien war-bot crashes on Earth and gets amnesia, forgetting that it's a war-bot. Young Hogarth befriends the bot, and adventures ensue. Meanwhile 1950s Fox Mulder tries to track down the "monster" and put a stop to the Communist threat it represents.
I know what you're saying: "there's nothing Christmas here!" But, based on this list so far, amnesia is a Christmas tradition! Setting that aside, I'm not religious, but if we're talking about keeping the "Christ" in "Christmas", you can't do better than a giant robot who dies for our sins and is reborn days later. Honestly, the Bible could have used more giant robots. Maybe a Godzilla or two. While the movie leans hard into Superman as its metaphor for heroism, Superman has frequently been appropriated as a Christ metaphor. Which, there's a whole lot to unpack there, given that Superman's creators were Jewish.
This story features incompetent government agents trying to regulate technology they don't understand. While the film colors it in with Red Scare tones, it echoes the same constant shrieking from the FBI and NSA that regular citizens shouldn't have access to strong encryption (and they need a magical backdoor into all encryption algorithms to keep you SAFE). Or the countless "think of the children!" bills that attempt to police the Internet and always fail. Or the classic "Felony Contempt of Business Model"- the sections of the DMCA that make it illegal for you to refill your printer cartridges or jailbreak your phones.
Rating: 💾💾💾
[Advertisement] Picking up NuGet is easy. Getting good at it takes time. Download our guide to learn the best practice of NuGet for the Enterprise.Tracking Time
Mihail was excited when, many years ago, he was invited to work for a local company. At the time, he was in college, so getting real-world experience (and a real-world paycheck) sounded great. It was a small company, with only a handful of developers.
The excitement didn't last long, as Mihail quickly learned what the project was: parsing commit messages in source control and generating a report of how many hours a developer worked on any given task. It was a timesheet tracking application, but built on commit messages.
"This… seems like a bad idea?" Mihail told his supervisor. "Couldn't we just do this in a timesheet tool? Or heck, a spreadsheet? Accounting would probably prefer a spreadsheet."
"If we did that, people could edit their numbers," the supervisor responded.
Apparently they hadn't heard about amending commits. Or just… lying in the commit message?
Now, Mihail wasn't allowed to start working. A design document needed to be crafted first. So several senior developers went into a room, and hammered out the design. Three weeks later, they had a basic structure of five classes: components, which were made up of milestones, which were made up of tickets, which had contributors, which made commits. It wasn't a complicated design, so it was mystifying as to why it took three weeks to write. More problematic- the project had only budgeted a month, so Mihail was left with a single week for implementation.
One frantic week later, Mihail handed in his work. It was insufficiently tested, but more or less worked according to the design. He had to take a week off of work for exams, and when he returned from those exams, the senior devs had some good news and bad news. The good news: they were happy with his work! The bad news: during the week the design had been completely changed and needed to be rewritten.
So the rewrite began, with a new design, and once again, too little time left to do the work. Tests went out the window first, but "basic coding practices" quickly followed. The second version was less reliable and usable than the first. Then the Big Boss sent down an edict: this whole system should get its data from their bug tracker, which had SQL integration options.
Once again, it was all thrown away, and a new version began. Mihail started writing queries for the database, starting by joining the three key tables to produce the data they wanted. Then he read the new version of the design doc, published while he was working, and joined the five tables together they'd need. After combining the six tables the design doc called for, Mihail was starting to think the code he was writing was bad.
The workflow that the design called for offered it's own challenges. After writing the query which joined eight tables together, with a nest of subqueries and summaries, the query itself weighed in at 2,000kb. And that was just for one report- there were a dozen reports that were part of the project, all similarly messy, and all subject to rapidly changing design documents. The queries were all hard-coded directly in a Python script, and the design was explicit: don't slow down developers by using prepared statements, just use string concatenation (aka SQL injection) because we can trust our inputs! This Python script would run its reporting queries, and then dump the results into tables in the application's database. Then a web UI would pick up the data from the tables and show it to the user.
The only thing we can say about the results is that the web UI looked nice. The underlying horror that was the code was hidden.
With the project finally done, it was time to show it off to upper management. Mihail's supervisor starts demoing their system, and after a minute, the Big Boss pipes up: "Why do we need this?"
"Oh, well, it's a more flexible-"
"No. Why do we need this?"
"Time tracking is fundamental to our billing-"
"Right, but why do we need this? You know what, never mind. Do whatever you want with this, just make sure that all the data ends up in an Excel spreadsheet at the end of the month. That's what we send to accounting."
All in all, Mihail spent six months working on this project. Once complete, it was never used by anyone.
[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!CodeSOD: Empty Reasoning
Rachel worked on a system which collected data about children, provided by parents and medical professionals. There was one bug that drew a lot of fire: no one could report the age of a child as less than one. That was a problem, as for most of their users, child ages are zero-indexed. One of the devs picked up the bug, made a change, and went on to the next bug.
This was the fix:
if (!empty($_POST["age_at_time"]) || empty($_POST["age_at_time"]))The original check had been !empty- which may seem like it's ensuring a value was provided, but in PHP the empty function returns true for null values, empty strings, and anything falsey- like the integer 0.
So they made a change to cover the other case, and never stopped to ask themselves, "Would doing this be stupid?"
[Advertisement] Plan Your .NET 9 Migration with ConfidenceYour journey to .NET 9 is more than just one decision.Avoid migration migraines with the advice in this free guide. Download Free Guide Now!
Error'd: Hypersensitive
Rational Tim R. observed "When setting up my security camera using the ieGeek app there seem to be two conflicting definitions of sensitivity. I hope the second one is wrong, but if it's right, I really hope the first one is wrong."
"That's what happens when you use a LLM to write your date handling code!" crowed an anonymous Errordian. "Actually, it is interesting that they store dates as days since the beginning of the current Julian period."
Sarcastic Michael P. grumped "Oh, shoot. I hope I can find time to charge my doorbell before it dies. I guess Google Home takes a much longer view of time than us mere humans."
"Hello To You Too!" cheered Simon T. when he happened on this friendly welcome. Not really. What he really said was "We all love a hello world, but probably not on almost the front page of a national system." Maybe, maybe not.
Mathematician Mark V. figures Firefox's math doesn't add up. "Apparently my browser has cached 17 Exabytes of data from YouTube - on my 512GB laptop. That's some serious video compression!" Technically, it depends on the lighting.
[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!
CodeSOD: Zero Competence
Michael had a co-worker who was new to the team. As such, there was definitely an expected ramp-up time. But this new developer got that ramp up time, and still wasn't performing. Worse, they ended up dragging down the entire team, as they'd go off, write a bunch of code, end up in a situation that they couldn't understand why nothing was working, and then beg for help.
For example, this dev was tasked with adding timestamps to a set of logging messages. The logs had started as simple "print" debugging messages, but had grown in complexity and it was time to treat them like real logging.
This stumped them, as the following C# code only ever printed out a zero:
DateTime d = new DateTime(); int timestamp = d.Minute + d.Second + d.Millisecond; Console.WriteLine(timestamp + message);On one hand, this is a clear example of not understanding operator overloading- clearly, they understood that + could be used for string concatenation, but they seem to have forgotten that it could also be used for arithmetic.
I don't think this actually only ever printed out a zero. It certainly didn't print out a timestamp, but it also didn't print out a zero. So not only is the code bad, but the understanding of how it's bad is also bad. It's bad. Bad. Bad.
[Advertisement] Picking up NuGet is easy. Getting good at it takes time. Download our guide to learn the best practice of NuGet for the Enterprise.Coded Smorgasbord: The Saddest Words: What If
Conditional statements, we would hope, are one of the most basic and well understood constructs in any programming language. Hope, of course, is for fools and suckers, so let's take a look at a few short snippets.
Our first installment comes from Jonas.
if (!checkAndDelete(Definitions.DirectoryName, currentTime)); //Empty statementI appreciate the comment, which informs us that this empty statement is intentional. Why it's intentional remains mysterious.
Jonas found this while going through linter warnings. After fixing this, there are only 25,000 more warnings to go.
Brodey has a similar construct, but from a very different language.
If (Session.Item(Session.SessionID & "Origional") IsNot Nothing) Then End IfI have to give bonus points for the origional spelling of "original". But spelling aside, there's a hint of something sinister here- we're concatenating strings with the SessionId- I don't know what is going wrong here, but it's definitely something.
Our last little snippet comes from Midiane. While not a conditional, it shows a misunderstanding of either booleans or comments.
$mail->SMTPAuth = false; // turn on SMTP authenticationThe comment clearly is out of date with the code (which is the main reason we shouldn't repeat what is in the code as a comment). At least, we hope the comment is just out of date. A worse scenario is that setting the flag equal to false enables it.
[Advertisement] Picking up NuGet is easy. Getting good at it takes time. Download our guide to learn the best practice of NuGet for the Enterprise.CodeSOD: One Month
Joseph sends us a tried and true classic: bad date handling code, in JavaScript. We've all seen so much bad date handling code that it takes something special to make me do the "confused dog" head tilt.
var months=new Array(13); months[1]='January'; months[2]='February'; months[3]='March'; months[4]='April'; months[5]='May'; months[6]='June'; months[7]='July'; months[8]='August'; months[9]='September'; months[10]='October'; months[11]='November'; months[12]='December'; var time=new Date(); var lmonth=months[time.getMonth() + 1]; var date=time.getDate(); var year=time.getFullYear(); document.write(lmonth + ' '); document.write(date + ', ' + year);We create a 13 element array to hold our twelve months, because we can't handle it being zero indexed. This array is going to be our lookup table for month names, so I almost forgive making it one-indexed- January is month 1, normally.
Almost. Because not only is that stupid, the getMonth() function on a date returns the month as a zero-indexed number. January is month 0. So they need to add one to the result of getMonth for their lookup table to work, and it's just so dumb.
Then of course, be output this all using document.write, so we just know it's terrible JavaScript, all the way around.
[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.CodeSOD: A Little Extra Padding
Today's anonymous submitter supplies us with a classic antipattern: padding via switch:
string TransactionOrder = (string)dr["TransactionOrder"].ToString().Trim(); switch (TransactionOrder.Length) { case 1: TransactionOrder = "000" + TransactionOrder; break; case 2: TransactionOrder = "00" + TransactionOrder; break; case 3: TransactionOrder = "0" + TransactionOrder; break; default: TransactionOrder = TransactionOrder; break; }There's not much to say here, as we've seen this before, and we'll see it again. It's wrong, it's not how anything should be done, yet here it is, yet again. In this case, it's C#, which also has a lovely set of built-in options for doing this, making this code totally unnecessary.
[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.Error'd: Infallabella
The weather isn't the only thing that's balmy around this parts.
For instance Bruce, who likes it hot. "Westford, MA is usually bracing for winter in December, but this year we got another day of warm temperatures. The feels like temperature was especially nice."
And Robert who wailed "Not only do I have to enter Coupon Code Invalid:3, but the small print pretty much prevents me from using the coupon in the first place!" But did he TRY the code to see if it worked? You never know.
But not Steven B. who sagely noted that "Datetime is hard, even for Facebook."
And definitely not this incensed anonymous reader who ranted "What do you call web devs in 2024? Web devs, obviously. What do you call web devs that don't know in 2024 how to correctly implement email validation for top level domains with more than 3 letters? I'm still trying to figure that one out since nothing nice has come to mind and I am trying not to offend. And to be clear Falabella isn't some small business that can't afford to hire proper devs but one of the largest retail and online marketplaces in Latin America. Where in some countries you say Amazon, in most of Latin America you say Falabella."
That's it! Time's up for now, but not for Phillip J. who has just a little bit extra. Tick tock, Phillip.
[Advertisement] Plan Your .NET 9 Migration with Confidence
Your journey to .NET 9 is more than just one decision.Avoid migration migraines with the advice in this free guide. Download Free Guide Now!
CodeSOD: Ready Xor Not
Phil's company hired a contractor. It was the typical overseas arrangement: bundle up a pile of work, send it off to another timezone, receive back terrible code, push back during code review, then the whole thing blows up when the contracting company pushes back about how while the code review is in the contract if you're going to be such sticklers about it, they'll never deliver, and then management steps in and says, "Just keep the code review to style comments," and then it ends up not mattering anyway because the contractor assigned to the contract leaves for another contracting company, and management opts to use the remaining billable hours for a new feature instead of finishing the inflight work, so you inherit a half-finished pile of trash and somehow have to make it work.
Like I said, pretty standard stuff.
Phil found this construct scattered all over the codebase:
if cond1 and cond2: pass elif cond1 or cond2: # do actual workI hesitate to post this, because what we're looking at is just an attempt at doing a xor operation. And it's not wrong- it's an if statement way of writing (not a and b) or (a and not b). And if we're being nit-picky, while Python has a xor operator, it's technically a bitwise xor, so I could see someone not connecting that they could use it in this case- cond1 ^ cond2 would work just fine, so long as both conditions are actual booleans. But Python often uses non-boolean comparisons, like:
text = "" if text: print("This won't print.")This is playing with truthiness, and the problem here is that you can't use a xor to chain these conditions together.
if text ^ otherText: # do stuffThat's a runtime error, as the ^ is only defined for integral types. You'd have to write:
if bool(text) ^ bool(otherText): # do stuffSo, would it have been better to use one of the logical equivalences for xor? Certainly. Would it have been even better to turn that equivalence into a function so you could actually call a xor function? Absolutely.
But I also can't complain too much about this one. I hate it, don't get me wrong, but it's not a trainwreck.
.comment { border: none; } [Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!CodeSOD: A Set of Mistakes
One of the long-tenured developers, Douglas at Patrick's company left, which meant Patrick was called upon to pick up that share of the work. The code left behind by Douglas the departing developer was, well… code.
For example, this block of Java:
private String[] getDomainId(Collection<ParticularCaseEntity> particularCase) { // Get all domainId Collection<String> ids = new ArrayList<String>(); for (ParticularCaseEntity case : particularCase) { ids.add(case.getDomainId()); } Set<String> domainIdsWithoutRepeat = new HashSet<String>(); domainIdsWithoutRepeat.addAll(ids); Collection<String> domainIds = new ArrayList<String>(); for (String domainId : domainIdsWithoutRepeat) { domainIds.add(domainId); } return domainIds.toArray(new String[0]); }The purpose of this code is to get a set of "domain IDs"- a set, specifically, because we want them without duplicates. And this code takes the long way around to do it.
First, it returns a String[]- but logically, what it should return is a set. Maybe it's meant to comply with an external interface, but it's a private method- so I actually think this developer just didn't understand collection types at all.
And I have more evidence for that, which is the rest of this code.
We iterate across our ParticularCaseEntitys, and add each one to an array list. Then we create a hash set, and add all of those to a hash set. Then we create another array list, and add each entry in the set to the array list. Then we convert that array list into an array so we can return it.
At most, we really only needed the HashSet. But this gives us a nice tour of all the wrong data structures to use for this problem, which is helpful.
Speaking of helpful, it didn't take long for Patrick's employer to realize that having Patrick doing his job, and also picking up the work that Douglas used to do was bad. So they opened a new position, at a higher pay grade, hoping to induce a more senior developer to step in. And wouldn't you know, after 6 months, they found a perfect candidate, who had just finished a short six month stint at one of their competitors: Douglas!
.comment { border: none; } [Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!CodeSOD: While This Works
Rob's co-worker needed to write a loop that iterated across every element in an array. This very common problem, and you'd imagine that a developer would use one of the many common solutions to this problem. The language, in this case, is JavaScript, which has many possible options for iterating across an array.
Perhaps that buffet of possible options was too daunting. Perhaps the developer thought to themselves, "a for each loop is easy mode, I'm a 10x programmer, and I want a 10x solution!" Or perhaps they just didn't know what the hell they were doing.
Regardless of why, this is the result:
try { var index = 0; while (true) { var nextItem = someArray[index]; doSomethingWithItem(nextItem); index++; } } catch (e) { }This code iterates across the array in an infinite while loop, passing each item to doSomethingWithItem. Eventually, they hit the end of the array, and someArray[index] starts returning undefined. Somewhere, deep in doSomethingWithItem, that causes an exception to be thrown.
That is how we break out of the loop- eventually something chokes on an undefined value, which lets us know there's nothing left in the array.
Which puts us in an interesting position- if anyone decided to add better error handling to doSomethingWithItem, the entire application could break, and it wouldn't be obvious why. This is a peak example of "every change breaks somebody's workflow", but specifically because that workflow is stupid.
[Advertisement] Picking up NuGet is easy. Getting good at it takes time. Download our guide to learn the best practice of NuGet for the Enterprise.CodeSOD: Enterprise Code Coverage
Alice has the dubious pleasure of working with SalesForce. Management wants to make sure that any code is well tested, so they've set a requirement that all deployed code needs 75% code coverage. Unfortunately, properly configuring a code coverage tool is too hard, so someone came up with a delightful solution: just count how many lines are in your tests and how many lines are in your code, and make sure that your tests make up 75% of the total codebase.
Given those metrics, someone added this test:
public void testThis() { int i = 0; i++; i++; i++; i++; i++; // snip 35,990 lines i++; i++; i++; i++; }Keep adding lines, and you could easily get close to 100% code coverage, this way. Heck, if you get close enough to round up, it'll look like 100% code coverage.
.comment { border: none; } [Advertisement] Plan Your .NET 9 Migration with ConfidenceYour journey to .NET 9 is more than just one decision.Avoid migration migraines with the advice in this free guide. Download Free Guide Now!
Error'd: Doubled Daniel
This week, a double dose of Daniel D.
First he shared a lesson he titled "Offer you can't refuse a.k.a. Falsehood programmers believe about prices" explaining "Some programmers believe that new prices per month (when paid annually) are always better then the old ones (when paid monthly). Only this time they have forgotten their long-time clients on legacy packages."
Then he found a few more effs. "This e-shop required to create an account to download an invoice for order already delivered. Which is kind of WTF on its own. But when I pasted a generated 62 mixed character (alphanumeric+special) password, their form still insisted on entering 8+ characters. not correct. Well, because their programmers didn't expect somebody to paste a password. Once I did another JS event - e.g. clicked a submit button, it fixed itself."
And our Best Beastie in Black discovered "Anomalies in the causal structure of our particular 4-dimensional Lorentzian manifold have apparently caused this secure message portal belonging to a tax prep/audit company to count emails that haven't yet been sent by sender."
Traveler Tim R. struggled to pay for a visa, and reports this result. Rather than an error reported as success, we appear to have here a success reported as an error. "We're all familiar with apps that throw up an eror dialog with the error message as success but it's particularly irritating when trying to submit a payment. This is what happened when I tried to pay for an Indian visa with Paypal. To add insult to injury, when you try to pay again, it says that due to errors and network problems, you must check back in 2 hours before attempting a repeat payment."
Finally Robert H. is all charged up about Chevy shenanigans. "I thought one of the advantages of EV vehicles was they don't need oil changes?"
[Advertisement] Plan Your .NET 9 Migration with Confidence
Your journey to .NET 9 is more than just one decision.Avoid migration migraines with the advice in this free guide. Download Free Guide Now!
CodeSOD: Building Blocks
Eli sends us something that's not quite a code sample, despite coming from code. It's not a representative line, because it's many lines. But it certainly is representative.
Here's the end of one of their code files:
}); } } ); }); } ) ); } }); } } ); });I feel like someone heard that JavaScript could do functional programming and decided to write LISP. That's a lot of nested blocks. I don't know what the code looks like, but also I don't want to know what the code looks like.
Also, as someone who programs with a large font size, this is a special kind of hell for me.
[Advertisement] Picking up NuGet is easy. Getting good at it takes time. Download our guide to learn the best practice of NuGet for the Enterprise.CodeSOD: On VVVacation
As often happens, Luka started some work but didn't get it across the finish line before a scheduled vacation. No problem: just hand it off to another experienced developer.
Luka went off for a nice holiday, the other developer hammered away at code, and when Luka came back, there was this lovely method already merged to production, sitting and waiting:
vvv(x, y) { return typeof x[y] !== 'undefined'; }"What is this?" Luka asked.
"Oh, it's a helper function to check if a property is defined on an object."
Luka could see that much, but that didn't really answer the question.
First, it wasn't the correct way to check if a property existed. Mind you, actually doing those checks in JavaScript is a complicated minefield because of prototype inheritance, but between the in operator, the hasOwn and hasOwnProperty methods, there are simpler and cleaner ways to get there.
But of course, that wasn't what got anyone's attention. What caught Luka up was the name of the function: vvv. And not only was it a terrible name, thanks to the other dev's industriousness, it was now called all over the codebase. Even places where a more "correct" call had been used had been refactored to use this method.
"But it's so brief, and memorable," the developer said.
Luka was vvvery upset by that attitude.
[Advertisement] Keep all your packages and Docker containers in one place, scan for vulnerabilities, and control who can access different feeds. ProGet installs in minutes and has a powerful free version with a lot of great features that you can upgrade when ready.Learn more.CodeSOD: Layered Like Spaghetti
"We use a three tier architecture," said the tech lead on Cristian's new team. "It helps us keep concerns separated."
This statement, as it turned out, was half true. They did divide the application into three tiers- a "database layer", a "business layer", and a "presentation layer". The "database layer" was a bunch of Java classes. The "business layer" was a collection of Servlets. And the "presentation layer" was a pile of JSP files.
What they didn't do, however, was keep the concerns separated.
Here's some code from their database layer:
public synchronized StringBuffer getStocTotGest(String den, String gest) { StringBuffer sb = new StringBuffer("<table width=\"100%\" border=\"1\" cellspacing=\"1\" cellpadding=\"1\">" + "<tr bgcolor=\"#999999\">" + "<td>Denumire</td>" + "<td>Cant</td>" + "<td>PretVanz</td>" + "</tr>"); try { ResultSet rs = connectionManager .executeQuery("select (if(length(SUBSTRING(den,1,instr(den,'(')-1))>0,SUBSTRING(den,1,instr(den,'(')-1),den)) as den,um,pret_vinz,sum(stoc) as stoc from stmarfzi_poli where den like '" + den + "%' " + gest + " group by den order by den"); while (rs.next()) { sb.append("<tr><td>" + rs.getString("den") + "</td>"); sb.append("<td><div align=\"right\">" + threeDecimalPlacesFormat.format(rs.getDouble("stoc")) + " " + rs.getString("um") + "</div></td>"); sb.append("<td><div align=\"right\">" + teoDecimalPlacesFormat.format(rs.getDouble("pret_vinz")) + "</div></td></tr>"); } sb.append("</table>"); } catch (Exception ex) { ex.printStackTrace(); } return sb; }I guess a sufficiently motivated programmer can write PHP in any language.
This just has a little bit of everything in it, doesn't it? There's the string-munged HTML generation in the database layer. The HTML is also wrong, as header fields are output with td tags, instead of th. There's the SQL injection vulnerability. There's the more-or-less useless exception handler. It's synchronized even though it's not doing anything thread unsafe. It's truly a thing of beauty, at least if you don't know what beauty is and thing it means something horrible.
This function was used in a few places. It was called from a few servlets in the "business layer", where the resulting StringBuffer was dumped into a session variable so that JSP files could access it. At least, that was for the JSP files which didn't invoke the function themselves- JSP files which mixed all the various layers together.
Cristian's first task in the code base was changing the background colors of all of the rendered table headers. Since, as you can see, they weren't using CSS to make this easy, that involved searching through the entire codebase, in every layer, to find all the places where maybe a table was generated.
Changing those colors was Cristian's first task in the code base. I assume that Cristian is still working on that, and will be working on that for some time to come.
[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!CodeSOD: A Pair of Loops
Alexandra inherited a codebase that, if we're being kind, could be called "verbose". Individual functions routinely cross into multiple thousands of lines, with the longest single function hitting 4,000 lines of code.
Very little of this is because the problems being solved are complicated, and much more of it is because people don't understand how anything works.
For example, in this C++ code, they have a vector of strings. The goal is to create a map where the keys are the strings from the vector, and the values are more strings, derived from a function call.
Essentially, what they wanted was:
for (std::string val : invec) { umap[val] = lookupValue(val); }This would have been the sane, obvious way to do things. That's not what they did.
unordered_map<string, string> func(vector<string> invec) { unordered_map<string, string> umap; vector<pair<string, string*> idxvec; for(string name : invec) { umap[name] = ""; idxvec.push_back(make_pair(name, &umap[name])); } for(auto thingy : idxvec) { //actual work, including assigning the string thingy.get<1>() = lookupValue(thingy.get<0>()); } return umap; }I won't pick on names here, as they're clearly anonymized. But let's take a look at the approach they used.
They create their map, and then create a new vector- a vector which is a pair<string, string*>- a string and a pointer to a string. Already, I'm confused by why any of this is happening, but let's press on and hope it becomes clear.
We iterate across our input vector, which this I get. Then we create a key in the map and give it an empty string as a value. Then we create a pair out of our key and our pointer to that empty string. That's how we populate our idxvec vector.
Once we've looped across all the values once, we do it again. This time, we pull out those pairs, and set the value at the pointer equal to the string returned by lookup value.
Which leads us all to our favorite letter of the alphabet: WHY?
I don't know. I also am hesitant to comment to much on the memory management and ownership issues here, as with the anonymization, there may be some reference management that got lost. But the fact that we're using bare pointers certainly makes this code more fraught than it needed to be. And, given how complex the STL data structures can be, I think we can also agree that passing around bare pointers to memory inside those structures is a recipe for disaster, even in simple cases like this.
What I really enjoy is that they create a vector of pairs, without ever seeming to understand that a list of pairs is essentially what a map is.
In conclusion: can we at least agree that, from now on, we won't iterate across the same values twice? I think about 15% of WTFs would go away if we all followed that rule.
Oh, wait, no. People who could understand rules like that aren't the ones writing this kind of code. Forget I said anything.
[Advertisement] Keep all your packages and Docker containers in one place, scan for vulnerabilities, and control who can access different feeds. ProGet installs in minutes and has a powerful free version with a lot of great features that you can upgrade when ready.Learn more.Error'd: It Figures
...or actually, it doesn't. A few fans found figures that just didn't add up. Here they are.
Steven J Pemberton deserves full credit for this finding. "My bank helpfully reminds me when it's time to pay my bill, and normally has no problem getting it right. But this month, the message sent Today 08:02, telling me I had to pay by tomorrow 21-Nov was sent on... 21-Nov. The amount I owed was missing the decimal point. They then apologised for freaking me out, but got that wrong too, by not replacing the placeholder for the amount I really needed to pay. "
Faithful Michael R. levels a charge of confusion against what looks like.. Ticketmaster, maybe? "My card indeed ends with 0000. Perhaps they do some weird math with their cc numbers to store them as numerics." It's not so much weird math as simply reification. Your so called "credit card number" is not actually a number; it is a digit string. And the last four digits are also a digit string.
Marc Würth,
who still uses Facebook, gripes that their webdevs
also don't understand the difference between numbers and digit strings.
"Clicking on Mehr dazu (Learn more), tells me:
> About facebook.com on older versions of mobile browsers
> [...]
> Visit facebook.com from one of these browsers, if it’s available to download on your mobile device:
> [...]
> Firefox (version 48 or higher)
> [...]
Um... Facebook, guess what modern mobile web browser I'm viewing you, right now? [132.0.2 from 2024-11-10]
"
Self-styled dragoncoder047 is baffled by what is probably a real simple bug in some display logic reporting the numerator where it should display the denominator (2). Grumbles DC "Somebody please explain to me how 5+2+2+2+2+2+2+0.75+2+2=23. If WebAssign itself can't even master basic arithmetic, how can I trust it teaching me calculus? "
Finally Andrew C. has a non-mathematical digit or two to share, assuming you're inclined to obscure puns. "As well as having to endure the indignity of job seeking, now I get called names too!" This probably requires explanation for those who are not both native speakers of the King's English and familiar with cryptographic engineering.
[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.
Classic WTF: Documentation by Sticky Note
Anita parked outside the converted garage, the printed graphic reading Global Entertainment Strategies (GES) above it. When the owner, an old man named Brad, had offered her a position after spotting her in a student computer lab, she thought he was crazy, but a background check confirmed everything he said. Now she wondered if her first intuition was correct.
“Anita, welcome!” Brad seemed to bounce like a toddler as he showed Anita inside. The walls of the converted garage were bare drywall; the wall-mounted AC unit rattled and spat in the corner. In three corners of the office sat discount computer desks. Walls partitioned off Brad’s office in the fourth corner.
He practically shoved Anita into an unoccupied desk. The computer seemed to be running an unlicensed version of Windows 8, with no Office applications of any kind. “Ross can fill you in!” He left the office, slamming the door shut behind him.
“Hi.” Ross rolled in his chair from his desk to Anita’s. “Brad’s a little enthusiastic sometimes.”
“I noticed. Uh, he never told me what game we’re working on, or what platform. Not even a title.”
Ross’s voice lowered to a whisper. “None of us know, either. We’ve been coding in Unity for now. He hired you as a programmer, right? Well, right now we just need someone to manage our documentation. I suggest you prepare yourself.”
Ross led Anita into Brad’s office. Above a cluttered desk hung a sagging whiteboard. Every square inch was covered by one, sometimes several, overlapping sticky notes. Each had a word or two written in Brad’s scrawl.
“We need more than just random post-its with ‘big guns!’ and ‘more action!’” Ross said. “We don’t even know what the title is! We’re going crazy without some kind of direction.”
Anita stared at the wall of sticky notes, feeling her sanity slipping from her mind like a wet noodle. “I’ll try.”
Sticky Escalation Brad, can we switch to Word for our documentation? It’s getting harder to read your handwriting, and there’s a lot of post-its that have nothing to do with the game. This will make it easier to proceed with development. -AnitaTwo minutes after she sent the email, Brad barged out of his office. “Anita, why spend thousands of dollars on software licenses when this works just fine? If you can’t do your job with the tools you have, what kind of a programmer does that make you?”
“Brad, this isn’t going to work forever. Your whiteboard is almost out of room, and you won’t take down any of your non-game stickies!”
“I can’t take any of them down, Anita! Any of them!” He slammed the door to his office behind him.
The next day, Anita was greeted at the door by the enthusiastic Brad she had met before the interview. “I listened to reason, Anita. I hope this is enough for you to finish this documentation and get coding again!”
Brad led Anita into his office. On every wall surface, over the door, even covering part of the floor, were whiteboards. Sticky notes dotted nearly a third of the new whiteboard space.
“Now, Anita, if I don’t see new code from you soon, I may just have to let you go! Now get to work!”
Anita went to sit at her desk, then stopped. Instead, she grabbed a bright red sticky note, wrote the words “I QUIT” with a sharpy, barged into Brad’s office, and stuck it to his monitor. Brad was too stunned to talk as she left the converted garage.
The Avalanche“Are you doing better?” Jason called Anita a few weeks later. Their short time together at GES has made them comrades-in-arms, and networking was crucial in the business.
“Much,” she said. “I got a real job with an indie developer in Santa Monica. We even have a wiki for our framework!”
“Well, listen to this. The day after you quit, the AC unit in the garage broke. I came into work to see Brad crying in a corner in his office. All of the sticky notes had curled in the humidity and fallen to the floor. The day after he got us all copies of Word.
“Too bad we still don’t know what the title of the game is.”
[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.