Feed the-daily-wtf The Daily WTF

Favorite IconThe Daily WTF

Link http://thedailywtf.com/
Feed http://syndication.thedailywtf.com/TheDailyWtf
Updated 2024-05-14 15:17
Ten Days
Steffen is the tech lead for an online shop. It's the kind of online shop that sell items with large enough prices that financing is an important function. They offer loans through a payment provider, and the payment provider handles all of the details.Anything relating to finance is complicated, and loans can get very complicated, especially these shorter-term loans. Generating a payment plan for a customer's order means creating a list of all the expected monthly installments, including the due dates, the remaining principal on the loan after the payment, how much goes to principal repayment, how much goes to interest, and the new balance of the loan after interest is added. It's a lot of information, and it's information that the payment provider can provide.But, in the interests of keeping their application responsive when providing a potential payment plan to their end user, Steffen's company opted to implement their own financial calculations. For actual payment handling, they'd still let the payment provider handle it, but for showing the customer "if you order now, this is what your payment plan will look like!", they could do that all on their side.Or could they? While it's complicated to calculate out all the loan elements, it's also well understood. There are libraries for it, there are copy/pasteable code snippets for it. It was complicated, but not hard.After ten days of effort, however, it wasn't working. Their test plan was simple: since the payment provider was the source of truth, they generated 10,000 sample payment plans. They fed those plans into their system, then into the payment provider's system, and then compared the results. And the results mostly matched. Mostly.There were a handful of test cases that were off by hundreds of Euros. That was way too much. Steffen called a meeting with the payment provider's technical staff, and developers from both companies sat down to go through the code, line by line.It was a long, tedious meeting, and while questions were raised about the varying implementations, by the end of the meeting, both companies agreed: the code was correct. But the output was wrong. The meeting ended with nothing resolved.So Steffen grabbed one of the developers, and they sat down to go through the test cases. They chose the one which had the largest deviation from the payment provider's values, and walked through each month of the payment plan.On the first month, both Steffen's code and the payment provider were in perfect agreement. But on the second month, Steffen's code said it was €932.28, while the payment provider said that it was €631.54. That was more than €300 off. But on the third month, things got weirder: the payment provider's plan said that the amount of interest owed went up. Loans don't work that way: as you pay the principal, the amount of interest you pay each month goes down. "Do you think they got it wrong?" Steffen wondered.It seemed promising, but then Steffen looked at the results in more detail. They had generated 10,000 random sample loans. This included random dates ranging from antiquity all the way out to the 30th century. It was very thorough testing.This particular loan's first due date was October 1st, 1582. When Steffen spotted that, he laughed and turned to the developer. "This is a joke, right?" When the developer didn't see the humor, Steffen explained.You see, Steffen didn't start life as a software developer. Before moving into the industry, he worked as a professional historian. And October 1582 was a very special month in history. A unique point in history: it was the month the Western world shifted from the Julian calendar to the Gregorian calendar.The Julian calendar assumed a year was exactly 365.25 days, which is not correct. Following that rule adds an extra leap day roughly every century. The Gregorian calendar was more precise, and mostly accurate about such thing. But to shift calendars, the Greogrian calendar needed to be synced with the seasons. That meant removing a few centuries worth of extra days left over from the Julian calendar. Call it "paying down calendrical debt". So, October 4th, 1582 was followed by October 15th, 1582. Ten days just vanished, and October 1582 had only 21 days in it.The payment provider's calendar system handled this perfectly well. Steffen's calendar system did not. That explained why they over-charged for October, and it also explained why it seemed like the interest payment went up- November 1582 was a normal, 30-day November.Since they would never be originating loans in the 16th century, Steffen's team generated a new set of test data, all after the start of the 21st century. This solved the problem, and after fixing a few minor bugs, their implementation matched the payment provider's.In the end, the Pope removed ten days from October 1582, and Steffen's team put them back, spending almost exactly that time on fixing this bug. [Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.
CodeSOD: Exceptional Numbers
"When handling user input, make sure to handle exceptions," is good advice. But sometimes, that can lead you astray.Bob is a junior programmer surrounded by veterans with 20+ years of experience. Normally, this means that when there's something unusual in the code, Bob writes it off as the senior devs vast experience. But not this time.
CodeSOD: Inside a Box
Yesterday, among many many problems in that gigantic switch statement, we highlighted one line that was a real mess of mixing Java's primitive/object types.(new Integer(1).equals(job.getSource().getLength()))Well, Daniel has an even worse example, but this one comes with an origin story.Many, many years ago, in the early 2000s, Daniel worked for a company that made banking software. As this was the early 2000s, their flagship product remained a text-based UI accessed via a terminal emulator (or, in some rare cases, even dumb terminals). Obviously, continuing this TUI approach wasn't going to work in the future, so the company needed to pivot to a Java-based web application.The CEO set the direction: "We need a modern, web-based interface to sell banks. How much would it cost to implement that?" Well, Daniel's team put together the estimate, which contained a large number of trailing zeroes before the decimal point. Too many, from the CEO's perspective, so the CEO went shopping for a third-party developer who could deliver the software on the cheap.Again, this was the early 2000s, which meant the CEO was filtering through a dozen different obscure offshoring companies. The CEO wasn't impressed by most of them, but one offshore company came to the meeting with a wireframe of the application built in PowerPoint. The CEO was impressed that they already had a UI where you could click buttons and navigate to the next screen, and took this to mean that they were basically done already. He wrote them a check for an amount in the millions, and off they went to work.Many months later, the offshore team handed off the code. The first time, it didn't build. The second time, what unit tests there were didn't pass. The third time, it didn't build again. By the fifth time, the offshore team handed them Java code which would build and run, and only crash unexpectedly some of the time.This code used certain… patterns. The same basic approaches to doing simple tasks were reused everywhere, because clearly this code base was implemented by copy-pasting snippets from other projects, from elsewhere in this project or from the first hit on a search result.On such pattern was how they handled passing primitive types around:
CodeSOD: Switching Jobs
If you have an object, say a Job, which can be in multiple states, you'll frequently need to execute different code, depending on the state. Enter the ever useful switch statement, and all those problems are solved.Or are they? Reva found this Java code. Enjoy your 112 line switch statement:
Error'd: Occidentally
We like to think of Error'd as a safe place for pedants.
CodeSOD: Wearing a Mask
Just because someone writes in C, and not some more modern language doesn't mean they're going to be an expert in how to operate on binary values.Carl W found this bit of C code with a simple goal: count the number of trailing zeroes in a 32-bit integer. At least, that's what the function name tells us. Reading the logic, I'm less certain.
CodeSOD: For Mere Mortals
Repentinus submitted a pull request to a project he was working on. The Python code Repentinus submitted was this:
CodeSOD: Retern your Linter
Today, let's just start with a single line of Java code, from Rich.
CodeSOD: A Fairly Generic Comparison to Make
Some languages support operator overloading. Others, like Java, do not. There are good arguments on either side for whether or not you should support the feature, but when you don't, you need an easy way to get the effects of operators without the syntactic sugar.For example, if you have a custom class, and you need a way to perform comparisons on them, you may choose to implement the Comparator interface. This allows you to add some kind of comparison to an object without actually touching the object's implementation. For example, you might do something like:
Error'd: Paris in the the Spring
Dating from a few months back, our opening submission for the week is only funny if you don't see it as a painful forecast of some comingsummer in the City of Lights. Keeping with the theme of trapped systems, mostly Windows, here follow more multinational kiosk misadventures."Wear sunscreen," warns Thomas, temperately. "It's unseasonably warm."
CodeSOD: A Proper Mode of Address
One of the advantages of interpreted languages, like Python, is that when your vendor ships a tool that uses Python… you can see how the Python bits actually work. Or maybe seeing how the sausage is made is a disadvantage?Delana's vendor tool needs to determine the IP address of the computer in a platform independent way. The "standard" way of doing this in Python is to check the computer's hostname then feed that into a function like one of these which turns it into IP addresses.Those methods should behave more-or-less the same on both Windows and Linux, so checking the IP address should be a simple and short function. Let's see how Delana's vendor did it:
CodeSOD: A Graceful Exit
Kaci had one of "those" co-workers who didn't believe in source control. As you modified code, you'd just comment out bits and pieces, maybe replace some of it. That way you could see how the code evolved without having to learn how to use git log correctly.At least, that was the rough argument. But it meant that when Kaci wanted to understand why this block of PHP code existed, she needed to ask the developer:
CodeSOD: Not to Contradict You…
Sometimes, readers submit code and say, "every line is wrong!" Usually, they mean that every line contains a bad choice, or represents a bad way of accomplishing the program's goal, or there's a series of compounding mistakes.David sends us a block which… well, yes, every line is wrong, because every line contradicts every other one.
CodeSOD: Magical Thinking
I have a very casual interest in magic tricks. I certainly don't have the patience to actually learn to perform any well, but I enjoy watching them and piecing together how they're done. What really captures my interest is that actually performing a trick is about following a well-defined path, and by following that path you can achieve incredibly impressive effects. But if you just see the effect without understanding the path, and try and replicate it yourself, it's probably not going to work.In programming, there are certain things I consider "frickin' magic". They can create impressive effects, but the actual mechanism is concealed behind enough layers of abstraction that, if you don't stick to the carefully defined path, you can make some mistakes.Object-Relational Mappers and .NET's LINQ features leap to mind as peak examples of this. We have a lot of LINQ related WTFs on the site.Today's is a simple one, which highlights how, when one attempts to replicate the magic without understanding it, problems arise.
Error'd: Deal of a Lifetime
Frequently we are sent submissions harking from that rainforest retailer,or the other one, or one of the smaller ones. It doesn't matter which,the wtferry is limited as these are almost always just some hacksupplier uploading bogus data. TRR only cares about speedy delivery,and TOO cares about being cheapest, while OOTSO are just trying to keep theirbricksnmortar shops alive. I don't usually run these, but this weekI've got a bunch of them saved up so I'm giving you six for the priceof NaN.
CodeSOD: A Bit Overcomplicated
Lets say you have a 64-bit integer. You want the first 42-bits. Now, if your language has a bitshift operator, you'd be tempted to do something like largeNumber >> 22.But what if your language also has all sorts of advanced stream processing and map functions? It'd be a shame to not use those. Tarah's shop uses Rust, and thus they do have all those exciting advanced stream processing. Her co-worker decided they just needed to be used:
CodeSOD: On Error Goto Anywhere but Here
One of the big pieces of advice about using exceptions and errors is that they shouldn't be used for flow control. You catch an exception when an exceptional event happens, but you don't, for example, throw an exception to break out of a loop.Unless you're Python, which throws exceptions to break out of loops. That's just how iteration works. But we're not here to talk about Python.If a sufficiently motivated programmer can write LISP in any language, today's code, found by Maxi attempts to write Python in VB.Net. This snippet represents a general pattern around fetching data from temporary files.
CodeSOD: Changing Your Type
Alex sends us some Objective-C code which… well, let's just say that the code is suspicious looking, but there's nothing clearly bad about it.
CodeSOD: Select Orders
Some time ago, Will started a new job- a four month contract to take an old, ugly DOS application and turn it into a new, shiny VisualBasic 6 application. "And," the new boss explained, "the new program is almost done anyway. It's just that the last guy left, so we need someone to take it over the finish line."A key feature was that it needed to be able to fetch PDF files stored on a shared network drive. The order numbers were serialized, but the PDFs themselves were organized by year, creating file paths like I:\ORDLOG\2007\172.pdf. Now, in this particular block of code, one had access to both the ordnum and the ordyear, so constructing this path could be a trivial exercise. The previous developer did not take the trivial path, though.
Error'd: It's Funny Because It's True
CodeSOD: Extensioning Yourself
It's bad news when you inherit a legacy PHP CMS. It's worse news when you see that the vast majority of the files were last changed in 2002 (of course there's no source control).That is the unfortunate position that Elda found herself in.Like most CMSes, it needed to let users upload files. But we don't want to let users upload any arbitrary file, so we need to check that the file extension is correct. I mean, ideally, we want to check that the file is a valid file of the appropriate type so we don't serve up badfile.exe.mp3, but for an ancient PHP CMS just checking the extension is likely asking a lot. Especially when we see how this code performs that check.
CodeSOD: All the News You Need
Alexandar works with a veteran software architect. It's important to note here that a veteran is someone who has had experience. It certainly doesn't mean that they learned anything from that experience.This veteran was given a task to write a C# method to populate a user's news feed. The goal was to find the five most recent news articles and add them to the list. Now, this is a large scale CMS, so those articles need to be fetched from ElasticSearch.This was their solution:
CodeSOD: Without Any Padding
Years ago, Aleshia W started a job in a VB.Net shop. There's a lot I could say about those kinds of environments, but I'd really just be padding out the article, so let's just get right to the code- which pads out a Year string.
CodeSOD: Ordering the Hash
Last week, we took a look at a hash array anti-pattern in JSON. This week, we get to see a Python version of that idea, with extra bonus quirks, from an anonymous submitter.In this specific case, the code needed to handle CSV files. The order of the columns absolutely matters, and thus the developer needed to make sure that they always handled columns in the correct order. This led to code like this:
Error'd: By The Clicking On My Thumbs
Music fan Erina leads off this week with a double contraction!"Who knew Tom Waits was such a gravelly-voiced Relational Databasepoet?" she Mused. "You'd've thought that SQL modes wasmore of an indy garage esthetic." You might've, Erina, but I wouldn't've.
CodeSOD: Where You At?
Validating email addresses according to the actual email specification is more complicated than you usually think. Most homebrew validation tends to just get something that's relatively close, because hitting all the rules requires some fancy regex work. And honestly, for most applications, "pretty close to correct" is probably fine. If you actually care about collecting valid email addresses, you'll need to actually send mail to the address and have the user confirm receipt to "prove" that the email address is real, valid, and actually accessible.Still, some "close enough" solutions are better than others. Jon found this C# code:
CodeSOD: Validate Freely
Validation highlights the evolution of a programmer as they gain experience. A novice programmer, when given a validation problem, will tend to treat the string like an array or use substrings and attempt to verify that the input is the correct format. A more experienced programmer is going to break out the regexes. A very experienced programmer is going to just find a library or built-in method that does it, because there are better ways to use your time.Andrea provides a rare example of a developer on the cusp between regexes and built-in methods.
CodeSOD: Putting the File Out
There's a lot of room for disagreement in technology, but there's one universal, unchangeable truth: Oracle is the worst. But a second truth is that there's nothing so bad a programmer can't make it worse.Someone at Ben's company needed to take data from a database and write it to a file. That file needed to have some specific formatting. So they used the best possible tool for the job: a PL/SQL stored procedure.Now, PL/SQL is a… special language. The procedural elements it adds to SQL have a distinctly "we want to sell this to mainframe programmers" vibe, which makes the syntax verbose and clumsy. It frequently creates situations where things which should be easy are incredibly hard, and things which should be hard are impossible. But it's technically a feature-rich language, and you can even write web servers in it, if you want. And if you want to do that, you either work for Oracle or you should go work for Oracle, but certainly shouldn't be allowed out to mix with the general public.In any case, Ben's predecessor decided to generate a carefully formatted text file in PL/SQL, and had… their own way of accomplishing things.
CodeSOD: The Hash Array
When Arbuzo joined a new team, they helpfully provided him some sample code to show him how to interact with their JSON API. It was all pretty standard-looking stuff. If, for example, they fetched a Customer object, it would have some fields about the customer, and an array containing links to orders that customer had made. One of the samples helpfully showed iterating across the orders array:
Error'd: Innocents Abroad
This week's opening Error'd submission required a bit of translation forthe monoglots among us, but it was worth the work. Not speaking even een beetje of Dutch, I was forced to use Google's own translationservice to see what it was that had so worried our friend Sebas. And it's a doozy.
CodeSOD: Just a Few Questions
Pete has had some terrible luck with the lead programmers he's worked with. He's had a few which are… well, they don't take feedback well. Like his current team lead, who absolutely doesn't let any of the other developers review or comment on his code. "Don't ask me questions, you should know this already," is a common refrain. Speaking of questions:
CodeSOD: A Parser Par Excellence
Jan's company has an application which needs to handle an Excel spreadsheet, because as I'm fond of pointing out, users love spreadsheets.The JavaScript code which handles parsing the spreadsheet contains… some choices. These choices caused it to fail on any spreadsheet with more than twenty six columns, and it's not hard to see why.
CodeSOD: Time Sensitive Comments
One of the arguments against comments in code is that they create a need to have two things updated: the code and the documentation have to be kept in sync. Inevitably, they'll drift apart.David works with a junior developer who came onto the team with strong opinions about, well, everything. One of those strong opinions is that every single line needs to have comments. Each and every one.This is the end result:
CodeSOD: A Little Extra Space
Folks who first learned to type on typewriters tend to prefer putting two spaces after a period. Most of the rest of us prefer just one. And this may have caused a performance problem.Rob's application had a quick search feature to track down customer claims. One day, the quick search was running quickly and efficiently. A user could type in a claim number, hit enter, and a moment later their screen would show the claim. Suddenly, it slowed down. It wasn't just the gradual decline of growing data or stale statistics or bad indexes. It was a code change, and it didn't take long to find the problem:
Error'd: Malice Reflected
In the wake of yet another extraordinary ransomware attack, most businessesare finally beginning to implement the sorts of security measures they knewall along they should put in place. "Someday soon, when we get the time."Some writers have been calling it "unprecedented" but you and I know just how precedented it really is.Loyal reader Aubrey leads off with an insider report,writing "Corporate IT recently migrated the entire companyto a new antivirus program, and it seems to have flagged*its own update* as likely malware." That's what we callfastidious.
CodeSOD: Another Iteration
One of the "legacy" PHP applications needed a few bugfixes. "Legacy" in this case, means "written by a developer who doesn't work here anymore", so mostly everyone tried to dodge getting those bugfixes assigned to them. Joe was taking a three day weekend at the time, so a helpful co-worker assigned the tickets to him.The code wasn't an absolute disaster, but it suffered from being written by a "smart" programmer. Since they were so smart, they couldn't just do things using the basic language constructs, they had to find clever ways to abuse them.For example, why would you write a for loop, with a counting variable, when you could do this instead?
CodeSOD: Constantly Querying
Arguably, the biggest problem with SQL as a query language is that we usually execute SQL statements from inside of some other programming language. It tempts us into finding quick hacks to generate dynamic SQL statements, and if we do it the quick way, we find ourselves doing a lot of string concatenation. That way lies SQL injection vulnerabilities.Constructing SQL statements by stringing together text is always a bad idea, even if you're still using query parameters. There's a reason why most modern database wrappers provide some sort of builder pattern to safely construct dynamic queries. Even so, everyone wants to find their own… special way to accomplish this.Take this sample from Sciros:
News Roundup: A Brillant Copilot
The story of the week in software development is Github's Copilot, which promises to throw machine learning at autocomplete for a "smarter" experience.Notably, one of their examples highlights its ability to store currency values in a float. Or to generate nonsense. Or outputting GPLed code that was used in its training set.That last one raises all sorts of questions about copyright law, and the boundaries of what constitutes fair use and derivative works, and whether the GPL's virality can "infect" an ML model. These are questions I'm not qualified to answer, and that may not have a good answer at the moment. And certainly, the answer which applies to the US may not apply elsewhere.Besides, copyright law is boring. What's fun is that Copilot also spits up API keys, because it was trained on open source projects, and sometimes people mess up and commit their API keys into their source control repository. Oops.And even their examples don't really constitute "good" code. Like their daysBetweenDates, straight from their website:
Classic WTF: Consultants of the Crystal Citadel
Error'd: The Past is Prologue
Last week we lightly brushed on the novel conspiracy theory thatperhaps the HBO hullabaloo had been intentionally inspiredby their social media team, and suggested you might join them.Apparently the media managers at Subway had been hungering forpublicity as well.TDWTF sandwich specialist Carlos buttered us up, saying "I'm sure you've receiveda ton of these already [ed: we hadn't], but what's one more?"
CodeSOD: Echo echo echo echo
Good logging is an invaluable tool for debugging and diagnosing your applications. No logging makes that job harder, but not as hard as bad logging. Logging that doesn't log useful information, that doesn't help highlight the flow of the application, etc.Volker was trying to track down a bug that was only raising its head in production, but the log files were spammed with nothing more than "echo". Millions and millions of log lines that were just that. A quick CTRL+F through the code later, and the offending method was found:
CodeSOD: Repository, Man
C++ templates are, notoriously, a Turing complete language on their own. They're complicated, even when you're trying to do something simple. Related languages avoid that complexity, and favor generics. Generics are templates with all the sharp bits filed down, but still powerful enough to make datastructures that don't need to know the details of the data they're operating on.This article isn't about generics, though. It's about ORMs, specifically the .NET Entity Framework system. It's common to use the Repository Pattern to abstract out data access a bit. Coupled with the underlying DBSet class, which roughly represents a database table, you can easily create repository objects and related mocks for testing.Making your repository class generic is also a good idea. Basic CRUD operations don't really need to know the details the data they're operating on. You can create one repository instance for each type of data you need to store- each table- all based on the same generic type.But it's possible to make your repository too generic. Take Paulina's company. Here's a few key lines from their generic repository.
CodeSOD: Big Number One
Patsy's company has a product that's "number one" in their particular industry. It generates lots of revenue, but a lot of the code dates back to the far-off year of… 2017. Coding practices were… uh… different, four years ago? Especially in the rapidly maturing language of… Java?Within Patsy's company, they do refer to their 2017 code as "legacy" code, and it has left quite the legacy. For example, here's how they parse numbers:
CodeSOD: Out of You and Umption
When we write code, we have certain assumptions. Most of these times, these assumptions are fine, and allow us to skip past some hard decisions. But sometimes, these can lead to problems. The infamous example would be the Y2K problem- the assumption that nobody'd be running this program in 40 years seemed reasonable at the time. We might assume that nobody'd type too fast. We might assume our sensor is accurate.Darren sends us some code that has a much milder assumption than those:
Error'd: Production Testing To The Max
The most eventful day in Error'dland narrowly missed our publication windowlast week. As everyone must surely know by now, somebody at HBO Max wastesting in production. And the Internet blew up.
Classic WTF: The Mainframe Database
Classic WTF: Front-Ahead Design
Classic WTF: Gaming the System
CodeSOD: Classic WTF: The Great Code Spawn
Error'd: Some Sunny Day
Greenville resident Terry K. discovers the weather is on the fritz today. "The chanceOfTemplateFailure seems high today," says he.
...11121314151617181920...